Commit 7dd74446 authored by 张九刚's avatar 张九刚

U

parent fb98a2e4
import path from 'path';
import 'color';
import generateUUID from 'uuid/v4';
import hash from 'object-hash';
import zlib from 'zlib';
/**
* Created by rockyl on 2019-08-09.
*/
const PSD = window['require']('psd');
async function getTree(file) {
let psd = await PSD.fromDroppedFile(file);
const root = {};
walk(psd.tree(), root);
return root;
}
function walk(psNode, dataNode) {
const {left: pLeft = 0, top: pTop = 0,} = psNode.parent || {};
const {left, top, width, height, name, layer: {opacity, visible}} = psNode;
const x = left - pLeft;
const y = top - pTop;
Object.assign(dataNode, {x, y, width, height, opacity: opacity / 255, visible, name, origin: psNode, label: `${name} > [${x}, ${y}, ${width}, ${height}]`});
if (psNode.children() && psNode.children().length > 0){
dataNode.children = [];
}
let children = psNode.children();
for (let i = children.length - 1; i >= 0; i--) {
const childPsNode = children[i];
const childDataNode = {};
dataNode.children.push(childDataNode);
walk(childPsNode, childDataNode);
}
}
/** /**
* Created by rockyl on 2019-08-10. * Created by rockyl on 2019-08-08.
*/ */
async function walkNode(node, callback, includeSelf = false) { const { getTree } = require('./psd-tree');
if (includeSelf) { const { execute } = require("./zeroing");
await callback(node, null);
}
if (node.children && node.children.length > 0) {
for (let childNode of node.children) {
await callback(childNode, node);
const result = await walkNode(childNode, callback);
if (result === true) {
break;
}
}
}
}
/**
* Created by renjianfeng on 2020-06-11.
*
* 导出spark的视图
*/
const relativePosPrefixMap = { module.exports = {
l: {field: 'left',}, getTree,
t: {field: 'top',}, execute
r: {field: 'right',},
b: {field: 'bottom',},
h: {field: 'horizonCenter',},
v: {field: 'verticalCenter',},
wp: {field: 'width', },
hp: {field: 'height', },
lp: {field: 'left', },
tp: {field: 'top', },
rp: {field: 'right', },
bp: {field: 'bottom', },
}; };
const offsetAll = 176;
async function execute(psdFile, options) {
const tree = await getTree(psdFile);
const {mode = 'none', singleView = true} = options;
let offset = {x: 0, y: 0};
let cutSize = {x: 0, y: 0};
if (mode !== 'none') {
cutSize.y = offsetAll;
}
switch (mode) {
case 'top':
offset.y = offsetAll;
break;
case 'center':
offset.y = offsetAll / 2;
break;
}
const isCenter = mode === 'center';
let viewRoot = {
name: path.basename(psdFile.name, '.psd'),
componentName : 'Div',
uuid: generateUUID(),
};
const assets = [];
const imageHashMap = {};
let {width: stageWidthOrigin, height: stageHeightOrigin} = tree;
const stageWidth = stageWidthOrigin - cutSize.x || 0;
const stageHeight = stageHeightOrigin - cutSize.y || 0;
await walkNode(tree, async function (node, parent) {
let {name} = node;
const {x, y, width, height, opacity, display, origin: {layer, layer: {typeTool, solidColor}}} = node;
//console.log('walk node:', name);
let properties = {
style:{
width, height, opacity,display ,
},
attrs:{
},
className:""
};
const isSecondLayer = singleView && !parent.origin.parent || !singleView && parent.origin.parent && !parent.origin.parent.parent;
const shouldVerticalCenter = isSecondLayer && isCenter;
if (name.includes('|') || shouldVerticalCenter) {
try {
let arr = name.split('|');
name = arr[0];
let paramsStr = arr[1];
let relativePos;
if(paramsStr){
let params = paramsStr.split(';');
relativePos = params[0];
}else if(shouldVerticalCenter){
relativePos = 'v';
}
if (relativePos) {
let items = relativePos.split(',');
for (let item of items) {
let result = item.match(/[a-zA-Z]+/);
if(!result){
continue;
}
let prefix = result[0];
let mapItem = relativePosPrefixMap[prefix];
if (mapItem) {
let {field,} = mapItem;
let value = item.substr(prefix.length);
let hasValue = value.length > 0;
let fieldChar = prefix[0];
if(!hasValue){
switch(fieldChar){
case 'l':
value = x - offset.x;
break;
case 't':
value = y - offset.y;
break;
case 'r':
value = stageWidth - (x - offset.x) - width;
break;
case 'b':
value = stageHeight - (y - offset.y) - height;
break;
case 'h':
value = x + width / 2 - stageWidthOrigin / 2;
break;
case 'v':
value = y + height / 2 - stageHeightOrigin / 2;
break;
}
}
let isPercent = prefix.endsWith('p');
if (isPercent) {
if(!hasValue){
switch(fieldChar){
case 'l':
case 'r':
value /= stageWidth;
break;
case 't':
case 'b':
value /= stageHeight;
break;
}
value = Math.floor(value * 100);
}
value += '%';
} else {
value = parseFloat(value);
if (isNaN(value)) {
value = 0;
}
}
console.log(properties);
properties.style[field] = value;
}
}
}
}catch (e) {
console.log(e);
}
}
let viewNode = {
name,
properties,
uuid: generateUUID(),
};
let dealLater = true;
if (x !== 0) {
console.log(properties);
if(!properties.style.left){
properties.style.left = x - (isSecondLayer ? offset.x : 0);
}
}
if (y !== 0) {
if(!properties.style.top){
properties.style.top = y - (isSecondLayer ? offset.y : 0);
}
}
properties.style.position="absolute";
properties.style.transformOrigin="0px 0px 0px";
viewNode.rect={
x: properties.style.left?properties.style.left:0,
y: properties.style.top?properties.style.top:0,
width: properties.style.width,
height: properties.style.height
};
if (typeTool) {
let fontInfo = typeTool();
properties.attrs.text = fontInfo.textValue;
const sizes = fontInfo.sizes();
const colors = fontInfo.colors();
properties.style.fontSize = sizes ? sizes[0] || 20 : 20;
let [r, g, b, a] = colors[0];
console.log("color",[r, g, b, a]);
properties.style.color = `rgba(${r}, ${g}, ${b}, ${a / 255})`;
viewNode.componentName = 'Label';
dealLater = false;
} else if (solidColor && layer.vectorMask) {
let paths = layer.vectorMask().paths;
if (paths[2].numPoints === 4) {
let isRect = true;
for (let i = 3; i < paths.length; i++) {
if (paths[i].recordType !== 2) {
isRect = false;
break;
}
}
if (isRect) {
viewNode.componentName = 'Div';
const {r, g, b} = solidColor();
properties.style.backgroundColor = `rgba(${r}, ${g}, ${b}, 1)`;
dealLater = false;
}
}
}
if (dealLater) {
if (node.hasOwnProperty('children')) {
viewNode.componentName = 'Div';
} else {
viewNode.componentName = 'Image';
let uuid = generateUUID();
const ext = '.png';
let dataUrl;
try {
let img = node.origin.toPng();
dataUrl = img.src;
} catch (e) {
}
if (dataUrl) {
let base64Data = dataUrl.replace(/^data:image\/\w+;base64,/, "");
let buffer = new Buffer(base64Data, 'base64');
const fileNameHash = hash(buffer);
if (imageHashMap.hasOwnProperty(fileNameHash)) {
uuid = imageHashMap[fileNameHash];
} else {
imageHashMap[fileNameHash] = uuid;
assets.push({
name,
ext,
uuid,
base64Data,
hash: fileNameHash,
});
}
properties.attrs.source = 'asset://' + uuid;
}
}
}
let viewParent = parent.view || viewRoot;
if (!viewParent.hasOwnProperty('children')) {
viewParent.children = [];
}
viewParent.children.push(viewNode);
node.view = viewNode;
});
console.log(psdFile);
let data = {
pluginVersion:"0.0.1",
reference:"psd",
fileName:psdFile.name,
assets,
view: viewRoot,
};
let dataString = JSON.stringify(data);
let buf = new Buffer(dataString);
return await new Promise((resolve, reject) => {
zlib.gzip(buf, function (err, res) {
if (err) {
reject(err);
} else {
console.log(res.length);
resolve(res);
}
});
})
}
export { getTree, execute as toZeroing };
//# sourceMappingURL=index.es.js.map //# sourceMappingURL=index.es.js.map
This diff is collapsed.
'use strict'; 'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
var path = _interopDefault(require('path'));
require('color');
var generateUUID = _interopDefault(require('uuid/v4'));
var hash = _interopDefault(require('object-hash'));
var zlib = _interopDefault(require('zlib'));
/** /**
* Created by rockyl on 2019-08-09. * Created by rockyl on 2019-08-08.
*/ */
const PSD = window['require']('psd'); const { getTree } = require('./psd-tree');
const { execute } = require("./zeroing");
async function getTree(file) {
let psd = await PSD.fromDroppedFile(file);
const root = {};
walk(psd.tree(), root);
return root;
}
function walk(psNode, dataNode) { module.exports = {
const {left: pLeft = 0, top: pTop = 0,} = psNode.parent || {}; getTree,
const {left, top, width, height, name, layer: {opacity, visible}} = psNode; execute
const x = left - pLeft;
const y = top - pTop;
Object.assign(dataNode, {x, y, width, height, opacity: opacity / 255, visible, name, origin: psNode, label: `${name} > [${x}, ${y}, ${width}, ${height}]`});
if (psNode.children() && psNode.children().length > 0){
dataNode.children = [];
}
let children = psNode.children();
for (let i = children.length - 1; i >= 0; i--) {
const childPsNode = children[i];
const childDataNode = {};
dataNode.children.push(childDataNode);
walk(childPsNode, childDataNode);
}
}
/**
* Created by rockyl on 2019-08-10.
*/
async function walkNode(node, callback, includeSelf = false) {
if (includeSelf) {
await callback(node, null);
}
if (node.children && node.children.length > 0) {
for (let childNode of node.children) {
await callback(childNode, node);
const result = await walkNode(childNode, callback);
if (result === true) {
break;
}
}
}
}
/**
* Created by renjianfeng on 2020-06-11.
*
* 导出spark的视图
*/
const relativePosPrefixMap = {
l: {field: 'left',},
t: {field: 'top',},
r: {field: 'right',},
b: {field: 'bottom',},
h: {field: 'horizonCenter',},
v: {field: 'verticalCenter',},
wp: {field: 'width', },
hp: {field: 'height', },
lp: {field: 'left', },
tp: {field: 'top', },
rp: {field: 'right', },
bp: {field: 'bottom', },
}; };
const offsetAll = 176;
async function execute(psdFile, options) {
const tree = await getTree(psdFile);
const {mode = 'none', singleView = true} = options;
let offset = {x: 0, y: 0};
let cutSize = {x: 0, y: 0};
if (mode !== 'none') {
cutSize.y = offsetAll;
}
switch (mode) {
case 'top':
offset.y = offsetAll;
break;
case 'center':
offset.y = offsetAll / 2;
break;
}
const isCenter = mode === 'center';
let viewRoot = {
name: path.basename(psdFile.name, '.psd'),
componentName : 'Div',
uuid: generateUUID(),
};
const assets = [];
const imageHashMap = {};
let {width: stageWidthOrigin, height: stageHeightOrigin} = tree;
const stageWidth = stageWidthOrigin - cutSize.x || 0;
const stageHeight = stageHeightOrigin - cutSize.y || 0;
await walkNode(tree, async function (node, parent) {
let {name} = node;
const {x, y, width, height, opacity, display, origin: {layer, layer: {typeTool, solidColor}}} = node;
//console.log('walk node:', name);
let properties = {
style:{
width, height, opacity,display ,
},
attrs:{
},
className:""
};
const isSecondLayer = singleView && !parent.origin.parent || !singleView && parent.origin.parent && !parent.origin.parent.parent;
const shouldVerticalCenter = isSecondLayer && isCenter;
if (name.includes('|') || shouldVerticalCenter) {
try {
let arr = name.split('|');
name = arr[0];
let paramsStr = arr[1];
let relativePos;
if(paramsStr){
let params = paramsStr.split(';');
relativePos = params[0];
}else if(shouldVerticalCenter){
relativePos = 'v';
}
if (relativePos) {
let items = relativePos.split(',');
for (let item of items) {
let result = item.match(/[a-zA-Z]+/);
if(!result){
continue;
}
let prefix = result[0];
let mapItem = relativePosPrefixMap[prefix];
if (mapItem) {
let {field,} = mapItem;
let value = item.substr(prefix.length);
let hasValue = value.length > 0;
let fieldChar = prefix[0];
if(!hasValue){
switch(fieldChar){
case 'l':
value = x - offset.x;
break;
case 't':
value = y - offset.y;
break;
case 'r':
value = stageWidth - (x - offset.x) - width;
break;
case 'b':
value = stageHeight - (y - offset.y) - height;
break;
case 'h':
value = x + width / 2 - stageWidthOrigin / 2;
break;
case 'v':
value = y + height / 2 - stageHeightOrigin / 2;
break;
}
}
let isPercent = prefix.endsWith('p');
if (isPercent) {
if(!hasValue){
switch(fieldChar){
case 'l':
case 'r':
value /= stageWidth;
break;
case 't':
case 'b':
value /= stageHeight;
break;
}
value = Math.floor(value * 100);
}
value += '%';
} else {
value = parseFloat(value);
if (isNaN(value)) {
value = 0;
}
}
console.log(properties);
properties.style[field] = value;
}
}
}
}catch (e) {
console.log(e);
}
}
let viewNode = {
name,
properties,
uuid: generateUUID(),
};
let dealLater = true;
if (x !== 0) {
console.log(properties);
if(!properties.style.left){
properties.style.left = x - (isSecondLayer ? offset.x : 0);
}
}
if (y !== 0) {
if(!properties.style.top){
properties.style.top = y - (isSecondLayer ? offset.y : 0);
}
}
properties.style.position="absolute";
properties.style.transformOrigin="0px 0px 0px";
viewNode.rect={
x: properties.style.left?properties.style.left:0,
y: properties.style.top?properties.style.top:0,
width: properties.style.width,
height: properties.style.height
};
if (typeTool) {
let fontInfo = typeTool();
properties.attrs.text = fontInfo.textValue;
const sizes = fontInfo.sizes();
const colors = fontInfo.colors();
properties.style.fontSize = sizes ? sizes[0] || 20 : 20;
let [r, g, b, a] = colors[0];
console.log("color",[r, g, b, a]);
properties.style.color = `rgba(${r}, ${g}, ${b}, ${a / 255})`;
viewNode.componentName = 'Label';
dealLater = false;
} else if (solidColor && layer.vectorMask) {
let paths = layer.vectorMask().paths;
if (paths[2].numPoints === 4) {
let isRect = true;
for (let i = 3; i < paths.length; i++) {
if (paths[i].recordType !== 2) {
isRect = false;
break;
}
}
if (isRect) {
viewNode.componentName = 'Div';
const {r, g, b} = solidColor();
properties.style.backgroundColor = `rgba(${r}, ${g}, ${b}, 1)`;
dealLater = false;
}
}
}
if (dealLater) {
if (node.hasOwnProperty('children')) {
viewNode.componentName = 'Div';
} else {
viewNode.componentName = 'Image';
let uuid = generateUUID();
const ext = '.png';
let dataUrl;
try {
let img = node.origin.toPng();
dataUrl = img.src;
} catch (e) {
}
if (dataUrl) {
let base64Data = dataUrl.replace(/^data:image\/\w+;base64,/, "");
let buffer = new Buffer(base64Data, 'base64');
const fileNameHash = hash(buffer);
if (imageHashMap.hasOwnProperty(fileNameHash)) {
uuid = imageHashMap[fileNameHash];
} else {
imageHashMap[fileNameHash] = uuid;
assets.push({
name,
ext,
uuid,
base64Data,
hash: fileNameHash,
});
}
properties.attrs.source = 'asset://' + uuid;
}
}
}
let viewParent = parent.view || viewRoot;
if (!viewParent.hasOwnProperty('children')) {
viewParent.children = [];
}
viewParent.children.push(viewNode);
node.view = viewNode;
});
console.log(psdFile);
let data = {
pluginVersion:"0.0.1",
reference:"psd",
fileName:psdFile.name,
assets,
view: viewRoot,
};
let dataString = JSON.stringify(data);
let buf = new Buffer(dataString);
return await new Promise((resolve, reject) => {
zlib.gzip(buf, function (err, res) {
if (err) {
reject(err);
} else {
console.log(res.length);
resolve(res);
}
});
})
}
exports.getTree = getTree;
exports.toZeroing = execute;
//# sourceMappingURL=index.js.map //# sourceMappingURL=index.js.map
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
{
"name": "psd-parse-web",
"version": "1.0.2",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"at-least-node": {
"version": "1.0.0",
"resolved": "http://npm.dui88.com:80/at-least-node/-/at-least-node-1.0.0.tgz",
"integrity": "sha1-YCzUtG6EStTv/JKoARo8RuAjjcI="
},
"coffee-script": {
"version": "1.7.1",
"resolved": "http://npm.dui88.com:80/coffee-script/-/coffee-script-1.7.1.tgz",
"integrity": "sha1-YplqhheAx15tUGnROCJyO3NAS/w=",
"requires": {
"mkdirp": "~0.3.5"
}
},
"coffeescript-module": {
"version": "0.2.1",
"resolved": "http://npm.dui88.com:80/coffeescript-module/-/coffeescript-module-0.2.1.tgz",
"integrity": "sha1-LGGqhpg8rNImcZ+fHdqSPLCuZ7A="
},
"color": {
"version": "3.1.3",
"resolved": "http://npm.dui88.com:80/color/-/color-3.1.3.tgz",
"integrity": "sha1-ymf7TnuX1hHc3jns7tQiBn2RWW4=",
"requires": {
"color-convert": "^1.9.1",
"color-string": "^1.5.4"
}
},
"color-convert": {
"version": "1.9.3",
"resolved": "http://npm.dui88.com:80/color-convert/-/color-convert-1.9.3.tgz",
"integrity": "sha1-u3GFBpDh8TZWfeYp0tVHHe2kweg=",
"requires": {
"color-name": "1.1.3"
}
},
"color-name": {
"version": "1.1.3",
"resolved": "http://npm.dui88.com:80/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
},
"color-string": {
"version": "1.5.4",
"resolved": "http://npm.dui88.com:80/color-string/-/color-string-1.5.4.tgz",
"integrity": "sha1-3VHNJc/ulT0Tj+QAI3LMPQ5QTLY=",
"requires": {
"color-name": "^1.0.0",
"simple-swizzle": "^0.2.2"
}
},
"fs-extra": {
"version": "9.0.1",
"resolved": "http://npm.dui88.com:80/fs-extra/-/fs-extra-9.0.1.tgz",
"integrity": "sha1-kQ2gBiQ3ukw5/t2GPxZ1zP78ufw=",
"requires": {
"at-least-node": "^1.0.0",
"graceful-fs": "^4.2.0",
"jsonfile": "^6.0.1",
"universalify": "^1.0.0"
}
},
"graceful-fs": {
"version": "4.2.4",
"resolved": "http://npm.dui88.com:80/graceful-fs/-/graceful-fs-4.2.4.tgz",
"integrity": "sha1-Ila94U02MpWMRl68ltxGfKB6Kfs="
},
"iconv-lite": {
"version": "0.4.24",
"resolved": "http://npm.dui88.com:80/iconv-lite/-/iconv-lite-0.4.24.tgz",
"integrity": "sha1-ICK0sl+93CHS9SSXSkdKr+czkIs=",
"requires": {
"safer-buffer": ">= 2.1.2 < 3"
}
},
"is-arrayish": {
"version": "0.3.2",
"resolved": "http://npm.dui88.com:80/is-arrayish/-/is-arrayish-0.3.2.tgz",
"integrity": "sha1-RXSirlb3qyBolvtDHq7tBm/fjwM="
},
"jsonfile": {
"version": "6.1.0",
"resolved": "http://npm.dui88.com:80/jsonfile/-/jsonfile-6.1.0.tgz",
"integrity": "sha1-vFWyY0eTxnnsZAMJTrE2mKbsCq4=",
"requires": {
"graceful-fs": "^4.1.6",
"universalify": "^2.0.0"
},
"dependencies": {
"universalify": {
"version": "2.0.0",
"resolved": "http://npm.dui88.com:80/universalify/-/universalify-2.0.0.tgz",
"integrity": "sha1-daSYTv7cSwiXXFrrc/Uw0C3yVxc="
}
}
},
"jspack": {
"version": "0.0.4",
"resolved": "http://npm.dui88.com:80/jspack/-/jspack-0.0.4.tgz",
"integrity": "sha1-Mt01x/3LPjRWwY+7fvntC8YjgXc="
},
"lodash": {
"version": "2.4.2",
"resolved": "http://npm.dui88.com:80/lodash/-/lodash-2.4.2.tgz",
"integrity": "sha1-+t2DS5aDBz2hebPq5tnA0VBT9z4="
},
"mkdirp": {
"version": "0.3.5",
"resolved": "http://npm.dui88.com:80/mkdirp/-/mkdirp-0.3.5.tgz",
"integrity": "sha1-3j5fiWHIjHh+4TaN+EmsRBPsqNc="
},
"object-hash": {
"version": "2.0.3",
"resolved": "http://npm.dui88.com:80/object-hash/-/object-hash-2.0.3.tgz",
"integrity": "sha1-0S2wROA80so9d8BXDYciWwLh5uo="
},
"parse-engine-data": {
"version": "0.1.2",
"resolved": "http://npm.dui88.com:80/parse-engine-data/-/parse-engine-data-0.1.2.tgz",
"integrity": "sha1-UWH2EzyYiPUhVezO1CcWV13+oFI=",
"requires": {
"iconv-lite": "^0.4.4"
}
},
"pngjs": {
"version": "3.2.0",
"resolved": "http://npm.dui88.com:80/pngjs/-/pngjs-3.2.0.tgz",
"integrity": "sha1-/J/OoaijddpUpRFIAZ1avUHbq94="
},
"psd": {
"version": "3.2.0",
"resolved": "http://npm.dui88.com:80/psd/-/psd-3.2.0.tgz",
"integrity": "sha1-1yHEAgfUyZ2C/uSuLXz8pPsHPag=",
"requires": {
"coffee-script": "~ 1.7.1",
"coffeescript-module": "~ 0.2.1",
"iconv-lite": "~ 0.4.4",
"jspack": "~ 0.0.3",
"lodash": "~ 2.4",
"parse-engine-data": "~ 0.1",
"pngjs": "3.2.0",
"rsvp": "~ 3.0.6"
}
},
"rsvp": {
"version": "3.0.21",
"resolved": "http://npm.dui88.com:80/rsvp/-/rsvp-3.0.21.tgz",
"integrity": "sha1-ScWI/hjvKTvNCrn05nVuasQzNZ8="
},
"safer-buffer": {
"version": "2.1.2",
"resolved": "http://npm.dui88.com:80/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha1-RPoWGwGHuVSd2Eu5GAL5vYOFzWo="
},
"simple-swizzle": {
"version": "0.2.2",
"resolved": "http://npm.dui88.com:80/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
"integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=",
"requires": {
"is-arrayish": "^0.3.1"
}
},
"universalify": {
"version": "1.0.0",
"resolved": "http://npm.dui88.com:80/universalify/-/universalify-1.0.0.tgz",
"integrity": "sha1-thodoXPoQ1sv48Z9Kbmt+FlL0W0="
},
"uuid": {
"version": "3.4.0",
"resolved": "http://npm.dui88.com:80/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha1-sj5DWK+oogL+ehAK8fX4g/AgB+4="
}
}
}
...@@ -5,12 +5,15 @@ ...@@ -5,12 +5,15 @@
"module": "dist/index.es.js", "module": "dist/index.es.js",
"license": "MIT", "license": "MIT",
"scripts": { "scripts": {
"test": "node test/index.js",
"dev": "rollup -c -w", "dev": "rollup -c -w",
"build": "rollup -c" "build": "rollup -c"
}, },
"dependencies": { "dependencies": {
"color": "^3.1.2", "color": "^3.1.2",
"fs-extra": "^9.0.1",
"object-hash": "^2.0.1", "object-hash": "^2.0.1",
"psd": "^3.2.0",
"uuid": "^3.3.3" "uuid": "^3.3.3"
} }
} }
...@@ -2,6 +2,11 @@ ...@@ -2,6 +2,11 @@
* Created by rockyl on 2019-08-08. * Created by rockyl on 2019-08-08.
*/ */
export {getTree} from "./psd-tree"; const { getTree } = require('./psd-tree');
const { execute } = require("./zeroing");
module.exports = {
getTree,
execute
}
export {execute as toZeroing} from "./zeroing";
...@@ -2,15 +2,17 @@ ...@@ -2,15 +2,17 @@
* Created by rockyl on 2019-08-09. * Created by rockyl on 2019-08-09.
*/ */
const PSD = window['require']('psd'); var PSD = require('psd');
// var psd = PSD.fromFile("path/to/file.psd");
export async function getTree(file) { // psd.parse();
let psd = await PSD.fromDroppedFile(file);
async function getTree(psdFilePath) {
const psd = await PSD.open(psdFilePath);
const root = {}; const root = {};
walk(psd.tree(), root); walk(psd.tree(), root);
return root; return root;
} }
function walk(psNode, dataNode) { function walk(psNode, dataNode) {
...@@ -19,7 +21,7 @@ function walk(psNode, dataNode) { ...@@ -19,7 +21,7 @@ function walk(psNode, dataNode) {
const x = left - pLeft; const x = left - pLeft;
const y = top - pTop; const y = top - pTop;
Object.assign(dataNode, {x, y, width, height, opacity: opacity / 255, visible, name, origin: psNode, label: `${name} > [${x}, ${y}, ${width}, ${height}]`}); Object.assign(dataNode, {x, y, width, height, alpha: opacity / 255, visible, name, origin: psNode, label: `${name} > [${x}, ${y}, ${width}, ${height}]`});
if (psNode.children() && psNode.children().length > 0){ if (psNode.children() && psNode.children().length > 0){
dataNode.children = []; dataNode.children = [];
} }
...@@ -32,4 +34,8 @@ function walk(psNode, dataNode) { ...@@ -32,4 +34,8 @@ function walk(psNode, dataNode) {
dataNode.children.push(childDataNode); dataNode.children.push(childDataNode);
walk(childPsNode, childDataNode) walk(childPsNode, childDataNode)
} }
}
module.exports={
getTree
} }
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* Created by rockyl on 2019-08-10. * Created by rockyl on 2019-08-10.
*/ */
export async function walkNode(node, callback, includeSelf = false) { async function walkNode(node, callback, includeSelf = false) {
if (includeSelf) { if (includeSelf) {
await callback(node, null); await callback(node, null);
} }
...@@ -17,7 +17,7 @@ export async function walkNode(node, callback, includeSelf = false) { ...@@ -17,7 +17,7 @@ export async function walkNode(node, callback, includeSelf = false) {
} }
} }
export async function walkObject(obj, callback) { async function walkObject(obj, callback) {
if(typeof obj === "object"){ if(typeof obj === "object"){
for (let key of Object.keys(obj)) { for (let key of Object.keys(obj)) {
const value = obj[key]; const value = obj[key];
...@@ -29,3 +29,7 @@ export async function walkObject(obj, callback) { ...@@ -29,3 +29,7 @@ export async function walkObject(obj, callback) {
} }
} }
} }
module.exports={
walkNode,
walkObject
}
\ No newline at end of file
/** /**
* Created by renjianfeng on 2020-06-11. * Created by rockyl on 2019-09-26.
* *
* 导出spark的视图 * 导出zeroing的视图
*/ */
import {getTree} from "./psd-tree"; var { getTree } = require("./psd-tree");
import {walkNode} from "./utils"; var { walkNode } = require("./utils");
import path from 'path' var path = require('path');
import Color from 'color' var Color = require('color');
import generateUUID from 'uuid/v4' var generateUUID = require('uuid/v4');
import hash from 'object-hash'; var fs = require("fs-extra");
import zlib from 'zlib'; var hash = require('object-hash');
const relativePosPrefixMap = { async function execute(psdFile, options={}) {
l: {field: 'left',}, const {
t: {field: 'top',}, imagesPath='imagesPath',
r: {field: 'right',}, } = options;
b: {field: 'bottom',},
h: {field: 'horizonCenter',},
v: {field: 'verticalCenter',},
wp: {field: 'width', },
hp: {field: 'height', },
lp: {field: 'left', },
tp: {field: 'top', },
rp: {field: 'right', },
bp: {field: 'bottom', },
};
const offsetAll = 176;
export async function execute(psdFile, options) {
const tree = await getTree(psdFile); const tree = await getTree(psdFile);
const {mode = 'none', singleView = true} = options;
let offset = {x: 0, y: 0};
let cutSize = {x: 0, y: 0};
if (mode !== 'none') {
cutSize.y = offsetAll;
}
switch (mode) {
case 'top':
offset.y = offsetAll;
break;
case 'center':
offset.y = offsetAll / 2;
break;
}
const isCenter = mode === 'center';
let viewRoot = { let viewRoot = {
name: path.basename(psdFile.name, '.psd'), name: path.basename(psdFile, '.psd'),
componentName : 'Div', type: 'node',
uuid: generateUUID(), uuid: generateUUID(),
}; };
const assets = []; const assets = [];
const imageHashMap = {}; const imageHashMap = {};
let {width: stageWidthOrigin, height: stageHeightOrigin} = tree;
const stageWidth = stageWidthOrigin - cutSize.x || 0;
const stageHeight = stageHeightOrigin - cutSize.y || 0;
await walkNode(tree, async function (node, parent) { await walkNode(tree, async function (node, parent) {
let {name} = node; const { name, x, y, width, height, alpha, visible, origin: { layer, layer: { typeTool, solidColor } } } = node;
const {x, y, width, height, opacity, display, origin: {layer, layer: {typeTool, solidColor}}} = node;
//console.log('walk node:', name);
let properties = { let properties = {
style:{ width, height, alpha, visible,
width, height, opacity,display ,
},
attrs:{
},
className:""
}; };
const isSecondLayer = singleView && !parent.origin.parent || !singleView && parent.origin.parent && !parent.origin.parent.parent;
const shouldVerticalCenter = isSecondLayer && isCenter;
const {width: parentWidth, height: parentHeight} = parent;
if (name.includes('|') || shouldVerticalCenter) {
try {
let arr = name.split('|');
name = arr[0];
let paramsStr = arr[1];
let relativePos;
if(paramsStr){
let params = paramsStr.split(';');
relativePos = params[0];
}else if(shouldVerticalCenter){
relativePos = 'v';
}
if (relativePos) {
let items = relativePos.split(',');
for (let item of items) {
let result = item.match(/[a-zA-Z]+/);
if(!result){
continue;
}
let prefix = result[0];
let mapItem = relativePosPrefixMap[prefix];
if (mapItem) {
let {field,} = mapItem;
let value = item.substr(prefix.length);
let hasValue = value.length > 0;
let fieldChar = prefix[0];
if(!hasValue){
switch(fieldChar){
case 'l':
value = x - offset.x;
break;
case 't':
value = y - offset.y;
break;
case 'r':
value = stageWidth - (x - offset.x) - width;
break;
case 'b':
value = stageHeight - (y - offset.y) - height;
break;
case 'h':
value = x + width / 2 - stageWidthOrigin / 2;
break;
case 'v':
value = y + height / 2 - stageHeightOrigin / 2;
break;
}
}
let isPercent = prefix.endsWith('p');
if (isPercent) {
if(!hasValue){
switch(fieldChar){
case 'l':
case 'r':
value /= stageWidth;
break;
case 't':
case 'b':
value /= stageHeight;
break;
}
value = Math.floor(value * 100);
}
value += '%';
} else {
value = parseFloat(value);
if (isNaN(value)) {
value = 0;
}
}
console.log(properties)
properties.style[field] = value;
}
}
}
}catch (e) {
console.log(e);
}
}
let viewNode = { let viewNode = {
name, name,
properties, properties,
...@@ -169,38 +40,33 @@ export async function execute(psdFile, options) { ...@@ -169,38 +40,33 @@ export async function execute(psdFile, options) {
}; };
let dealLater = true; let dealLater = true;
if (x !== 0) { if (x !== 0) {
console.log(properties) properties.x = x;
if(!properties.style.left){
properties.style.left = x - (isSecondLayer ? offset.x : 0);
}
} }
if (y !== 0) { if (y !== 0) {
if(!properties.style.top){ properties.y = y;
properties.style.top = y - (isSecondLayer ? offset.y : 0);
}
}
properties.style.position="absolute"
properties.style.transformOrigin="0px 0px 0px";
viewNode.rect={
x: properties.style.left?properties.style.left:0,
y: properties.style.top?properties.style.top:0,
width: properties.style.width,
height: properties.style.height
} }
if (typeTool) { if (typeTool) {
let fontInfo = typeTool(); let fontInfo = typeTool();
properties.attrs.text = fontInfo.textValue; //const fonts = fontInfo.fonts();
//const styles = fontInfo.styles();
//const {RunLengthArray} = fontInfo.engineData.EngineDict.StyleRun;
properties.text = fontInfo.textValue;
const sizes = fontInfo.sizes(); const sizes = fontInfo.sizes();
const colors = fontInfo.colors(); const colors = fontInfo.colors();
properties.style.fontSize = sizes ? sizes[0] || 20 : 20; properties.size = sizes ? sizes[0] || 20 : 20;
let [r, g, b, a] = colors[0]; let [r, g, b, a] = colors[0];
console.log("color",[r, g, b, a]) properties.fillColor = `rgba(${r}, ${g}, ${b}, ${a / 255})`;
properties.style.color = `rgba(${r}, ${g}, ${b}, ${a / 255})`; /*properties.textflow = {
viewNode.componentName = 'Label'; fonts, styles, RunLengthArray,
};*/
viewNode.type = 'label';
dealLater = false; dealLater = false;
} else if (solidColor && layer.vectorMask) { } else if (solidColor) {
const { r, g, b } = solidColor();
let color = Color({ r, g, b });
let paths = layer.vectorMask().paths; let paths = layer.vectorMask().paths;
if (paths[2].numPoints === 4) { if (paths[2].numPoints === 4) {
let isRect = true; let isRect = true;
...@@ -211,9 +77,8 @@ export async function execute(psdFile, options) { ...@@ -211,9 +77,8 @@ export async function execute(psdFile, options) {
} }
} }
if (isRect) { if (isRect) {
viewNode.componentName = 'Div'; viewNode.type = 'rect';
const {r, g, b} = solidColor(); properties.fillColor = '#' + color.rgbNumber().toString(16);
properties.style.backgroundColor = `rgba(${r}, ${g}, ${b}, 1)`;
dealLater = false; dealLater = false;
} }
} }
...@@ -221,24 +86,21 @@ export async function execute(psdFile, options) { ...@@ -221,24 +86,21 @@ export async function execute(psdFile, options) {
if (dealLater) { if (dealLater) {
if (node.hasOwnProperty('children')) { if (node.hasOwnProperty('children')) {
viewNode.componentName = 'Div'; viewNode.type = 'div';
} else { } else {
viewNode.componentName = 'Image'; viewNode.type = 'image';
let uuid = generateUUID(); let uuid = generateUUID();
const ext = '.png'; const ext = '.png';
let dataUrl; const imageFilePath = path.join(imagesPath, uuid + ext);
try { await fs.ensureDir(path.dirname(imageFilePath));
let img = node.origin.toPng(); let png = node.origin.toPng();
dataUrl = img.src; let buffer = await savePng(png, imageFilePath).catch(e => {
} catch (e) { });
//await node.origin.saveAsPng(imageFilePath);
} if (buffer) {
if (dataUrl) {
let base64Data = dataUrl.replace(/^data:image\/\w+;base64,/, "");
let buffer = new Buffer(base64Data, 'base64');
const fileNameHash = hash(buffer); const fileNameHash = hash(buffer);
if (imageHashMap.hasOwnProperty(fileNameHash)) { if (imageHashMap.hasOwnProperty(fileNameHash)) {
uuid = imageHashMap[fileNameHash]; uuid = imageHashMap[fileNameHash];
...@@ -248,12 +110,14 @@ export async function execute(psdFile, options) { ...@@ -248,12 +110,14 @@ export async function execute(psdFile, options) {
name, name,
ext, ext,
uuid, uuid,
base64Data,
hash: fileNameHash, hash: fileNameHash,
}); });
} }
properties.attrs.source = 'asset://' + uuid; const hashFilePath = path.join(imagesPath, fileNameHash + ext);
await fs.rename(imageFilePath, hashFilePath);
properties.source = 'asset://' + uuid;
} }
} }
} }
...@@ -266,26 +130,29 @@ export async function execute(psdFile, options) { ...@@ -266,26 +130,29 @@ export async function execute(psdFile, options) {
node.view = viewNode; node.view = viewNode;
}); });
console.log(psdFile)
let data = {
pluginVersion:"0.0.1",
reference:"psd",
fileName:psdFile.name,
assets,
view: viewRoot,
};
let dataString = JSON.stringify(data); return {
view: viewRoot,
assets,
}
}
let buf = new Buffer(dataString); function savePng(png, output) {
return await new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
zlib.gzip(buf, function (err, res) { let buffer, buffers = [];
if (err) { png.pack()
reject(err); .on('error', reject)
} else { .on('data', (data) => buffers.push(data))
console.log(res.length); .on('end', () => {
resolve(res); buffer = Buffer.concat(buffers)
} })
}); .pipe(fs.createWriteStream(output))
}) .on('finish', () => {
resolve(buffer);
});
});
} }
module.exports={
execute
}
\ No newline at end of file
var {execute}= require( '../src/index');
let test = async()=>{
let result = await execute('/Users/davezh/Downloads/1.psd')
console.log("---------");
console.log(JSON.stringify(result));
}
test();
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment