aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormeltingice <meltingice8917@gmail.com>2012-07-24 21:11:07 -0400
committermeltingice <meltingice8917@gmail.com>2012-07-24 21:11:07 -0400
commit5534d471f250ff3afe40144a5af37c7a8cbabecc (patch)
tree753f2059d638b236a11b2b1aa0b6d3ff3f50831f
parentUpdate documentation (diff)
downloadpsd.js-5534d471f250ff3afe40144a5af37c7a8cbabecc.tar.xz
psd.js-5534d471f250ff3afe40144a5af37c7a8cbabecc.zip
Added parsing of both legacy and current layer effects. Current layer effects needs a lot of work to make it more human readable though.
-rw-r--r--lib/psd.js145
-rw-r--r--lib/psd.min.js20
-rwxr-xr-xsrc/layerdata/layereffect.coffee63
-rw-r--r--src/psddescriptor.coffee12
-rwxr-xr-xsrc/psdlayer.coffee45
5 files changed, 191 insertions, 94 deletions
diff --git a/lib/psd.js b/lib/psd.js
index b26b954..fbdd635 100644
--- a/lib/psd.js
+++ b/lib/psd.js
@@ -307,7 +307,7 @@ var jspack = new JSPack(); ;
END DEPENDENCIES
*/
- var Log, PSD, PSDBlackWhite, PSDBrightnessContrast, PSDChannelImage, PSDColor, PSDColorBalance, PSDCurves, PSDDescriptor, PSDDropDownLayerEffect, PSDExposure, PSDFile, PSDGradient, PSDHeader, PSDHueSaturation, PSDImage, PSDInvert, PSDLayer, PSDLayerEffect, PSDLayerEffectCommonStateInfo, PSDLayerMask, PSDLevels, PSDPattern, PSDPhotoFilter, PSDPosterize, PSDResource, PSDSelectiveColor, PSDSolidColor, PSDThreshold, PSDTypeTool, PSDVibrance, Root, Util, assert, fs,
+ var Log, PSD, PSDBlackWhite, PSDBrightnessContrast, PSDChannelImage, PSDColor, PSDColorBalance, PSDCurves, PSDDescriptor, PSDDropDownLayerEffect, PSDEffectsDescriptor, PSDEffectsInfo, PSDExposure, PSDFile, PSDGradient, PSDHeader, PSDHueSaturation, PSDImage, PSDInvert, PSDLayer, PSDLayerEffect, PSDLayerEffectCommonStateInfo, PSDLayerMask, PSDLevels, PSDPattern, PSDPhotoFilter, PSDPosterize, PSDResource, PSDSelectiveColor, PSDSolidColor, PSDThreshold, PSDTypeTool, PSDVibrance, Root, Util, assert, fs,
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
@@ -1032,15 +1032,23 @@ var jspack = new JSPack(); ;
};
PSDDescriptor.prototype.parseKeyItem = function() {
+ var id, value;
+ id = this.parseID();
+ value = this.parseItem(id);
return {
- id: this.parseID(),
- value: this.parseItem()
+ id: id,
+ value: value
};
};
- PSDDescriptor.prototype.parseItem = function() {
- var type, value;
- type = this.file.readString(4);
+ PSDDescriptor.prototype.parseItem = function(id, type) {
+ var value;
+ if (type == null) {
+ type = null;
+ }
+ if (!type) {
+ type = this.file.readString(4);
+ }
Log.debug("Found descriptor type: " + type);
value = (function() {
switch (type) {
@@ -1208,7 +1216,7 @@ var jspack = new JSPack(); ;
PSDDescriptor.prototype.parseUnitDouble = function() {
var unit, unitID, value;
- unitID = this.file.parseString(4);
+ unitID = this.file.readString(4);
unit = (function() {
switch (unitID) {
case "#Ang":
@@ -2435,9 +2443,12 @@ var jspack = new JSPack(); ;
this.readLayerSectionDivider();
break;
case "lrFX":
- this.parseEffectsLayer();
+ this.adjustments.legacyEffects = (new PSDEffectsInfo(this, length)).parseLegacy();
this.file.read(2);
break;
+ case "lfx2":
+ this.adjustments.effects = (new PSDEffectsInfo(this, length)).parse();
+ break;
case "selc":
this.adjustments.selectiveColor = (new PSDSelectiveColor(this, length)).parse();
break;
@@ -2446,7 +2457,7 @@ var jspack = new JSPack(); ;
Log.debug("Skipping additional layer info with key " + key);
}
if (this.file.tell() !== (pos + length)) {
- Log.debug("Warning: additional layer info with key " + key + " - unexpected end");
+ Log.debug("Warning: additional layer info with key " + key + " - unexpected end. Position = " + (this.file.tell()) + ", Expected = " + (pos + length));
_results.push(this.file.seek(pos + length, false));
} else {
_results.push(void 0);
@@ -2455,39 +2466,6 @@ var jspack = new JSPack(); ;
return _results;
};
- PSDLayer.prototype.parseEffectsLayer = function() {
- var count, data, effect, effects, left, pos, signature, size, type, v, _ref, _ref1;
- effects = [];
- _ref = this.file.readf(">HH"), v = _ref[0], count = _ref[1];
- while (count-- > 0) {
- _ref1 = this.file.readf(">4s4s"), signature = _ref1[0], type = _ref1[1];
- size = this.file.readf(">i")[0];
- pos = this.file.tell();
- Log.debug("Parsing effect layer with type " + type + " and size " + size);
- effect = (function() {
- switch (type) {
- case "cmnS":
- return new PSDLayerEffectCommonStateInfo(this.file);
- case "dsdw":
- return new PSDDropDownLayerEffect(this.file);
- case "isdw":
- return new PSDDropDownLayerEffect(this.file, true);
- }
- }).call(this);
- data = effect != null ? effect.parse() : void 0;
- left = (pos + size) - this.file.tell();
- if (left !== 0) {
- Log.debug("Failed to parse effect layer with type " + type);
- this.file.seek(left);
- } else {
- if (type !== "cmnS") {
- effects.push(data);
- }
- }
- }
- return this.adjustments.effects = effects;
- };
-
PSDLayer.prototype.readLayerSectionDivider = function() {
var code;
code = this.file.readInt();
@@ -2891,6 +2869,89 @@ var jspack = new JSPack(); ;
})();
+ PSDEffectsInfo = (function() {
+
+ function PSDEffectsInfo(layer, length) {
+ this.layer = layer;
+ this.length = length;
+ this.file = this.layer.file;
+ }
+
+ PSDEffectsInfo.prototype.parse = function() {
+ var effectsVersion, version;
+ effectsVersion = this.file.readInt();
+ assert(effectsVersion === 0);
+ version = this.file.readInt();
+ assert(version === 16);
+ return (new PSDEffectsDescriptor(this.file)).parse();
+ };
+
+ PSDEffectsInfo.prototype.parseLegacy = function() {
+ var count, data, effect, effects, left, pos, signature, size, type, v, _ref, _ref1;
+ effects = [];
+ _ref = this.file.readf(">HH"), v = _ref[0], count = _ref[1];
+ while (count-- > 0) {
+ _ref1 = this.file.readf(">4s4s"), signature = _ref1[0], type = _ref1[1];
+ size = this.file.readf(">i")[0];
+ pos = this.file.tell();
+ Log.debug("Parsing effect layer with type " + type + " and size " + size);
+ effect = (function() {
+ switch (type) {
+ case "cmnS":
+ return new PSDLayerEffectCommonStateInfo(this.file);
+ case "dsdw":
+ return new PSDDropDownLayerEffect(this.file);
+ case "isdw":
+ return new PSDDropDownLayerEffect(this.file, true);
+ }
+ }).call(this);
+ data = effect != null ? effect.parse() : void 0;
+ left = (pos + size) - this.file.tell();
+ if (left !== 0) {
+ Log.debug("Failed to parse effect layer with type " + type);
+ this.file.seek(left);
+ } else {
+ if (type !== "cmnS") {
+ effects.push(data);
+ }
+ }
+ }
+ return {
+ legacy: true,
+ effects: effects
+ };
+ };
+
+ return PSDEffectsInfo;
+
+ })();
+
+ PSDEffectsDescriptor = (function(_super) {
+
+ __extends(PSDEffectsDescriptor, _super);
+
+ function PSDEffectsDescriptor() {
+ return PSDEffectsDescriptor.__super__.constructor.apply(this, arguments);
+ }
+
+ PSDEffectsDescriptor.prototype.parseItem = function(id) {
+ var data, type;
+ type = this.file.readString(4);
+ data = (function() {
+ switch (id) {
+ case "patternFill":
+ return this.parseLayerPatternOverlay();
+ default:
+ return PSDEffectsDescriptor.__super__.parseItem.call(this, id, type);
+ }
+ }).call(this);
+ return data;
+ };
+
+ return PSDEffectsDescriptor;
+
+ })(PSDDescriptor);
+
PSDLayerEffect = (function() {
function PSDLayerEffect(file) {
diff --git a/lib/psd.min.js b/lib/psd.min.js
index 6274749..55dc8e4 100644
--- a/lib/psd.min.js
+++ b/lib/psd.min.js
@@ -69,7 +69,7 @@ return a;};m.Pack=function(fmt,values)
{return this.PackTo(fmt,new Array(this.CalcLength(fmt)),0,values);};m.CalcLength=function(fmt)
{var re=new RegExp(this._sPattern,'g'),m,sum=0;while(m=re.exec(fmt))
{sum+=(((m[1]==undefined)||(m[1]==''))?1:parseInt(m[1]))*this._lenLut[m[2]];}
-return sum;};};var jspack=new JSPack();;var Log,PSD,PSDBlackWhite,PSDBrightnessContrast,PSDChannelImage,PSDColor,PSDColorBalance,PSDCurves,PSDDescriptor,PSDDropDownLayerEffect,PSDExposure,PSDFile,PSDGradient,PSDHeader,PSDHueSaturation,PSDImage,PSDInvert,PSDLayer,PSDLayerEffect,PSDLayerEffectCommonStateInfo,PSDLayerMask,PSDLevels,PSDPattern,PSDPhotoFilter,PSDPosterize,PSDResource,PSDSelectiveColor,PSDSolidColor,PSDThreshold,PSDTypeTool,PSDVibrance,Root,Util,assert,fs,__hasProp={}.hasOwnProperty,__extends=function(child,parent){for(var key in parent){if(__hasProp.call(parent,key))child[key]=parent[key];}function ctor(){this.constructor=child;}ctor.prototype=parent.prototype;child.prototype=new ctor();child.__super__=parent.prototype;return child;};assert=(function(assert){if(typeof exports!=="undefined"&&exports!==null){return require('assert');}
+return sum;};};var jspack=new JSPack();;var Log,PSD,PSDBlackWhite,PSDBrightnessContrast,PSDChannelImage,PSDColor,PSDColorBalance,PSDCurves,PSDDescriptor,PSDDropDownLayerEffect,PSDEffectsDescriptor,PSDEffectsInfo,PSDExposure,PSDFile,PSDGradient,PSDHeader,PSDHueSaturation,PSDImage,PSDInvert,PSDLayer,PSDLayerEffect,PSDLayerEffectCommonStateInfo,PSDLayerMask,PSDLevels,PSDPattern,PSDPhotoFilter,PSDPosterize,PSDResource,PSDSelectiveColor,PSDSolidColor,PSDThreshold,PSDTypeTool,PSDVibrance,Root,Util,assert,fs,__hasProp={}.hasOwnProperty,__extends=function(child,parent){for(var key in parent){if(__hasProp.call(parent,key))child[key]=parent[key];}function ctor(){this.constructor=child;}ctor.prototype=parent.prototype;child.prototype=new ctor();child.__super__=parent.prototype;return child;};assert=(function(assert){if(typeof exports!=="undefined"&&exports!==null){return require('assert');}
assert=function(test){if(test!==true){throw"Assertion error";}};assert.equal=function(actual,expected){if(actual!==expected){throw"Assertion error";}};return assert;})(assert);if(typeof exports!=="undefined"&&exports!==null){Root=exports;fs=require('fs');}else{Root=window;}
Root.PSD=PSD=(function(){PSD.VERSION="0.4.5";PSD.DEBUG=false;PSD.fromFile=function(file,cb){var data,reader;if(cb==null){cb=function(){};}
if(typeof exports!=="undefined"&&exports!==null){data=fs.readFileSync(file);return new PSD(data);}else{reader=new FileReader();reader.onload=function(f){var bytes,psd;bytes=new Uint8Array(f.target.result);psd=new PSD(bytes);return cb(psd);};return reader.readAsArrayBuffer(file);}};PSD.fromURL=function(url,cb){var xhr;if(cb==null){cb=function(){};}
@@ -126,11 +126,13 @@ return this.argbToColor(alpha,r,g,b);};PSDColor.hueToColor=function(hue,m1,m2){v
return v*255;};PSDColor.cmykToColor=function(cyan,magenta,yellow,black){var b,g,r;r=1-(cyan*(1-black)+black)*255;g=1-(magenta*(1-black)+black)*255;b=1-(yellow*(1-black)+black)*255;r=Util.clamp(r,0,255);g=Util.clamp(g,0,255);b=Util.clamp(b,0,255);return this.rgbToColor(r,g,b);};PSDColor.labToColor=function(l,a,b){return this.alabToColor(255,l,a,b);};PSDColor.alabToColor=function(alpha,lightness,a,b){var xyz;xyz=this.labToXYZ(lightness,a,b);return this.axyzToColor(alpha,xyz.x,xyz.y,xyz.z);};PSDColor.axyzToColor=function(alpha,x,y,z){var rgb;rgb=this.xyzToRGB(x,y,z);return this.argbToColor(alpha,rgb.r,rgb.g,rgb.b);};PSDColor.colorSpaceToARGB=function(colorSpace,colorComponent){var dstColor;switch(colorSpace){case 0:dstColor=this.rgbToColor(colorComponent[0],colorComponent[1],colorComponent[2]);break;case 1:dstColor=this.hsbToColor(colorComponent[0],colorComponent[1]/100.0,colorComponent[2]/100.0);break;case 2:dstColor=this.cmykToColor(colorComponent[0]/100.0,colorComponent[1]/100.0,colorComponent[2]/100.0,colorComponent[3]/100.0);break;case 7:dstColor=this.labToColor(colorComponent[0],colorComponent[1],colorComponent[2]);break;default:dstColor=0x00FFFFFF;}
return dstColor;};return PSDColor;})();PSDDescriptor=(function(){function PSDDescriptor(file){this.file=file;}
PSDDescriptor.prototype.parse=function(){var data,i,item,numItems,_i;Log.debug("Parsing descriptor...");data={};data["class"]=this.parseClass();numItems=this.file.readInt();Log.debug("Descriptor contains "+numItems+" items");for(i=_i=0;0<=numItems?_i<numItems:_i>numItems;i=0<=numItems?++_i:--_i){item=this.parseKeyItem();data[item.id]=item.value;}
-return data;};PSDDescriptor.prototype.parseID=function(){var len;len=this.file.readInt();if(len===0){return this.file.readInt();}else{return this.file.readString(len);}};PSDDescriptor.prototype.parseClass=function(){return{name:this.file.readUnicodeString(),id:this.parseID()};};PSDDescriptor.prototype.parseKeyItem=function(){return{id:this.parseID(),value:this.parseItem()};};PSDDescriptor.prototype.parseItem=function(){var type,value;type=this.file.readString(4);Log.debug("Found descriptor type: "+type);value=(function(){switch(type){case'bool':return this.parseBoolean();case'type':case'GlbC':return this.parseClass();case'Objc':case'GlbO':return this.parse();case'doub':return this.parseDouble();case'enum':return this.parseEnum();case'alis':return this.parseAlias();case'Pth ':return this.parseFilePath();case'long':return this.parseInteger();case'comp':return this.parseLargeInteger();case'VlLs':return this.parseList();case'ObAr':return this.parseObjectArray();case'tdta':return this.parseRawData();case'obj ':return this.parseReference();case'TEXT':return this.file.readUnicodeString();case'UntF':return this.parseUnitDouble();}}).call(this);return value;};PSDDescriptor.prototype.parseBoolean=function(){return this.file.readBoolean();};PSDDescriptor.prototype.parseDouble=function(){return this.file.readDouble();};PSDDescriptor.prototype.parseInteger=function(){return this.file.readInt();};PSDDescriptor.prototype.parseLargeInteger=function(){return this.file.readLongLong();};PSDDescriptor.prototype.parseIdentifier=function(){return this.file.readInt();};PSDDescriptor.prototype.parseIndex=function(){return this.file.readInt();};PSDDescriptor.prototype.parseOffset=function(){return this.file.readInt();};PSDDescriptor.prototype.parseProperty=function(){return this.parseID();};PSDDescriptor.prototype.parseEnum=function(){this.parseID();return this.parseID();};PSDDescriptor.prototype.parseAlias=function(){var len;len=this.file.readInt();return this.file.read(len);};PSDDescriptor.prototype.parseFilePath=function(){var charBytes,len,numChars,path,pathSize,sig,_ref;len=this.file.readInt();_ref=this.file.readf("<4s2i"),sig=_ref[0],pathSize=_ref[1],numChars=_ref[2];charBytes=numChars*2;path=this.file.read(charBytes);return{sig:sig,path:path};};PSDDescriptor.prototype.parseList=function(){var i,items,numItems,_i;numItems=this.file.readInt();items=[];for(i=_i=0;0<=numItems?_i<numItems:_i>numItems;i=0<=numItems?++_i:--_i){items.push(this.parseItem());}
+return data;};PSDDescriptor.prototype.parseID=function(){var len;len=this.file.readInt();if(len===0){return this.file.readInt();}else{return this.file.readString(len);}};PSDDescriptor.prototype.parseClass=function(){return{name:this.file.readUnicodeString(),id:this.parseID()};};PSDDescriptor.prototype.parseKeyItem=function(){var id,value;id=this.parseID();value=this.parseItem(id);return{id:id,value:value};};PSDDescriptor.prototype.parseItem=function(id,type){var value;if(type==null){type=null;}
+if(!type){type=this.file.readString(4);}
+Log.debug("Found descriptor type: "+type);value=(function(){switch(type){case'bool':return this.parseBoolean();case'type':case'GlbC':return this.parseClass();case'Objc':case'GlbO':return this.parse();case'doub':return this.parseDouble();case'enum':return this.parseEnum();case'alis':return this.parseAlias();case'Pth ':return this.parseFilePath();case'long':return this.parseInteger();case'comp':return this.parseLargeInteger();case'VlLs':return this.parseList();case'ObAr':return this.parseObjectArray();case'tdta':return this.parseRawData();case'obj ':return this.parseReference();case'TEXT':return this.file.readUnicodeString();case'UntF':return this.parseUnitDouble();}}).call(this);return value;};PSDDescriptor.prototype.parseBoolean=function(){return this.file.readBoolean();};PSDDescriptor.prototype.parseDouble=function(){return this.file.readDouble();};PSDDescriptor.prototype.parseInteger=function(){return this.file.readInt();};PSDDescriptor.prototype.parseLargeInteger=function(){return this.file.readLongLong();};PSDDescriptor.prototype.parseIdentifier=function(){return this.file.readInt();};PSDDescriptor.prototype.parseIndex=function(){return this.file.readInt();};PSDDescriptor.prototype.parseOffset=function(){return this.file.readInt();};PSDDescriptor.prototype.parseProperty=function(){return this.parseID();};PSDDescriptor.prototype.parseEnum=function(){this.parseID();return this.parseID();};PSDDescriptor.prototype.parseAlias=function(){var len;len=this.file.readInt();return this.file.read(len);};PSDDescriptor.prototype.parseFilePath=function(){var charBytes,len,numChars,path,pathSize,sig,_ref;len=this.file.readInt();_ref=this.file.readf("<4s2i"),sig=_ref[0],pathSize=_ref[1],numChars=_ref[2];charBytes=numChars*2;path=this.file.read(charBytes);return{sig:sig,path:path};};PSDDescriptor.prototype.parseList=function(){var i,items,numItems,_i;numItems=this.file.readInt();items=[];for(i=_i=0;0<=numItems?_i<numItems:_i>numItems;i=0<=numItems?++_i:--_i){items.push(this.parseItem());}
return items;};PSDDescriptor.prototype.parseObjectArray=function(){var i,item,itemsInObj,j,klass,numItems,obj,_i,_j;numItems=this.file.readInt();klass=this.parseClass();itemsInObj=this.file.readInt();obj=[];for(i=_i=0;0<=numItems?_i<numItems:_i>numItems;i=0<=numItems?++_i:--_i){item=[];for(j=_j=0;0<=itemsInObj?_j<itemsInObj:_j>itemsInObj;j=0<=itemsInObj?++_j:--_j){item.push(this.parseObjectArray());}
obj.push(item);}
return obj;};PSDDescriptor.prototype.parseObjectArray=function(){var i,id,num,type,unitID,values,_i;id=this.parseID();type=this.file.readString(4);unitID=this.file.readString();num=this.file.readInt();values=[];for(i=_i=0;0<=num?_i<num:_i>num;i=0<=num?++_i:--_i){values.push(this.file.readDouble());}
-return values;};PSDDescriptor.prototype.parseRawData=function(){var len;len=this.file.readInt();return this.file.read(len);};PSDDescriptor.prototype.parseReference=function(){var form,klass,value;form=this.file.readString(4);klass=this.parseClass();value=(function(){switch(form){case"Clss":return null;case"Enmr":return this.parseEnum();case"Idnt":return this.parseIdentifier();case"indx":return this.parseIndex();case"name":return this.file.readUnicodeString();case"rele":return this.parseOffset();case"prop":return this.parseProperty();}}).call(this);return value;};PSDDescriptor.prototype.parseUnitDouble=function(){var unit,unitID,value;unitID=this.file.parseString(4);unit=(function(){switch(unitID){case"#Ang":return"Angle";case"#Rsl":return"Density";case"#Rlt":return"Distance";case"#Nne":return"None";case"#Prc":return"Percent";case"#Pxl":return"Pixels";case"#Mlm":return"Millimeters";case"#Pnt":return"Points";}})();value=this.file.readDouble();return{id:unitID,unit:unit,value:value};};return PSDDescriptor;})();PSDFile=(function(){PSDFile.prototype.unicodeRegex=/\\u([\d\w]{4})/gi;function PSDFile(data){this.data=data;this.pos=0;}
+return values;};PSDDescriptor.prototype.parseRawData=function(){var len;len=this.file.readInt();return this.file.read(len);};PSDDescriptor.prototype.parseReference=function(){var form,klass,value;form=this.file.readString(4);klass=this.parseClass();value=(function(){switch(form){case"Clss":return null;case"Enmr":return this.parseEnum();case"Idnt":return this.parseIdentifier();case"indx":return this.parseIndex();case"name":return this.file.readUnicodeString();case"rele":return this.parseOffset();case"prop":return this.parseProperty();}}).call(this);return value;};PSDDescriptor.prototype.parseUnitDouble=function(){var unit,unitID,value;unitID=this.file.readString(4);unit=(function(){switch(unitID){case"#Ang":return"Angle";case"#Rsl":return"Density";case"#Rlt":return"Distance";case"#Nne":return"None";case"#Prc":return"Percent";case"#Pxl":return"Pixels";case"#Mlm":return"Millimeters";case"#Pnt":return"Points";}})();value=this.file.readDouble();return{id:unitID,unit:unit,value:value};};return PSDDescriptor;})();PSDFile=(function(){PSDFile.prototype.unicodeRegex=/\\u([\d\w]{4})/gi;function PSDFile(data){this.data=data;this.pos=0;}
PSDFile.prototype.tell=function(){return this.pos;};PSDFile.prototype.read=function(bytes){var i,_i,_results;_results=[];for(i=_i=0;0<=bytes?_i<bytes:_i>bytes;i=0<=bytes?++_i:--_i){_results.push(this.data[this.pos++]);}
return _results;};PSDFile.prototype.seek=function(amount,rel){if(rel==null){rel=true;}
if(rel){return this.pos+=amount;}else{return this.pos=amount;}};PSDFile.prototype.readInt=function(){var int;int=this.readUInt();if(int>=0x80000000){return int-0x100000000;}else{return int;}};PSDFile.prototype.readUInt=function(){var b1,b2,b3,b4;b1=this.read(1)[0]<<24;b2=this.read(1)[0]<<16;b3=this.read(1)[0]<<8;b4=this.read(1)[0];return b1|b2|b3|b4;};PSDFile.prototype.readShortInt=function(){var int;int=this.readShortUInt();if(int>=0x8000){return int-0x10000;}else{return int;}};PSDFile.prototype.readShortUInt=function(){var b1,b2;b1=this.read(1)[0]<<8;b2=this.read(1)[0];return b1|b2;};PSDFile.prototype.readLongInt=function(){return this.readf(">l")[0];};PSDFile.prototype.readLongUInt=function(){return this.readf(">L")[0];};PSDFile.prototype.readDouble=function(){return this.readf(">d")[0];};PSDFile.prototype.readBoolean=function(){return this.read(1)[0]!==0;};PSDFile.prototype.readLongLong=function(){return this.read(8);};PSDFile.prototype.readULongLong=function(){return this.read(8);};PSDFile.prototype.readString=function(length){var ret;ret=String.fromCharCode.apply(null,this.read(length));return ret.replace(/\u0000/g,"");};PSDFile.prototype.readUnicodeString=function(){var len,str;len=this.readInt()*2;str=this.readf(">"+len+"s")[0];str=str.replace(this.unicodeRegex,function(match,grp){return String.fromCharCode(parseInt(grp,16));});return str.replace(/\u0000/g,"");};PSDFile.prototype.readLengthWithString=function(defaultLen){var length,str;if(defaultLen==null){defaultLen=4;}
@@ -217,10 +219,9 @@ return _results;};PSDLayer.prototype.parseBlendModes=function(){var filler,flags
this.blendingMode=this.blendMode.blender;this.opacity=this.blendMode.opacity;this.visible=this.blendMode.visible;return Log.debug("Blending mode:",this.blendMode);};PSDLayer.prototype.parseMaskData=function(){var flags,_ref,_ref1,_ref2,_ref3;this.mask.size=this.file.readInt();assert((_ref=this.mask.size)===36||_ref===20||_ref===0);if(this.mask.size===0){return true;}
_ref1=this.file.readf(">llllBB"),this.mask.top=_ref1[0],this.mask.left=_ref1[1],this.mask.bottom=_ref1[2],this.mask.right=_ref1[3],this.mask.defaultColor=_ref1[4],flags=_ref1[5];assert((_ref2=this.mask.defaultColor)===0||_ref2===255);this.mask.width=this.mask.right-this.mask.left;this.mask.height=this.mask.bottom-this.mask.top;this.mask.relative=flags&0x01;this.mask.disabled=(flags&(0x01<<1))>0;this.mask.invert=(flags&(0x01<<2))>0;if(this.mask.size===20){this.file.seek(2);}else{_ref3=this.file.readf(">BB"),flags=_ref3[0],this.mask.defaultColor=_ref3[1];this.mask.relative=flags&0x01;this.mask.disabled=(flags&(0x01<<1))>0;this.mask.invert=(flags&(0x01<<2))>0;this.file.seek(16);}
return true;};PSDLayer.prototype.parseBlendingRanges=function(){var i,length,pos,_i,_ref,_results;length=this.file.readInt();this.blendingRanges.grey={source:{black:this.file.readShortInt(),white:this.file.readShortInt()},dest:{black:this.file.readShortInt(),white:this.file.readShortInt()}};pos=this.file.tell();this.blendingRanges.numChannels=(length-8)/8;assert(this.blendingRanges.numChannels>0);this.blendingRanges.channels=[];_results=[];for(i=_i=0,_ref=this.blendingRanges.numChannels;0<=_ref?_i<_ref:_i>_ref;i=0<=_ref?++_i:--_i){_results.push(this.blendingRanges.channels.push({source:{black:this.file.readShortInt(),white:this.file.readShortInt()},dest:{black:this.file.readShortInt(),white:this.file.readShortInt()}}));}
-return _results;};PSDLayer.prototype.parseLegacyLayerName=function(){var namelen;namelen=Util.pad4(this.file.read(1)[0]);return this.legacyName=Util.decodeMacroman(this.file.read(namelen)).replace(/\u0000/g,'');};PSDLayer.prototype.parseExtraData=function(){var key,length,pos,signature,_ref,_results;_results=[];while(this.file.tell()<this.layerEnd){_ref=this.file.readf(">4s4s"),signature=_ref[0],key=_ref[1];assert.equal(signature,"8BIM");length=Util.pad2(this.file.readInt());pos=this.file.tell();Log.debug("Extra layer info: key = "+key+", length = "+length);switch(key){case"SoCo":this.adjustments.solidColor=(new PSDSolidColor(this,length)).parse();break;case"GdFl":this.adjustments.gradient=(new PSDGradient(this,length)).parse();break;case"PtFl":this.adjustments.pattern=(new PSDPattern(this,length)).parse();break;case"brit":this.adjustments.brightnessContrast=(new PSDBrightnessContrast(this,length)).parse();break;case"levl":this.adjustments.levels=(new PSDLevels(this,length)).parse();break;case"curv":this.adjustments.curves=(new PSDCurves(this,length)).parse();break;case"expA":this.adjustments.exposure=(new PSDExposure(this,length)).parse();break;case"vibA":this.adjustments.vibrance=(new PSDVibrance(this,length)).parse();break;case"hue2":this.adjustments.hueSaturation=(new PSDHueSaturation(this,length)).parse();break;case"blnc":this.adjustments.colorBalance=(new PSDColorBalance(this,length)).parse();break;case"blwh":this.adjustments.blackWhite=(new PSDBlackWhite(this,length)).parse();break;case"phfl":this.adjustments.photoFilter=(new PSDPhotoFilter(this,length)).parse();break;case"thrs":this.adjustments.threshold=(new PSDThreshold(this,length)).parse();break;case"nvrt":this.adjustments.invert=(new PSDInvert(this,length)).parse();break;case"post":this.adjustments.posterize=(new PSDPosterize(this,length)).parse();break;case"tySh":this.adjustments.typeTool=(new PSDTypeTool(this,length)).parse(true);break;case"TySh":this.adjustments.typeTool=(new PSDTypeTool(this,length)).parse();break;case"luni":this.name=this.file.readUnicodeString();this.file.seek(pos+length,false);break;case"lyid":this.layerId=this.file.readInt();break;case"lsct":this.readLayerSectionDivider();break;case"lrFX":this.parseEffectsLayer();this.file.read(2);break;case"selc":this.adjustments.selectiveColor=(new PSDSelectiveColor(this,length)).parse();break;default:this.file.seek(length);Log.debug("Skipping additional layer info with key "+key);}
-if(this.file.tell()!==(pos+length)){Log.debug("Warning: additional layer info with key "+key+" - unexpected end");_results.push(this.file.seek(pos+length,false));}else{_results.push(void 0);}}
-return _results;};PSDLayer.prototype.parseEffectsLayer=function(){var count,data,effect,effects,left,pos,signature,size,type,v,_ref,_ref1;effects=[];_ref=this.file.readf(">HH"),v=_ref[0],count=_ref[1];while(count-->0){_ref1=this.file.readf(">4s4s"),signature=_ref1[0],type=_ref1[1];size=this.file.readf(">i")[0];pos=this.file.tell();Log.debug("Parsing effect layer with type "+type+" and size "+size);effect=(function(){switch(type){case"cmnS":return new PSDLayerEffectCommonStateInfo(this.file);case"dsdw":return new PSDDropDownLayerEffect(this.file);case"isdw":return new PSDDropDownLayerEffect(this.file,true);}}).call(this);data=effect!=null?effect.parse():void 0;left=(pos+size)-this.file.tell();if(left!==0){Log.debug("Failed to parse effect layer with type "+type);this.file.seek(left);}else{if(type!=="cmnS"){effects.push(data);}}}
-return this.adjustments.effects=effects;};PSDLayer.prototype.readLayerSectionDivider=function(){var code;code=this.file.readInt();this.layerType=SECTION_DIVIDER_TYPES[code];Log.debug("Layer type:",this.layerType);switch(code){case 1:case 2:return this.isFolder=true;case 3:return this.isHidden=true;}};PSDLayer.prototype.toJSON=function(){var data,section,sections,_i,_len;sections=['name','legacyName','top','left','bottom','right','channels','rows','cols','channelsInfo','mask','layerType','blendMode','adjustments','visible'];data={};for(_i=0,_len=sections.length;_i<_len;_i++){section=sections[_i];data[section]=this[section];}
+return _results;};PSDLayer.prototype.parseLegacyLayerName=function(){var namelen;namelen=Util.pad4(this.file.read(1)[0]);return this.legacyName=Util.decodeMacroman(this.file.read(namelen)).replace(/\u0000/g,'');};PSDLayer.prototype.parseExtraData=function(){var key,length,pos,signature,_ref,_results;_results=[];while(this.file.tell()<this.layerEnd){_ref=this.file.readf(">4s4s"),signature=_ref[0],key=_ref[1];assert.equal(signature,"8BIM");length=Util.pad2(this.file.readInt());pos=this.file.tell();Log.debug("Extra layer info: key = "+key+", length = "+length);switch(key){case"SoCo":this.adjustments.solidColor=(new PSDSolidColor(this,length)).parse();break;case"GdFl":this.adjustments.gradient=(new PSDGradient(this,length)).parse();break;case"PtFl":this.adjustments.pattern=(new PSDPattern(this,length)).parse();break;case"brit":this.adjustments.brightnessContrast=(new PSDBrightnessContrast(this,length)).parse();break;case"levl":this.adjustments.levels=(new PSDLevels(this,length)).parse();break;case"curv":this.adjustments.curves=(new PSDCurves(this,length)).parse();break;case"expA":this.adjustments.exposure=(new PSDExposure(this,length)).parse();break;case"vibA":this.adjustments.vibrance=(new PSDVibrance(this,length)).parse();break;case"hue2":this.adjustments.hueSaturation=(new PSDHueSaturation(this,length)).parse();break;case"blnc":this.adjustments.colorBalance=(new PSDColorBalance(this,length)).parse();break;case"blwh":this.adjustments.blackWhite=(new PSDBlackWhite(this,length)).parse();break;case"phfl":this.adjustments.photoFilter=(new PSDPhotoFilter(this,length)).parse();break;case"thrs":this.adjustments.threshold=(new PSDThreshold(this,length)).parse();break;case"nvrt":this.adjustments.invert=(new PSDInvert(this,length)).parse();break;case"post":this.adjustments.posterize=(new PSDPosterize(this,length)).parse();break;case"tySh":this.adjustments.typeTool=(new PSDTypeTool(this,length)).parse(true);break;case"TySh":this.adjustments.typeTool=(new PSDTypeTool(this,length)).parse();break;case"luni":this.name=this.file.readUnicodeString();this.file.seek(pos+length,false);break;case"lyid":this.layerId=this.file.readInt();break;case"lsct":this.readLayerSectionDivider();break;case"lrFX":this.adjustments.legacyEffects=(new PSDEffectsInfo(this,length)).parseLegacy();this.file.read(2);break;case"lfx2":this.adjustments.effects=(new PSDEffectsInfo(this,length)).parse();break;case"selc":this.adjustments.selectiveColor=(new PSDSelectiveColor(this,length)).parse();break;default:this.file.seek(length);Log.debug("Skipping additional layer info with key "+key);}
+if(this.file.tell()!==(pos+length)){Log.debug("Warning: additional layer info with key "+key+" - unexpected end. Position = "+(this.file.tell())+", Expected = "+(pos+length));_results.push(this.file.seek(pos+length,false));}else{_results.push(void 0);}}
+return _results;};PSDLayer.prototype.readLayerSectionDivider=function(){var code;code=this.file.readInt();this.layerType=SECTION_DIVIDER_TYPES[code];Log.debug("Layer type:",this.layerType);switch(code){case 1:case 2:return this.isFolder=true;case 3:return this.isHidden=true;}};PSDLayer.prototype.toJSON=function(){var data,section,sections,_i,_len;sections=['name','legacyName','top','left','bottom','right','channels','rows','cols','channelsInfo','mask','layerType','blendMode','adjustments','visible'];data={};for(_i=0,_len=sections.length;_i<_len;_i++){section=sections[_i];data[section]=this[section];}
return data;};return PSDLayer;})();PSDLayerMask=(function(){function PSDLayerMask(file,header,options){this.file=file;this.header=header;this.options=options;this.layers=[];this.mergedAlpha=false;this.globalMask={};this.extras=[];}
PSDLayerMask.prototype.skip=function(){return this.file.seek(this.file.readInt());};PSDLayerMask.prototype.parse=function(){var endLoc,i,layer,layerInfoSize,maskSize,pos,_i,_j,_len,_ref,_ref1;maskSize=this.file.readInt();endLoc=this.file.tell()+maskSize;Log.debug("Layer mask size is "+maskSize);if(maskSize<=0){return;}
layerInfoSize=Util.pad2(this.file.readInt());pos=this.file.tell();if(layerInfoSize>0){this.numLayers=this.file.readShortInt();if(this.numLayers<0){Log.debug("Note: first alpha channel contains transparency data");this.numLayers=Math.abs(this.numLayers);this.mergedAlpha=true;}
@@ -250,7 +251,10 @@ PSDGradient.prototype.parse=function(){var version;version=this.file.readInt();a
PSDHueSaturation.prototype.parse=function(){var i,j,version,_i,_j,_k;version=this.file.getShortInt();assert(version===2);this.data.colorization=this.file.readBoolean();this.file.seek(1);this.data.hue=this.file.getShortInt();this.data.saturation=this.file.getShortInt();this.data.lightness=this.file.getShortInt();this.data.masterHue=this.file.getShortInt();this.data.masterSaturation=this.file.getShortInt();this.data.masterLightness=this.file.getShortInt();this.data.rangeValues=[];this.data.settingValues=[];for(i=_i=0;_i<6;i=++_i){this.data.rangeValues[i]=[];this.data.settingValues[i]=[];for(j=_j=0;_j<4;j=++_j){this.data.rangeValues[i][j]=this.file.getShortInt();}
for(j=_k=0;_k<3;j=++_k){this.data.settingValues[i][j]=this.file.getShortInt();}}
return this.data;};return PSDHueSaturation;})();PSDInvert=(function(){function PSDInvert(layer,length){this.layer=layer;this.length=length;this.file=this.layer.file;}
-PSDInvert.prototype.parse=function(){return true;};return PSDInvert;})();PSDLayerEffect=(function(){function PSDLayerEffect(file){this.file=file;}
+PSDInvert.prototype.parse=function(){return true;};return PSDInvert;})();PSDEffectsInfo=(function(){function PSDEffectsInfo(layer,length){this.layer=layer;this.length=length;this.file=this.layer.file;}
+PSDEffectsInfo.prototype.parse=function(){var effectsVersion,version;effectsVersion=this.file.readInt();assert(effectsVersion===0);version=this.file.readInt();assert(version===16);return(new PSDEffectsDescriptor(this.file)).parse();};PSDEffectsInfo.prototype.parseLegacy=function(){var count,data,effect,effects,left,pos,signature,size,type,v,_ref,_ref1;effects=[];_ref=this.file.readf(">HH"),v=_ref[0],count=_ref[1];while(count-->0){_ref1=this.file.readf(">4s4s"),signature=_ref1[0],type=_ref1[1];size=this.file.readf(">i")[0];pos=this.file.tell();Log.debug("Parsing effect layer with type "+type+" and size "+size);effect=(function(){switch(type){case"cmnS":return new PSDLayerEffectCommonStateInfo(this.file);case"dsdw":return new PSDDropDownLayerEffect(this.file);case"isdw":return new PSDDropDownLayerEffect(this.file,true);}}).call(this);data=effect!=null?effect.parse():void 0;left=(pos+size)-this.file.tell();if(left!==0){Log.debug("Failed to parse effect layer with type "+type);this.file.seek(left);}else{if(type!=="cmnS"){effects.push(data);}}}
+return{legacy:true,effects:effects};};return PSDEffectsInfo;})();PSDEffectsDescriptor=(function(_super){__extends(PSDEffectsDescriptor,_super);function PSDEffectsDescriptor(){return PSDEffectsDescriptor.__super__.constructor.apply(this,arguments);}
+PSDEffectsDescriptor.prototype.parseItem=function(id){var data,type;type=this.file.readString(4);data=(function(){switch(id){case"patternFill":return this.parseLayerPatternOverlay();default:return PSDEffectsDescriptor.__super__.parseItem.call(this,id,type);}}).call(this);return data;};return PSDEffectsDescriptor;})(PSDDescriptor);PSDLayerEffect=(function(){function PSDLayerEffect(file){this.file=file;}
PSDLayerEffect.prototype.parse=function(){var _ref;return _ref=this.file.readf(">i"),this.version=_ref[0],_ref;};PSDLayerEffect.prototype.getSpaceColor=function(){this.file.read(2);return this.file.readf(">HHHH");};return PSDLayerEffect;})();PSDLayerEffectCommonStateInfo=(function(_super){__extends(PSDLayerEffectCommonStateInfo,_super);function PSDLayerEffectCommonStateInfo(){return PSDLayerEffectCommonStateInfo.__super__.constructor.apply(this,arguments);}
PSDLayerEffectCommonStateInfo.prototype.parse=function(){PSDLayerEffectCommonStateInfo.__super__.parse.call(this);this.visible=this.file.readBoolean();this.file.read(2);return{visible:this.visible};};return PSDLayerEffectCommonStateInfo;})(PSDLayerEffect);PSDDropDownLayerEffect=(function(_super){__extends(PSDDropDownLayerEffect,_super);function PSDDropDownLayerEffect(file,inner){this.inner=inner!=null?inner:false;PSDDropDownLayerEffect.__super__.constructor.call(this,file);this.blendMode="mul";this.color=this.nativeColor=[0,0,0,0];this.opacity=191;this.angle=120;this.useGlobalLight=true;this.distance=5;this.spread=0;this.size=5;this.antiAliased=false;this.knocksOut=false;}
PSDDropDownLayerEffect.prototype.parse=function(){var data,key,val,_ref,_ref1;PSDDropDownLayerEffect.__super__.parse.call(this);_ref=this.file.readf(">hiii"),this.blur=_ref[0],this.intensity=_ref[1],this.angle=_ref[2],this.distance=_ref[3];this.file.read(2);this.color=this.getSpaceColor();_ref1=this.file.readf(">4s4s"),this.signature=_ref1[0],this.blendMode=_ref1[1];this.enabled=this.file.readBoolean();this.useAngleInAllFX=this.file.readBoolean();this.opacity=this.file.read(1)[0];if(this.version===2){this.nativeColor=this.getSpaceColor();}
diff --git a/src/layerdata/layereffect.coffee b/src/layerdata/layereffect.coffee
index d69586d..7255358 100755
--- a/src/layerdata/layereffect.coffee
+++ b/src/layerdata/layereffect.coffee
@@ -1,6 +1,69 @@
# libpsd has effect layer parsing
# see https://github.com/alco/psdump/blob/master/libpsd-0.9
+class PSDEffectsInfo
+ constructor: (@layer, @length) ->
+ @file = @layer.file
+
+ parse: ->
+ effectsVersion = @file.readInt()
+ assert effectsVersion is 0
+
+ version = @file.readInt()
+ assert version is 16
+
+ (new PSDEffectsDescriptor(@file)).parse()
+
+ parseLegacy: ->
+ effects = []
+
+ [
+ v, # always 0
+ count
+ ] = @file.readf ">HH"
+
+ while count-- > 0
+ [
+ signature,
+ type
+ ] = @file.readf ">4s4s"
+
+ [size] = @file.readf ">i"
+
+ pos = @file.tell()
+
+ Log.debug("Parsing effect layer with type #{type} and size #{size}")
+
+ effect =
+ switch type
+ when "cmnS" then new PSDLayerEffectCommonStateInfo @file
+ when "dsdw" then new PSDDropDownLayerEffect @file
+ when "isdw" then new PSDDropDownLayerEffect @file, true # inner drop shadow
+
+ data = effect?.parse()
+
+ left = (pos + size) - @file.tell()
+ if left != 0
+ Log.debug("Failed to parse effect layer with type #{type}")
+ @file.seek left
+ else
+ effects.push(data) unless type == "cmnS" # ignore commons state info
+
+ legacy: true
+ effects: effects
+
+# This is ridiculous. The effects layer does not follow the standard
+# descriptor structure. Have to do a little hacking here.
+class PSDEffectsDescriptor extends PSDDescriptor
+ parseItem: (id) ->
+ type = @file.readString(4)
+
+ data = switch id
+ when "patternFill" then @parseLayerPatternOverlay()
+ else super(id, type)
+
+ data
+
class PSDLayerEffect
constructor: (@file) ->
diff --git a/src/psddescriptor.coffee b/src/psddescriptor.coffee
index 2d0322c..3b6213b 100644
--- a/src/psddescriptor.coffee
+++ b/src/psddescriptor.coffee
@@ -29,11 +29,13 @@ class PSDDescriptor
id: @parseID()
parseKeyItem: ->
- id: @parseID()
- value: @parseItem()
+ id = @parseID()
+ value = @parseItem(id)
- parseItem: ->
- type = @file.readString(4)
+ id: id, value: value
+
+ parseItem: (id, type = null) ->
+ type = @file.readString(4) unless type
Log.debug "Found descriptor type: #{type}"
value = switch type
@@ -142,7 +144,7 @@ class PSDDescriptor
value
parseUnitDouble: ->
- unitID = @file.parseString(4)
+ unitID = @file.readString(4)
unit = switch unitID
when "#Ang" then "Angle"
when "#Rsl" then "Density"
diff --git a/src/psdlayer.coffee b/src/psdlayer.coffee
index 14c371d..5e1a2bd 100755
--- a/src/psdlayer.coffee
+++ b/src/psdlayer.coffee
@@ -324,8 +324,11 @@ class PSDLayer
@layerId = @file.readInt()
when "lsct"
@readLayerSectionDivider()
- when "lrFX"
- @parseEffectsLayer(); @file.read(2) # why these 2 bytes?
+ when "lrFX" # PS 5.0
+ @adjustments.legacyEffects = (new PSDEffectsInfo(@, length)).parseLegacy()
+ @file.read(2) # why these 2 bytes?
+ when "lfx2" # PS 6.0
+ @adjustments.effects = (new PSDEffectsInfo(@, length)).parse()
when "selc"
@adjustments.selectiveColor = (new PSDSelectiveColor(@, length)).parse()
else
@@ -333,45 +336,9 @@ class PSDLayer
Log.debug("Skipping additional layer info with key #{key}")
if @file.tell() != (pos + length)
- Log.debug "Warning: additional layer info with key #{key} - unexpected end"
+ Log.debug "Warning: additional layer info with key #{key} - unexpected end. Position = #{@file.tell()}, Expected = #{(pos + length)}"
@file.seek pos + length, false # Attempt to recover
- parseEffectsLayer: ->
- effects = []
-
- [
- v, # always 0
- count
- ] = @file.readf ">HH"
-
- while count-- > 0
- [
- signature,
- type
- ] = @file.readf ">4s4s"
-
- [size] = @file.readf ">i"
-
- pos = @file.tell()
-
- Log.debug("Parsing effect layer with type #{type} and size #{size}")
-
- effect =
- switch type
- when "cmnS" then new PSDLayerEffectCommonStateInfo @file
- when "dsdw" then new PSDDropDownLayerEffect @file
- when "isdw" then new PSDDropDownLayerEffect @file, true # inner drop shadow
-
- data = effect?.parse()
-
- left = (pos + size) - @file.tell()
- if left != 0
- Log.debug("Failed to parse effect layer with type #{type}")
- @file.seek left
- else
- effects.push(data) unless type == "cmnS" # ignore commons state info
-
- @adjustments.effects = effects
readLayerSectionDivider: ->
code = @file.readInt()