예제 #1
0
def decode(effects):
    """
    Reads and decodes info about layer effects.
    """
    fp = io.BytesIO(effects)

    version, effects_count = read_fmt("HH", fp)

    effects_list = []
    for idx in range(effects_count):
        sig = fp.read(4)
        if sig != b'8BIM':
            raise Error("Error parsing layer effect: invalid signature (%r)" %
                        sig)

        effect_type = fp.read(4)
        if not EffectOSType.is_known(effect_type):
            warnings.warn("Unknown effect type (%s)" % effect_type)

        effect_info_length = read_fmt("I", fp)[0]
        effect_info = fp.read(effect_info_length)

        decoder = _effect_info_decoders.get(effect_type, lambda data: data)
        effects_list.append(LayerEffect(effect_type, decoder(effect_info)))

    return Effects(version, effects_count, effects_list)
예제 #2
0
def _read_layer_record(fp, encoding, version):
    """
    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):
        if version == 1:
            info = ChannelInfo(*read_fmt("hI", fp))
        elif version == 2:
            info = ChannelInfo(*read_fmt("hQ", 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, version)

    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)
예제 #3
0
def _read_blend_mode(fp):
    sig = fp.read(4)
    if sig != b'8BIM':
        raise Error("Error parsing layer effect: invalid signature (%r)" % sig)

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

    return blend_mode
예제 #4
0
def read(fp):
    """
    Reads PSD file header.
    """
    logger.debug("reading header..")
    signature = fp.read(4)
    if signature != b'8BPS':
        raise Error("This is not a PSD or PSB file")

    version = read_fmt("H", fp)[0]
    if not version in (1, 2):
        raise Error("Unsupported PSD version (%s)" % version)

    header = PsdHeader(version, *read_fmt("6x HIIHH", fp))

    if not ColorMode.is_known(header.color_mode):
        warnings.warn("Unknown color mode: %s" % header.color_mode)

    logger.debug(header)
    return header
예제 #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 sig not 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)
    data = fp.read(data_size)

    return ImageResource(resource_id, name, data)
예제 #6
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
    )