sunilwang

V1

2023/03/22阅读:47主题:绿意

Psd设计稿解析之路

伟大的马老师曾经说过,生产工具是生产力的决定因素之一。实际工作中,一个好用的工具确实可以有效提升开发效率。

起源

一次和设计同学的闲聊中,了解到他们的设计稿交付时,大多数都是基于sketch,而Psd的设计稿非常少,使得他们一身Psd技艺无用武之地。究其原因,是因为sketch对css样式支持度较高,转换到HTML元素相对容易,但Psd并无一一映射规则,且Psd的样式繁杂,解析起来相当麻烦。 鲁迅先生说过:“即使艰难,也还要做;愈艰难,就愈要做”。打了一番鸡血,几位小伙伴一拍即合,便开始去做这件“艰难”的事情——将Psd设计稿转译成HTML。

image.png

调研

目前市面上可用的转换插件以这两种为主,具体特点分析如下:

解析插件名称 psd.js ag-psd
解析依据 psd.rb解析器 photoshop官方文档
star数 2.5k 297
更新频率 去年 上个月
issue回复速度 周甚至月 天级
图像模式支持度 深度和图像模式有限 几乎所有
遍历方式 插件API方法 自由操作原始数据
颜色模式 rgba rgba
图片操作方式 转png 支持canvas所有API
转换css属性 属性有限 大量属性可转换
解析数据(以6.8MB的Psd文稿为例) 135KB 34.1MB
解析成功率 重名图层会出现卡死/报错 100%

结果一目了然,除star数稍逊色之外,其他方面ag-psd一骑绝尘,选定插件,开始搬砖。


架构设定

经过设计讨论,最终决定了解析的具体步骤,如下图所示。 image.png


图层分类

目前图层可分为三类:组(group)文字(text)图片(image)。其中图层有children属性,它是可以包含所有类型图层的列表;文字图层也拥有children属性,但它仅能包含文字图层。

enum LayerShowType {
  GROUP = 'group',
  TEXT = 'text',
  IMAGE = 'image',
}

样式转换

解析得到的是接近Psd源格式的数据,要想将其转换为HTML文件,首要任务是将Psd属性“翻译”成css样式。 但Psd的样式无法和css样式一一对应,需要做转换映射;而且同一文本框中,可能出现多种样式文字,针对于此,需要做文字样式拆离

转换映射

其中,常见的opacity(透明度),borderRadius(圆角),backgroundColor(背景色)等样式是通用样式,也很容易找到对应属性,但文字就相对难处理一些。 诸如删除线、下划线,加粗,倾斜等样式,Psd属性中是以Boolean形式存在;行高属性在Psd中是leading,单位是Psd文稿定义的单位;圆角在Psd中以Object存储,等等;而css样式中,是以单独样式及固定值存在,这里都需要转换映射。 image.png

样式拆离

如下图所示,2种不同的样式糅合在一个文本图层中,需要从图层的TextStyleRun列表中,将各自样式单独拆离出来,再做转换映射。 image.png

// Psd解析原始数据
"styleRuns": [
    {
      "length"1,
      "style": {
        "fontSize"24,
        "autoKerning"false,
        "fillColor": {
          "r"225.99885,
          "g"61.15665,
          "b"61.15665,
          "a"1
        }
      }
    },
    {
      "length"69,
      "style": {
        "fontSize"24,
        "autoKerning"true,
        "fillColor": {
          "r"225.99885,
          "g"61.15665,
          "b"61.15665,
          "a"1
        }
      }
    },
    {
      "length"88,
      "style": {
        "fontSize"48,
        "autoKerning"true,
        "fillColor": {
          "r"26.9994,
          "g"23.715,
          "b"23.715,
          "a"1
        }
      }
    },
    {
      "length"39,
      "style": {
        "fontSize"36,
        "autoKerning"true,
        "fillColor": {
          "r"129.999,
          "g"46.39215,
          "b"46.39215,
          "a"1
        }
      }
    }
]

定位处理

由于Psd源数据本身就是绝对定位,最简单高效的方式是沿用它。所以我们直接使用position: absolute的样式,将图层属性top, right, bottom, left直接转换。 image.png


图片处理

考虑到时间及转化难度的问题,目前的图片分为两部分:设计稿中本身的图片图层非文字图层。由于ag-psd基于canvas处理图片,此处借用canvas的toDataURL方法,将所有图片统一转换成base64格式来存储备用。 image.png


HTML文件拼接

准备就绪,开始拼接HTML元素。但因为场景在node端,无法直接使用Document.createElement来创建DOM,更无法直接添加css样式。 image.png 几经寻找对比,终于找到一款在node端操作DOM的包——cheerio,它提供了在node端操作DOM的一套API,是jQuery的子集。有了它,何愁不能拼接完整的HTML,想到这里,不禁沾沾自喜。 image.png 拼接分为如下3个步骤:

1. 数据解析

利用上述结论,将原Psd数据进行解析转换,将图层类型转换成固定三类(组,文字,图片),同时将样式转换成对应图层类型的css属性。

2. 递归处理

对转换后的数据进行递归处理,使用 cheerio 的API,对 组(group) 图层,新建div元素;对 文字(text) 图层,新建p元素;对 图片(image) 图层,新建img元素。再通过attr及css方法把对应的css样式添加到DOM元素中。 image.png

3. 单位变换

本次解析是基于移动端设计稿处理,但由于移动端屏幕尺寸多种多样,px单位是无法在HTML中直接使用。考虑到大部分移动端设计稿是基于750px宽度来定义尺寸,此处均将px转换为rem单位,同时定义基准fontSize = 100px。 由于单位转换后,文字样式的宽度会有一定差异性,会出现折行问题。经过多次尝试,基于rem单位,我们会给文字添加一定数值的宽度补偿,最终展示的文字能够完美适配原设计稿。

let newWidth = (Math.ceil(width / 10) * 10 * ratio + 0.3) + unit;

结果展示

最终,我们得到了这样的结果:用户中心设计稿 😄,所幸还原度还不错,粗略估计在85%以上。

原设计稿:

image.png 转换后页面效果(在线设计稿地址 ):

image.png

未来规划

目前Psd设计稿的还原度并非最理想状态,同时仅还原出HTML也不是我们的目的。未来有如下的规划:

  • 大幅提升设计稿的还原度
  • 完成Psd在线设计稿功能开发,方便前端开发者使用

如何体验

进入毕加索官网,点击右上角 解析PSD 按钮即可体验Psd设计稿转换。 同时,也欢迎大家关注58开源项目 Picasso ,体验效果、改进代码、协作开发都可以提到issue中。

作者介绍

王明忠:天生的乐观派,而且永不止步

姜娜娜:踏实做好每一件事

分类:

前端

标签:

HTML

作者介绍

sunilwang
V1