diff --git a/PSD2HTML2/lib/json2-min.jsx b/PSD2HTML2/lib/json2-min.jsx
new file mode 100644
index 0000000..4cd380f
--- /dev/null
+++ b/PSD2HTML2/lib/json2-min.jsx
@@ -0,0 +1,326 @@
+var JSON;
+if (!JSON) {
+ JSON = {};
+}
+
+(function () {
+ 'use strict';
+
+ function f(n) {
+ // Format integers to have at least two digits.
+ return n < 10 ? '0' + n : n;
+ }
+
+ if (typeof Date.prototype.toJSON !== 'function') {
+
+ Date.prototype.toJSON = function (key) {
+
+ return isFinite(this.valueOf())
+ ? this.getUTCFullYear() + '-' +
+ f(this.getUTCMonth() + 1) + '-' +
+ f(this.getUTCDate()) + 'T' +
+ f(this.getUTCHours()) + ':' +
+ f(this.getUTCMinutes()) + ':' +
+ f(this.getUTCSeconds()) + 'Z'
+ : null;
+ };
+
+ String.prototype.toJSON =
+ Number.prototype.toJSON =
+ Boolean.prototype.toJSON = function (key) {
+ return this.valueOf();
+ };
+ }
+
+ var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
+ escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
+ gap,
+ indent,
+ meta = { // table of character substitutions
+ '\b': '\\b',
+ '\t': '\\t',
+ '\n': '\\n',
+ '\f': '\\f',
+ '\r': '\\r',
+ '"' : '\\"',
+ '\\': '\\\\'
+ },
+ rep;
+
+
+ function quote(string) {
+
+// If the string contains no control characters, no quote characters, and no
+// backslash characters, then we can safely slap some quotes around it.
+// Otherwise we must also replace the offending characters with safe escape
+// sequences.
+
+ escapable.lastIndex = 0;
+ return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
+ var c = meta[a];
+ return typeof c === 'string'
+ ? c
+ : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+ }) + '"' : '"' + string + '"';
+ }
+
+
+ function str(key, holder) {
+
+// Produce a string from holder[key].
+
+ var i, // The loop counter.
+ k, // The member key.
+ v, // The member value.
+ length,
+ mind = gap,
+ partial,
+ value = holder[key];
+
+// If the value has a toJSON method, call it to obtain a replacement value.
+
+ if (value && typeof value === 'object' &&
+ typeof value.toJSON === 'function') {
+ value = value.toJSON(key);
+ }
+
+// If we were called with a replacer function, then call the replacer to
+// obtain a replacement value.
+
+ if (typeof rep === 'function') {
+ value = rep.call(holder, key, value);
+ }
+
+// What happens next depends on the value's type.
+
+ switch (typeof value) {
+ case 'string':
+ return quote(value);
+
+ case 'number':
+
+// JSON numbers must be finite. Encode non-finite numbers as null.
+
+ return isFinite(value) ? String(value) : 'null';
+
+ case 'boolean':
+ case 'null':
+
+// If the value is a boolean or null, convert it to a string. Note:
+// typeof null does not produce 'null'. The case is included here in
+// the remote chance that this gets fixed someday.
+
+ return String(value);
+
+// If the type is 'object', we might be dealing with an object or an array or
+// null.
+
+ case 'object':
+
+// Due to a specification blunder in ECMAScript, typeof null is 'object',
+// so watch out for that case.
+
+ if (!value) {
+ return 'null';
+ }
+
+// Make an array to hold the partial results of stringifying this object value.
+
+ gap += indent;
+ partial = [];
+
+// Is the value an array?
+
+ if (Object.prototype.toString.apply(value) === '[object Array]') {
+
+// The value is an array. Stringify every element. Use null as a placeholder
+// for non-JSON values.
+
+ length = value.length;
+ for (i = 0; i < length; i += 1) {
+ partial[i] = str(i, value) || 'null';
+ }
+
+// Join all of the elements together, separated with commas, and wrap them in
+// brackets.
+
+ v = partial.length === 0
+ ? '[]'
+ : gap
+ ? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']'
+ : '[' + partial.join(',') + ']';
+ gap = mind;
+ return v;
+ }
+
+// If the replacer is an array, use it to select the members to be stringified.
+
+ if (rep && typeof rep === 'object') {
+ length = rep.length;
+ for (i = 0; i < length; i += 1) {
+ if (typeof rep[i] === 'string') {
+ k = rep[i];
+ v = str(k, value);
+ if (v) {
+ partial.push(quote(k) + (gap ? ': ' : ':') + v);
+ }
+ }
+ }
+ } else {
+
+// Otherwise, iterate through all of the keys in the object.
+
+ for (k in value) {
+ if (Object.prototype.hasOwnProperty.call(value, k)) {
+ v = str(k, value);
+ if (v) {
+ partial.push(quote(k) + (gap ? ': ' : ':') + v);
+ }
+ }
+ }
+ }
+
+// Join all of the member texts together, separated with commas,
+// and wrap them in braces.
+
+ v = partial.length === 0
+ ? '{}'
+ : gap
+ ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}'
+ : '{' + partial.join(',') + '}';
+ gap = mind;
+ return v;
+ }
+ }
+
+// If the JSON object does not yet have a stringify method, give it one.
+
+ if (typeof JSON.stringify !== 'function') {
+ JSON.stringify = function (value, replacer, space) {
+
+// The stringify method takes a value and an optional replacer, and an optional
+// space parameter, and returns a JSON text. The replacer can be a function
+// that can replace values, or an array of strings that will select the keys.
+// A default replacer method can be provided. Use of the space parameter can
+// produce text that is more easily readable.
+
+ var i;
+ gap = '';
+ indent = '';
+
+// If the space parameter is a number, make an indent string containing that
+// many spaces.
+
+ if (typeof space === 'number') {
+ for (i = 0; i < space; i += 1) {
+ indent += ' ';
+ }
+
+// If the space parameter is a string, it will be used as the indent string.
+
+ } else if (typeof space === 'string') {
+ indent = space;
+ }
+
+// If there is a replacer, it must be a function or an array.
+// Otherwise, throw an error.
+
+ rep = replacer;
+ if (replacer && typeof replacer !== 'function' &&
+ (typeof replacer !== 'object' ||
+ typeof replacer.length !== 'number')) {
+ throw new Error('JSON.stringify');
+ }
+
+// Make a fake root object containing our value under the key of ''.
+// Return the result of stringifying the value.
+
+ return str('', {'': value});
+ };
+ }
+
+
+// If the JSON object does not yet have a parse method, give it one.
+
+ if (typeof JSON.parse !== 'function') {
+ JSON.parse = function (text, reviver) {
+
+// The parse method takes a text and an optional reviver function, and returns
+// a JavaScript value if the text is a valid JSON text.
+
+ var j;
+
+ function walk(holder, key) {
+
+// The walk method is used to recursively walk the resulting structure so
+// that modifications can be made.
+
+ var k, v, value = holder[key];
+ if (value && typeof value === 'object') {
+ for (k in value) {
+ if (Object.prototype.hasOwnProperty.call(value, k)) {
+ v = walk(value, k);
+ if (v !== undefined) {
+ value[k] = v;
+ } else {
+ delete value[k];
+ }
+ }
+ }
+ }
+ return reviver.call(holder, key, value);
+ }
+
+
+// Parsing happens in four stages. In the first stage, we replace certain
+// Unicode characters with escape sequences. JavaScript handles many characters
+// incorrectly, either silently deleting them, or treating them as line endings.
+
+ text = String(text);
+ cx.lastIndex = 0;
+ if (cx.test(text)) {
+ text = text.replace(cx, function (a) {
+ return '\\u' +
+ ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+ });
+ }
+
+// In the second stage, we run the text against regular expressions that look
+// for non-JSON patterns. We are especially concerned with '()' and 'new'
+// because they can cause invocation, and '=' because it can cause mutation.
+// But just to be safe, we want to reject all unexpected forms.
+
+// We split the second stage into 4 regexp operations in order to work around
+// crippling inefficiencies in IE's and Safari's regexp engines. First we
+// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
+// replace all simple value tokens with ']' characters. Third, we delete all
+// open brackets that follow a colon or comma or that begin the text. Finally,
+// we look to see that the remaining characters are only whitespace or ']' or
+// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
+
+ if (/^[\],:{}\s]*$/
+ .test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
+ .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
+ .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
+
+// In the third stage we use the eval function to compile the text into a
+// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
+// in JavaScript: it can begin a block or an object literal. We wrap the text
+// in parens to eliminate the ambiguity.
+
+ j = eval('(' + text + ')');
+
+// In the optional fourth stage, we recursively walk the new structure, passing
+// each name/value pair to a reviver function for possible transformation.
+
+ return typeof reviver === 'function'
+ ? walk({'': j}, '')
+ : j;
+ }
+
+// If the text is not JSON parseable, then a SyntaxError is thrown.
+
+ throw new SyntaxError('JSON.parse');
+ };
+ }
+}());
\ No newline at end of file
diff --git a/PSD2HTML2/lib/net.jsx b/PSD2HTML2/lib/net.jsx
new file mode 100644
index 0000000..967e268
--- /dev/null
+++ b/PSD2HTML2/lib/net.jsx
@@ -0,0 +1,109 @@
+(function(){
+ PSD = {};
+ PSD.net = {
+ remote:function(conf){
+ var opt = {
+ dataType:"GET",
+ data:{},
+ files:{},
+ url:"",
+ port:80,
+ header:{
+ "Content-Type": "multipart/form-data",
+ //"Accept": "*/*",
+ "Content-Length": 99999999999,
+ //"User-Agent": "PSD2HTML",
+ "Connection": "Keep-Alive",
+ "Pragma": "no-cache",
+ //"Referer": "http://127.0.0.1:8000/"
+ }
+ };
+
+ var dataArr = [];
+ if(conf.constructor == Object){
+ for(var k in conf){
+ opt[k] = conf[k];
+ }
+ }
+ // 协议
+ dataArr.push(opt.dataType);
+ dataArr.push(" ")
+ if(opt.url.substr(0,7) == "http://") opt.url = opt.url.substr(7);
+
+ var domain = opt.url.split("/")[0] + ":" + opt.port;
+ //opt.header.Host = domain;
+ if(opt.url.indexOf("/") < 0){
+ dataArr.push("/");
+ }else{
+ dataArr.push(opt.url.substr(opt.url.indexOf("/")));
+ }
+ dataArr.push(" HTTP/1.1\r\n");
+ // 头
+ var header = opt.header;
+ var sp = "---------------------------p2h"+ (Math.random() * 10000 | 0) + +new Date;
+
+ for(var k in header){
+ dataArr.push(k);
+ dataArr.push(": ");
+ dataArr.push(header[k]);
+ if(k == "Content-Type") dataArr.push("; boundary="+sp);
+ dataArr.push("\r\n");
+ }
+ dataArr.push("\r\n");
+ // 数据
+ for(var k in opt.data){
+ dataArr.push("--"+sp+"\r\n");
+ dataArr.push("Content-Disposition: form-data; ");
+ dataArr.push('name="'+k+'"');
+ dataArr.push("\r\n\r\n");
+ dataArr.push(opt.data[k]+"\r\n");
+ //dataArr.push(sp+"\r\n");
+ }
+ // 文件
+ for(var k in opt.files){
+ dataArr.push("--"+sp+"\r\n");
+ dataArr.push("Content-Disposition: form-data; ");
+ dataArr.push('name="'+k+'";');
+ dataArr.push('filename="'+(opt.files[k].fsName.replace(/([^\x00-\xff])/g, function(s){ return encodeURI(s)}))+'"');
+ dataArr.push("\r\n\r\n");
+ var f = opt.files[k];
+ f.encoding = "BINARY";
+ f.open('r');
+ var str = f.read();
+ f.close();
+ dataArr.push(str+"\r\n");
+ //dataArr.push(sp+"\r\n");
+ }
+ dataArr.push("--"+sp+"--\r\n");
+ var dataStr = dataArr.join("");
+ $.writeln(dataStr);
+
+ var reply = "";
+
+ var conn = new Socket();
+
+ conn.encoding = "binary";
+ if (conn.open (domain, "binary")) {
+ conn.write (dataStr);
+ reply = conn.read(99999999999);
+ reply = reply.split("\r\n").join("\n");
+ reply = reply.split("\r").join("\n");
+ //file.write(reply.substr(reply.indexOf("\n\n")+2));
+ //file.close();
+ //file.rename(fileName);
+ conn.close();
+ }else{
+ alert("CONNECTION TO DATABASE FAILED");
+ reply = "";
+ }
+ //$.writeln(reply);
+ }
+ }
+})();
+PSD.net.remote({
+ dataType:"POST",
+ url:"http://127.0.0.1/upload",
+ port:8000,
+ data:{te:"wanxianjia"},
+ files:{psd:File("C:/Users/xianjia.wanxj/Desktop/服务介绍页面-我是采购商.png"), txt:File("C:/Users/xianjia.wanxj/Desktop/test.txt")}
+});
\ No newline at end of file
diff --git a/PSD2HTML2/lib/psd.jsx b/PSD2HTML2/lib/psd.jsx
new file mode 100644
index 0000000..9a1d144
--- /dev/null
+++ b/PSD2HTML2/lib/psd.jsx
@@ -0,0 +1,573 @@
+// @include "json2-min.jsx"
+// @include "web-fonts.jsx"
+
+//setting for app preferences
+app.preferences.rulerUnits = Units.PIXELS;
+app.preferences.typeUnits = TypeUnits.PIXELS;
+
+
+function PSD(option){
+ this.doc = app.activeDocument;
+ this.docs = app.documents;
+ this.tree = {name:this.doc.name, width:this.doc.width.value, height:this.doc.height.value, imgCount:0, childs:[]};
+ this.textLayers = []; //存储所有的文本图层
+ this.contentLayers = []; //存储所有的文本图层和图片
+ this.allLayers = [];
+ this.linkReg = /^[aA]$|^[aA]-/;
+ this.imgReg = /img/;
+ this.layers = this.doc.layers;
+ this.option = {
+ exportImages: false, //是否对每个图层到处图层
+ output: File($.fileName).parent.parent+'/output/'
+ }
+ if(option){
+ for(k in option){
+ this.option[k] = option[k];
+ }
+ }
+ this._init();
+}
+
+app.activeDocument.colorSamplers.removeAll();
+PSD.colorSampler = app.activeDocument.colorSamplers.add([UnitValue(0, 'px'), UnitValue(0, 'px')]);
+
+(function(){
+
+var _index = -1,
+ _sliceCount = 0,
+ _content = [],
+ _slices = [],
+ _exportConfig = new ExportOptionsSaveForWeb(),
+ // get image extension from export configuration
+ _getExtension = function(op){
+ switch(op.format){
+ case SaveDocumentType.JPEG:
+ return 'jpg';
+ case SaveDocumentType.PNG:
+ return 'png';
+
+ default:
+ return 'gif';
+ }
+ };
+
+ _exportConfig.format = SaveDocumentType.JPEG;
+ _exportConfig.quality = 60;
+
+
+PSD.fn = PSD.prototype = {
+ _init: function(){
+ this.output = Folder(this.option.output);
+ !this.output.exists && this.output.create();
+
+ this.dir = Folder(this.output + '/' + this.getPSDName());
+ !this.dir.exists && this.dir.create();
+
+ //this.createSnapshotOnStart();
+ },
+ // 遍历所有图层
+ parse: function(layers, context, skip){
+ layers = layers || this.layers;
+
+ if(this.option.exportImages){
+ this.layersImgs = new Folder(this.dir + '/layersImgs/');
+ !this.layersImgs.exists && this.layersImgs.create();
+ }
+
+ for(var i = layers.length - 1; i >= 0; i--){
+ var layer = layers[i];
+ this._getLayerInfo(layer, context, skip);
+ }
+ },
+ getWidth: function(){
+ return this.doc.width.value;
+ },
+ getHeight: function(){
+ return this.doc.height.value;
+ },
+ getPSDName: function(){
+ return this.doc.name.substr (0, this.doc.name.length - 4);
+ },
+ // 获取当前图层text样式
+ getEffects: function(){
+ var ref = new ActionReference();
+ var effects = [];
+ ref.putEnumerated(charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt"));
+
+ var desc = executeActionGet(ref);
+ if (desc.hasKey( stringIDToTypeID('layerEffects'))){
+ var effectDesc = desc.getObjectValue(stringIDToTypeID('layerEffects'));
+ // first key is scale so skip and start with 1
+ for ( var effect = 1; effect < effectDesc.count; effect++ ){
+ effects.push(typeIDToStringID(effectDesc.getKey(effect )));
+ }
+ }
+ return effects;
+ },
+ // 获取当前图层 id
+ getLayerId: function(){
+ var ref = new ActionReference();
+ ref.putEnumerated(charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt"));
+
+ var desc = executeActionGet(ref);
+
+ if (desc.hasKey( charIDToTypeID('LyrI'))){
+ var desc = executeActionGet(ref);
+ var layerId = desc.getInteger(charIDToTypeID('LyrI'));
+ return layerId;
+ }else{
+ return -1;
+ }
+ },
+ _getTextInfo: function(layer){
+ var textInfo = {};
+ if(!layer.kind || (layer.kind && layer.kind.toString() !== "LayerKind.TEXT")) return null;
+
+ var textItem = layer.textItem;
+
+ textInfo = {
+ /*color: textItem.color.rgb.hexValue,
+ contents:textItem.contents,
+ font: WEBFONTS.getWebFont(textItem.font),
+ size: Math.round(textItem.size.value),
+ textType: textItem.kind.toString(),
+ bold: textItem.fauxBold,
+ italic: textItem.fauxItalic,
+ indent: Math.round(textItem.firstLineIndent.value),
+ underline: textItem.underline == UnderlineType.UNDERLINEOFF ? false : true,
+ textRange: this.getTextRange(),
+ position:{x: textItem.position[0].value, y: textItem.position[1].value},
+ leftIndent: textItem.leftIndent.value,
+ rightIndent: textItem.rightIndent.value*/
+ };
+ if(textItem.kind == TextType.PARAGRAPHTEXT){
+ textInfo.width = layer.textItem.width.value;
+ textInfo.height = layer.textItem.height.value;
+
+ // text justification
+ switch(textItem.justification.toString()){
+ case 'Justification.LEFT':
+ textInfo.textAlign = 'left';
+ break;
+ case 'Justification.RIGHT':
+ textInfo.textAlign = 'right';
+ break;
+ case 'Justification.CENTER':
+ textInfo.textAlign = 'center';
+ break;
+ case 'Justification.CENTERJUSTIFIED':
+ case 'Justification.FULLYJUSTIFIED':
+ case 'Justification.LEFTJUSTIFIED':
+ case 'Justification.RIGHTJUSTIFIED':
+ textInfo.textAlign = 'justify';
+ break;
+ default:
+ textInfo.textAlign = 'left';
+
+ }
+ }
+ // line height
+ if(!textItem.useAutoLeading){
+ textInfo.lineHeight = Math.round(textItem.leading.value);
+ }else{
+ try{
+ textInfo.lineHeight = Math.round(textItem.autoLeadingAmount) + '%';
+ }catch(e){}
+ }
+
+ return textInfo;
+ },
+ _processTagsFun: {
+ img: function(layer){
+ if(layer.typename === 'LayerSet'){
+ layer = layer.merge();
+ }else if(layer.typename === 'ArtLayer' && layer.kind.toString () === "LayerKind.TEXT"){
+ layer.rasterize(RasterizeType.ENTIRELAYER); //栅格化
+ }
+
+ layer.tag = "img";
+ return layer;
+ },
+ a: function(layer){
+ layer.link = true;
+
+ if(layer.typename === 'LayerSet'){
+ layer = layer.merge();
+ this._processTagsFun.img(layer);
+ }else if(layer.typename === 'ArtLayer'){
+
+ /*if(layer.kind.toString () === "LayerKind.TEXT"){
+ var textItem = layer.textItem;
+
+ if(WEBFONTS.indexOf(textItem.font) < 0 || this.getEffects().length > 0 || textItem.warpStyle !== WarpStyle.NONE){
+ layer.rasterize(); //栅格化
+ this._processTagsFun.img(layer);
+ }
+ }*/
+ }
+
+ return layer;
+ }
+ },
+ _processTags: function(tags, layer){
+ if(layer.kind && layer.kind.toString () === "LayerKind.TEXT"){
+ var textItem = layer.textItem;
+
+ if(WEBFONTS.indexOf(textItem.font) < 0 || this.getEffects().length > 0 || textItem.warpStyle !== WarpStyle.NONE){
+ layer.rasterize(); //栅格化
+ }
+ }
+
+ if(tags){
+ for(var i = 0, len = tags.length; i < len; i++){
+ layer = this._processTagsFun[tags[i].substring (1)].call(this, layer);
+ }
+ }
+
+ return layer;
+ },
+ // 获取图层信息
+ _getLayerInfo: function(layer, context, skip){
+ _index++;
+
+ context = context || this.tree;
+
+ if(layer.visible === false) return "the layer is hidden";
+
+ try{
+ if(skip && skip(layer)) return "skip this layer";
+ }catch(e){}
+
+ this.doc.activeLayer = layer;
+
+ /* get layer bounds, fix layer bounds */
+ var bounds = layer.bounds,
+ left = bounds[0].value,
+ left = left > 0 ? left : 0;
+ right = bounds[2].value,
+ right = right < this.doc.width.value ? right : this.doc.width.value,
+ top = bounds[1].value,
+ top = top > 0 ? bounds[1].value : 0,
+ bottom = bounds[3].value,
+ bottom = bottom < this.doc.height.value ? bottom : this.doc.height.value;
+
+ if(right <= left || top >= bottom){
+ return "out of viewport";
+ }
+ var kind = layer.kind ? layer.kind.toString() : layer.typename;
+ var id = this.getLayerId();
+ layer.id = id;
+
+ var child = {
+ type: layer.typename,
+ name: layer.name,
+ visible: layer.visible,
+ left: left, top: top,
+ right: right, bottom: bottom,
+ width: right - left,
+ height: bottom - top,
+ kind: kind,
+ isBackgroundLayer: layer.isBackgroundLayer,
+ index: id,
+ id: id
+ }
+
+ child.textInfo = this._getTextInfo(layer);
+
+ var reg = /#img|#a/g;
+ var tags = layer.name.match(reg);
+
+ layer = this._processTags(tags, layer);
+ this.allLayers.push(layer);
+
+ child.tag = layer.tag;
+ child.link = layer.link;
+ child.layer = layer;
+
+ if(layer.typename === 'ArtLayer'){
+
+ _content.push(child);
+ context.childs.push(child);
+
+ if(layer.kind.toString () === "LayerKind.TEXT"){
+ this.contentLayers.push(layer);
+ this.textLayers.push(layer);
+ }
+
+ if(layer.tag === "img"){
+ this.contentLayers.push(layer);
+ }
+
+ }else if(layer.typename == 'LayerSet'){
+
+ var o = {type:layer.typename, name:layer.name, index:_index, childs:[]};
+ context.childs.push(o);
+ this.parse(layer.layers, o, skip);
+ }
+ },
+ exportPng: function(){
+ this.hiddenTextLayers();
+ var img= new File(this.dir + "/psd.png");
+ var options = new ExportOptionsSaveForWeb();
+ options.format = SaveDocumentType.PNG;
+ options.PNG8 = false;
+ this.doc.exportDocument (img, ExportType.SAVEFORWEB, options);
+ //$.writeln(img.length);
+ this.visibleTextLayers();
+ return img;
+ //this.visibleTextLayers();
+ },
+ exportImage: function(layer, index){
+ this.hiddenTextLayers();
+ try{
+ var bounds = layer.bounds;
+ layer.copy();
+ layerWidth = UnitValue(bounds[2].value - bounds[0].value, 'px'),
+ layerHeight = UnitValue(bounds[3].value - bounds[1].value, 'px');
+ var newDoc = this.docs.add(layerWidth, layerHeight);
+ newDoc.paste();
+ newDoc.layers[newDoc.layers.length - 1].remove();
+
+ var img= new File(this.imagesFolder + "/layer_"+_index+".png");
+ var options = new ExportOptionsSaveForWeb();
+ options.format = SaveDocumentType.PNG;
+ newDoc.exportDocument (img, ExportType.SAVEFORWEB, options);
+ newDoc.close(SaveOptions.DONOTSAVECHANGES);
+ }catch(e){
+ alert(e+'#####'+layer.name);
+ }
+ this.visibleTextLayers();
+ },
+ exportJSON: function(data, format){
+ var f = new File(this.dir + "/json.txt");
+ f.encoding = format || 'UTF-8';
+ f.open('w', 'TEXT');
+ f.write(JSON.stringify(data || this.tree));
+ f.close();
+ return f;
+ },
+ getJSON: function(){
+ return this.tree;
+ },
+ hiddenTextLayers: function(){
+ for(var i = 0, l = this.contentLayers.length; i < l; i++){
+ if(!this.contentLayers[i].visible) continue;
+ this.contentLayers[i].visible = false;
+ }
+ },
+ visibleTextLayers: function(){
+ for(var i = 0, l = this.contentLayers.length; i < l; i++){
+ if(this.contentLayers[i].visible) continue;
+ this.contentLayers[i].visible = true;
+ }
+ },
+ /* 自动切片并导出图片 */
+ autoSliceAndExport: function(exportConfig, height){
+ this.hiddenTextLayers();
+
+ var conf = exportConfig || _exportConfig;
+ var extension = _getExtension(conf);
+
+ if(!height){
+ // 生成测试img,用于计算切片高度
+ var testImg = File(this.dir + '/' + 'img.tmp.' + extension);
+ this.doc.exportDocument (testImg, ExportType.SAVEFORWEB, exportConfig);
+ var size = testImg.length, HEIGHT = 120;
+
+ if(size < 70000){
+ HEIGHT = this.getHeight();
+ }else{
+ HEIGHT = Math.round(this.getHeight() / Math.ceil(size / 70000));
+ }
+ testImg.remove(); //删除测试img
+ }else{
+ var HEIGHT = height;
+ }
+
+ var selection = this.doc.selection,
+ docWidth = this.doc.width.value,
+ docHeight = this.doc.height.value,
+ region = [],
+ y = 0, fy;
+
+
+ var slicesFolder = new Folder(this.dir + '/slices/');
+ !slicesFolder.exists && slicesFolder.create();
+
+ try{
+ while(y < docHeight){
+ _index++;
+
+ y = y + HEIGHT;
+ fy = y > docHeight ? docHeight : y;
+ region = [[0, y - HEIGHT], [docWidth, y - HEIGHT], [docWidth, fy], [0, fy]];
+
+ this.exportSelection(region, exportConfig);
+
+ _slices.push({index:_index, type:"ArtLayer", visible:true, kind:"LayerKind.NORMAL", isBackgroundLayer:false,
+ name:'slice_'+_index+'.'+extension, right: docWidth, top:y - HEIGHT, left:0, bottom:fy});
+ _sliceCount++;
+ }
+ selection.deselect();
+ }catch(e){
+ // TODO
+ }
+ this.visibleTextLayers();
+ return _slices;
+ },
+ // 导出选择区域
+ exportSelection: function(region, exportConfig){
+ if(!region) return;
+ // image config
+
+ var conf = exportConfig || _exportConfig;
+ var extension = _getExtension(conf);
+ // copy selected area
+ var selection = this.doc.selection, xset = [], yset = [];
+ selection.select(region);
+ selection.copy(true);
+ //selection.deselect();
+
+ for(var i = 0, l = region.length; i < l; i++){
+ xset.push(region[i][0]);
+ yset.push(region[i][1]);
+ }
+ // var width = Math.max.apply(null, xset) - Math.min.apply(null, xset),
+ // height = Math.max.apply(null, yset) - Math.min.apply(null, yset);
+ xset.sort(function(a,b){return a-b;});
+ yset.sort(function(a,b){return a-b;});
+ var width = xset[xset.length-1] - xset[0],
+ height = yset[yset.length-1] - yset[0];
+
+ // export image
+ var newDoc = this.docs.add(width, height);
+ newDoc.paste();
+ newDoc.layers[newDoc.layers.length - 1].remove();
+ _index++;
+
+ var slicesFolder = new Folder(this.dir + '/slices/');
+ !slicesFolder.exists && slicesFolder.create();
+
+ var img = new File(slicesFolder + "/slice_" + _index + "." + extension);
+ newDoc.exportDocument (img, ExportType.SAVEFORWEB, conf);
+ newDoc.close(SaveOptions.DONOTSAVECHANGES);
+ img.name = 'slice_'+_index+'.'+extension;
+ return {name:img.name,width:width,height:height};
+ },
+ getTextLayersAndSlices: function(option, height){
+ if(_slices.length <= 0) this.autoSliceAndExport(option, height);
+ var data = {name: this.doc.name, imgCount:_sliceCount, childs:_slices.concat(_content)};
+ //this.exportJSON(data);
+ return data;
+ },
+
+ getTextLayers: function(){
+ return _content;
+ },
+ // 获取text range
+ getTextRange: function(){
+ var desc = (function(){
+ var ref = new ActionReference();
+ ref.putEnumerated(charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt"));
+ return executeActionGet(ref);
+ })();
+
+ var list = desc.getObjectValue(charIDToTypeID("Txt "));
+ var tsr = list.getList(charIDToTypeID("Txtt"));
+ var info = [];
+
+ for(var i = 0, l = tsr.count;i < l; i++){
+ var tsr0 = tsr.getObjectValue(i) ;
+ var from = tsr0.getInteger(charIDToTypeID("From"));
+ var to = tsr0.getInteger(charIDToTypeID("T "));
+ var range = [from, to];
+ var textStyle = tsr0.getObjectValue(charIDToTypeID("TxtS"));
+ var font = textStyle.getString(charIDToTypeID("FntN" ));
+ var size = textStyle.getDouble(charIDToTypeID("Sz " ));
+ var color = textStyle.getObjectValue(charIDToTypeID('Clr '));
+ var bold = textStyle.getBoolean(stringIDToTypeID('syntheticBold'));
+ var italic = textStyle.getBoolean(stringIDToTypeID('syntheticItalic'));
+ var underlineValue = textStyle.getEnumerationValue(stringIDToTypeID( "underline" ));
+ var underline = underlineValue == 1647 ? true : false;
+ var autoLeading = textStyle.getBoolean(stringIDToTypeID( "autoLeading" ));
+ var textColor = new SolidColor;
+
+ textColor.rgb.red = color.getDouble(charIDToTypeID('Rd '));
+ textColor.rgb.green = color.getDouble(charIDToTypeID('Grn '));
+ textColor.rgb.blue = color.getDouble(charIDToTypeID('Bl '));
+ var o = {range:range, font:font, size:size, color:textColor.rgb.hexValue, bold:bold, italic:italic, underline:underline};
+ if(!autoLeading) o.lineHeight = textStyle.getUnitDoubleValue(charIDToTypeID( "Ldng" ));
+ info.push(o);
+ }
+ return info;
+ },
+ // get pointer (x, y) color
+ getRGBColor: function(x, y){
+ if(!x || !y) return;
+ PSD.colorSampler.move([UnitValue(x, 'px'), UnitValue(y, 'px')]);
+ return PSD.colorSampler.color.rgb.hexValue;
+ },
+ selectionIsMonochrome: function(region){
+ var selection = this.doc.selection,
+ cs = this.doc.channels;
+
+ selection.select(region);
+
+ for(var i = 0, l = cs.length; i < l; i++){
+ var histogram = cs[i].histogram.concat();
+ $.writeln(histogram.join('-'));
+ histogram.sort().reverse();
+ if(histogram[1] != 0) return false;
+ }
+ //var his = this.doc.historyStates;
+ //this.doc.activeHistoryState = his[his.length - 1];
+ return true;
+ },
+ reset: function(){
+ this.doc.activeHistoryState = this.doc.historyStates.getByName("psdtohtml");
+ this.doc.save();
+ },
+ createSnapshotOnStart: function(){
+ var his = this.doc.historyStates;
+ try{
+ // if has psdtohtml snapshot
+ var snapshot = his.getByName("psdtohtml");
+ this.doc.activeHistoryState = snapshot;
+ // delete it
+ var idDlt = charIDToTypeID( "Dlt " );
+ var desc175 = new ActionDescriptor();
+ var idnull = charIDToTypeID( "null" );
+ var ref131 = new ActionReference();
+ var idHstS = charIDToTypeID( "HstS" );
+ var idCrnH = charIDToTypeID( "CrnH" );
+ ref131.putProperty( idHstS, idCrnH );
+ desc175.putReference( idnull, ref131 );
+ executeAction( idDlt, desc175, DialogModes.NO );
+ }catch(e){
+
+ }
+ // create snapshot
+ var idMk = charIDToTypeID( "Mk " );
+ var desc202 = new ActionDescriptor();
+ var idnull = charIDToTypeID( "null" );
+ var ref163 = new ActionReference();
+ var idSnpS = charIDToTypeID( "SnpS" );
+ ref163.putClass( idSnpS );
+ desc202.putReference( idnull, ref163 );
+ var idFrom = charIDToTypeID( "From" );
+ var ref164 = new ActionReference();
+ var idHstS = charIDToTypeID( "HstS" );
+ var idCrnH = charIDToTypeID( "CrnH" );
+ ref164.putProperty( idHstS, idCrnH );
+ desc202.putReference( idFrom, ref164 );
+ var idNm = charIDToTypeID( "Nm " );
+ desc202.putString( idNm, "psdtohtml" );
+ var idUsng = charIDToTypeID( "Usng" );
+ var idHstS = charIDToTypeID( "HstS" );
+ var idFllD = charIDToTypeID( "FllD" );
+ desc202.putEnumerated( idUsng, idHstS, idFllD );
+ executeAction( idMk, desc202, DialogModes.NO );
+ }
+}
+
+})();
diff --git a/PSD2HTML2/lib/web-fonts.jsx b/PSD2HTML2/lib/web-fonts.jsx
new file mode 100644
index 0000000..4c422c7
--- /dev/null
+++ b/PSD2HTML2/lib/web-fonts.jsx
@@ -0,0 +1,17 @@
+var WEBFONTS = ['Arial', 'Arial Narrow', 'ArialMT' , 'Verdana', 'Georgia', 'Times New Roman',
+'Trebuchet MS', 'Courier New', 'Impact', 'Comic Sans MS', 'Tahoma', 'Courier', 'Lucida Sans Unicode',
+'Lucida Console', 'Garamond', ' MS Sans Serif', 'MS Serif', 'Palatino Linotype', 'Symbol', '宋体','新宋体', '微软雅黑', '黑体', '楷体',
+'幼圆', '仿宋', 'MicrosoftYaHei', 'SimSun','NSimSun', 'AdobeSongStd-Light', 'SimHei'];
+
+WEBFONTS.webFont = {microsoftyahei:'Microsoft YaHei'};
+
+WEBFONTS.getWebFont = function(font){
+ return WEBFONTS.webFont[font.toLowerCase()] || font;
+}
+
+WEBFONTS.indexOf = function(s){
+ for(var i = 0, l = WEBFONTS.length; i < l; i++){
+ if(WEBFONTS[i].toLowerCase() === s.toLowerCase()) return i;
+ }
+ return -1;
+}
\ No newline at end of file
diff --git a/test/psd-core.jsx b/test/psd-core.jsx
new file mode 100644
index 0000000..62ee3b3
--- /dev/null
+++ b/test/psd-core.jsx
@@ -0,0 +1,10 @@
+#target photoshop
+// @include "../PSD2HTML2/lib/psd.jsx"
+
+(function(){
+ var psd = new PSD();
+ psd.parse();
+ var layers = psd.allLayers;
+ var textLayers = psd.textLayers;
+ var contentLayers = psd.contentLayers;
+})();
\ No newline at end of file