def _get_band_images(channel_data, channel_ids, color_mode, size, depth): bands = {} for channel, channel_id in zip(channel_data, channel_ids): pil_band = _channel_id_to_PIL(channel_id, color_mode) if pil_band is None: warnings.warn("Unsupported channel type (%d)" % channel_id) continue if channel.compression in [Compression.RAW, Compression.ZIP, Compression.ZIP_WITH_PREDICTION]: if depth == 8: im = _from_8bit_raw(channel.data, size) elif depth == 16: im = _from_16bit_raw(channel.data, size) elif depth == 32: im = _from_32bit_raw(channel.data, size) else: warnings.warn("Unsupported depth (%s)" % depth) continue elif channel.compression == Compression.PACK_BITS: if depth != 8: warnings.warn("Depth %s is unsupported for PackBits compression" % depth) continue im = frombytes('L', size, channel.data, "packbits", 'L') else: if Compression.is_known(channel.compression): warnings.warn("Compression method is not implemented (%s)" % channel.compression) else: warnings.warn("Unknown compression method (%s)" % channel.compression) continue bands[pil_band] = im.convert('L') return bands
def _decompress_channel(channel, depth, size): if channel.compression in (Compression.RAW, Compression.ZIP, Compression.ZIP_WITH_PREDICTION): if depth == 8: im = _from_8bit_raw(channel.data, size) elif depth == 16: im = _from_16bit_raw(channel.data, size) elif depth == 32: im = _from_32bit_raw(channel.data, size) else: warnings.warn("Unsupported depth (%s)" % depth) return None elif channel.compression == Compression.PACK_BITS: if depth != 8: warnings.warn("Depth %s is unsupported for PackBits compression" % depth) im = frombytes('L', size, channel.data, "packbits", 'L') else: if Compression.is_known(channel.compression): warnings.warn("Compression method is not implemented " "(%s)" % channel.compression) else: warnings.warn("Unknown compression method (%s)" % channel.compression) return None return im.convert('L')
def set_data(self, size, data, depth, compression=0, version=1): self.data = compress(data, compression, size[0], size[1], depth, version) self.depth = int(depth) self.pixel_depth = int(depth) self.rectangle = (0, 0, int(size[1]), int(size[0])) self.compression = Compression(compression) self.is_written = True
def read(cls, fp): """Read the element from a file-like object. :param fp: file-like object :rtype: :py:class:`.ChannelData` """ compression = Compression(read_fmt('H', fp)[0]) data = fp.read() return cls(compression, data)
def read_image_data(fp, header): """ Reads merged image pixel data which is stored at the end of PSD file. """ w, h = header.width, header.height bytes_per_pixel = header.depth // 8 compress_type = read_fmt("H", fp)[0] logger.debug('reading composite image data...') logger.debug(' start_pos=%s, compress_type=%s', fp.tell() - 2, Compression.name_of(compress_type)) if compress_type == Compression.RAW: data_size = w * h * bytes_per_pixel logger.debug(' data size = %sx%sx%s=%s bytes', w, h, bytes_per_pixel, data_size) elif compress_type == Compression.PACK_BITS: channel_byte_counts = [] for _ in range(header.number_of_channels): channel_byte_counts.append(read_be_array("H", h, fp)) # are there any ZIP-encoded composite images in a wild? elif compress_type in (Compression.ZIP, Compression.ZIP_WITH_PREDICTION): warnings.warn( "%s compression of composite image is not supported." % Compression.name_of(compress_type) ) return [] else: warnings.warn("Bad compression type %s" % compress_type) return [] channel_data = [] for channel_id in range(header.number_of_channels): if compress_type == Compression.PACK_BITS: byte_counts = channel_byte_counts[channel_id] data_size = sum(byte_counts) logger.debug(' data size = %s bytes', data_size) data = fp.read(data_size) channel_data.append(ChannelData(compress_type, data)) return channel_data
def _channels_data_to_PIL(channels_data, channel_types, size, depth, icc_profile): if Image is None: raise Exception("This module requires PIL (or Pillow) installed.") if size == (0, 0): return bands = {} for channel, channel_type in zip(channels_data, channel_types): pil_band = channel_id_to_PIL(channel_type) if pil_band is None: warnings.warn("Unsupported channel type (%d)" % channel_type) continue if channel.compression in [Compression.RAW, Compression.ZIP, Compression.ZIP_WITH_PREDICTION]: if depth == 8: im = _from_8bit_raw(channel.data, size) elif depth == 16: im = _from_16bit_raw(channel.data, size) elif depth == 32: im = _from_32bit_raw(channel.data, size) else: warnings.warn("Unsupported depth (%s)" % depth) continue elif channel.compression == Compression.PACK_BITS: if depth != 8: warnings.warn("Depth %s is unsupported for PackBits compression" % depth) continue im = frombytes('L', size, channel.data, "packbits", 'L') else: if Compression.is_known(channel.compression): warnings.warn("Compression method is not implemented (%s)" % channel.compression) else: warnings.warn("Unknown compression method (%s)" % channel.compression) continue bands[pil_band] = im.convert('L') mode = _get_mode(bands.keys()) merged_image = Image.merge(mode, [bands[band] for band in mode]) if mode == 'CMYK': # invert CMYK data merged_image = frombytes('CMYK', size, merged_image.tobytes(), 'raw', 'CMYK;I') # convert with inner profile, better brightness merged_image = merged_image.convert('RGB') elif icc_profile is not None: display_profile = ImageCms.createProfile('sRGB') # XXX: ImageCms.get_display_profile()? ImageCms.profileToProfile(merged_image, icc_profile, display_profile, inPlace=True) return merged_image
def read(cls, fp): """Read the element from a file-like object. :param fp: file-like object :rtype: :py:class:`.ImageData` """ start_pos = fp.tell() compression = Compression(read_fmt('H', fp)[0]) data = fp.read() # TODO: Parse data here. Need header. logger.debug(' read image data, len=%d' % (fp.tell() - start_pos)) return cls(compression, data)
def _channels_data_to_PIL(channels_data, channel_types, size, depth, icc_profile): if Image is None: raise Exception("This module requires PIL (or Pillow) installed.") if size == (0, 0): return bands = {} for channel, channel_type in zip(channels_data, channel_types): pil_band = channel_id_to_PIL(channel_type) if pil_band is None: warnings.warn("Unsupported channel type (%d)" % channel_type) continue if channel.compression in [Compression.RAW, Compression.ZIP, Compression.ZIP_WITH_PREDICTION]: if depth == 8: im = _from_8bit_raw(channel.data, size) elif depth == 16: im = _from_16bit_raw(channel.data, size) elif depth == 32: im = _from_32bit_raw(channel.data, size) else: warnings.warn("Unsupported depth (%s)" % depth) continue elif channel.compression == Compression.PACK_BITS: if depth != 8: warnings.warn("Depth %s is unsupported for PackBits compression" % depth) continue im = frombytes('L', size, channel.data, "packbits", 'L') else: if Compression.is_known(channel.compression): warnings.warn("Compression method is not implemented (%s)" % channel.compression) else: warnings.warn("Unknown compression method (%s)" % channel.compression) continue bands[pil_band] = im.convert('L') mode = _get_mode(bands.keys()) merged_image = Image.merge(mode, [bands[band] for band in mode]) if icc_profile is not None: display_profile = ImageCms.createProfile('sRGB') # XXX: ImageCms.get_display_profile()? ImageCms.profileToProfile(merged_image, icc_profile, display_profile, inPlace=True) return merged_image
def _decompress_pattern_channel(channel): depth = channel.depth size = (channel.rectangle[3], channel.rectangle[2]) if channel.compression in (Compression.RAW, Compression.ZIP, Compression.ZIP_WITH_PREDICTION): if depth == 8: im = _from_8bit_raw(channel.data.value, size) elif depth == 16: im = _from_16bit_raw(channel.data.value, size) elif depth == 32: im = _from_32bit_raw(channel.data.value, size) else: warnings.warn("Unsupported depth (%s)" % depth) return None elif channel.compression == Compression.PACK_BITS: if depth != 8: warnings.warn( "Depth %s is unsupported for PackBits compression" % depth) try: import packbits channel_data = packbits.decode(channel.data.value) except ImportError as e: warnings.warn("Install packbits (%s)" % e) channel_data = b'\x00' * (size[0] * size[1]) # Default fill except IndexError as e: warnings.warn("Failed to decode pattern (%s)" % e) channel_data = b'\x00' * (size[0] * size[1]) # Default fill # Packbit pattern tends not to have the correct size ??? padding = len(channel_data) - size[0] * size[1] if padding < 0: warnings.warn('Broken pattern data (%g for %g)' % ( len(channel_data), size[0] * size[1])) channel_data += b'\x00' * -padding # Append default fill padding = 0 im = frombytes('L', size, channel_data[padding:], "raw", 'L') else: if Compression.is_known(channel.compression): warnings.warn( "Compression method is not implemented " "(%s)" % channel.compression) else: warnings.warn( "Unknown compression method (%s)" % channel.compression) return None return im.convert('L')
def read(cls, fp): start_pos = fp.tell() compression = Compression(read_fmt('H', fp)[0]) data = fp.read() # TODO: Parse data here. Need header. logger.debug(' read image data, len=%d' % (fp.tell() - start_pos)) return cls(compression, data)
def _get_band_images(layer, channel_data, channel_ids, color_mode, size, depth): bands = {} for channel, channel_id in zip(channel_data, channel_ids): im = None mask_im = None mask_size = None pil_band = _channel_id_to_PIL(channel_id, color_mode) if pil_band is None: warnings.warn("Unsupported channel type (%d)" % channel_id) continue if channel.compression in [ Compression.RAW, Compression.ZIP, Compression.ZIP_WITH_PREDICTION ]: if pil_band == 'M': mask_size = (channel.mask_data.width(), channel.mask_data.height()) if mask_size[0] == 0 or mask_size[1] == 0: # warnings.warn("Empty layer mask found on layer '%s', ignoring it." % layer.name) continue try: mask_im = _from_8bit_raw(channel.data, mask_size) except Exception as e: warnings.warn("Failed parsing layer mask! " + str(e)) continue elif depth == 8: im = _from_8bit_raw(channel.data, size) elif depth == 16: im = _from_16bit_raw(channel.data, size) elif depth == 32: im = _from_32bit_raw(channel.data, size) else: warnings.warn("Unsupported depth (%s)" % depth) continue elif channel.compression == Compression.PACK_BITS: if depth != 8: warnings.warn( "Depth %s is unsupported for PackBits compression" % depth) continue if pil_band == 'M': mask_size = (channel.mask_data.width(), channel.mask_data.height()) if mask_size[0] == 0 or mask_size[1] == 0: # warnings.warn("Empty layer mask found on layer '%s', ignoring it." % layer.name) continue try: mask_im = frombytes('L', mask_size, channel.data, "packbits", 'L') except Exception as e: warnings.warn("Failed parsing layer mask! " + str(e)) continue else: im = frombytes('L', size, channel.data, "packbits", 'L') else: if Compression.is_known(channel.compression): warnings.warn("Compression method is not implemented (%s)" % channel.compression) else: warnings.warn("Unknown compression method (%s)" % channel.compression) continue if pil_band == 'M': if layer_mask_callback(layer) == False: continue im = Image.new('L', size, 255) offset = (channel.mask_data.left - layer.left, channel.mask_data.top - layer.top) im.paste(mask_im, offset) bands[pil_band] = im.convert('L') return bands
def __repr__(self): return "ChannelData(compression=%r %s, len(data)=%r)" % ( self.compression, Compression.name_of(self.compression), len(self.data) if self.data is not None else None )
def read(cls, fp, length=0, **kwargs): compression = Compression(read_fmt('H', fp)[0]) data = fp.read(length) return cls(compression, data)
def read(cls, fp): compression = Compression(read_fmt('H', fp)[0]) data = fp.read() return cls(compression, data)
def _read_channel_image_data(fp, layer, depth): """ Reads image data for all channels in a layer. """ bytes_per_pixel = depth // 8 channel_data = [] for channel in layer.channels: logger.debug(" reading %s", channel) if channel.id == ChannelID.USER_LAYER_MASK: w, h = layer.mask_data.width(), layer.mask_data.height() elif channel.id == ChannelID.REAL_USER_LAYER_MASK: w, h = layer.mask_data.real_width(), layer.mask_data.real_height() else: w, h = layer.width(), layer.height() start_pos = fp.tell() compress_type = read_fmt("H", fp)[0] logger.debug(" start_pos=%s, compress_type=%s", start_pos, Compression.name_of(compress_type)) # read or calculate data size if compress_type == Compression.RAW: data_size = w * h * bytes_per_pixel logger.debug(' data size = %sx%sx%s=%s bytes', w, h, bytes_per_pixel, data_size) elif compress_type == Compression.PACK_BITS: byte_counts = read_be_array("H", h, fp) data_size = sum(byte_counts) logger.debug(' data size = %s bytes', data_size) elif compress_type in (Compression.ZIP, Compression.ZIP_WITH_PREDICTION): data_size = channel.length - 2 logger.debug(' data size = %s-2=%s bytes', channel.length, data_size) else: warnings.warn("Bad compression type %s" % compress_type) return [] # read the data itself if data_size > channel.length: warnings.warn("Incorrect data size: %s > %s" % (data_size, channel.length)) else: data = fp.read(data_size) if compress_type == Compression.ZIP: data = zlib.decompress(data) elif compress_type == Compression.ZIP_WITH_PREDICTION: data = zlib.decompress(data) data = compression.decode_prediction(data, w, h, bytes_per_pixel) if data is None: warnings.warn("Prediction decode failed!") return [] channel_data.append(ChannelData(compress_type, data)) remaining_length = channel.length - (fp.tell() - start_pos) if remaining_length > 0: fp.seek(remaining_length, 1) logger.debug(' skipping %s bytes', remaining_length) return channel_data
def _read_channel_image_data(fp, layer, depth): """ Reads image data for all channels in a layer. """ channel_data = [] bytes_per_pixel = depth // 8 for idx, channel in enumerate(layer.channels): logger.debug(" reading %s", channel) if channel.id == ChannelID.USER_LAYER_MASK: w, h = layer.mask_data.width(), layer.mask_data.height() else: w, h = layer.width(), layer.height() start_pos = fp.tell() compress_type = read_fmt("H", fp)[0] logger.debug(" start_pos=%s, compress_type=%s", start_pos, Compression.name_of(compress_type)) data = None # read data size if compress_type == Compression.RAW: data_size = w * h * bytes_per_pixel logger.debug(' data size = %sx%sx%s=%s bytes', w, h, bytes_per_pixel, data_size) elif compress_type == Compression.PACK_BITS: byte_counts = read_be_array("H", h, fp) sum_counts = sum(byte_counts) data_size = sum_counts * bytes_per_pixel logger.debug(' data size = %sx%s=%s bytes', sum_counts, bytes_per_pixel, data_size) elif compress_type == Compression.ZIP: data_size = channel.length - 2 logger.debug(' data size = %s-2=%s bytes', channel.length, data_size) elif compress_type == Compression.ZIP_WITH_PREDICTION: data_size = channel.length - 2 logger.debug(' data size = %s-2=%s bytes', channel.length, data_size) else: warnings.warn("Bad compression type %s" % compress_type) return [] # read the data itself if data_size > channel.length: warnings.warn("Incorrect data size: %s > %s" % (data_size, channel.length)) else: raw_data = fp.read(data_size) if compress_type in (Compression.RAW, Compression.PACK_BITS): data = raw_data elif compress_type == Compression.ZIP: data = zlib.decompress(raw_data) elif compress_type == Compression.ZIP_WITH_PREDICTION: decompressed = zlib.decompress(raw_data) data = compression.decode_prediction(decompressed, w, h, bytes_per_pixel) if data is None: return [] channel_data.append(ChannelData(compress_type, data)) remaining_bytes = channel.length - (fp.tell() - start_pos) - 2 if remaining_bytes > 0: fp.seek(remaining_bytes, 1) logger.debug(' skipping %s bytes', remaining_bytes) return channel_data
def __repr__(self): return "ChannelData(compression=%r %s, len(data)=%r)" % ( self.compression, Compression.name_of(self.compression), len(self.data) if self.data is not None else None)
def _read_channel_image_data(fp, layer, depth): """ Reads image data for all channels in a layer. """ channel_data = [] bytes_per_pixel = depth // 8 for idx, channel in enumerate(layer.channels): logger.debug(" reading %s", channel) if channel.id == ChannelID.USER_LAYER_MASK: w, h = layer.mask_data.width(), layer.mask_data.height() elif channel.id == ChannelID.REAL_USER_LAYER_MASK: w, h = layer.mask_data.real_width(), layer.mask_data.real_height() else: w, h = layer.width(), layer.height() start_pos = fp.tell() compress_type = read_fmt("H", fp)[0] logger.debug(" start_pos=%s, compress_type=%s", start_pos, Compression.name_of(compress_type)) data = None # read data size if compress_type == Compression.RAW: data_size = w * h * bytes_per_pixel logger.debug(' data size = %sx%sx%s=%s bytes', w, h, bytes_per_pixel, data_size) elif compress_type == Compression.PACK_BITS: byte_counts = read_be_array("H", h, fp) data_size = sum(byte_counts) logger.debug(' data size = %s bytes', data_size) elif compress_type in (Compression.ZIP, Compression.ZIP_WITH_PREDICTION): data_size = channel.length - 2 logger.debug(' data size = %s-2=%s bytes', channel.length, data_size) else: warnings.warn("Bad compression type %s" % compress_type) return [] # read the data itself if data_size > channel.length: warnings.warn("Incorrect data size: %s > %s" % (data_size, channel.length)) else: raw_data = fp.read(data_size) if compress_type in (Compression.RAW, Compression.PACK_BITS): data = raw_data elif compress_type == Compression.ZIP: data = zlib.decompress(raw_data) elif compress_type == Compression.ZIP_WITH_PREDICTION: decompressed = zlib.decompress(raw_data) data = compression.decode_prediction(decompressed, w, h, bytes_per_pixel) if data is None: return [] channel_data.append(ChannelData(compress_type, data)) remaining_length = channel.length - (fp.tell() - start_pos) if remaining_length > 0: fp.seek(remaining_length, 1) logger.debug(' skipping %s bytes', remaining_length) return channel_data