Example #1
0
def _read_layer_record(fp, encoding):
    """
    Reads single layer record.
    """
    top, left, bottom, right, num_channels = read_fmt("4i H", fp)
    logger.debug('  top=%d, left=%d, bottom=%d, right=%d, num_channels=%d',
                 top, left, bottom, right, num_channels)

    channel_info = []
    for channel_num in range(num_channels):
        info = ChannelInfo(*read_fmt("hI", fp))
        channel_info.append(info)

    sig = fp.read(4)
    if sig != b'8BIM':
        raise Error("Error parsing layer: invalid signature (%r)" % sig)

    blend_mode = fp.read(4)
    if not BlendMode.is_known(blend_mode):
        warnings.warn("Unknown blend mode (%s)" % blend_mode)

    opacity, clipping, flags, extra_length = read_fmt("BBBxI", fp)

    if not Clipping.is_known(clipping):
        warnings.warn("Unknown clipping (%s)" % clipping)
    logger.debug('  extra_length=%s', extra_length)

    flags = LayerFlags(
        bool(flags & 1), not bool(flags & 2),           # why "not"?
        bool(flags & 16) if bool(flags & 8) else None
    )

    start_pos = fp.tell()
    mask_data = _read_layer_mask_data(fp)
    blending_ranges = _read_layer_blending_ranges(fp)

    name = read_pascal_string(fp, encoding, 4)

    remaining_length = extra_length - (fp.tell() - start_pos)

    logger.debug('  reading layer tagged blocks...')
    logger.debug('    length=%d, start_pos=%d', remaining_length, fp.tell())

    tagged_blocks = _read_layer_tagged_blocks(fp, remaining_length)

    remaining_length = extra_length - (fp.tell() - start_pos)
    if remaining_length > 0:
        fp.seek(remaining_length, 1) # skip the remainder
        logger.debug('  skipping %s bytes', remaining_length)

    return LayerRecord(
        top, left, bottom, right,
        num_channels, channel_info,
        blend_mode, opacity, clipping, flags,
        mask_data, blending_ranges, name,
        tagged_blocks
    )
Example #2
0
def decode(data):
    """
    Reads and decodes info about linked layers.

    These are embedded files (embedded smart objects). But Adobe calls
    them "linked layers", so we'll follow that nomenclature. Note that
    non-embedded smart objects are not included here.
    """
    fp = io.BytesIO(data)
    layers = []
    while True:
        start = fp.tell()
        length_buf = fp.read(8)
        if not length_buf:
            break   # end of file
        length = struct.unpack(str('>Q'), length_buf)[0]
        liFD, version = read_fmt('4s I', fp)
        if liFD != b'liFD':
            warnings.warn('unknown layer type')
            break
        unique_id = read_pascal_string(fp, 'ascii')
        filename = read_unicode_string(fp)
        filetype, creator, filelength, have_file_open_descriptor = read_fmt('4s 4s Q B', fp)
        filetype = str(filetype)
        if have_file_open_descriptor:
            # Does not seem to contain any useful information
            undocumented_integer = read_fmt("I", fp)
            file_open_descriptor = decode_descriptor(None, fp)
        else:
            file_open_descriptor = None
        decoded = fp.read(filelength)
        # Undocumented extra field
        if version == 5:
            uuid = read_unicode_string(fp)
        else:
            uuid = None
        layers.append(
            LinkedLayer(version, unique_id, filename, filetype, file_open_descriptor,
                        creator, decoded, uuid)
        )
        # Gobble up anything that we don't know how to decode
        expected_position = start + 8 + length      # first 8 bytes contained the length
        if expected_position != fp.tell():
            warnings.warn('skipping over undocumented additional fields')
            fp.read(expected_position - fp.tell())
        # Each layer is padded to start and end at 4-byte boundary
        pad = -fp.tell() % 4
        fp.read(pad)
    return LinkedLayerCollection(layers)
Example #3
0
def _read_block(fp, encoding):
    """
    Reads single image resource block. Such blocks contain non-pixel data
    for the images (e.g. pen tool paths).
    """
    sig = fp.read(4)
    if sig != b"8BIM":
        raise Error("Invalid resource signature (%r)" % sig)

    resource_id = read_fmt("H", fp)[0]
    name = read_pascal_string(fp, encoding, 2)

    data_size = pad(read_fmt("I", fp)[0], 2)
    data = fp.read(data_size)

    return ImageResource(resource_id, name, data)
Example #4
0
def _read_layer_record(fp, encoding):
    """
    Reads single layer record.
    """
    top, left, bottom, right, num_channels = read_fmt("4i H", fp)

    channel_info = []
    for channel_num in range(num_channels):
        info = ChannelInfo(*read_fmt("hI", fp))
        channel_info.append(info)

    sig = fp.read(4)
    if sig != b'8BIM':
        raise Error("Error parsing layer: invalid signature (%r)" % sig)

    blend_mode = fp.read(4).decode('ascii')
    if not BlendMode.is_known(blend_mode):
        warnings.warn("Unknown blend mode (%s)" % blend_mode)

    opacity, clipping, flags, extra_length = read_fmt("BBBxI", fp)

    flags = LayerFlags(bool(flags & 1), not bool(flags & 2)) # why not?

    if not Clipping.is_known(clipping):
        warnings.warn("Unknown clipping: %s" % clipping)

    start = fp.tell()
    mask_data = _read_layer_mask_data(fp)
    blending_ranges = _read_layer_blending_ranges(fp)

    name = read_pascal_string(fp, encoding, 4)

    remaining_length = extra_length - (fp.tell()-start)
    tagged_blocks = _read_layer_tagged_blocks(fp, remaining_length)

    remaining_length = extra_length - (fp.tell()-start)
    fp.seek(remaining_length, 1) # skip the reminder

    return LayerRecord(
        top, left, bottom, right,
        num_channels, channel_info,
        blend_mode, opacity, clipping, flags,
        mask_data, blending_ranges, name,
        tagged_blocks
    )
Example #5
0
def _read_block(fp, encoding):
    """
    Reads single image resource block. Such blocks contain non-pixel data
    for the images (e.g. pen tool paths).
    """
    sig = fp.read(4)
    if not sig in (b'8BIM', b'MeSa'):
        raise Error("Invalid resource signature (%r)" % sig)

    resource_id = read_fmt("H", fp)[0]
    name = read_pascal_string(fp, encoding, 2)

    data_size = pad(read_fmt("I", fp)[0], 2)
    if not data_size:
        logger.debug(
            "Found image resource with no data (%d %s). Dropping..." % (
            resource_id, ImageResourceID.name_of(resource_id)
        ))
        return None

    data = fp.read(data_size)
    return ImageResource(resource_id, name, data)
Example #6
0
def _decode_caption_pascal(data):
    fp = io.BytesIO(data)
    return read_pascal_string(fp, 'ascii')
 def read(cls, fp, **kwargs):
     return cls(read_pascal_string(fp, 'macroman'))
 def read(cls, fp, **kwargs):
     items = []
     while is_readable(fp):
         items.append(read_pascal_string(fp, 'macroman', padding=1))
     return cls(items)
Example #9
0
 def _read_extra(cls, fp, encoding, version):
     mask_data = MaskData.read(fp)
     blending_ranges = LayerBlendingRanges.read(fp)
     name = read_pascal_string(fp, encoding, padding=4)
     tagged_blocks = TaggedBlocks.read(fp, version=version, padding=1)
     return mask_data, blending_ranges, name, tagged_blocks
Example #10
0
def _decode_caption_pascal(data):
    fp = io.BytesIO(data)
    return read_pascal_string(fp, 'ascii')
Example #11
0
def _decode_clipping_path_name(data):
    fp = io.BytesIO(data)  # TODO: flatness and fill rule decoding?
    return read_pascal_string(fp, 'ascii')
Example #12
0
def pascal_string(data):
    return read_pascal_string(io.BytesIO(data))