尊重原创,转载请在文首注明出处:http://blog.csdn.net/cai612781/article/details/78072531
在做unity项目中,用到了psd2ngui插件来把psd直接导出成prefab,psd2ngui的原理就是解析psd中图层的命名来生成组件。用的还是最早的版本,插件中导出的文本只有一个文本内容,其余属性例如颜色、字号、描边、投影都得另外设置,很麻烦,新版不知有没这功能,一直没有继续研究。于是当时就有了这么个想法,写个ps脚本,解析文本的属性并命名,再扩展插件来实现导出ui后不用额外修改文本属性。这也是很早很早之前做的,现在来总结下。
ps支持几种脚本语言,Mac平台有AppleScript,Windows平台有VBScript,以及两个平台都支持的JavaScript。我用的就是Js语言,后缀是jsx。
可以使用任何文本编辑来写代码,这里推荐Adobe的IDE,叫Adobe ExtendScript Tookit,支持断点调试,还可以通过Data Browser窗口查看对象的属性和方法。
ps script一种方式是通过文本对象模型DOM(Document Object Model)来访问和修改psd中的对象的属性,直观而方便,但不能实现所有的ps操作。
ps dom类结构图:
另一种方式是通过动作代理(ActionManager)的方式,可以实现比DOM更多的操作,但貌似不支持AppleScript。
动作代理主要类有ActionDescriptor,ActionReference,ActionList。
ActionDescriptor相当于一个存储属性和值的字典,
ActionList是一个存储相同属性的值的数组,
ActionReference存储一个action的引用,
举个栗子:
function emboss(inAngle, inHeight, inAmount)
{
var keyAngleID = charIDToTypeID("Angl");
var keyHeightID = charIDToTypeID("Hght");
var keyAmountID = charIDToTypeID("Amnt");
var eventEmbossID = charIDToTypeID("Embs");
var filterDescriptor = new ActionDescriptor();
filterDescriptor.putInteger(keyAngleID, inAngle);
filterDescriptor.putInteger(keyHeightID, inHeight);
filterDescriptor.putInteger(keyAmountID, inAmount);
executeAction(eventEmbossID, filterDescriptor);
}
emboss(120, 10, 100);
运行该脚本,会给选中图层添加一个浮雕滤镜
ActionManager看起来比DOM复杂繁琐,好在Adobe有个监听Action的插件,下载地址:
Windows: ScriptingListenerPlugInForWindow
Mac:ScriptingListenerPlugInForMac
下载解压后将ScriptListener.8li拷贝到Adobe Photoshop/Plug-ins/目录下即可。
重开ps,操作将会被记录在桌面的ScriptingListenerJS.log和ScriptingListenerVB.log中
切记不用时把该插件移除,需要时再复制到Plug-ins目录下,以免撑爆磁盘以及影响ps操作性能。或者使用下载的压缩包里带有两个开关插件的脚本。
上图记录了我打开一张图片,选中它,改变颜色三个步骤的脚步。
ps script中跟图层相关的对象有LayerSet(组),ArtLayer(图层),Layer(包括组和图层)。
function getTextLayers(layers)
{
for(var i = 0, len = layers.length; i < len; i++)
{
if(layers[i].typename == "LayerSet")
{
getTextLayers(layers[i].layers)
}
else
{
if(layers[i].kind == LayerKind.TEXT)
{
//得到文本图层
}
}
}
}
getTextLayers(app.activeDocument.layers);
var text = layer.textItem;//layer即上文得到的layers[i]
var color = text.color.rgb["hexValue"];
var size = text.size.value;
下面代码是怎么从layer获得ActionDescriptor, 需要先将layer设置为目标图层:
app.activeDocument.activeLayer = layer;
function char2Type(charId)
{
return app.charIDToTypeID(charId);
}
function getActiveLayerDescriptor()
{
var ref = new ActionReference();
ref.putEnumerated(char2Type("Lyr "), char2Type("Ordn"), char2Type("Trgt"));
return executeActionGet(ref);
}
var layerDesc = getActiveLayerDescriptor();
function getOutline(layerDesc)//layerDesc参数即上文通过layer获得的ActionDescriptor类型对象
{
var isEffectVisible = layerDesc.getVal("layerFXVisible");//判断图层是否有可见效果
if(!isEffectVisible)
{
return "";
}
var lfxDesc = layerDesc.getVal("layerEffects");//获得图层效果属性
var dsDesc = lfxDesc ? lfxDesc.getVal("frameFX") : null;//获得图层描边属性
//var dsDesc = lfxDesc ? lfxDesc.getVal("dropShadow") : null;//获得图层投影属性
if(dsDesc == null)
{
return "";
}
var enable = dsDesc.getVal("enabled");//判断描边/投影是否启用
if(!enable)
{
return "";
}
var rgbTxt = descToColorList(dsDesc, "color");//获得图层描边/投影颜色
return changeToHex(rgbTxt);//转换成16进制
}
function getGradientFill(layerDesc)
{
var isEffectVisible = layerDesc.getVal("layerFXVisible");
if(!isEffectVisible)
{
return "";
}
var lfxDesc = layerDesc.getVal("layerEffects");
var dsDesc = lfxDesc ? lfxDesc.getVal("gradientFill") : null;
if(dsDesc == null)
{
return "";
}
var enable = dsDesc.getVal("enabled");
if(!enable)
{
return "";
}
var graDesc = dsDesc.getVal("gradient");
var colorList = graDesc.getVal("colors", false);//ps中可以有多个渐变颜色,unity中一般两个
var result = "";
for(s in colorList)
{
var rgbTxt = descToColorList(colorList[s], "color");
result += changeToHex(rgbTxt) + ",";
}
result = result.substr(0, result.length - 1);
return result;
}
///desc.getVal( keyList );方法的实现,获得desc的属性keyList对应的值
ActionDescriptor.prototype.getVal = function(keyList, firstListItemOnly)
{
if (typeof(keyList) == 'string')
{
keyList = keyList.split('.');
}
if (typeof(firstListItemOnly) == "undefined")
{
firstListItemOnly = true;
}
if (keyList.length == 0)
{
return this;
}
keyStr = keyList.shift();
keyID = makeID(keyStr);
if (this.hasKey(keyID))
{
switch (this.getType(keyID))
{
case DescValueType.OBJECTTYPE://属性类型为Object
{
return this.getObjectValue(keyID).getVal(keyList, firstListItemOnly);
}
case DescValueType.LISTTYPE://属性类型为列表
{
var list = this.getList(keyID);
return list.getVal(keyList, firstListItemOnly);
}
default:
{
return this.getFlatType(keyID);
}
}
}
else
{
return null;
}
}
///将charID或stringID转换成TypeID
charID、string相当于底层定义的属性枚举
function makeID(keyStr)
{
if (keyStr[0] == "'")
{
return app.charIDToTypeID(keyStr);
}
else
{
return app.stringIDToTypeID(keyStr);
}
}
///根据不同类型获得最终的值
function getFlatType(desc, ID)
{
switch (desc.getType(ID))
{
case DescValueType.BOOLEANTYPE: return desc.getBoolean(ID);
case DescValueType.STRINGTYPE: return desc.getString(ID);
case DescValueType.INTEGERTYPE: return desc.getInteger(ID);
case DescValueType.DOUBLETYPE: return desc.getDouble(ID);
case DescValueType.UNITDOUBLE: return getPSUnitValue(desc, ID);
case DescValueType.ENUMERATEDTYPE: return typeIDToStringID(desc.getEnumerationValue(ID));
case DescValueType.REFERENCETYPE: return getReference(desc.getReference(ID));
default: return desc.getType(ID).toString();
}
}
///获得颜色rgb值
function descToColorList(colorDesc, colorPath)
{
var i, rgb = ["'Rd '", "'Grn '","'Bl '"];
var rgbTxt = [];
colorDesc = colorDesc.getVal(colorPath);
if (!colorDesc)
{
return null;
}
for (i in rgb)
{
rgbTxt.push( roundColor(colorDesc.getVal(rgb[i])));
}
return rgbTxt;
}
///转换成16进制颜色值
function changeToHex(rgbTxt)
{
var value = "";
for(var i = 0, len = rgbTxt.length; i < len; i++)
{
var string = rgbTxt[i].toString(16);
if(string.length < 2)
{
string = "0" + string;
}
value += string;
}
return value;
}
将代码保存为.jsx后缀文件,放在ps安装目录\Presets\Scripts\下
运行路径:ps中文件-脚本-.jsx
运行结果图
运行前:
运行后:
以上就是ps脚本解析psd中文本图层的描边、投影、渐变等属性的主要代码,文本还有许多其它属性,不过unity项目中基本不用。
完整的脚本在github:https://github.com/503913873/PhotoshopTextParse
该脚本写得比较早,脚本中一些方法写得比较繁琐,例如遍历图层是用ActionManager方式,没有文中采用DOM方式来得简洁易懂,
github里第二个脚本就是文中的方式。
貌似ps不同版本的代码也有些差异,该脚本在cs5、cs6中都运行过,基本都可以用,小概率会出现解析的文本字号带小数。
更详细的语法可以在Adobe官网上查看:http://www.adobe.com/devnet/photoshop/scripting.html
文笔不好,又是第一次写,写了好多天,ps script研究得也不深,基本是需要什么功能才去搜索,欢迎大家一起讨论学习。