JavaScript_利用JavaScript,编写PS脚本,开发图片量产工具

JavaScript_利用JavaScript,编写PS脚本,开发图片量产工具

背景:身在一个有实业的电商公司,设计部的妹子们总是会有做不完的商品图片,当然了,要是做点有技术含量的美化工作也罢,但是最近她们很是无聊,总是要做一些重复性的工作,就比如如题所说的,图片量产,量产什么呢?价格牌。。。这东西很没意思哎!就是给你一个模板,然后你自己把模板原来的文字图片换掉就行了,再排一下版,纯体力劳动好么!博主做过一阵子的对日外包工作,深知她们的痛苦,如果说某些对日外包的程序猿是人肉转码器的话,那么设计部的妹子们现在就成了。。算了,词就不说了,太残酷了

========================================炫炸天的分割线========================================

线索:针对背景交代的情况,BOSS给了我一个提示:PS脚本,顺着这个线索,我就进行了一系列调查,我分别做了@#¥%……&*()的努力,简而言之,photoShop自带的开发文档帮了我大忙,文档位于Adobe Photoshop CS5\Scripting\Documents\,参考了Photoshop CS5 Scripting Guide.pdf和Photoshop CS5 JavaScript Ref.pdf,当然了,自带的文档貌似还不能完全满足我的需求,我还自己下载了一个JavaScriptToolsGuide_CS5.pdf,抱着这三个文档啃了又啃,总归算是完成了这样一个量产工具。

========================================酷炸天的分割线========================================

开发思路:既然是量产工具,那么他的工作流程应该是这样的,1工具读了一个文件,文件包含了所有产品的信息,2循环抽取每一个商品的信息,生成图片并保存,3循环完毕,给出一个提示,OK,大概思路就是这样了,然后接下来就是顺着这个思路啃文档了。。。

========================================拽炸天的分割线========================================

代码如下:

  1  // 测试版本:PhotoShop CS5 12.0.3 x32 通过
  2  // 作者:Duke
  3  // 测试完结日期:2014/08/24
  4 
  5 priceCardGenerator()
  6 
  7  function priceCardGenerator(){
  8 
  9      /* *
 10      * 定义统一的赋值变量
 11       */
 12      var title  // 标题
 13       var liwaiCode  // 里外编码
 14       var priceTitle  // 售价标题,为了方便替换
 15       var price  // 售价
 16       var sample  // 价格符号
 17       var fiveAssureFeeTitle  // 五包费用标题,为方便替换
 18       var fiveAssureFee  // 五包费用
 19       var seftFeeTitle  // 自提费用标题,为方便替换
 20       var seftFee  // 自提费用
 21       var size  // 尺寸
 22       var producingArea  // 产地
 23       var material  // 材质
 24 
 25      /* *
 26      * 定义统一的字体配置
 27       */
 28      var tipFont = "MicrosoftYaHei-Bold"
 29      var valueFont = "MicrosoftYaHei"
 30      var priceFont = "Century Gothic"
 31 
 32      /* *
 33      * 定义统一的颜色配置
 34       */
 35      // 价格的颜色
 36       var priceColor =  new SolidColor()
 37     priceColor.rgb.red  = 208
 38     priceColor.rgb.green = 28
 39     priceColor.rgb.blue = 119
 40      // 顶部栏的颜色
 41       var topBarColor =  new SolidColor()
 42     topBarColor.rgb.red  = 212
 43     topBarColor.rgb.green = 0
 44     topBarColor.rgb.blue = 102
 45 
 46      /* *
 47      * 在此读取文件
 48       */
 49      // 打开logo图片
 50       var logoImg = app.open(File("D:/priceCard/liwailogo.jpg"))
 51 
 52      // 读取数据文件
 53       var dataFile =  new File("D:/priceCard/priceCardData.xml")
 54      // 后续操作设置为“读”操作
 55      dataFile.open("r")
 56 
 57      // 缓冲变量
 58       var xmlCode = dataFile.read()
 59      // alert(xmlCode)
 60 
 61      // 空文件直接退出
 62       if(xmlCode == ""){
 63         alert("文件没有内容")
 64          return
 65     }
 66 
 67      // 新建XML对象
 68       var products =  new XML(xmlCode)
 69     
 70      // 产品总数
 71       var productCount = products.product.length()
 72 
 73      // 遍历
 74       for( i = 0;i < productCount;i++){
 75 
 76          // 变量赋值
 77          title = products.product[i].elements()[0]
 78         liwaiCode = "里外编码:" + products.product[i].elements()[1]
 79         priceTitle = "售价"
 80         price = products.product[i].elements()[2]
 81         sample = "¥"
 82         fiveAssureFeeTitle = "五包费用"
 83         fiveAssureFee = "¥" + products.product[i].elements()[3]
 84         seftFeeTitle = "自提费用"
 85         seftFee = "¥" + products.product[i].elements()[4]
 86         size = products.product[i].elements()[5]
 87         producingArea = products.product[i].elements()[6]
 88         material = products.product[i].elements()[7]
 89 
 90          //  存储当前的单位长度,并设置自定义的单位
 91           var originalUnit = preferences.rulerUnits
 92         preferences.rulerUnits = Units.PIXELS
 93 
 94          //  声明一个文档
 95           var docRef = app.documents.add( 886, 561 ,72.0,"tempDoc")
 96 
 97          //  顶部栏,创建选区并上色
 98           //  “选区”的填充要在定义组之前操作,否则会报出“fill方法在当前版本不可用”
 99          docRef.selection.select([[0,0],[0,20],[886,20],[886,0]],SelectionType.EXTEND)
100          var selRef = docRef.selection
101         selRef.fill( topBarColor, ColorBlendMode.NORMAL, 100,  false)
102 
103          //  定义一个图片组
104           var layerSetRef =docRef.layerSets.add()
105             layerSetRef.name = "图片组"
106 
107          // 设置logo所在的文档为活动文档
108          app.activeDocument = logoImg
109          // 声明logo图层
110           var logoLayer = logoImg.activeLayer
111          // 复制商品图层到背景文档
112           var logoLayerTemp = logoLayer.duplicate(layerSetRef,
113         ElementPlacement.PLACEATEND)
114          // 设置背景文档为活动文档
115          app.activeDocument=docRef
116          // logo移动至左下角
117          logoLayerTemp.translate(-265,225)
118 
119          // 读取当前商品对应的二维码图片
120           var qrCodeImg = app.open(File(products.product[i].elements()[9]))
121          // 设置二维码图片所在的文档为活动文档
122          app.activeDocument = qrCodeImg
123          // 声明二维码图片图层
124           var qrCodeImgLayer = qrCodeImg.activeLayer
125          // 复制二维码图片到背景文档
126           var qrCodeImgLayerTemp = qrCodeImgLayer.duplicate(layerSetRef,
127         ElementPlacement.PLACEATEND)
128          // 设置背景文档为活动文档
129          app.activeDocument=docRef
130          // 商品图片移动至中间偏右
131          qrCodeImgLayerTemp.translate(320,180)
132          // 关闭商品图片文档
133          qrCodeImg.close(SaveOptions.DONOTSAVECHANGES)
134 
135          // 读取当前价格牌的商品图片
136           var productImg = app.open(File(products.product[i].elements()[8]))
137          // 设置商品图片所在的文档为活动文档
138          app.activeDocument = productImg
139          // 声明商品图片图层
140           var productImgLayer = productImg.activeLayer
141          // 复制商品图层到背景文档
142           var productImgLayerTemp = productImgLayer.duplicate(layerSetRef,
143         ElementPlacement.PLACEATEND)
144          // 设置背景文档为活动文档
145          app.activeDocument=docRef
146          // 商品图片移动至中间偏右
147          productImgLayerTemp.translate(200,-50)
148          // 关闭商品图片文档
149          productImg.close(SaveOptions.DONOTSAVECHANGES)
150 
151          /* *
152          *内容开始
153           */
154          //  商品名称
155           var proNameLayerRef = docRef.artLayers.add()
156         proNameLayerRef.kind = LayerKind.TEXT
157          var proNameTextItemRef = proNameLayerRef.textItem
158         proNameTextItemRef.contents = title
159         proNameTextItemRef.position = Array(55, 70)
160         proNameTextItemRef.font = tipFont
161         proNameTextItemRef.size = 30
162 
163          // 里外编码
164           var liwaiCodeLayerRef = docRef.artLayers.add()
165         liwaiCodeLayerRef.kind = LayerKind.TEXT
166          var liwaiCodeTextItemRef = liwaiCodeLayerRef.textItem
167         liwaiCodeTextItemRef.contents = liwaiCode
168         liwaiCodeTextItemRef.position = Array(55, 95)
169         liwaiCodeTextItemRef.font = valueFont
170         liwaiCodeTextItemRef.size = 14
171 
172          // 售价标题
173           var liwaiCodeLayerRef = docRef.artLayers.add()
174         liwaiCodeLayerRef.kind = LayerKind.TEXT
175          var liwaiCodeTextItemRef = liwaiCodeLayerRef.textItem
176         liwaiCodeTextItemRef.contents = priceTitle
177         liwaiCodeTextItemRef.position = Array(55, 135)
178         liwaiCodeTextItemRef.font = tipFont
179         liwaiCodeTextItemRef.size = 22
180 
181          //
182           var sampleLayerRef = docRef.artLayers.add()
183         sampleLayerRef.kind = LayerKind.TEXT
184          var sampleTextItemRef = sampleLayerRef.textItem
185         sampleTextItemRef.contents = sample
186         sampleTextItemRef.position = Array(50, 235)
187         sampleTextItemRef.font = tipFont
188         sampleTextItemRef.size = 40
189         sampleTextItemRef.color = priceColor
190 
191          // 金额
192           var liwaiPriceLayerRef = docRef.artLayers.add()
193         liwaiPriceLayerRef.kind = LayerKind.TEXT
194          var liwaiPriceTextItemRef = liwaiPriceLayerRef.textItem
195         liwaiPriceTextItemRef.contents = price
196         liwaiPriceTextItemRef.position = Array(105, 235)
197         liwaiPriceTextItemRef.font = valueFont
198         liwaiPriceTextItemRef.size = 100
199         liwaiPriceTextItemRef.color = priceColor
200 
201          // 五包费用
202           var liwaiPriceLayerRef = docRef.artLayers.add()
203         liwaiPriceLayerRef.kind = LayerKind.TEXT
204          var liwaiPriceTextItemRef = liwaiPriceLayerRef.textItem
205         liwaiPriceTextItemRef.contents = fiveAssureFeeTitle
206         liwaiPriceTextItemRef.position = Array(55, 275)
207         liwaiPriceTextItemRef.font = tipFont
208         liwaiPriceTextItemRef.size = 20
209 
210          // 五包费用金额
211           var liwaiPriceLayerRef = docRef.artLayers.add()
212         liwaiPriceLayerRef.kind = LayerKind.TEXT
213          var liwaiPriceTextItemRef = liwaiPriceLayerRef.textItem
214         liwaiPriceTextItemRef.contents = fiveAssureFee
215         liwaiPriceTextItemRef.position = Array(140, 275)
216         liwaiPriceTextItemRef.font = valueFont
217         liwaiPriceTextItemRef.size = 18
218         liwaiPriceTextItemRef.color = priceColor
219 
220          // 自提费用
221           var liwaiPriceLayerRef = docRef.artLayers.add()
222         liwaiPriceLayerRef.kind = LayerKind.TEXT
223          var liwaiPriceTextItemRef = liwaiPriceLayerRef.textItem
224         liwaiPriceTextItemRef.contents = seftFeeTitle
225         liwaiPriceTextItemRef.position = Array(250, 275)
226         liwaiPriceTextItemRef.font = tipFont
227         liwaiPriceTextItemRef.size = 20
228 
229          // 自提费用金额
230           var liwaiPriceLayerRef = docRef.artLayers.add()
231         liwaiPriceLayerRef.kind = LayerKind.TEXT
232          var liwaiPriceTextItemRef = liwaiPriceLayerRef.textItem
233         liwaiPriceTextItemRef.contents = seftFee
234         liwaiPriceTextItemRef.position = Array(335, 275)
235         liwaiPriceTextItemRef.font = valueFont
236         liwaiPriceTextItemRef.size = 18
237         liwaiPriceTextItemRef.color = priceColor
238 
239          // 规格
240           var liwaiPriceLayerRef = docRef.artLayers.add()
241         liwaiPriceLayerRef.kind = LayerKind.TEXT
242          var liwaiPriceTextItemRef = liwaiPriceLayerRef.textItem
243         liwaiPriceTextItemRef.contents = "规格:"
244         liwaiPriceTextItemRef.position = Array(55, 345)
245         liwaiPriceTextItemRef.font = tipFont
246         liwaiPriceTextItemRef.size = 20
247 
248          // 规格数值
249           var liwaiPriceLayerRef = docRef.artLayers.add()
250         liwaiPriceLayerRef.kind = LayerKind.TEXT
251          var liwaiPriceTextItemRef = liwaiPriceLayerRef.textItem
252         liwaiPriceTextItemRef.contents = size
253         liwaiPriceTextItemRef.position = Array(125, 345)
254         liwaiPriceTextItemRef.font = valueFont
255         liwaiPriceTextItemRef.size = 20
256 
257          // 产地
258           var liwaiPriceLayerRef = docRef.artLayers.add()
259         liwaiPriceLayerRef.kind = LayerKind.TEXT
260          var liwaiPriceTextItemRef = liwaiPriceLayerRef.textItem
261         liwaiPriceTextItemRef.contents = "产地:"
262         liwaiPriceTextItemRef.position = Array(55, 375)
263         liwaiPriceTextItemRef.font = tipFont
264         liwaiPriceTextItemRef.size = 20
265 
266          // 产地值
267           var liwaiPriceLayerRef = docRef.artLayers.add()
268         liwaiPriceLayerRef.kind = LayerKind.TEXT
269          var liwaiPriceTextItemRef = liwaiPriceLayerRef.textItem
270         liwaiPriceTextItemRef.contents = producingArea
271         liwaiPriceTextItemRef.position = Array(125, 375)
272         liwaiPriceTextItemRef.font = valueFont
273         liwaiPriceTextItemRef.size = 20
274 
275          // 材质
276           var liwaiPriceLayerRef = docRef.artLayers.add()
277         liwaiPriceLayerRef.kind = LayerKind.TEXT
278          var liwaiPriceTextItemRef = liwaiPriceLayerRef.textItem
279         liwaiPriceTextItemRef.contents = "材质:"
280         liwaiPriceTextItemRef.position = Array(55, 405)
281         liwaiPriceTextItemRef.font = tipFont
282         liwaiPriceTextItemRef.size = 20
283 
284          // 材质值
285           var liwaiPriceLayerRef = docRef.artLayers.add()
286         liwaiPriceLayerRef.kind = LayerKind.TEXT
287         liwaiPriceLayerRef.textItem.kind = TextType.PARAGRAPHTEXT
288          var liwaiPriceTextItemRef = liwaiPriceLayerRef.textItem
289         liwaiPriceTextItemRef.contents = material
290         liwaiPriceTextItemRef.position = Array(125, 391)
291         liwaiPriceTextItemRef.font = valueFont
292         liwaiPriceTextItemRef.width = 550
293         liwaiPriceTextItemRef.height = 200
294         liwaiPriceTextItemRef.size = 20
295 
296          // 保存文件
297           new Folder("D:/priceCard/result").create ()
298         jpgFile =  new File( "D:/priceCard/result/" + products.product[i].elements()[1] + ".jpeg" )
299         jpgSaveOptions =  new JPEGSaveOptions()
300         jpgSaveOptions.embedColorProfile =  true
301         jpgSaveOptions.formatOptions = FormatOptions.STANDARDBASELINE
302         jpgSaveOptions.matte = MatteType.NONE
303         jpgSaveOptions.quality = 12
304         app.activeDocument.saveAs(jpgFile, jpgSaveOptions,  true,
305         Extension.LOWERCASE)
306 
307          // 强制关闭
308          docRef.close(SaveOptions.DONOTSAVECHANGES)
309 
310          // 恢复默认长度单位
311          app.preferences.rulerUnits = originalUnit
312     }
313      // 关闭logo所在的文档
314      logoImg.close(SaveOptions.DONOTSAVECHANGES)
315     alert("生成" + productCount + "条产品信息,请在以下位置\"D:/priceCard/result/\"查看")
316 }

代码里的priceCardData.xml的文档格式是下面这个样子的

 1  < products >
 2      < product >
 3          <!-- 模板文件禁止修改 -->
 4          < 产品名称 ></ 产品名称 > 
 5          <!-- 里外编码 -->
 6          < 里外编码 ></ 里外编码 >
 7          <!-- 售价 -->
 8          < 售价 ></ 售价 >
 9          <!-- 五包费用 -->
10          < 五包费用 ></ 五包费用 >
11          <!-- 自提费用 -->
12          < 自提费用 ></ 自提费用 >
13          <!-- 规格大小 -->
14          < 规格大小 ></ 规格大小 >
15          <!-- 产地 -->
16          < 产地 ></ 产地 >
17          <!-- 材质 -->
18          < 材质 ></ 材质 >
19          <!-- 产品图片地址 -->
20          < 产品图片地址 ></ 产品图片地址 >
21          <!-- 产品二维码地址 -->
22          < 产品二维码地址 ></ 产品二维码地址 >
23      </ product >
24      < product >
25          <!-- 模板文件禁止修改 -->
26          < 产品名称 ></ 产品名称 > 
27          <!-- 里外编码 -->
28          < 里外编码 ></ 里外编码 >
29          <!-- 售价 -->
30          < 售价 ></ 售价 >
31          <!-- 五包费用 -->
32          < 五包费用 ></ 五包费用 >
33          <!-- 自提费用 -->
34          < 自提费用 ></ 自提费用 >
35          <!-- 规格大小 -->
36          < 规格大小 ></ 规格大小 >
37          <!-- 产地 -->
38          < 产地 ></ 产地 >
39          <!-- 材质 -->
40          < 材质 ></ 材质 >
41          <!-- 产品图片地址 -->
42          < 产品图片地址 ></ 产品图片地址 >
43          <!-- 产品二维码地址 -->
44          < 产品二维码地址 ></ 产品二维码地址 >
45      </ product >
46  </ products >

看完了这个文档格式,你应该会有以下的疑问:

1:博主逗比吧,XML标签怎么用中文?!

2:写两遍product节点干什么?手抖么?

哎,我知道自己挺逗的,但是这事要从开发之初说起,我最开始不是用XML来存放数据的,我本来幻想着可以使用CVS文件,或者PRN文件来存放数据源,然而都是以失败告终,因为商品的描述里什么都有可能存,一些卖萌的编辑什么都会写的。。。都怪我太年轻,用什么分割数据搞不清啊。。。

好了,回到问题1,我为什么用中文?因为,是为了避免装13,和让非技术人员看懂。为什么这么说呢,因为用Excel打开这个模板文件,Excel会把子节点当字段名来显示,比如

1  < 产品二维码地址 ></ 产品二维码地址 >

这个节点在Excel里的标题就是“产品二维码地址”,这就是用中文的原因,方便理解。不过呢,这里提一个有趣的现象,使用中文去取节点里的内容竟然是可以的,很是让我惊喜哎

代码里可以看到,我是通过

1 title = products.product[i].elements()[0]

去取商品名称的值的,但是实际上

1 title = products.product[i].产品名称

也能取得商品名称的值,感觉帅帅哒!
不过呢,我怕出问题,还是没有用中文去取。。。

再看问题2,为什么写两遍,这个就要问Excel了,因为只写一个子节点的话,Excel里是没有表头的, 写两个才有带表头的表格,如下

产品名称 里外编码 售价 五包费用 自提费用 规格大小 产地 材质 产品图片地址 产品二维码地址
                   

好了,使用Excel填写产品信息,再保存为XMl数据文件,准备工作就算完成了,接下来就是见证奇迹的时刻了

怎么运行?在页面里运行?看着不像啊。。app是个啥?浏览器认识么。。

其实是在photoShop里运行的,将写好的脚本放置于Adobe Photoshop CS5\Presets\Scripts下,打开PS,已经打开的就重启一下PS,之后你会在PS->文件->脚本下发现放入的脚本文件,默认是支持.jsx结尾的脚本文件,记得文档里说.js结尾的文件也支持来着。点击运行之后,你就会发现,图层啊,文字啊,刷刷的生成,刷刷的关闭,自动化的感觉很好啊,代码中的图片生成速度是10s左右一张,最高画质的,还可以接受。

好了,洋洋洒洒写了这么多,一是为了记录一下自己的心得,二是希望能给那些深陷在重复性设计工作中的人们一些帮助,只要稍微懂得一些脚本知识,能看懂英文文档就可以写啦,很炫酷的。PS脚本对我来说是一个新鲜的东西,或许我写的这些小玩意早就有大神在我之前写过,而且效率更高,或许有现成的软件可以直接生成,或许我做了很多无用功,但是都没关系啦,因为有时候是不是坑,你只有跳进去再爬出来才能知道它是不是,这样以后才好绕着走。博文至此,希望技术大神,和设计大师不用过分重视,毕竟这篇小小的博文只能是一个针对初学者的小例子,就比如说我,我作为一个程序员,两天前都不知道PS可以运行脚本,而对于那些和我一样的小伙伴们,如果你们感兴趣,自己可以先去写个脚本,alert一下自己的helloworld!哈哈~

你可能感兴趣的:(JavaScript_利用JavaScript,编写PS脚本,开发图片量产工具)