psd转成html实现

1、首先将psd文件的图层级分组中的图层重新命名:

rename.jsx:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
    //获取当前活动文档
    var doc = activeDocument;

    //获取文档活动图层
    var layers = doc.layers;
    var sum = 0;

    function rename(layers) {
        //循环图层
        for (var i = 0; i < layers.length; i++) {
            //递归
            if (layers[i].layers && layers[i].layers.length > 0) {
                rename(layers[i].layers)
                continue;
            }
            //根据图层类型分别将其命名
            if (layers[i].kind === LayerKind.TEXT) {
                layers[i].name = "txt_" + sum;
            } else if (layers[i].kind === LayerKind.NORMAL) {
                layers[i].name = "pic_normal_" + sum;
            }else if ( layers[i].kind === LayerKind.SMARTOBJECT) {
                layers[i].rasterize(RasterizeType.ENTIRELAYER)
                layers[i].name = "pic_smart_" + sum;
            }else{
                layers[i].name = "pic_" + sum;
                // alert(layers[i].name+"----"+layers[i].kind)
            }
            sum++;
        }
    }
    rename(layers)

photoshop可以识别后缀为jsx和js的文件,支持三种脚本语言:applescript、vbscript、javascript。

2、创建node项目的主框架,并创建两个空文件夹,分别是:src/img、src/json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
    const express = require('express');
    const multer = require('multer');
    const adm_zip = require('adm-zip');
    const deleteFolderRecursive = require('./src/js/folderClear');
    const psdParse = require('./src/js/psd.js')
    const psd2svg = require('./src/js/psd2svg.js')
    const {exec} = require('child_process');

    let upload = multer({dest: 'uploads/'}).single('uploadfile');
    const fs = require('fs');

    let app = express();
    let zip = new adm_zip();
    app.get('/', function (req, res) {
        res.sendFile(__dirname + "/src/index.html")
    });

    app.get('/*.html*', function (req, res) {
        // console.log(req)
        res.sendFile(__dirname + "/src/" + req.url.split('?')[0])
    });

    app.get('/getdata.json', function (req, res) {
        var data = fs.readFileSync('./src/json/' + req.query.temp + '.json')
        res.send(JSON.parse(data))
    });

    app.post('/profile', function (req, res, next) {
        upload(req, res, function (err) {
            if (err) {
                // An error occurred when uploading
                throw err;
            }
            fs.rename('./uploads/' + req.file.filename, './uploads/' + req.file.originalname, (err) => {//req.file.filename
                if (err) throw err;
                let stemp = psdParse('./uploads/' + req.file.originalname)
                exec('gulp sprite --filenname ' + stemp, ()=>{ //创建异步进程 合并成雪碧图 sprite
                    res.redirect("/psd.html?temp=" + stemp)//redirect 默认的状态码是302
                    fs.unlinkSync('./uploads/' + req.file.originalname);//这里只能是相对路径
                });
            });
        })
    })

    //图片静态资源化
    app.use(express.static('src'));
    app.listen(3002, function () {
        console.log('local server app listening on port 3002!');
    });

3、index.html

1
2
3
4
5
6
7
8
9
10
11
12
13
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <form method="post"  enctype="multipart/form-data" action="/profile">
        <input name="uploadfile" type="file" >
        <Button type="submit">提交</Button>
    </form>
    </body>
    </html>

4、psd.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
    const PSD = require('psd');
    const fs = require('fs');

    function transform(item, filename) {
        item.layer.image.saveAsPng('src/img/' + filename + '/' + item.name + '.png')
    }

    module.exports = psdParse = (file) => {
        const psd = PSD.fromFile(file);
        psd.parse();
        const root = psd.tree();//To access the document as a tree structure, use psd.tree() to get the root node
        const data = root.export();//这里是用来获取psd文件的各图层的数据 递归的将任何节点导出到对象  包括位置、图片、文字、透明度、字图层等等 json格式
        const filename = (new Date).getTime();
        let layers = root.descendants();//get all descendant(后代) nodes not including the current one

        fs.writeFile('src/json/' + filename + '.json', JSON.stringify(data))//异步地将数据写入到文件,如果文件已存在则覆盖该文件
        fs.mkdirSync('src/img/' + filename + '/')//异步地创建目录。 除了可能的异常,完成回调没有其他参数

        layers.forEach((layer, i) => {
            // console.log(layer.name)
            if (layer.name.includes('pic_')) {//这是我们重新命名过图层名称的关键字
                transform(layer, filename)//遍历图层 转成png图片
            }
        })
        return filename;
    }

5、psd.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
        * {
            padding: 0;
            margin: 0;
        }
    </style>
</head>
<body>
<div id="root" style="position: relative;"></div>
</body>
<script src="./lib/jquery.js"></script>
<script>
    (function(){
        const filename = location.search.split('=')[1];
        $('head').append('<link type="text/css" rel="stylesheet" href="./img/'+filename+'.css">')
        $('#download').attr('href','/download.json?temp='+filename)
        const $root = $('#root');
        let difleft = diftop = 0;

        $.get('/getdata.json' + location.search, function (data) {//???
            $root.css({
                width: data.document.width,
                height: data.document.height
            })
            transform(data.children, $root)
        })

        function transform(arr, target) {
            // body...
            arr.forEach((item, i) => {
                item.name = item.name.replace(/ /g, 's')
                target.append('<div id="' + item.name + '"></div>')
                let $div = target.find('#'+item.name)
                $div.css({
                    'position': 'absolute',
                    'z-index': 1000 - i
                });
                if (item.type != 'group') {
                    $div.css({
                        height: item.height,
                        top: item.top - diftop,
                        left: item.left - difleft
                    });
                    if (item.text && item.text != {}) {
                        $div.html(item.text.value.replace(' ', '&nbsp;'))
                        $div.css({
                            width: item.width + 5
                        });
                        $div.css({
                            'font-size': item.text.font.sizes[0] * item.text.transform['xx'],
                            'line-height': item.text.font.sizes[0] * item.text.transform['xx'] + 'px',
                            'font-family': item.text.font.name,
                            'color': 'rgba(' + arr2Str(item.text.font.colors[0]) + ')',
                            'text-align': item.text.font.alignment
                        });
                    } else {
                        $div.css({
                            width: item.width
                        });
                        $div.addClass('icon-sprite-'+item.name)
                    }
                }

                if (item.mask && item.mask != {}) {
                    $div.css({
                        height: item.height,
                        top: item.top - diftop,
                        left: item.left - difleft,
                    });
                }

                if (item.children) {
                    transform(item.children, $div)
                }
            })
        }
        function arr2Str(colors) {
            return colors[0] + ',' + colors[1] + ',' + colors[2] + ',' + colors[3]
        }
        function obj2Str(obj) {
            let str = []
            Object.keys(obj).forEach((v) => {
                str.push(obj[v])
            })
            return str.slice(0, 4).join(',')
        }
    })();
</script>
</html>

6、学习札记

1)express 框架 快速搭建完整功能的网站

a.可以设置中间件来响应http请求
b.定义了路由表用于执行不同的http 请求动作
c.可以向模板传参 动态渲染HTML

2) mutler 中间件 处理文件上传的nodejs中间件 只支持enctype=”multipart/form-data”的表单数据 需同1)一起下载

通过设置dest属性,表示上传文件的存储位置

1
    let objmulter = multer({ dest: path.join(__dirname,'uploads')});

方法集合:

a.single(fieldname) 接收单个文件,通过req.file访问该文件 fieldname是input的name属性名
b.array(fieldnaem,[maxcount]) 接收多个文件,通过req.files数组方法文件.maxcount指定接收文件最大数.
c.fields(fields) 接受指定fieldname的文件,fieldname由客户端决定,通过req.files数组方法
d.any 接收所有文件上传,通过req.files访问文件

multer关联的文件信息:

filedname : 在form表单中指定的name属性值

orginalname : 原始文件名

encoding : 文件编码方式

mimetype : 多媒体类型

size : 文件大小,单位b

destination : 文件上传后存储在服务端的路径

filename : 文件在服务端的命名

path : 文件在服务端的完整路径

buffer : 文件二进制数据

参考文档:

图层类型

express redirect

psd.js