psdparser.py 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649
  1. #!/usr/bin/env python
  2. # This file is part of psdparser.
  3. #
  4. # Psdparser is free software: you can redistribute it and/or modify
  5. # it under the terms of the GNU General Public License as published by
  6. # the Free Software Foundation, either version 3 of the License, or
  7. # (at your option) any later version.
  8. #
  9. # Psdparser is distributed in the hope that it will be useful,
  10. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. # GNU General Public License for more details.
  13. #
  14. # You should have received a copy of the GNU General Public License
  15. # along with Psdparser. If not, see <http://www.gnu.org/licenses/>.
  16. import logging
  17. import sys
  18. from struct import unpack, calcsize
  19. import Image
  20. logger = logging.getLogger(__name__)
  21. """
  22. Header mode field meanings
  23. """
  24. CHANNEL_SUFFIXES = {
  25. -2: 'layer mask',
  26. -1: 'A',
  27. 0: 'R',
  28. 1: 'G',
  29. 2: 'B',
  30. 3: 'RGB',
  31. 4: 'CMYK', 5: 'HSL', 6: 'HSB',
  32. 9: 'Lab', 11: 'RGB',
  33. 12: 'Lab', 13: 'CMYK',
  34. }
  35. """
  36. Resource id descriptions
  37. """
  38. RESOURCE_DESCRIPTIONS = {
  39. 1000: 'PS2.0 mode data',
  40. 1001: 'Macintosh print record',
  41. 1003: 'PS2.0 indexed color table',
  42. 1005: 'ResolutionInfo',
  43. 1006: 'Names of the alpha channels',
  44. 1007: 'DisplayInfo',
  45. 1008: 'Caption',
  46. 1009: 'Border information',
  47. 1010: 'Background color',
  48. 1011: 'Print flags',
  49. 1012: 'Grayscale/multichannel halftoning info',
  50. 1013: 'Color halftoning info',
  51. 1014: 'Duotone halftoning info',
  52. 1015: 'Grayscale/multichannel transfer function',
  53. 1016: 'Color transfer functions',
  54. 1017: 'Duotone transfer functions',
  55. 1018: 'Duotone image info',
  56. 1019: 'B&W values for the dot range',
  57. 1021: 'EPS options',
  58. 1022: 'Quick Mask info',
  59. 1024: 'Layer state info',
  60. 1025: 'Working path',
  61. 1026: 'Layers group info',
  62. 1028: 'IPTC-NAA record (File Info)',
  63. 1029: 'Image mode for raw format files',
  64. 1030: 'JPEG quality',
  65. 1032: 'Grid and guides info',
  66. 1033: 'Thumbnail resource',
  67. 1034: 'Copyright flag',
  68. 1035: 'URL',
  69. 1036: 'Thumbnail resource',
  70. 1037: 'Global Angle',
  71. 1038: 'Color samplers resource',
  72. 1039: 'ICC Profile',
  73. 1040: 'Watermark',
  74. 1041: 'ICC Untagged',
  75. 1042: 'Effects visible',
  76. 1043: 'Spot Halftone',
  77. 1044: 'Document specific IDs',
  78. 1045: 'Unicode Alpha Names',
  79. 1046: 'Indexed Color Table Count',
  80. 1047: 'Transparent Index',
  81. 1049: 'Global Altitude',
  82. 1050: 'Slices',
  83. 1051: 'Workflow URL',
  84. 1052: 'Jump To XPEP',
  85. 1053: 'Alpha Identifiers',
  86. 1054: 'URL List',
  87. 1057: 'Version Info',
  88. 2999: 'Name of clipping path',
  89. 10000: 'Print flags info',
  90. }
  91. MODES = {
  92. 0: 'Bitmap',
  93. 1: 'GrayScale',
  94. 2: 'IndexedColor',
  95. 3: 'RGBColor',
  96. 4: 'CMYKColor',
  97. 5: 'HSLColor',
  98. 6: 'HSBColor',
  99. 7: 'Multichannel',
  100. 8: 'Duotone',
  101. 9: 'LabColor',
  102. 10: 'Gray16',
  103. 11: 'RGB48',
  104. 12: 'Lab48',
  105. 13: 'CMYK64',
  106. 14: 'DeepMultichannel',
  107. 15: 'Duotone16',
  108. }
  109. COMPRESSIONS = {
  110. 0: 'Raw',
  111. 1: 'RLE',
  112. 2: 'ZIP',
  113. 3: 'ZIPPrediction',
  114. }
  115. BLENDINGS = {
  116. 'norm': 'normal',
  117. 'dark': 'darken',
  118. 'mul ': 'multiply',
  119. 'lite': 'lighten',
  120. 'scrn': 'screen',
  121. 'over': 'overlay',
  122. 'sLit': 'soft-light',
  123. 'hLit': 'hard-light',
  124. 'lLit': 'linear-light',
  125. 'diff': 'difference',
  126. 'smud': 'exclusion',
  127. }
  128. PIL_BANDS = {
  129. 'R': 0,
  130. 'G': 1,
  131. 'B': 2,
  132. 'A': 3,
  133. 'L': 0,
  134. }
  135. def INDENT_OUTPUT(depth, msg):
  136. return ''.join([' ' for i in range(0, depth)]) + msg
  137. class PSDParser(object):
  138. header = None
  139. ressources = None
  140. num_layers = 0
  141. layers = None
  142. images = None
  143. merged_image = None
  144. def __init__(self, filename):
  145. self.filename = filename
  146. def _pad2(self, i):
  147. """same or next even"""
  148. return (i + 1) / 2 * 2
  149. def _pad4(self, i):
  150. """same or next multiple of 4"""
  151. return (i + 3) / 4 * 4
  152. def _readf(self, format):
  153. """read a strct from file structure according to format"""
  154. return unpack(format, self.fd.read(calcsize(format)))
  155. def _skip_block(self, desc, indent=0, new_line=False):
  156. (n,) = self._readf('>L') # (n,) is a 1-tuple.
  157. if n:
  158. self.fd.seek(n, 1) # 1: relative
  159. if new_line:
  160. logger.debug('')
  161. logger.debug(INDENT_OUTPUT(indent, 'Skipped %s with %s bytes' % (desc, n)))
  162. def parse(self):
  163. logger.debug("Opening '%s'" % self.filename)
  164. self.fd = open(self.filename, 'rb')
  165. try:
  166. self.parse_header()
  167. self.parse_image_resources()
  168. self.parse_layers_and_masks()
  169. self.parse_image_data()
  170. finally:
  171. self.fd.close()
  172. logger.debug("")
  173. logger.debug("DONE")
  174. def parse_header(self):
  175. logger.debug("")
  176. logger.debug("# Header #")
  177. self.header = {}
  178. C_PSD_HEADER = ">4sH 6B HLLHH"
  179. (
  180. self.header['sig'],
  181. self.header['version'],
  182. self.header['r0'],
  183. self.header['r1'],
  184. self.header['r2'],
  185. self.header['r3'],
  186. self.header['r4'],
  187. self.header['r5'],
  188. self.header['channels'],
  189. self.header['rows'],
  190. self.header['cols'],
  191. self.header['depth'],
  192. self.header['mode']
  193. ) = self._readf(C_PSD_HEADER)
  194. self.size = [self.header['rows'], self.header['cols']]
  195. if self.header['sig'] != "8BPS":
  196. raise ValueError("Not a PSD signature: '%s'" % self.header['sig'])
  197. if self.header['version'] != 1:
  198. raise ValueError("Can not handle PSD version:%d" % self.header['version'])
  199. self.header['modename'] = MODES[self.header['mode']] if 0 <= self.header['mode'] < 16 else "(%s)" % self.header['mode']
  200. logger.debug(INDENT_OUTPUT(1, "channels:%(channels)d, rows:%(rows)d, cols:%(cols)d, depth:%(depth)d, mode:%(mode)d [%(modename)s]" % self.header))
  201. logger.debug(INDENT_OUTPUT(1, "%s" % self.header))
  202. # Remember position
  203. self.header['colormodepos'] = self.fd.tell()
  204. self._skip_block("color mode data", 1)
  205. def parse_image_resources(self):
  206. def parse_irb():
  207. """return total bytes in block"""
  208. r = {}
  209. r['at'] = self.fd.tell()
  210. (r['type'], r['id'], r['namelen']) = self._readf(">4s H B")
  211. n = self._pad2(r['namelen'] + 1) - 1
  212. (r['name'],) = self._readf(">%ds" % n)
  213. r['name'] = r['name'][:-1] # skim off trailing 0byte
  214. r['short'] = r['name'][:20]
  215. (r['size'],) = self._readf(">L")
  216. self.fd.seek(self._pad2(r['size']), 1) # 1: relative
  217. r['rdesc'] = "[%s]" % RESOURCE_DESCRIPTIONS.get(r['id'], "?")
  218. logger.debug(INDENT_OUTPUT(1, "Resource: %s" % r))
  219. logger.debug(INDENT_OUTPUT(1, "0x%(at)06x| type:%(type)s, id:%(id)5d, size:0x%(size)04x %(rdesc)s '%(short)s'" % r))
  220. self.ressources.append(r)
  221. return 4 + 2 + self._pad2(1 + r['namelen']) + 4 + self._pad2(r['size'])
  222. logger.debug("")
  223. logger.debug("# Ressources #")
  224. self.ressources = []
  225. (n,) = self._readf(">L") # (n,) is a 1-tuple.
  226. while n > 0:
  227. n -= parse_irb()
  228. if n != 0:
  229. logger.debug("Image resources overran expected size by %d bytes" % (-n))
  230. def parse_image(self, li, is_layer=True):
  231. def parse_channel(li, idx, count, rows, cols, depth):
  232. """params:
  233. li -- layer info struct
  234. idx -- channel number
  235. count -- number of channels to process ???
  236. rows, cols -- dimensions
  237. depth -- bits
  238. """
  239. chlen = li['chlengths'][idx]
  240. if chlen is not None and chlen < 2:
  241. raise ValueError("Not enough channel data: %s" % chlen)
  242. if li['chids'][idx] == -2:
  243. rows, cols = li['mask']['rows'], li['mask']['cols']
  244. rb = (cols * depth + 7) / 8 # round to next byte
  245. # channel header
  246. chpos = self.fd.tell()
  247. (comp,) = self._readf(">H")
  248. if chlen:
  249. chlen -= 2
  250. pos = self.fd.tell()
  251. # If empty layer
  252. if cols * rows == 0:
  253. logger.debug(INDENT_OUTPUT(1, "Empty channel, skiping"))
  254. return
  255. if COMPRESSIONS.get(comp) == 'RLE':
  256. logger.debug(INDENT_OUTPUT(1, "Handling RLE compressed data"))
  257. rlecounts = 2 * count * rows
  258. if chlen and chlen < rlecounts:
  259. raise ValueError("Channel too short for RLE row counts (need %d bytes, have %d bytes)" % (rlecounts,chlen))
  260. pos += rlecounts # image data starts after RLE counts
  261. rlecounts_data = self._readf(">%dH" % (count * rows))
  262. for ch in range(count):
  263. rlelen_for_channel = sum(rlecounts_data[ch * rows:(ch + 1) * rows])
  264. data = self.fd.read(rlelen_for_channel)
  265. channel_name = CHANNEL_SUFFIXES[li['chids'][idx]]
  266. if li['channels'] == 2 and channel_name == 'B': channel_name = 'L'
  267. p = Image.fromstring("L", (cols, rows), data, "packbits", "L" )
  268. if is_layer:
  269. if channel_name in PIL_BANDS:
  270. self.images[li['idx']][PIL_BANDS[channel_name]] = p
  271. else:
  272. self.merged_image.append(p)
  273. elif COMPRESSIONS.get(comp) == 'Raw':
  274. logger.debug(INDENT_OUTPUT(1, "Handling Raw compressed data"))
  275. for ch in range(count):
  276. data = self.fd.read(cols * rows)
  277. channel_name = CHANNEL_SUFFIXES[li['chids'][idx]]
  278. if li['channels'] == 2 and channel_name == 'B': channel_name = 'L'
  279. p = Image.fromstring("L", (cols, rows), data, "raw", "L")
  280. if is_layer:
  281. if channel_name in PIL_BANDS:
  282. self.images[li['idx']][PIL_BANDS[channel_name]] = p
  283. else:
  284. self.merged_image.append(p)
  285. else:
  286. # TODO: maybe just skip channel...:
  287. # f.seek(chlen, SEEK_CUR)
  288. # return
  289. raise ValueError("Unsupported compression type: %s" % COMPRESSIONS.get(comp, comp))
  290. if (chlen is not None) and (self.fd.tell() != chpos + 2 + chlen):
  291. logger.debug("currentpos:%d should be:%d!" % (f.tell(), chpos + 2 + chlen))
  292. self.fd.seek(chpos + 2 + chlen, 0) # 0: SEEK_SET
  293. return
  294. if not self.header:
  295. self.parse_header()
  296. if not self.ressources:
  297. self._skip_block("image resources", new_line=True)
  298. self.ressources = 'not parsed'
  299. logger.debug("")
  300. logger.debug("# Image: %s/%d #" % (li['name'], li['channels']))
  301. # channels
  302. if is_layer:
  303. for ch in range(li['channels']):
  304. parse_channel(li, ch, 1, li['rows'], li['cols'], self.header['depth'])
  305. else:
  306. parse_channel(li, 0, li['channels'], li['rows'], li['cols'], self.header['depth'])
  307. return
  308. def _read_descriptor(self):
  309. # Descriptor
  310. def _unicode_string():
  311. len = self._readf(">L")[0]
  312. result = u''
  313. for count in range(len):
  314. val = self._readf(">H")[0]
  315. if val:
  316. result += unichr(val)
  317. return result
  318. def _string_or_key():
  319. len = self._readf(">L")[0]
  320. if not len:
  321. len = 4
  322. return self._readf(">%ds" % len)[0]
  323. def _desc_TEXT():
  324. return _unicode_string()
  325. def _desc_enum():
  326. return { 'typeID' : _string_or_key(),
  327. 'enum' : _string_or_key(),
  328. }
  329. def _desc_long():
  330. return self._readf(">l")[0]
  331. def _desc_bool():
  332. return self._readf(">?")[0]
  333. def _desc_doub():
  334. return self._readf(">d")[0]
  335. def _desc_tdta():
  336. # Apparently it is pdf data?
  337. # http://telegraphics.com.au/svn/psdparse
  338. # descriptor.c pdf.c
  339. len = self._readf(">L")[0]
  340. pdf_data = self.fd.read(len)
  341. return pdf_data
  342. _desc_item_factory = {
  343. 'TEXT' : _desc_TEXT,
  344. 'enum' : _desc_enum,
  345. 'long' : _desc_long,
  346. 'bool' : _desc_bool,
  347. 'doub' : _desc_doub,
  348. 'tdta' : _desc_tdta,
  349. }
  350. class_id_name = _unicode_string()
  351. class_id = _string_or_key()
  352. logger.debug(INDENT_OUTPUT(4, u"name='%s' clsid='%s'" % (class_id_name, class_id)))
  353. item_count = self._readf(">L")[0]
  354. #logger.debug(INDENT_OUTPUT(4, "item_count=%d" % (item_count)))
  355. items = {}
  356. for item_index in range(item_count):
  357. item_key = _string_or_key()
  358. item_type = self._readf(">4s")[0]
  359. if not item_type in _desc_item_factory:
  360. logger.debug(INDENT_OUTPUT(4, "unknown descriptor item '%s', skipping ahead." % item_type))
  361. break
  362. items[item_key] = _desc_item_factory[item_type]()
  363. #logger.debug(INDENT_OUTPUT(4, "item['%s']='%r'" % (item_key,items[item_key])))
  364. #print items[item_key]
  365. return items
  366. def parse_layers_and_masks(self):
  367. if not self.header:
  368. self.parse_header()
  369. if not self.ressources:
  370. self._skip_block('image resources', new_line=True)
  371. self.ressources = 'not parsed'
  372. logger.debug("")
  373. logger.debug("# Layers & Masks #")
  374. self.layers = []
  375. self.images = []
  376. self.header['mergedalpha'] = False
  377. (misclen,) = self._readf(">L")
  378. if misclen:
  379. miscstart = self.fd.tell()
  380. # process layer info section
  381. (layerlen,) = self._readf(">L")
  382. if layerlen:
  383. # layers structure
  384. (self.num_layers,) = self._readf(">h")
  385. if self.num_layers < 0:
  386. self.num_layers = -self.num_layers
  387. logger.debug(INDENT_OUTPUT(1, "First alpha is transparency for merged image"))
  388. self.header['mergedalpha'] = True
  389. logger.debug(INDENT_OUTPUT(1, "Layer info for %d layers:" % self.num_layers))
  390. if self.num_layers * (18 + 6 * self.header['channels']) > layerlen:
  391. raise ValueError("Unlikely number of %s layers for %s channels with %s layerlen. Giving up." % (self.num_layers, self.header['channels'], layerlen))
  392. linfo = [] # collect header infos here
  393. for i in range(self.num_layers):
  394. l = {}
  395. l['idx'] = i
  396. #
  397. # Layer Info
  398. #
  399. (l['top'], l['left'], l['bottom'], l['right'], l['channels']) = self._readf(">llllH")
  400. (l['rows'], l['cols']) = (l['bottom'] - l['top'], l['right'] - l['left'])
  401. logger.debug(INDENT_OUTPUT(1, "layer %(idx)d: (%(left)4d,%(top)4d,%(right)4d,%(bottom)4d), %(channels)d channels (%(cols)4d cols x %(rows)4d rows)" % l))
  402. # Sanity check
  403. if l['bottom'] < l['top'] or l['right'] < l['left'] or l['channels'] > 64:
  404. logger.debug(INDENT_OUTPUT(2, "Something's not right about that, trying to skip layer."))
  405. self.fd.seek(6 * l['channels'] + 12, 1) # 1: SEEK_CUR
  406. self._skip_block("layer info: extra data", 2)
  407. continue # next layer
  408. # Read channel infos
  409. l['chlengths'] = []
  410. l['chids'] = []
  411. # - 'hackish': addressing with -1 and -2 will wrap around to the two extra channels
  412. l['chindex'] = [ -1 ] * (l['channels'] + 2)
  413. for j in range(l['channels']):
  414. chid, chlen = self._readf(">hL")
  415. l['chids'].append(chid)
  416. l['chlengths'].append(chlen)
  417. logger.debug(INDENT_OUTPUT(3, "Channel %2d: id=%2d, %5d bytes" % (j, chid, chlen)))
  418. if -2 <= chid < l['channels']:
  419. # pythons negative list-indexs: [ 0, 1, 2, 3, ... -2, -1]
  420. l['chindex'][chid] = j
  421. else:
  422. logger.debug(INDENT_OUTPUT(3, "Unexpected channel id %d" % chid))
  423. l['chidstr'] = CHANNEL_SUFFIXES.get(chid, "?")
  424. # put channel info into connection
  425. linfo.append(l)
  426. #
  427. # Blend mode
  428. #
  429. bm = {}
  430. (bm['sig'], bm['key'], bm['opacity'], bm['clipping'], bm['flags'], bm['filler'],
  431. ) = self._readf(">4s4sBBBB")
  432. bm['opacp'] = (bm['opacity'] * 100 + 127) / 255
  433. bm['clipname'] = bm['clipping'] and "non-base" or "base"
  434. bm['blending'] = BLENDINGS.get(bm['key'])
  435. l['blend_mode'] = bm
  436. logger.debug(INDENT_OUTPUT(3, "Blending mode: sig=%(sig)s key=%(key)s opacity=%(opacity)d(%(opacp)d%%) clipping=%(clipping)d(%(clipname)s) flags=%(flags)x" % bm))
  437. # remember position for skipping unrecognized data
  438. (extralen,) = self._readf(">L")
  439. extrastart = self.fd.tell()
  440. #
  441. # Layer mask data
  442. #
  443. m = {}
  444. (m['size'],) = self._readf(">L")
  445. if m['size']:
  446. (m['top'], m['left'], m['bottom'], m['right'], m['default_color'], m['flags'],
  447. ) = self._readf(">llllBB")
  448. # skip remainder
  449. self.fd.seek(m['size'] - 18, 1) # 1: SEEK_CUR
  450. m['rows'], m['cols'] = m['bottom'] - m['top'], m['right'] - m['left']
  451. l['mask'] = m
  452. self._skip_block("layer blending ranges", 3)
  453. #
  454. # Layer name
  455. #
  456. name_start = self.fd.tell()
  457. (l['namelen'],) = self._readf(">B")
  458. addl_layer_data_start = name_start + self._pad4(l['namelen'] + 1)
  459. # - "-1": one byte traling 0byte. "-1": one byte garble.
  460. # (l['name'],) = readf(f, ">%ds" % (self._pad4(1+l['namelen'])-2))
  461. (l['name'],) = self._readf(">%ds" % (l['namelen']))
  462. logger.debug(INDENT_OUTPUT(3, "Name: '%s'" % l['name']))
  463. self.fd.seek(addl_layer_data_start, 0)
  464. #
  465. # Read add'l Layer Information
  466. #
  467. while self.fd.tell() < extrastart + extralen:
  468. (signature, key, size, ) = self._readf(">4s4sL") # (n,) is a 1-tuple.
  469. logger.debug(INDENT_OUTPUT(3, "Addl info: sig='%s' key='%s' size='%d'" %
  470. (signature, key, size)))
  471. next_addl_offset = self.fd.tell() + self._pad2(size)
  472. if key == 'luni':
  473. namelen = self._readf(">L")[0]
  474. l['name'] = u''
  475. for count in range(0, namelen):
  476. l['name'] += unichr(self._readf(">H")[0])
  477. logger.debug(INDENT_OUTPUT(4, u"Unicode Name: '%s'" % l['name']))
  478. elif key == 'TySh':
  479. version = self._readf(">H")[0]
  480. (xx, xy, yx, yy, tx, ty,) = self._readf(">dddddd") #transform
  481. text_version = self._readf(">H")[0]
  482. text_desc_version = self._readf(">L")[0]
  483. text_desc = self._read_descriptor()
  484. warp_version = self._readf(">H")[0]
  485. warp_desc_version = self._readf(">L")[0]
  486. warp_desc = self._read_descriptor()
  487. (left,top,right,bottom,) = self._readf(">llll")
  488. logger.debug(INDENT_OUTPUT(4, "ver=%d tver=%d dver=%d"
  489. % (version, text_version, text_desc_version)))
  490. logger.debug(INDENT_OUTPUT(4, "%f %f %f %f %f %f" % (xx, xy, yx, yy, tx, ty,)))
  491. logger.debug(INDENT_OUTPUT(4, "l=%f t=%f r=%f b=%f"
  492. % (left, top, right, bottom)))
  493. l['text_layer'] = {}
  494. l['text_layer']['text_desc'] = text_desc
  495. l['text_layer']['text_transform'] = (xx, xy, yx, yy, tx, ty,)
  496. l['text_layer']['left'] = left
  497. l['text_layer']['top'] = top
  498. l['text_layer']['right'] = right
  499. l['text_layer']['bottom'] = bottom
  500. self.fd.seek(next_addl_offset, 0)
  501. # Skip over any extra data
  502. self.fd.seek(extrastart + extralen, 0) # 0: SEEK_SET
  503. self.layers.append(l)
  504. for i in range(self.num_layers):
  505. # Empty layer
  506. if linfo[i]['rows'] * linfo[i]['cols'] == 0:
  507. self.images.append(None)
  508. self.parse_image(linfo[i], is_layer=True)
  509. continue
  510. self.images.append([0, 0, 0, 0])
  511. self.parse_image(linfo[i], is_layer=True)
  512. if linfo[i]['channels'] == 2:
  513. l = self.images[i][0]
  514. a = self.images[i][3]
  515. self.images[i] = Image.merge('LA', [l, a])
  516. else:
  517. # is there an alpha channel?
  518. if type(self.images[i][3]) is int:
  519. self.images[i] = Image.merge('RGB', self.images[i][0:3])
  520. else:
  521. self.images[i] = Image.merge('RGBA', self.images[i])
  522. else:
  523. logger.debug(INDENT_OUTPUT(1, "Layer info section is empty"))
  524. skip = miscstart + misclen - self.fd.tell()
  525. if skip:
  526. logger.debug("")
  527. logger.debug("Skipped %d bytes at end of misc data?" % skip)
  528. self.fd.seek(skip, 1) # 1: SEEK_CUR
  529. else:
  530. logger.debug(INDENT_OUTPUT(1, "Misc info section is empty"))
  531. def parse_image_data(self):
  532. if not self.header:
  533. self.parse_header()
  534. if not self.ressources:
  535. self._skip_block("image resources", new_line=True)
  536. self.ressources = 'not parsed'
  537. if not self.layers:
  538. self._skip_block("image layers", new_line=True)
  539. self.layers = 'not parsed'
  540. self.merged_image = []
  541. li = {}
  542. li['chids'] = range(self.header['channels'])
  543. li['chlengths'] = [ None ] * self.header['channels'] # dummy data
  544. (li['name'], li['channels'], li['rows'], li['cols']) = ('merged', self.header['channels'], self.header['rows'], self.header['cols'])
  545. li['layernum'] = -1
  546. self.parse_image(li, is_layer=False)
  547. if li['channels'] == 1:
  548. self.merged_image = self.merged_image[0]
  549. elif li['channels'] == 3:
  550. self.merged_image = Image.merge('RGB', self.merged_image)
  551. elif li['channels'] >= 4 and self.header['mode'] == 3:
  552. self.merged_image = Image.merge('RGBA', self.merged_image[:4])
  553. else:
  554. raise ValueError('Unsupported mode or number of channels')