页面载入中...

Ps高端教程系列(一)- 初识脚本语言(翻译)

xingphotoshop, 2013-10-120

 Ps高端教程系列(一)- 初识脚本语言 by Gaoyoungor

Gaoyoungor 翻译

写在前面

利用Ps脚本我们可以简化工作流程,甚至能创造出让人震惊的数字艺术。卓越的设计师不是沉迷于幻想,而是将幻想变为现实的人。而技术,则是你的魔术棒... 原文作者Ross Aitken(个人教程站:http://psdlearning.com/)这篇文章写得很详细,力图让每一个读者都能看懂。本文主要涉及到三块主要技术:调色、添加边框和阴影以及随机旋转。调色的方法是复制图片图层,然后平均模糊取得该图片的平均色,其后用图片RGB通道直方图校验的方法取得该平均色的色值,并根据各通道颜色比例作出调整,然后用所得的颜色填充复制的图片层,其后反相,更改混合模式为颜色,降低不透明度,从而形成影楼级调色效果;添加阴影和边框则主要涉及到画布大小的重定和高斯模糊滤镜。图片的随机旋转则涉及到Math.random(),创建一种随机的效果。教程最终实现的效果很简单,但通篇教程旨在渗透原理和思想,抛砖引玉,相信聪明的你能发挥才思完成惊人的作品!感谢Black_Ray大神的贴身技术指导,没有他的帮助这篇文章会夭折。大家可以查看jsx源文件每一步我都有注明过程及作用,想要学习更多的朋友可以下载ps官方的api文档阅读。欢迎大家关注我的微博@Gaoyoungor,与你分享更多关于设计。  

jsx源文件共享:http://vdisk.weibo.com/s/JjyMe(亲测可用);
官方api文档Photoshop_CS5_s cripting_Guide: http://vdisk.weibo.com/s/JjyTk

脚本控制在常规的ps教程中是很少涉及到的东西,但绝对是值得学习的技巧。脚本在自动化任务流程控制方面相对于ps action(动作)来说更为强大,而且能完成一些利用photoshop常规软件技巧不能实现的任务。下面我们来创建一个脚本来编辑照片,让你的图片以一种更为时髦的方式去展示。

介绍

在这篇教程中,我旨在介绍怎样用脚本来实现这样的效果,但同时也会介绍在photoshop中和该脚本语言的相对应的操作,从而让大家更能明白怎样去修改你的脚本来实现不同的效果。Photoshop能编译三种编程语言的脚本:VBs cript,Apples cript和java s cript,其中只有java s cript是跨平台的脚本语言,所以在这篇教程中我们选择使用java s cript,同时,学习java s cript对于我们也更为有利。即使你从未使用java s cript编过程,也能很轻易的理解这篇教程,因为我对每一概念都有很细节的讲解。当编写JS代码的时候你可以使用任何适合你自己的编辑器,较新版本的ps为大家提供了一个叫做Extends cript Tooklkit(以下简称ESTK)的软件,可以让编写这类脚本更为便捷。通常情况下装好ps都会附带这个软件,如果你安装绿色版的ps或者确实找不到该软件的话(译者著:建议大家直接在开始菜单搜索)可以从这里下载。注意:ESTK可能不适用于低版本的photoshop软件。使用ESTK编写PS脚本语言的优势在于可以更方便的调试,你甚至可以在直接在该软件里运行脚本,这在接下来的学习中大家会深有体会。在这片教程中我使用了stock.xhng的这张图片,你可以保存这张图片的一个小尺寸版本来测试你的脚本,而且运行速度会更快。当然,脚本语言能应对不同图片的不同尺寸。

步骤一

打开你想使用的编辑器,不管是ESTK还是windows平台下的notepad之类的文本编辑器,但不要使用word这类的程序。如果你使用ESTK,那么窗口的左上角应该会出现一个下拉菜单,在这个下拉列表中选择adobe photoshop就能和ps程序链接起来。现在我们来编写一段简单的程序来验证我们的设置的正确性。将如下的代码输入你的编辑器:

Alert(“Hello World”)

这条简单命令的作用是弹出一个警告框,显示“Hello World”;在这篇教程的过程中我们用警告弹出框来测试我们的部分代码。使用引号的是表明引号内的字符串是一个字符。现在运行你的脚本,如果你使用的是像notepad之类的常规编辑器,那么运行你脚本最简单的方法就是将你的脚本储存为“mys cript.jsx”,然后打开ps,文件>脚本>浏览,然后选择你的脚本。如果你使用的是ESTK,你就只需要点击窗口右上角的播放按钮就可以了。这时候你应该能看到一个警告弹出框。在测试你的脚本之前,请关闭当前在ps中打开的文件。



步骤二

编辑器中的警告代码段只是来测试设置的正确性,所以这时候我们要把它删掉。每次运行脚本的时候我们都想要运用两个设置,分别是设置ps的标尺单位为像素和禁止在非需要的情况下出现弹出对话框。在ps内实现该设置的方法是 编辑>首选项>单位和标尺,然后将标尺的值改为像素,显然关闭对话框只针对脚本语言控制程序的情况。实现该设置的代码如下:

preferences.rulerUnits = Units.PIXELS;

displayDialogs =DialogModes.NO

第一条命令指令PS更改首选项里的单位和标尺的值为像素。我们可以发现代码的引用有明显的分层结构,比如说单位和标尺是属于首选项下面的一个子选项,显而易见,Photoshop的软件结构也是如此。第二条命令只是将对话框的属性值改为“NO”,在执行脚本的过程中如果你需要弹出对话框,可以直接更改NO为YES。


步骤三

现在我们希望用户选择一个文件打开,为此我们需要弹出一个打开文件的对话框,即使我们关闭了对话框的显示但是我们只要编些脚本依然可以控制对话框的显示。下面我们将定义一个和打开的文件对应的变量,然后复制该文件的背景层。实现代码如下:

open(File(openDialog()));

var docRef_1 = activeDocument

docRef_1.backgroundLayer.duplicate();

第一条命令由三部分组成,the open命令是用来打开括号内的文件,然后the file()命令是抓取括号里的文件路径,但这里我们添加的是openDialog()命令。所以该命令行的作用是弹出一个对话框让用户选择一个文件,然后程序能获取文件路径并打开它。如果你每次都想打开同一个文件,那么你可以用具体的文件路径来代替openDialog()代码片段。第二条命令我用var来定义了一个变量docRef_1,该变量名可以是规范内的任意值,如果我还想打开另一个文件,我就可以定一个名为docRef_2的变量。然后我们把变量docRef_1定义为当前文件。最后一条命令我们所做的是指令Photoshop复制docRef_1文件中的背景图层,该文件目前也是我们唯一运行的文件。大家会再次发现这和我们在ps中的操作类似,在ps中,你会选择你想要复制图层所在的文件,然后你要选择该文件中你要复制的图层并复制它。现在运行完整的代码我们将得到一个拥有你选择的图片的背景图层和在其上方的复制层。如果要在photoshop中完成同样的操作你只需要简单的按Ctrl+O,然后选择图片,随后右击图层面板的背景图层,选择“复制图层”。

3

 

步骤四

下面我将讲解如何用十六进制代码来定义颜色,同时大家也将看到颜色也可以由RGB的值来表述。在这里我们将定一个白色和一个黑色,然后将黑色设为前景色,白色设为背景色。实现这个目的有很多其他的方法,但在这个教程里面我们采用这样的脚本命令:

var white = new SolidColor();

white.rgb["hexValue"] = “ffffff”;

var black = new SolidColor();

black.rgb["hexValue"] = “000000″;

foregroundColor =black;

backgroundColor = white

大家很容易就能发现前两行代码和三、四行类似,我们在这里所做的就是定义两个可以任意命名的变量,这里我们根据即将给变量赋于的颜色命名。随后我们定义该变量”= new SolidColor()”,则是一个创造新颜色的函数。随后便是给该颜色变量定义一个十六进制的颜色变量,这里是白色我们用”#ffffff”。我们最终要说明的就是变量white就是指白色,black就是指黑色,最后两行代码的目的是设置前景色为黑色背景色为白色。这段代码是相当浅显可读的。在PS软件内与之等价的操作便是点击“D”键充值背景色和前景色。现在试试在ps软件中给前景色和背景色设置任意的值,然后运行整段代码仍然可以的大相同的结果,前景色和背景色都将恢复设置。


步骤五

下面我们要做的是将背景填充我们在上一步骤中定义的白色。为了实现该目的我们首先要全选该文件的画布区域然后填充选区。代码如下:

docRef_1.selection.selectAll();

docRef_1.selection.fill(white);

docRef_1.selection.deselect();

第一行命令采用了selectAll()函数来定义了一个选区,对于任何可以作用于不同文件的命令我们必须要告知ps我们正在处理的文件,即使当前只有一个打开的文件。第二条命令是指令ps对选取填充白色。有时候挺让人迷惑的,因为大家或许会想到给选区填充白色的命令应该是docRef_1.selection.fill = white,而这也并不是毫无道理。然而这并不是正确的代码,此时ESTK的提示功能就非常有用了,只要你输入fill或者其他关键词,它就会以下拉框的形式告诉你该关键词的正确用法。第三行代码浅显易懂,就是取消选区,等同于ps中的ctrl+D。再次测试代码你将得到一个白色的背景图层和其上的图片图层。在ps软件中,目前所有的脚本控制可以由ctrl+A和shift+F5来全选和填充来实现相同的效果。


步骤六

在接下来的两个步骤中我们将用脚本语言来找到图片的平均颜色值,随后我们将根据这个颜色值来确定将如何编辑该图片。这段代码可以有很多其他用处,比如说你可以用一段类似的代码通过分析图片的颜色组成来建立一个颜色图表。在这一步中我们将复制图片图层然后对该层施加平均模糊滤镜进而找到图像的平均颜色值,并将图层填充为该平均色。代码如下:

docRef_1.layers[0].duplicate();

docRef_1.activeLayer=docRef_1.layers[0];

docRef_1.activeLayer.applyAverage();

第一行命令大家很熟悉,我们在步骤三中使用过相同的命令,只是这里我们将背景图层换成了layer[0]。为了很好的理解layer[0]的含义我们需要了解一点java s cript中关于数组的知识。数组简单的来说就是有不同值的变量集合,在一个数组中,变量就像是带有独立信息的盒子,而数组则像是一个大盒子,里面装了很多贴有从零到无穷大的数字标签的小盒子。比如你想建立一个包含一周前三天的数组,你可以编写如下代码:

var days = ["Monday", "Tuesday", "Wednesday"]

你可以采用如下代码来引用该数组中的第一天:

days[0]

这就等同于“Monday”,当然这里还没有涉及到后两行代码。了解了数组的基础知识后我们可以回过头去看看我们刚刚所添加的三行代码。在第一行当中,layers是一个包含当前文件所有图层的数组。在图层面板的最顶层是数组的第一个子元素,对应为layers[0]而不是layers[1]因为数组的子元素是从0开始计数的。第二行脚本语句将顶部图层设置为活动图层,等效于在图层面板中选中某个图层。我们没有必要改变活动图层但它让接下来的工作变得更加简单。最后一行脚本是对活动图层施加一个平均模糊滤镜,该脚本的代码格式与我们目前为止用到的命令格式基本一致,即是所谓的方法,通常是document.layer.function的格式,在这个实例中layer(图层)是指当前的活动图层,而函数则是指平均模糊。这在photoshop软件中可以通过滤镜〉模糊〉平均来实现。再一次测试你的代码,我们应该可以在图片所在的图层上方得到一个填充了颜色的新图层。

 

步骤七

这一步会略微复杂一点,我们要用脚本语言找出步骤六中得到的填充图层颜色的RGB值。实现这个目的没有所谓的捷径,我使用的方法是首先用脚本命令选中第一个红色通道,然后获取到它的直方图,再从0到255对该直方图的值进行校验,直到发现一个非零值即为R的数值,然后对绿色和蓝色通道重复同样的方法。这个过程在photoshop软件中会更加好理解。如果你还没有跟随我们脚本的节奏打开文件,那么再执行一次以上的脚本。然后在ps软件中,通过窗口>通道打开通道面板,选择红色通道,此时其他通道都会被暂时隐藏,画布中的图像则是灰度模式。使用快捷键Ctrl+L打开色阶调节面板,我们将看到只有一条垂直线的直方图,拖动输出色阶滑块中的一个大致位于这条线的下面,对应的表单框里显示则是R的数值。可以用同样的方法来获取G和B的数值。获取R值的脚本如下,大家可以根据该原理写出获取G和B值的脚本:

for (RLevel = 0; RLevel <= 255; RLevel ++)

{ if (docRef_1.channels["Red"].histogram[RLevel]) { break; } }

这段代码是一个“for循环”,第一行代码是指RLevel从0开始,以增量1循环到255。RLevel++是指RLevel的增量为1。循环语句内部是一个“if条件语句”,只有当小括号里的条件为真时,程序才会执行花括号里的代码。小括号内的代码是指让ps获取docRef_1的红色通道并且获取直方图对应的数组。我们看到的直方图并不像是一排小盒子组成的但事实上它是的,

对于每一个输出的值,在水平方向从0到255都是一个对应的垂直方向的值。在这个直方图中可以看出只有一个输出值和非零的值对应那么RLevel的值就可以看作是输出色阶的值。因为我们没有在小括号内添加类似等号或者大于号之类的符号,程序会在直方图返回非零值的返回true,因为只有一个非零值,那么该返回值即为R的值。If条件语句返回true时执行的命令是break命令,这将终止循环,所以在找到正确值后该段脚本即会停止。这两个靠近的花括号则是为了结束“for循环”和“if条件语句”。



步骤八

如下我总结了目前所有的代码,包括关于绿色通道和蓝色通道颜色值的校验:

open(File(openDialog()));

var docRef_1 = activeDocument;

docRef_1.backgroundLayer.duplicate();

var white = new SolidColor();

white.rgb["hexValue"] = “ffffff”;

var black = new SolidColor();

black.rgb["hexValue"] = “000000″;

foregroundColor = black;

backgroundColor = white;

docRef_1.selection.selectAll();

docRef_1.selection.fill(white);

docRef_1.selection.deselect();

docRef_1.layers[0].duplicate();

docRef_1.activeLayer = docRef_1.layers[0];

docRef_1.activeLayer.applyAverage();

for (RLevel = 0; RLevel <= 255; RLevel ++)

{ if (docRef_1.channels[0].histogram[RLevel]) { break; } }

for (GLevel = 0; GLevel <= 255; GLevel ++)

{ if (docRef_1.channels[1].histogram[GLevel]) { break; } }

for (BLevel = 0; BLevel <= 255; BLevel ++)

{ if (docRef_1.channels[2].histogram[BLevel]) { break; } }

(译者注:channels[1]、channels[2]和channels[3]分别是指红、绿、蓝颜色通道)

现在我们来检验最后一段代码的可行性,我们用一个弹出框来显示RGB的值。在以上代码片段结尾处添加如下代码:

alert(RLevel + “, ” + GLevel + “, ” + BLevel)

运行脚本,该弹框中应该会出现RGB的值,可以通过双击前景色切换到取色工具进行验证。如果颜色匹配就删掉这行代码,如果不匹配或者运行错误的话仔细检查或者直接复制以上代码重复尝试。



步骤九

从现在起我不再反复去捣那些细枝末节的东西因为接下来涉及到的问题基本都有讲解过。基于平均色我们可以灵活的用多种方法来处理图片。现在我们要做的是给图层填充一个颜色并更改它的混合模式为颜色。当然,该图层的填充色的的来由也是依据的。如果平均色偏蓝,那么我们将使用黄色,如果偏绿我们则使用品红,如果偏红我们就使用蓝绿色(青色)。我用一个较长的步骤来实现这个效果同时给大家展现更多的命令规则。在这一步当中,我们将获得该填充色的RGB值。代码如下:

var R = 0; var G = 0; var B = 0;

if (RLevel > GLevel && RLevel > BLevel) { R = 255; }

if (GLevel > BLevel && GLevel > RLevel) { G = 255; }

if (BLevel > RLevel && BLevel > GLevel) { B = 255; }

首先定义变量R、G、B并都赋值为0,然后用三个“if条件语句”来重新赋值,第一条条件语句表明如果平均色的RLevel值大于GLevel和BLevel那么R=255。对于G和B的值用同样的方法判断和执行。如果很巧所有值都相等,那么R、G、B的值就保持为0。


步骤十

在这一步中我们根据上一步的结果新建一个颜色值,并用和步骤四和步骤五类似的方法给图层填充该颜色,代码如下:

var color = new SolidColor();

color.rgb.red = R;

color.rgb.green = G;

color.rgb.blue = B;

docRef_1.selection.selectAll();

docRef_1.selection.fill(color);

docRef_1.selection.deselect();

唯一的区别是这里将变量命名为color,因为它可能是红色、绿色或者蓝色,这个案例为蓝色。

 


步骤十一

接下来执行如下代码:

docRef_1.activeLayer.invert();

docRef_1.activeLayer.blendMode = BlendMode.COLORBLEND;

docRef_1.activeLayer.opacity = 50;

docRef_1.activeLayer.merge();

这里的每条代码应该都像白话文一样浅显易懂,该过程在ps软件中实现方法是:快捷键Ctrl+I图层反相,然后更改图层混合模式为颜色,并且在图层面板修改图层的不透明度最后Ctrl+E合并图层。(译者注:倡导无损编辑,杜绝轻易合并图层)

运行脚本,我们将得到下图:



步骤十二

现在我们想给图片添加一个边框,我的实现方法是用脚本命令扩大画布,然后新建一个图层并全选填充白色。在此之前我们需要根据图片的尺寸算出边框的合适尺寸。经过一系列尝试和失败,我发现短边的7.5%是较为合适的边框厚度。当然,我们首先要找出短边再来算出它的7%,最后还要为画布的宽度和高度增加双倍的该尺寸。简而言之就是画布的宽和高都要增加图片短边的15%。代码如下:

var width = docRef_1.width;

var height = docRef_1.height;

if (width <= height) { var borderSize = Math.round(width * 0.15); }

else { var borderSize = Math.round(height * 0.15); }

docRef_1.resizeCanvas(width + borderSize, height + borderSize);

Okay,我们来分析一下这段脚本。前两行代码很简单,我们分别定义了一个变量等于该文件的宽度和高度。然后是一个“if条件语句”来声明如果宽度小于或等于高度则执行花括号内的命令。命令的第一部分大家很熟悉,就是新建一个变量,第二部分则使用使用了一个叫做“round”的Math Function(数学函数),作用就是对括号里的任意数值取整。这样做是因为有时候宽度或者高度的15%可能为小数(译者注:避免出现像素不精确的问题)。接下来的“else”语句表明如果宽度大于高度则执行该行代码花括号里的命令。最后一行代码根据边框的厚度重新定义了画布大小。注意图片的周围加上了1px的灰色边框因为考虑到文章背景也是白色以示区分,和脚本操作无关。



步骤十三

现在你测试已有的脚本或许会觉得这看起来不错,但是背景图层会因为画布尺寸的更改而变化,造成边框尺寸的变化。所以我们需要新建一个图层将边框画在里面并且和图片所在的图层合并。代码如下:

docRef_1.artLayers.add();

docRef_1.activeLayer.move(docRef_1.backgroundLayer, ElementPlacement.PLACEBEFORE); docRef_1.selection.selectAll();

docRef_1.selection.fill(white);

docRef_1.selection.deselect();

docRef_1.layers[0].merge();

这段代码中我们唯一不熟悉的部分就是我们用在即将创建的一个活动图层上的move(移动)命令。括号里的第一部分指明引用我们所定义的背景图层,第二部分是用方法ElementPlacement.PLACEBEFORE移动活动图层到引用的图层(即这里的背景层)上方。

步骤十四

下面我们来添加图片的阴影图层,这将成为背景图层上方一个黑色填充层。代码如下:

docRef_1.artLayers.add();

docRef_1.activeLayer.move(docRef_1.backgroundLayer,ElementPlacement.PLACEBEFORE); docRef_1.selection.selectAll();

docRef_1.selection.fill(black);

docRef_1.selection.deselect();

这段代码和上一步的几乎相同,只是我们给该图层填充了黑色,同时也还没有合并图层。如果这时候你运行脚本,就画布中的内容而言应该看不出和上一步有什么变化。

 

步骤十五

Okay,下面我想要再次扩展画布让它能适应图片任意角度的旋转,这需要一点简单的毕达哥拉斯经典定理。代码如下:

var width = docRef_1.width;

var height = docRef_1.height;

var newSize = Math.round(Math.sqrt(width * width + height * height)) + borderSize; docRef_1.resizeCanvas(newSize, newSize)

前两行代码为宽度和高度各自定义了一个变量。第三行则为当前文件的新尺寸定义了一个变量,函数Math.sqrt 是指对括号里的内容开根号,最后我们加上了边框的距离最主要是考虑到我们要施加的阴影图层。最后一行重定了画布大小。

 

步骤十六

为了创建阴影,我们希望能用脚本控制之前创建黑色图层对它施加一个高斯模糊滤镜。

通过尝试我发现高斯模糊的大小用边框的1/3,不透明度采用50%能达到较好的效果。该部分代码如下:

docRef_1.activeLayer.applyGaussianBlur(borderSize / 3);

docRef_1.activeLayer.opacity = 50;

第一行的代码原理同第六步中我们对图片所在图层施加平均模糊滤镜。

 

步骤十七

现在我们想用脚本控制图片和阴影一起旋转,然后合并它们,这比先合并后旋转能得到更好的结果。我们希望脚本能够实现图片每次的旋转尺寸是-20°到20°之间的随机值,可以编写如下代码:

var angle = Math.round(Math.random() * 40) - 20; docRef_1.activeLayer.rotate(angle, AnchorPosition.MIDDLECENTER); docRef_1.activeLayer = docRef_1.layers[0]; docRef_1.activeLayer.rotate(angle, AnchorPosition.MIDDLECENTER); docRef_1.activeLayer.merge();

在第一行代码中,函数Math.random可以得到一个0到1之间的随机值,不是一个整数,这也是我们使用Math.round取整函数的原因。为了得到-20到20之间的随机数,我们用40与0到1之间的小数相乘并且对结果取整,再减去20,将所得的结果保存在变量angle中。下面执行旋转操作的代码将作用于当前的活动图层即阴影层,第二行代码括号里定义了旋转的角度为angle,而锚点的位置则是中心点。在ps软件中可以用过快捷键Ctrl+T执行旋转操作。最后三行代码执行了选中图片图层,和阴影图层旋转相同角度并且合并的操作。结果如下图:

 

最终代码请查看jsx源文件。

jsx源文件共享:http://vdisk.weibo.com/s/JjyMe
官方api文档Photoshop_CS5_s cripting_Guide: http://vdisk.weibo.com/s/JjyTk

结语

这只是ps脚本语言的一个入门,重在理解它的方法和思想。如果你能阅读官方api文档继续学习,或许能实现很多手动操作软件无法实现的效果。

或者你代码能力够强,也能用脚本语言为大家编写ps外挂滤镜和插件。当然,最重要的还是对设计的理解和追求,这要胜过所有的软件技巧。

 


分享:

设计原的发展离不开您的支持与帮助,如果您觉得设计原对您有所帮助 可以用微信扫描

相应二维码打赏设计原,赏金将全部用于网站建设

微信