PhotoShop插件开发笔记

2,065 阅读8分钟

本文写于2018年。中文世界关于PhotoShop插件开发的内容比较少,该文记录了对一些基础概念的理解,可能对初学者有些帮助

本文涉及的ps是ps cc 2017 && 2018

Photoshop

  1. 智能对象的内容不仅仅可以是图片,也可以是psd、svg等文件类型

Photoshop scripting

  1. ExtendScript和JavaScript区别

    ExtendScript是Adobe开发的脚本语言,基于JavaScript,针对Adobe的产品特性,增强了脚本语言的功能。后缀名是jsx

    ps:Windows系统中如果双击.js的文件,系统会使用微软的js解析引擎来执行脚本。而改为jsx则不会,而是优先使用Photoshop的脚本即系引擎来执行。

  2. ps怎样执行脚本

    • 将脚本文件放到ps.app/Presets(mac)中,重启ps,在file -> scripts中执行
    • file -> browse -> 选择脚本执行
  3. photoshop object model

    也称为DOM(Photoshop Document Object model),是通过脚本文件操作ps中文件的API

    其中包含了许多类和方法。比如appdocumentpreferences

  4. ExtendScript SDK中也包含了UI的组件和网络组件

    但网络组件是socket的请求,没有上层封装。估计用起来不爽。

  5. ExtendScript中一些小技巧

    • layers["Layer1"] && layers.getByName("Layer1"),通过图层名称获取图层
    • layer.bounds是取值以左上角为原点,bounds属性是layer的四个顶点的值组成的数组----[minX, minY, maxX, maxY],所以访问width时需bounds[2] - bounds[0]
    • 图层合并后的图层的尺寸是所有图层的最小包围矩形,此处所说的尺寸不一定是bounds
    • 上面说的最小包围矩形,有一种情况例外,就是有剪贴蒙版的情况
    • layer的bounds属性,是图层有像素值的点组成的四个点即不包含透明部分。如果要看包含透明的大小,需要command+T,通过参考点才能看到
    • 直接用ps 打开image时,可能是索引模式,要记得先convertRGB,否则后续操作可能不work
    • 转智能对象方式来替换图层内容时,一般会新建一个图层,然后转为智能对象。后续操作中,新建图层时的变量就不能再用了,要重新获取一遍图层。
    • saveas要比export快
    • app.open(new File(""));,如果出错会抛出异常
    • 执行shell命令时,文件路径中不能包含空格,空格要是用\空格代替
    • 学习了剪贴蒙版和图片蒙版
    • 怎么从画布整体上,进行缩放?
      • resizeImage(但速度比较慢)
      • 创建一个图层,将图层涂色并弄成透明(opacity=0),然后选中要进行缩放的图层和这个空白图层(script不方便选中多个图层,可以将这两个图层放到一个图层组中,将图层组转为智能对象),创建为智能对象。缩放这个智能对象就可以了(这个速度快)
    • 由于对document进行裁剪的操作比较耗时,可以用新建文档的方式进行替换
    • 图层复制到另一个文档中后,图层的bounds不会变
    • document.artLayers[0]是ps树状图层图中最上面的图层
  6. ExtendScript的坑

    • document.saveas方法保存的图片比较大,document.export使用saveforweb导出的图片比较小
    • saveas的操作可以使用command+option+z进行撤销,但export却不可以
    • 通过evalScript进行html端和jsx端交互时,返回和传入的只有一种数据类型,就是字符串,包括jsx返回其他数据类型时。
    • UnitValue使用说明
      • var w = UnitValue(1, "px");--1像素/var w = UnitValue(1, "in");
      • UnitValue.value
      • bounds的类型实际上是UnitValue的数组形式
    • exportDocument时,导出文件名中如果包含空格,导出后会被替换为横线
    • extendscript中用ps打开有透明通道的图片时,该会生成一个非锁定的图层,且是rgb模式;如果打开一个无透明通道的图片时,则是索引模式,且生成的图层是锁定的,此时如果要移动该图层等操作,需要先解锁。
    • 使用app.system执行shell命令时,如果要执行多行命令,需要将多条拼接成一条。比如想cd到某个目录,再操作。不能执行两边app.system。
    • 必须先选中要合并的图层组,再merge,否则之前被选中的图层的visible会自动改为true
    • 当两个智能对象图层关联着同一个对象时,修改这个对象,不仅两个图层的显示的内容会自动改变,两个图层的图层名也会修改
    • 通过export导出的图片dpi固定是72,不会跟随psd中设置的分辨率走,当使用存储功能保存图片时,dpi才会被更改。
  7. 关于ps和extendscript中的bounds

    我们先把所有跟bounds相关的东西列一下,[artlayer|layerset].[bounds|boundsNoEffects],在右侧面板位置的属性中也有bounds,command+T后左上角位置的参考点bounds

    • 必须选中图层树中的对象后,右侧面板中属性才有值。但不是所有对象,都有属性。图层组(layerset)就没有。普通图层有,画板也有

    • 由于artlayer和layerset都是layer的子类,所以都有bounds属性

    • 普通图层

      • 对于非智能对象,三者相同,都是有像素值的最小包围矩形
      • 对于智能对象且像素值的最小包围矩形周围还有透明区域的话,command+T是包含透明区域的矩形,而前两者则还是最小包围矩形
    • 图层组(layerset)

      • layerset.bounds和command+T都是像素值的最小包围矩形
      • 没有面板中的属性值
    • 画板(artboard)

      由于目前extendscript并没有artboard的api,所以会将artboard认为是layerset,但与上面的layerset区别很大。画板背后有个大区域,通过“图像大小”能看出来,我们假设这个大区域左上角原点是origin0

      • artboard
        • artboard没有command+T
        • artboard右侧面板属性有值,画板尺寸和距离origin0的坐标
        • artboard.bounds相当于layerset.bounds,有像素值的最小包围矩形,注意,是距离origin0
      • 对于artboard中的图层
        • 非智能对象
          • 右侧面板属性值和command+T,是像素最小包围矩形距离画板左上角原点的坐标
          • layer.bounds是,像素最小包围矩形距离origin0的坐标
        • 智能对象
          • command+T是包含像素值以外透明区域的矩形,距离画板原点的坐标
          • 右侧面板属性,有像素值最小包围矩形,距离画板原点坐标
          • layer.bounds,是有像素值区域最小包围矩形,距离origin0的位置,可不是距离当前画板左上角原点
      • 通过am获取的bounds
        • artboard的bounds是画板尺寸和距离origin0的坐标,等价于右侧面板属性
        • layer的bounds等价于layer通过api获取的bounds即layer.bounds
  8. ActionReference & ActionDescriptor & ActionList

    • ActionList类似一种数组数据结构
    • executeAction(typeID, desp, dialog) 和 executeActionGet(ref)都能返回结果,返回desp。但接收参数不同。desp是ActionDescriptor类型,ref是ActionReference类型
    • ActionDescriptor.putReference(ref);ref是ActionReference类型
    • ActionReference.putProperty(stringIDToTypeID('property') , stringIDToTypeID("targetLayers"));有过滤作用,该方法使得返回结果中只包含targetLayers这个属性
  9. 图层的itemIndex和action manager(简称am)中的index

    • am的ref.getIndex,获取

      • 有背景图层,getIndex从0开始
      • 无背景图层,getIndex从0开始
    • 对于layer.itemIndex

      • 有背景图层,itemIndex从1开始
      • 无背景图层,itemIndex从1开始
    • am的ref.putIndex(typeid, index),用于获取layer

      am的ref.putIndex逻辑中,背景图层永远占据着0位置,不管背景图层存不存在

      • 有背景图层时,putIndex(typeid, 0),表示获取背景图层
      • 无背景图层时,putIndex(typeid, 1),表示获取第一个图层,而putIndex(typeid, 0)是错误的
    • am中获取numberOfLayers,是不包括背景图层的图层数量

    • 如果有背景图层,而且其他图层都只能盖在背景图层之上。背景图层解锁后,就成为普通图层了

    • 发现一个奇怪现象,如果都是artlayer,则layer.itemIndex从1开始递增。但如果新建一个layerset(图层组),则itemIndex会跳过去。比如原来有四个artlayer,itemIndex是1、2、3,现在将2位置的artlayer删除,新建一个layerset,则新的itemIndex是1、3、4

  10. 关于sample

  11. adobe photoshop/preset/scripts/目录下有一些ps已经支持的脚本

  12. extend script tool kit目录下也有些例子

CC Extension

CC Extension是更先进的一组为Adobe工具扩展功能的开发平台

  1. 该平台只针对CC版本的Adobe工具。
  2. 支持HTML、JS、Nodejs开发
  3. 底层执行Adobe工具的工作仍然是调用上面章节所说的scripting api

相比使用ExtendScript进行scripting开发,CC Extension在网络操作、UI方面更强大。

  1. 感觉Nodejs是用于服务端开发的,CC Extension感觉主要是开发前段页面,所以哪些地方可以使用Nodejs?