/XeePhotoshopLayerParser.m

https://code.google.com/p/xee/ · Objective C · 531 lines · 413 code · 85 blank · 33 comment · 44 complexity · 8300391dba872eb816779e1a6b51a5c4 MD5 · raw file

  1. #import "XeePhotoshopLayerParser.h"
  2. #import "XeePhotoshopLoader.h"
  3. #import "XeeProperties.h"
  4. #import "XeeTypes.h"
  5. #import "XeeBitmapRawImage.h"
  6. #import "XeeIndexedRawImage.h"
  7. #import "XeeRawImage.h"
  8. #import "XeeInterleavingHandle.h"
  9. #import <XADMaster/CSZlibHandle.h>
  10. /*static int XeeOffsetOfStringInMemory(const char *str,const void *mem,int len)
  11. {
  12. int slen=strlen(str);
  13. const char *memstr=mem;
  14. for(int i=0;i<=len-slen;i++)
  15. {
  16. if(str[0]==memstr[i])
  17. {
  18. for(int j=1;j<slen;j++)
  19. {
  20. if(str[j]!=memstr[i+j]) goto end;
  21. }
  22. return i;
  23. }
  24. end: 0;
  25. }
  26. return -1;
  27. }*/
  28. @implementation XeePhotoshopLayerParser
  29. +(NSArray *)parseLayersFromHandle:(CSHandle *)fh parentImage:(XeePhotoshopImage *)parent alphaFlag:(BOOL *)hasalpha
  30. {
  31. NSMutableArray *layers=[NSMutableArray array];
  32. int numlayers=[fh readInt16BE];
  33. if(numlayers<0)
  34. {
  35. if(hasalpha) *hasalpha=YES;
  36. numlayers=-numlayers;
  37. }
  38. for(int i=0;i<numlayers;i++)
  39. {
  40. XeePhotoshopLayerParser *layer=[[[self alloc] initWithHandle:fh parentImage:parent] autorelease];
  41. [layers addObject:layer];
  42. }
  43. off_t offset=[fh offsetInFile];
  44. NSEnumerator *enumerator=[layers objectEnumerator];
  45. XeePhotoshopLayerParser *layer;
  46. while(layer=[enumerator nextObject])
  47. {
  48. [layer setDataOffset:offset];
  49. offset+=[layer totalSize];
  50. }
  51. return layers;
  52. }
  53. -(id)initWithHandle:(CSHandle *)fh parentImage:(XeePhotoshopImage *)parentimage
  54. {
  55. if(self=[super init])
  56. {
  57. handle=[fh retain];
  58. parent=parentimage;
  59. props=[NSMutableArray new];
  60. channeloffs=[NSMutableDictionary new];
  61. mode=[parent mode];
  62. depth=[parent bitDepth];
  63. int top=[fh readInt32BE];
  64. int left=[fh readInt32BE];
  65. int bottom=[fh readInt32BE];
  66. int right=[fh readInt32BE];
  67. width=right-left;
  68. height=bottom-top;
  69. channels=[fh readUInt16BE];
  70. totalsize=0;
  71. for(int j=0;j<channels;j++)
  72. {
  73. int channelid=[fh readInt16BE];
  74. uint32_t channellength=[fh readUInt32BE];
  75. [channeloffs setObject:[NSNumber numberWithLongLong:totalsize] forKey:[NSNumber numberWithInt:channelid]];
  76. totalsize+=channellength;
  77. }
  78. [fh skipBytes:4]; // '8BIM'
  79. uint32_t blendmode=[fh readUInt32BE];
  80. int opacity=[fh readUInt8];
  81. /*int clipping=*/[fh readUInt8];
  82. /*int flags=*/[fh readUInt8];
  83. [fh skipBytes:1];
  84. uint32_t extralen=[fh readUInt32BE];
  85. off_t nextoffs=[fh offsetInFile]+extralen;
  86. int bytesleft=extralen;
  87. NSString *layername=nil;
  88. if(bytesleft<4) goto outofbytes;
  89. uint32_t masksize=[fh readUInt32BE]; bytesleft-=4;
  90. if(bytesleft<masksize) goto outofbytes;
  91. [fh skipBytes:masksize]; bytesleft-=masksize;
  92. if(bytesleft<4) goto outofbytes;
  93. uint32_t blendsize=[fh readUInt32BE]; bytesleft-=4;
  94. if(bytesleft<blendsize) goto outofbytes;
  95. [fh skipBytes:blendsize]; bytesleft-=blendsize;
  96. if(bytesleft<1) goto outofbytes;
  97. int namelen=[fh readUInt8]; bytesleft-=1;
  98. if(bytesleft<namelen) goto outofbytes;
  99. if(namelen) layername=[[[NSString alloc] initWithData:[fh readDataOfLength:namelen] encoding:NSISOLatin1StringEncoding] autorelease];
  100. int padbytes=((3-namelen)&3);
  101. if(bytesleft<padbytes) goto outofbytes;
  102. [fh skipBytes:padbytes]; bytesleft-=padbytes;
  103. NSString *adjustmentname=nil;
  104. NSArray *typetoolfonts=nil,*typetooltext=nil;
  105. while(bytesleft>=12)
  106. {
  107. uint32_t signature=[fh readUInt32BE];
  108. if(signature!='8BIM') break;
  109. uint32_t key=[fh readUInt32BE];
  110. uint32_t chunklen=[fh readUInt32BE];
  111. off_t nextchunk=[fh offsetInFile]+chunklen;
  112. bytesleft-=12;
  113. if(chunklen>bytesleft) break;
  114. switch(key)
  115. {
  116. case 'levl': // levels adjustment layer
  117. adjustmentname=NSLocalizedString(@"Levels",@"Photoshop levels adjustment layer name property value");
  118. break;
  119. case 'curv': // curves adjustment layer
  120. adjustmentname=NSLocalizedString(@"Curves",@"Photoshop curves adjustment layer name property value");
  121. break;
  122. case 'brit': // brightness adjustment layer
  123. adjustmentname=NSLocalizedString(@"Brightness",@"Photoshop brightness adjustment layer name property value");
  124. break;
  125. case 'blnc': // color balance adjustment layer
  126. adjustmentname=NSLocalizedString(@"Color balance",@"Photoshop color balance adjustment layer name property value");
  127. break;
  128. case 'hue ': // old hue/saturation adjustment layer
  129. adjustmentname=NSLocalizedString(@"Hue/saturation (old)",@"Photoshop old hue/saturations adjustment layer name property value");
  130. break;
  131. case 'hue2': // new hue/saturation adjustment layer
  132. adjustmentname=NSLocalizedString(@"Hue/saturation",@"Photoshop hue/saturation adjustment layer name property value");
  133. break;
  134. case 'selc': // selective color adjustment layer
  135. adjustmentname=NSLocalizedString(@"Selective color",@"Photoshop selective color adjustment layer name property value");
  136. break;
  137. case 'thrs': // threshold adjustment layer
  138. adjustmentname=NSLocalizedString(@"Threshold",@"Photoshop threshold adjustment layer name property value");
  139. break;
  140. case 'nvrt': // invert adjustment layer
  141. adjustmentname=NSLocalizedString(@"Invert",@"Photoshop invert adjustment layer name property value");
  142. break;
  143. case 'post': // posterize adjustment layer
  144. adjustmentname=NSLocalizedString(@"Posterize",@"Photoshop posterize adjustment layer name property value");
  145. break;
  146. case 'lrFX': // effects layer
  147. break;
  148. case 'tySh': // type tool
  149. {
  150. NSMutableArray *fonts=[NSMutableArray array];
  151. [fh skipBytes:52];
  152. int numfonts=[fh readUInt16BE];
  153. for(int i=0;i<numfonts;i++)
  154. {
  155. [fh skipBytes:6];
  156. int len=[fh readUInt8];
  157. NSString *fontname=[[[NSString alloc] initWithData:[fh readDataOfLength:len] encoding:NSISOLatin1StringEncoding] autorelease];
  158. len=[fh readUInt8];
  159. [fh skipBytes:len]; // family
  160. len=[fh readUInt8];
  161. NSString *fontstyle=[[[NSString alloc] initWithData:[fh readDataOfLength:len] encoding:NSISOLatin1StringEncoding] autorelease];
  162. [fh skipBytes:2];
  163. int vecnum=[fh readUInt32BE];
  164. [fh skipBytes:vecnum*4];
  165. [fonts addObject:[NSString stringWithFormat:@"%@ %@",fontname,fontstyle]];
  166. }
  167. typetoolfonts=[XeePropertyItem itemsWithLabel:
  168. NSLocalizedString(@"Text layer fonts",@"Photoshop text layer fonts property title")
  169. valueArray:fonts];
  170. int numstyles=[fh readUInt16BE];
  171. [fh skipBytes:numstyles*26+26];
  172. NSMutableString *str=[NSMutableString string];
  173. int numlines=[fh readUInt16BE];
  174. for(int i=0;i<numlines;i++)
  175. {
  176. int numchars=[fh readUInt32BE];
  177. [fh skipBytes:4];
  178. for(int j=0;j<numchars;j++)
  179. {
  180. int c=[fh readUInt16BE];
  181. [fh skipBytes:2];
  182. if(c=='\n') continue; // skip \n
  183. if(c=='\r') c='\n'; // and turn \r into \n;
  184. [str appendFormat:@"%C",c];
  185. }
  186. }
  187. typetooltext=[XeePropertyItem itemsWithLabel:
  188. NSLocalizedString(@"Text layer contents",@"Photoshop text layer contents property title")
  189. textValue:str];
  190. }
  191. break;
  192. case 'luni': // unicode layer name
  193. {
  194. if(chunklen<4) break;
  195. int len=[fh readUInt32BE];
  196. if(chunklen<4+len*2) break;
  197. layername=[[[NSString alloc] initWithData:[fh readDataOfLength:len*2]
  198. encoding:CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingUTF16BE)]
  199. autorelease];
  200. }
  201. break;
  202. case 'lyid': // layer ID name
  203. break;
  204. case 'lfx2': // object based effects layer
  205. break;
  206. case 'Patt': // patterns
  207. break;
  208. case 'clbl': // blend clipping elements
  209. break;
  210. case 'infx': // blend interior elements
  211. break;
  212. case 'knko': // knockout setting
  213. break;
  214. case 'lspf': // protected setting
  215. break;
  216. case 'lclr': // sheet color setting
  217. break;
  218. case 'fxrp': // reference point
  219. break;
  220. case 'grdm': // gradient settings
  221. break;
  222. case 'lsct': // section divider setting
  223. break;
  224. case 'brst': // channel blending restrictions setting
  225. break;
  226. case 'SoCo': // solid color sheet setting
  227. break;
  228. case 'PtFl': // pattern fill setting
  229. break;
  230. case 'GdFl': // gradient fill setting
  231. break;
  232. case 'vmsk': // vector mask setting
  233. break;
  234. case 'TySh': // type tool object setting
  235. {
  236. [fh skipBytes:50];
  237. if([fh readUInt16BE]!=50) break; // text descriptor version
  238. if([fh readUInt32BE]!=16) break; // descriptor version
  239. int classlen=[fh readUInt32BE];
  240. [fh skipBytes:classlen*2];
  241. if([fh readUInt32BE]!=0) break;
  242. if([fh readUInt32BE]!='TxLr') break;
  243. int numitems=[fh readUInt32BE];
  244. if(numitems==0) break;
  245. if([fh readUInt32BE]!=0) break;
  246. if([fh readUInt32BE]!='Txt ') break;
  247. if([fh readUInt32BE]!='TEXT') break;
  248. int textlen=[fh readUInt32BE];
  249. NSMutableString *str=[[[NSMutableString alloc] initWithData:[fh readDataOfLength:textlen*2]
  250. encoding:CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingUTF16BE)]
  251. autorelease];
  252. int len=[str length];
  253. for(int i=0;i<len;i++)
  254. if([str characterAtIndex:i]=='\r') [str replaceCharactersInRange:NSMakeRange(i,1) withString:@"\n"];
  255. typetooltext=[XeePropertyItem itemsWithLabel:
  256. NSLocalizedString(@"Text layer contents",@"Photoshop text layer contents property title")
  257. textValue:str];
  258. /* NSData *rest=[fh readDataOfLength:nextchunk-[fh offsetInFile]];
  259. const uint8_t *restbytes=[rest bytes];
  260. int restlen=[rest length];
  261. int offs=XeeOffsetOfStringInMemory("EngineDatatdta",restbytes,restlen);
  262. if(offs>=0)
  263. {
  264. int blocklen=XeeBEUInt32(restbytes+offs+14);
  265. if(offs+18+blocklen>restlen) break;
  266. // NSData *block=[rest subdataWithRange:NSMakeRange(offs+18,blocklen)];
  267. NSMutableData *block=[NSMutableData dataWithData:[rest subdataWithRange:NSMakeRange(offs+18,blocklen)]];
  268. uint8_t *bytes=[block mutableBytes];
  269. for(int i=0;i<[block length];i++) if(!isspace(bytes[i])&&bytes[i]<=0x20) bytes[i]='.';
  270. NSLog(@"%@",[[[NSString alloc] initWithData:block encoding:NSISOLatin1StringEncoding] autorelease]);
  271. }*/
  272. }
  273. break;
  274. case 'ffxi': // foreign effect ID
  275. break;
  276. case 'lnsr': // layer name source setting
  277. break;
  278. case 'shpa': // pattern data
  279. break;
  280. case 'shmd': // meta data setting
  281. NSLog(@"found layer metadata");
  282. break;
  283. case 'Layr': // layer data - what
  284. break;
  285. }
  286. [fh seekToFileOffset:nextchunk];
  287. }
  288. outofbytes:
  289. if(layername) [props addObject:[XeePropertyItem itemWithLabel:
  290. NSLocalizedString(@"Layer name",@"Photoshop layer name property title")
  291. value:layername]];
  292. [props addObject:[XeePropertyItem itemWithLabel:
  293. NSLocalizedString(@"Opacity",@"Photoshop layer opacity property title")
  294. value:[NSString stringWithFormat:@"%d%%",(opacity*100)/255]]];
  295. NSString *blendname;
  296. switch(blendmode)
  297. {
  298. case 'norm': blendname=NSLocalizedString(@"Normal",@"Photoshop layer normal blending mode name property value"); break;
  299. case 'dark': blendname=NSLocalizedString(@"Darken",@"Photoshop layer darken blending mode name property value"); break;
  300. case 'lite': blendname=NSLocalizedString(@"Lighten",@"Photoshop layer lighten blending mode name property value"); break;
  301. case 'hue ': blendname=NSLocalizedString(@"Hue",@"Photoshop layer hue blending mode name property value"); break;
  302. case 'sat ': blendname=NSLocalizedString(@"Saturation",@"Photoshop layer normal blending mode name property value"); break;
  303. case 'colr': blendname=NSLocalizedString(@"Color",@"Photoshop layer color blending mode name property value"); break;
  304. case 'lum ': blendname=NSLocalizedString(@"Luminosity",@"Photoshop layer luminosity blending mode name property value"); break;
  305. case 'mul ': blendname=NSLocalizedString(@"Multiply",@"Photoshop layer multiply blending mode name property value"); break;
  306. case 'scrn': blendname=NSLocalizedString(@"Screen",@"Photoshop layer screen blending mode name property value"); break;
  307. case 'diss': blendname=NSLocalizedString(@"Dissolve",@"Photoshop layer dissolve blending mode name property value"); break;
  308. case 'over': blendname=NSLocalizedString(@"Overlay",@"Photoshop layer overlay blending mode name property value"); break;
  309. case 'hLit': blendname=NSLocalizedString(@"Hard light",@"Photoshop layer hard light blending mode name property value"); break;
  310. case 'sLit': blendname=NSLocalizedString(@"Soft light",@"Photoshop layer soft light blending mode name property value"); break;
  311. case 'diff': blendname=NSLocalizedString(@"Difference",@"Photoshop layer difference blending mode name property value"); break;
  312. case 'smud': blendname=NSLocalizedString(@"Exclusion",@"Photoshop layer exclusion blending mode name property value"); break;
  313. case 'div ': blendname=NSLocalizedString(@"Color dodge",@"Photoshop layer color dodge blending mode name property value"); break;
  314. case 'idiv': blendname=NSLocalizedString(@"Color burn",@"Photoshop layer color burn blending mode name property value"); break;
  315. default:
  316. blendname=[NSString stringWithFormat:
  317. NSLocalizedString(@"Unknown (%c%c%c%c)",@"Photoshop layer unknown blending mode name property value"),
  318. (blendmode>>24)&0xff,(blendmode>>16)&0xff,(blendmode>>8)&0xff,blendmode&0xff];
  319. break;
  320. }
  321. [props addObject:[XeePropertyItem itemWithLabel:
  322. NSLocalizedString(@"Blending mode",@"Photoshop layer blending mode property title")
  323. value:blendname]];
  324. if(adjustmentname) [props addObject:[XeePropertyItem itemWithLabel:
  325. NSLocalizedString(@"Adjustment layer",@"Photoshop adjustment layer property title")
  326. value:adjustmentname]];
  327. if(typetooltext) [props addObjectsFromArray:typetooltext];
  328. if(typetoolfonts) [props addObjectsFromArray:typetoolfonts];
  329. [fh seekToFileOffset:nextoffs];
  330. }
  331. return self;
  332. }
  333. -(void)dealloc
  334. {
  335. [handle release];
  336. [props release];
  337. [channeloffs release];
  338. [super dealloc];
  339. }
  340. -(void)setDataOffset:(off_t)offset
  341. {
  342. dataoffs=offset;
  343. [handle seekToFileOffset:offset];
  344. compression=[handle readUInt16BE];
  345. }
  346. -(off_t)totalSize { return totalsize; }
  347. -(XeeImage *)image
  348. {
  349. XeeImage *image=nil;
  350. BOOL hasalpha=[self hasAlpha];
  351. switch(mode)
  352. {
  353. case XeePhotoshopBitmapMode:
  354. image=[[[XeeBitmapRawImage alloc] initWithHandle:[self handleForChannel:0] width:width height:height] autorelease];
  355. [image setDepthBitmap];
  356. break;
  357. // case XeePhotoshopIndexedMode: [self setDepthIndexed:1<<bitdepth]; break;
  358. case XeePhotoshopGreyscaleMode:
  359. case XeePhotoshopDuotoneMode:
  360. image=[[[XeeRawImage alloc] initWithHandle:[self handleForNumberOfChannels:1]
  361. width:width height:height depth:depth colourSpace:XeeGreyRawColourSpace
  362. flags:XeeBigEndianRawFlag|(hasalpha?XeeAlphaLastRawFlag:0)|(depth==32?XeeFloatingPointRawFlag:0)]
  363. autorelease];
  364. if(mode==XeePhotoshopGreyscaleMode) [image setDepthGrey:depth alpha:hasalpha floating:depth==32?YES:NO];
  365. else [image setDepth:[NSString stringWithFormat:NSLocalizedString(@"%d bits duotone",@"Description for duotone (Photoshop) images"),depth]
  366. iconName:@"depth_rgb"];
  367. break;
  368. case XeePhotoshopRGBMode:
  369. image=[[[XeeRawImage alloc] initWithHandle:[self handleForNumberOfChannels:3]
  370. width:width height:height depth:depth colourSpace:XeeRGBRawColourSpace
  371. flags:XeeBigEndianRawFlag|(hasalpha?XeeAlphaLastRawFlag:0)|(depth==32?XeeFloatingPointRawFlag:0)]
  372. autorelease];
  373. [image setDepthRGB:depth alpha:hasalpha floating:depth==32?YES:NO];
  374. break;
  375. case XeePhotoshopCMYKMode:
  376. image=[[[XeeRawImage alloc] initWithHandle:[self handleForNumberOfChannels:4]
  377. width:width height:height depth:depth colourSpace:XeeCMYKRawColourSpace
  378. flags:XeeBigEndianRawFlag|(hasalpha?XeeAlphaLastRawFlag:0)]
  379. autorelease];
  380. [(XeeRawImage *)image setZeroPoint:1 onePoint:0 forChannel:0];
  381. [(XeeRawImage *)image setZeroPoint:1 onePoint:0 forChannel:1];
  382. [(XeeRawImage *)image setZeroPoint:1 onePoint:0 forChannel:2];
  383. [(XeeRawImage *)image setZeroPoint:1 onePoint:0 forChannel:3];
  384. [image setDepthCMYK:depth alpha:hasalpha];
  385. break;
  386. case XeePhotoshopLabMode:
  387. image=[[[XeeRawImage alloc] initWithHandle:[self handleForNumberOfChannels:3]
  388. width:width height:height depth:depth colourSpace:XeeLabRawColourSpace
  389. flags:XeeBigEndianRawFlag|(hasalpha?XeeAlphaLastRawFlag:0)]
  390. autorelease];
  391. [image setDepthLab:depth alpha:hasalpha];
  392. break;
  393. default:
  394. return nil;
  395. }
  396. [image setProperties:[NSArray arrayWithObject:[XeePropertyItem itemWithLabel:
  397. NSLocalizedString(@"Photoshop layer properties",@"Photoshop layer properties section title")
  398. value:props identifier:@"pslayer"]]];
  399. return image;
  400. }
  401. -(CSHandle *)handleForNumberOfChannels:(int)requiredchannels
  402. {
  403. NSMutableArray *array=[NSMutableArray array];
  404. for(int i=0;i<requiredchannels;i++)
  405. {
  406. CSHandle *fh=[self handleForChannel:i];
  407. if(!handle) return nil;
  408. [array addObject:fh];
  409. }
  410. CSHandle *alphahandle=[self handleForChannel:-1];
  411. if(alphahandle) [array addObject:alphahandle];
  412. if([array count]==1) return [array objectAtIndex:0];
  413. else return [[[XeeInterleavingHandle alloc] initWithHandles:array elementSize:depth] autorelease];
  414. }
  415. -(CSHandle *)handleForChannel:(int)channel
  416. {
  417. NSNumber *offs=[channeloffs objectForKey:[NSNumber numberWithInt:channel]];
  418. if(!offs) return nil;
  419. off_t start=dataoffs+2+[offs longLongValue];
  420. CSFileHandle *fh;
  421. switch(compression)
  422. {
  423. case 0:
  424. fh=[[handle copy] autorelease];
  425. [fh seekToFileOffset:start];
  426. return fh;
  427. case 1:
  428. fh=[[handle copy] autorelease];
  429. [fh seekToFileOffset:start];
  430. return [[[XeePackbitsHandle alloc] initWithHandle:fh rows:height bytesPerRow:(width*depth+7)/8
  431. channel:0 of:1 previousSize:0] autorelease];
  432. case 2:
  433. fh=[[handle copy] autorelease];
  434. [fh seekToFileOffset:start];
  435. return [CSZlibHandle zlibHandleWithHandle:fh];
  436. case 3:
  437. fh=[[handle copy] autorelease];
  438. [fh seekToFileOffset:start];
  439. return [[[XeeDeltaHandle alloc] initWithHandle:[CSZlibHandle zlibHandleWithHandle:fh]
  440. depth:depth columns:width] autorelease];
  441. default:
  442. return nil;
  443. }
  444. }
  445. -(BOOL)hasAlpha { return [channeloffs objectForKey:[NSNumber numberWithInt:-1]]?YES:NO; }
  446. @end