Photopshop 中的文字解析及其在前端的应用
背景
在笔者负责的营销活动项目中,不同时间和场景需要不同的文案图片,传统方式下,设计需求需要多次沟通后设计师才能修改文案并提供图片。但借助 Photoshop 插件 (下面简称 CEP),设计师可以创建模板并将文字样式和背景图片解析,让运营人员在在线编辑器上修改文案,提高工作效率。本文将探讨如何利用 Photoshop 插件进行文字样式解析,实现精准的设计还原。
Photoshop 插件 (CEP) 是什么
CEP 是 Adobe 为 Photoshop 等软件提供的扩展平台,使用 HTML5 和 Node.js 技术扩展 Adobe 系列软件功能。简单来说,它是通过一个本地 Web 应用调用 Node.js 和 Photoshop 提供的 JavaScript API 来扩展 Photoshop 的能力。本文将介绍如何利用 CEP 实现文字样式解析。
CEP 开发环境搭建
快速搭建开发环境,有两种方式,一是在官方提供 demo 的基础开发,还有一种脚手架 (bolt-cep) 生成工程化的开发环境 (极力推荐)。
不管你采用哪种方式,都需要安装插件,其实就是放置在 PS 的某个路径下的一个文件夹,里头包含了必备需要的文件。具体安装方式,可以参考 imgcook Photoshop 插件手动安装,我们直接将 CSXS 的父级文件夹导出到对应位置即可。
另外,如果你不想将开发项目存放到 ps 指定的文件夹下,可以通过软链的方式,下面是 MacOS 写法:
# cep:CSXS的父级文件夹
# /Library/Application\ Support/Adobe/CEP/extensions:PS插件安装的路径
ln -s cep /Library/Application\ Support/Adobe/CEP/extensions
文字样式解析
文字样式比较多,比如 lineHeight、fontSize、Shadow、matrix、Stroke...
我们通过 Action Manager 方式来解析文字。Action Manager 是 Photoshop 的编程接口,允许使用 JavaScript 执行各种操作,例如创建图层、调整图层属性等。比如通过 Action Manager 选中为图层名为 “Hello,World!” 的图层。
// 创建一个新的动作
var ref1 = new ActionReference();
ref1.putName(stringIDToTypeID('layer'), 'Hello, World!');
// 设置动作描述
var desc1 = new ActionDescriptor();
desc1.putReference(stringIDToTypeID('null'), ref1);
// 执行动作
executeAction(stringIDToTypeID('select'), desc1, DialogModes.NO);
Action Manager 的入门可以参考 Action Manager 从好奇到劝退
现在我们来获取文字的 color、fontSize、Shadow,其他的可以类比获取了
本次解析的文字如下,“每天最高多赚 888 元”:
想要解析该文字,需要通过代码获取该图层的 ActionDescriptor,为了快速获取,我们先手动选中该图层
通过代码获取图层的 ActionDescriptor
// 获取当前被选中图层的 ActionDescriptor
const getSelectedLayerDesc = () => {
// 创建一个ActionReference对象,用于指定要执行操作的目标图层
const layerReference = new ActionReference();
// 创建一个ActionDescriptor对象,用于存储操作的参数
const getDescriptor = new ActionDescriptor();
// 将目标图层的类型设置为“layer”,并指定获取选中图层
layerReference.putEnumerated(
stringIDToTypeID('layer'),
stringIDToTypeID('ordinal'),
stringIDToTypeID('targetEnum'),
);
// 将ActionReference对象添加到ActionDescriptor中,以指定要执行操作的图层
getDescriptor.putReference(app.stringIDToTypeID('null'), layerReference);
// 执行获取选中图层描述的操作,并返回当前选中图层的ActionDescriptor
return app.executeAction(
app.charIDToTypeID('getd'),
getDescriptor,
DialogModes.NO,
);
};
获取 color
当你将 Action Manager 从好奇到劝退上中下三篇看完之后,你就会发现获取文字样式,就是就是通过 ActionDescriptor 去获取对应的属性而已,我们可以借助脚本辅助工具获取各个属性所在位置,然后通过 ActionDescriptor 来获取。比如下面我们想要获取 color
{
"name": "每天最高多赚888元",
"layerEffects": {
"dropShadow": {
"enabled": true,
"color": {
"red": 43.9993286132812,
"grain": 173.001251220703,
"blue": 253.000030517578
},
"opacity": 29,
"distance": 6
}
},
"textKey": {
"textKey": "每天最高多赚888元",
"textStyleRange": [
{
"textStyleRange": {
"textStyle": {
"fontPostScriptName": "FZLTZHJW--GB1-0",
"size": 54,
"impliedFontSize": 54,
"syntheticItalic": false,
"syntheticBold": false,
"color": {
"red": 255,
"grain": 255,
"blue": 255
}
}
}
}
]
}
}
// 获取当前被选中图层的ActionDescriptor
const desc = getSelectedLayerDesc();
// 获取第一层textKey,它是Object类型,因此需要用desc.getObjectValue获取
const textKeyDesc = desc.getObjectValue(app.stringIDToTypeID('textKey'));
// 获取 textStyleRange,他是一个数组 因此需要用 textKeyDesc.getList 获取
const textStyleRanges = textKeyDesc.getList(
app.stringIDToTypeID('textStyleRange'),
);
// 获取样式描述,textStyleRanges.getObjectValue(0) 代表获取数组中第一个对象
const styleDesc = textStyleRanges
.getObjectValue(0)
.getObjectValue(app.stringIDToTypeID('textStyle'));
// 这里获取的是 对象{"red": 255,"grain": 255,"blue": 255}
const colorDesc = styleDesc.getObjectValue(app.stringIDToTypeID('color'));
// 转成rgb
const red = colorDesc.getDouble(app.stringIDToTypeID('red'));
const green = colorDesc.getDouble(app.stringIDToTypeID('grain'));
const blue = colorDesc.getDouble(app.stringIDToTypeID('blue'));
return `rgb(${red},${green},${blue})`;
获取 fontSize
// 按照获取color的方式获取 styleDesc
const fontSize = styleDesc.getDouble(app.stringIDToTypeID('size'));
这里需要注意的是,fontSize 是 Double 类型,而不是 int 类型,另外要注意的是,size、impliedFontSize 的区别,
impliedFontSize 是当前文字在 ps 渲染的大小,size 是实际大小,这两个在文字斜切等相关处理的时候,就会产生差异,如果想要在浏览器根据 CEP 提供的 transform 还原的话,需要使用 size。
获取 Shadow
Shadow、Stroke、Filling 等并不在 styleDesc 中,而是在 layerEffects 中。我们拿 Shadow 来说。
Shadow 是对应的 dropShadow
// 获取当前被选中图层的 ActionDescriptor
const desc = getSelectedLayerDesc();
// 获取 layerEffects 的 ActionDescriptor
const layerEffects = descriptor.getObjectValue(
app.stringIDToTypeID('layerEffects'),
);
// 获取 dropShadow 的 ActionDescriptor
const dropShadowDesc = layerEffects.getObjectValue(
app.stringIDToTypeID('dropShadow'),
);
// 获取 enabled,为true的时候,打标有阴影,否则未开启阴影,不做后面的解析了,我们这里默认开启了
const enabled = dropShadowDesc.getBoolean(app.stringIDToTypeID('enabled'));
const blur = dropShadowDesc.getDouble(app.stringIDToTypeID('blur'));
const offsetX = dropShadowDesc.getDouble(app.stringIDToTypeID('distance'));
const offsetY = dropShadowDesc.getDouble(app.stringIDToTypeID('distance'));
const opacity = desc.getDouble(app.stringIDToTypeID('opacity'));
const colorDesc = dropShadowDesc.getObjectValue(app.stringIDToTypeID('color'));
// 转成rgba
const red = colorDesc.getDouble(app.stringIDToTypeID('red'));
const green = colorDesc.getDouble(app.stringIDToTypeID('grain'));
const blue = colorDesc.getDouble(app.stringIDToTypeID('blue'));
const alpha = ((opacity ?? 100) / 100) * 255;
const color = `rgb(${red},${green},${blue}),${opacity}`;
return { color, blur, offsetX, offsetY };
你可以尝试去解析剩下的样式了。
效果演示
解析了图层信息后,使用 CSS 和 HTML 在线还原设计稿。
总结
这期主要讲解简单的文字解析,其实现流程:获取当前文字图层的 ActionDescriptor → 使用脚本辅助工具获取需要解析属性的位置 → 根据 ActionDescriptor 提供获取属性的 API 获取对应的属性。
总的来说,以上内容仍处于摸索阶段,需要进一步的研究和实践。如果有任何不妥之处,欢迎指正,共同进步。🙏🙏🙏
转载自:https://juejin.cn/post/7365879319597416460