Files
core/DesktopEditor/cximage/libpsd/layer_mask.c
Elen.Subbotina e89cf2f58f .....
git-svn-id: svn://fileserver/activex/AVS/Sources/TeamlabOffice/trunk/ServerComponents@61945 954022d7-b5bf-4e40-9824-e11837661b57
2016-05-20 23:54:34 +03:00

918 lines
32 KiB
C
Raw Permalink Blame History

/**
* libpsd - Photoshop file formats (*.psd) decode library
* Copyright (C) 2004-2007 Graphest Software.
*
* libpsd is the legal property of its developers, whose names are too numerous
* to list here. Please refer to the COPYRIGHT file distributed with this
* source distribution.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* $Id: layer_mask.c, created by Patrick in 2006.05.19, libpsd@graphest.com Exp $
*/
#include "libpsd.h"
#include "psd_system.h"
#include "psd_stream.h"
#include "psd_color.h"
extern psd_status psd_get_layer_levels(psd_context * context, psd_layer_record * layer, psd_int data_length);
extern void psd_layer_levels_free(psd_uint info_data);
extern psd_status psd_get_layer_curves(psd_context * context, psd_layer_record * layer, psd_int data_length);
extern void psd_layer_curves_free(psd_uint info_data);
extern psd_status psd_get_layer_brightness_contrast(psd_context * context, psd_layer_record * layer);
extern psd_status psd_get_layer_color_balance(psd_context * context, psd_layer_record * layer);
extern psd_status psd_get_layer_hue_saturation(psd_context * context, psd_layer_record * layer);
extern psd_status psd_get_layer_selective_color(psd_context * context, psd_layer_record * layer);
extern psd_status psd_get_layer_threshold(psd_context * context, psd_layer_record * layer);
extern psd_status psd_get_layer_invert(psd_context * context, psd_layer_record * layer);
extern psd_status psd_get_layer_posterize(psd_context * context, psd_layer_record * layer);
extern psd_status psd_get_layer_channel_mixer(psd_context * context, psd_layer_record * layer);
extern psd_status psd_get_layer_photo_filter(psd_context * context, psd_layer_record * layer);
extern psd_status psd_get_layer_gradient_map(psd_context * context, psd_layer_record * layer);
extern void psd_layer_gradient_map_free(psd_uint info_data);
extern psd_status psd_get_layer_effects(psd_context * context, psd_layer_record * layer);
extern psd_status psd_get_layer_effects2(psd_context * context, psd_layer_record * layer);
extern psd_status psd_get_layer_solid_color(psd_context * context, psd_layer_record * layer);
extern psd_status psd_get_layer_gradient_fill(psd_context * context, psd_layer_record * layer);
extern psd_status psd_get_layer_pattern_fill(psd_context * context, psd_layer_record * layer);
extern psd_status psd_get_layer_channel_image_data(psd_context * context, psd_layer_record * layer);
extern psd_status psd_get_layer_type_tool(psd_context * context, psd_layer_record * layer);
extern psd_status psd_get_pattern(psd_context * context);
extern psd_status psd_get_layer_vector_mask(psd_context * context, psd_layer_record * layer, psd_int size);
extern void psd_layer_type_tool_free(psd_uint info_data);
extern void psd_layer_vector_mask_free(psd_layer_record * layer);
extern void psd_layer_effects_free(psd_uint layer_info);
extern void psd_pattern_free(psd_context * context);
psd_static void psd_layer_free(psd_layer_record * layer);
// Layer name source setting (Photoshop 6.0)
psd_static psd_status psd_get_layer_name_id(psd_context * context, psd_layer_record * layer)
{
// ID for the layer name
layer->layer_name_id = psd_stream_get_int(context);
return psd_status_done;
}
// Unicode layer name (Photoshop 5.0)
psd_static psd_status psd_get_layer_unicode_name(psd_context * context, psd_layer_record * layer)
{
// Unicode string (4 bytes length + string).
layer->unicode_name_length = psd_stream_get_int(context);
layer->unicode_name = (psd_ushort *)psd_malloc(2 * layer->unicode_name_length);
if(layer->unicode_name == NULL)
return psd_status_malloc_failed;
memset(layer->unicode_name, 0, 2 * layer->unicode_name_length);
psd_stream_get(context, (psd_uchar *)layer->unicode_name, 2 * layer->unicode_name_length);
return psd_status_done;
}
// Layer ID (Photoshop 5.0)
psd_static psd_status psd_get_layer_id(psd_context * context, psd_layer_record * layer)
{
// ID
layer->layer_id = psd_stream_get_int(context);
return psd_status_done;
}
// Blend clipping elements (Photoshop 6.0)
psd_static psd_status psd_get_layer_blend_clipped(psd_context * context, psd_layer_record * layer)
{
// Blend clipped elements: boolean
layer->blend_clipped = psd_stream_get_bool(context);
// padding
psd_stream_get_null(context, 3);
return psd_status_done;
}
// Blend interior elements (Photoshop 6.0)
psd_static psd_status psd_get_layer_blend_interior(psd_context * context, psd_layer_record * layer)
{
// Blend interior elements: boolean
layer->blend_interior = psd_stream_get_bool(context);
// padding
psd_stream_get_null(context, 3);
return psd_status_done;
}
// Knockout setting (Photoshop 6.0)
psd_static psd_status psd_get_layer_knockout(psd_context * context, psd_layer_record * layer)
{
// Knockout: boolean
layer->knockout = psd_stream_get_bool(context);
// padding
psd_stream_get_null(context, 3);
return psd_status_done;
}
// Protected setting (Photoshop 6.0)
psd_static psd_status psd_get_layer_protected(psd_context * context, psd_layer_record * layer)
{
psd_uint tag;
// Protection flags: bits 0 - 2 are used for Photoshop 6.0. Transparency,
// composite and position respectively.
tag = psd_stream_get_int(context);
layer->transparency = tag & 0x01;
layer->composite = (tag & (0x01 << 1)) > 0;
layer->position_respectively = (tag & (0x01 << 2)) > 0;
return psd_status_done;
}
// Sheet color setting (Photoshop 6.0)
psd_static psd_status psd_get_layer_sheet_color(psd_context * context, psd_layer_record * layer)
{
psd_int i;
psd_ushort color_component[4];
// Color. Only the first color setting is used for Photoshop 6.0;
for(i = 0; i < 4; i ++)
color_component[i] = psd_stream_get_char(context);
psd_color_space_to_argb(&layer->sheet_color, psd_color_space_rgb, color_component);
// the rest are zeros
psd_stream_get_null(context, 4);
return psd_status_done;
}
// Reference point (Photoshop 6.0)
psd_static psd_status psd_get_layer_reference_point(psd_context * context, psd_layer_record * layer)
{
// 2 double values for the reference point
layer->reference_point_x = (psd_int)psd_stream_get_double(context);
layer->reference_point_y = (psd_int)psd_stream_get_double(context);
return psd_status_done;
}
// Layer version (Photoshop 7.0)
psd_static psd_status psd_get_layer_version(psd_context * context, psd_layer_record * layer)
{
// A 32-bit number representing the version of Photoshop needed to read
// and interpret the layer without data loss. 70 = 7.0, 80 = 8.0, etc.
// NOTE: The minimum value is 70, because just having the field present in
// 6.0 triggers a warning. For the future, Photoshop 7 checks to see
// whether this number is larger than the current version -- i.e., 70 --
// and if so, warns that it is ignoring some data.
layer->layer_version = psd_stream_get_int(context);
return psd_status_done;
}
// Transparency shapes layer (Photoshop 7.0)
psd_static psd_status psd_get_layer_transparency_shapes_layer(psd_context * context, psd_layer_record * layer)
{
// 1: the transparency of the layer is used in determining the shape of the
// effects. This is the default for behavior like previous versions.
// 0: treated in the same way as fill opacity including modulating blend
// modes, rather than acting as strict transparency.
// Using this feature is useful for achieving effects that otherwise would
// require complex use of clipping groups.
layer->transparency_shapes_layer = psd_stream_get_bool(context);
// Padding
psd_stream_get_null(context, 3);
return psd_status_done;
}
// Layer mask as global mask (Photoshop 7.0)
psd_static psd_status psd_get_layer_layer_mask_hides_effects(psd_context * context, psd_layer_record * layer)
{
// 1: the layer mask is used in a final crossfade masking the layer and
// effects rather than being used to shape the layer and its effects.
// This behavior was previously tied to the link status flag for the layer mask.
// (An unlinked mask acted like a flag value of 1, a linked mask like 0). For
// old files that lack this key, the link status is used in order to preserve
// compositing results.
layer->layer_mask_hides_effects = psd_stream_get_bool(context);
// Padding
psd_stream_get_null(context, 3);
return psd_status_done;
}
// Vector mask as global mask (Photoshop 7.0)
psd_static psd_status psd_get_layer_vector_mask_hides_effects(psd_context * context, psd_layer_record * layer)
{
// 1: the vector mask is used in a final crossfade masking the vector and
// effects rather than being used to shape the vector and its effects.
// This behavior was previously tied to the link status flag for the vector mask.
// (An unlinked mask acted like a flag value of 1, a linked mask like 0). For
// old files that lack this key, the link status is used in order to preserve
// compositing results.
layer->vector_mask_hides_effects = psd_stream_get_bool(context);
// Padding
psd_stream_get_null(context, 3);
return psd_status_done;
}
// fill opacity
psd_static psd_status psd_get_layer_fill_opacity(psd_context * context, psd_layer_record * layer)
{
layer->fill_opacity = psd_stream_get_char(context);
// Padding
psd_stream_get_null(context, 3);
return psd_status_done;
}
// Section divider setting (Photoshop 6.0)
psd_static psd_status psd_get_layer_section_divider(psd_context * context, psd_layer_record * layer, psd_int size)
{
// Type. 4 possible values, 0 = any other type of layer, 1 = open <20><>folder<65><72>, 2 =
// closed <20><>folder<65><72>, 3 = bounding section divider, hidden in the UI
layer->divider_type = psd_stream_get_int(context);
switch(layer->divider_type)
{
case 1:
case 2:
layer->layer_type = psd_layer_type_folder;
break;
case 3:
layer->layer_type = psd_layer_type_hidden;
break;
}
// Following is only present if length = 12
if(size == 12)
{
// Signature: '8BIM'
if(psd_stream_get_int(context) != '8BIM')
return psd_status_divider_signature_error;
// blend mode
layer->divider_blend_mode = psd_stream_get_blend_mode(context);
}
return psd_status_done;
}
// Channel blending restrictions setting (Photoshop 6.0)
psd_static psd_status psd_get_layer_channel_blending_restrictions(psd_context * context, psd_layer_record * layer, psd_int size)
{
psd_int i, j, channel_number;
// Following is repeated length / 4 times.
for(i = 0; i < size / 4; i ++)
{
// Channel number that is restricted
channel_number = psd_stream_get_int(context);
for(j = 0; j < layer->number_of_channels; j ++)
{
if(layer->channel_info[j].channel_id == channel_number)
{
layer->channel_info[j].restricted = psd_true;
break;
}
}
}
return psd_status_done;
}
// shows the high-level organization of the layer information.
psd_static psd_status psd_get_layer_info(psd_context * context)
{
psd_int length, extra_length, i, j, size;
psd_int prev_stream_pos, prev_layer_stream_pos, extra_stream_pos;
psd_bool skip_first_alpha = psd_false;
psd_layer_record * layer, * group_layer;
psd_uchar flags;
psd_uint tag;
psd_status status = psd_status_done;
// Length of the layers info section. (**PSB** length is 8 bytes.)
length = psd_stream_get_int(context);
// rounded up to a multiple of 2
if(length & 0x01)
length ++;
if(length <= 0)
return psd_status_done;
prev_layer_stream_pos = context->stream.current_pos;
// Layer count.
context->layer_count = psd_stream_get_short(context);
// If it is a negative number, its absolute value is the number of
// layers and the first alpha channel contains the transparency data for the
// merged result.
if(context->layer_count < 0)
{
skip_first_alpha = psd_true;
context->layer_count = -context->layer_count;
}
psd_assert(context->layer_count > 0);
context->layer_records = (psd_layer_record *)psd_malloc(context->layer_count * sizeof(psd_layer_record));
if(context->layer_records == NULL)
return psd_status_malloc_failed;
memset(context->layer_records, 0, context->layer_count * sizeof(psd_layer_record));
for(i = 0, layer = context->layer_records; i < context->layer_count; i ++, layer ++)
{
// INFORMATION ABOUT EACH LAYER
// value as default
layer->layer_type = psd_layer_type_normal;
layer->blend_mode = psd_blend_mode_normal;
layer->opacity = 255;
layer->fill_opacity = 255;
layer->blend_clipped = psd_true;
layer->blend_interior = psd_false;
layer->knockout = 0;
layer->transparency_shapes_layer = psd_true;
layer->layer_mask_hides_effects = psd_false;
layer->vector_mask_hides_effects = psd_false;
layer->divider_blend_mode = psd_blend_mode_pass_through;
layer->layer_mask_info.default_color = 255;
layer->layer_mask_info.disabled = psd_true;
// Rectangle containing the contents of the layer. Specified as top, left,
// bottom, right coordinates
layer->top = psd_stream_get_int(context);
layer->left = psd_stream_get_int(context);
layer->bottom = psd_stream_get_int(context);
layer->right = psd_stream_get_int(context);
layer->width = layer->right - layer->left;
layer->height = layer->bottom - layer->top;
// the size of layer size is 0.
//psd_assert(layer->width > 0 && layer->height > 0);
// Number of channels in the layer
layer->number_of_channels = psd_stream_get_short(context);
psd_assert(layer->number_of_channels > 0);
layer->channel_info = (psd_channel_info *)psd_malloc(layer->number_of_channels * sizeof(psd_channel_info));
if(layer->channel_info == NULL)
{
psd_layer_free(layer);
return psd_status_malloc_failed;
}
// Channel information. Six bytes per channel, consisting of:
// 2 bytes for Channel ID: 0 = red, 1 = green, etc.;
// <20>C1 = transparency mask; <20>C2 = user supplied layer mask
// 4 bytes for length of corresponding channel data. (**PSB** 8 bytes for
// length of corresponding channel data.)
for(j = 0; j < layer->number_of_channels; j ++)
{
layer->channel_info[j].channel_id = psd_stream_get_short(context);
layer->channel_info[j].data_length = psd_stream_get_int(context);
layer->channel_info[j].restricted = psd_false;
}
// Blend mode signature: '8BIM'
tag = psd_stream_get_int(context);
if(tag != '8BIM')
{
psd_layer_free(layer);
return psd_status_blend_mode_signature_error;
}
// Blend mode key
layer->blend_mode = psd_stream_get_blend_mode(context);
// Opacity. 0 = transparent ... 255 = opaque
layer->opacity = psd_stream_get_char(context);
// Clipping: 0 = base, 1 = non<6F>Cbase
layer->clipping = psd_stream_get_bool(context);
// Flags
flags = psd_stream_get_char(context);
// bit 0 = transparency protected
layer->transparency_protected = flags & 0x01;
// bit 1 = visible
layer->visible = (flags & (0x01 << 1)) > 0;
layer->visible = psd_true - layer->visible;
// bit 2 = obsolete
layer->obsolete = (flags & (0x01 << 2)) > 0;
// bit 3 = 1 for Photoshop 5.0 and later, tells if bit 4 has useful information
if((flags & (0x01 << 3)) > 0)
{
// bit 4 = pixel data irrelevant to appearance of document
layer->pixel_data_irrelevant = (flags & (0x01 << 4)) > 0;
}
// Filler (zero)
flags = psd_stream_get_char(context);
psd_assert(flags == 0);
// Length of the extra data field ( = the total length of the next five fields).
extra_length = psd_stream_get_int(context);
extra_stream_pos = context->stream.current_pos;
psd_assert(extra_length > 0);
// LAYER MASK / ADJUSTMENT LAYER DATA
// Size of the data: 36, 20, or 0. If zero, the following fields are not present
size = psd_stream_get_int(context);
psd_assert(size == 36 || size == 20 || size == 0);
if(size > 0)
{
// Rectangle enclosing layer mask: Top, left, bottom, right
layer->layer_mask_info.top = psd_stream_get_int(context);
layer->layer_mask_info.left = psd_stream_get_int(context);
layer->layer_mask_info.bottom = psd_stream_get_int(context);
layer->layer_mask_info.right = psd_stream_get_int(context);
layer->layer_mask_info.width = layer->layer_mask_info.right - layer->layer_mask_info.left;
layer->layer_mask_info.height = layer->layer_mask_info.bottom - layer->layer_mask_info.top;
// Default color. 0 or 255
layer->layer_mask_info.default_color = psd_stream_get_char(context);
psd_assert(layer->layer_mask_info.default_color == 0 ||
layer->layer_mask_info.default_color == 255);
// Flags
flags = psd_stream_get_char(context);
// bit 0 = position relative to layer
layer->layer_mask_info.relative = flags & 0x01;
// bit 1 = layer mask disabled
layer->layer_mask_info.disabled = (flags & (0x01 << 1)) > 0;
// bit 2 = invert layer mask when blending
layer->layer_mask_info.invert = (flags & (0x01 << 2)) > 0;
if(size == 20)
{
// Padding. Only present if size = 20. Otherwise the following is present
psd_stream_get_short(context);
}
else
{
// Real Flags. Same as Flags information above.
flags = psd_stream_get_char(context);
// bit 0 = position relative to layer
layer->layer_mask_info.relative = flags & 0x01;
// bit 1 = layer mask disabled
layer->layer_mask_info.disabled = (flags & (0x01 << 1)) > 0;
// bit 2 = invert layer mask when blending
layer->layer_mask_info.invert = (flags & (0x01 << 2)) > 0;
// Real user mask background. 0 or 255. Same as Flags information above.
layer->layer_mask_info.default_color = psd_stream_get_char(context);
psd_assert(layer->layer_mask_info.default_color == 0 ||
layer->layer_mask_info.default_color == 255);
// Rectangle enclosing layer mask: Top, left, bottom, right.
layer->layer_mask_info.top = psd_stream_get_int(context);
layer->layer_mask_info.left = psd_stream_get_int(context);
layer->layer_mask_info.bottom = psd_stream_get_int(context);
layer->layer_mask_info.right = psd_stream_get_int(context);
layer->layer_mask_info.width = layer->layer_mask_info.right - layer->layer_mask_info.left;
layer->layer_mask_info.height = layer->layer_mask_info.bottom - layer->layer_mask_info.top;
}
}
// LAYER BLENDING RANGES DATA
// Length of layer blending ranges data
size = psd_stream_get_int(context);
// Composite gray blend source. Contains 2 black values followed by 2
// white values. Present but irrelevant for Lab & Grayscale.
layer->layer_blending_ranges.gray_black_src = psd_stream_get_short(context);
layer->layer_blending_ranges.gray_white_src = psd_stream_get_short(context);
// Composite gray blend destination range
layer->layer_blending_ranges.gray_black_dst = psd_stream_get_short(context);
layer->layer_blending_ranges.gray_white_dst = psd_stream_get_short(context);
layer->layer_blending_ranges.number_of_blending_channels = (size - 8) / 8;
if (layer->layer_blending_ranges.number_of_blending_channels <= 0)
{
psd_layer_free(layer);
return psd_status_invalid_blending_channels;
}
layer->layer_blending_ranges.channel_black_src = (psd_ushort *)psd_malloc(layer->layer_blending_ranges.number_of_blending_channels * 2);
layer->layer_blending_ranges.channel_white_src = (psd_ushort *)psd_malloc(layer->layer_blending_ranges.number_of_blending_channels * 2);
layer->layer_blending_ranges.channel_black_dst = (psd_ushort *)psd_malloc(layer->layer_blending_ranges.number_of_blending_channels * 2);
layer->layer_blending_ranges.channel_white_dst = (psd_ushort *)psd_malloc(layer->layer_blending_ranges.number_of_blending_channels * 2);
if(layer->layer_blending_ranges.channel_black_src == NULL ||
layer->layer_blending_ranges.channel_white_src == NULL ||
layer->layer_blending_ranges.channel_black_dst == NULL ||
layer->layer_blending_ranges.channel_white_dst == NULL)
{
psd_layer_free(layer);
return psd_status_malloc_failed;
}
for(j = 0; j < layer->layer_blending_ranges.number_of_blending_channels; j ++)
{
// channel source range
layer->layer_blending_ranges.channel_black_src[j] = psd_stream_get_short(context);
layer->layer_blending_ranges.channel_white_src[j] = psd_stream_get_short(context);
// channel destination range
layer->layer_blending_ranges.channel_black_dst[j] = psd_stream_get_short(context);
layer->layer_blending_ranges.channel_white_dst[j] = psd_stream_get_short(context);
}
// Layer name: Pascal string, padded to a multiple of 4 bytes.
size = psd_stream_get_char(context);
size = ((size + 1 + 3) & ~0x03) - 1;
psd_stream_get(context, layer->layer_name, size);
while(context->stream.current_pos - extra_stream_pos < extra_length)
{
// ADDITIONAL LAYER INFORMATION
// Signature
tag = psd_stream_get_int(context);
if(tag != '8BIM')
return psd_status_layer_information_signature_error;
// Key: a 4-character code
tag = psd_stream_get_int(context);
// Length data below, rounded up to an even byte count.
// (**PSB**, the following keys have a length count of 8 bytes: LMsk, Lr16,
// Layr, Mt16, Mtrn, Alph.
size = psd_stream_get_int(context);
size = (size + 1) & ~0x01;
prev_stream_pos = context->stream.current_pos;
// Adjustment layer
// Adjustment layers can have one of the following keys
status = psd_status_done;
switch(tag)
{
case 'levl':
status = psd_get_layer_levels(context, layer, size);
break;
case 'curv':
status = psd_get_layer_curves(context, layer, size);
break;
case 'brit':
status = psd_get_layer_brightness_contrast(context, layer);
break;
case 'blnc':
status = psd_get_layer_color_balance(context, layer);
break;
//case 'hue ':
// Old Hue/saturation, Photoshop 4.0
//break;
case 'hue2':
status = psd_get_layer_hue_saturation(context, layer);
break;
case 'selc':
status = psd_get_layer_selective_color(context, layer);
break;
case 'thrs':
status = psd_get_layer_threshold(context, layer);
break;
case 'nvrt':
status = psd_get_layer_invert(context, layer);
break;
case 'post':
status = psd_get_layer_posterize(context, layer);
break;
case 'mixr':
status = psd_get_layer_channel_mixer(context, layer);
break;
case 'grdm':
status = psd_get_layer_gradient_map(context, layer);
break;
case 'phfl':
status = psd_get_layer_photo_filter(context, layer);
break;
case 'lrFX':
status = psd_get_layer_effects(context, layer);
break;
case 'lfx2':
status = psd_get_layer_effects2(context,layer);
break;
case 'tySh':
status = psd_get_layer_type_tool(context, layer);
break;
//case 'TySh':
// Type tool object setting (Photoshop 6.0)
//break;
case 'SoCo':
status = psd_get_layer_solid_color(context, layer);
break;
case 'GdFl':
status = psd_get_layer_gradient_fill(context, layer);
break;
case 'PtFl':
status = psd_get_layer_pattern_fill(context, layer);
break;
case 'luni':
status = psd_get_layer_unicode_name(context, layer);
break;
case 'lnsr':
status = psd_get_layer_name_id(context, layer);
break;
case 'lyid':
status = psd_get_layer_id(context, layer);
break;
case 'clbl':
status = psd_get_layer_blend_clipped(context, layer);
break;
case 'infx':
status = psd_get_layer_blend_interior(context, layer);
break;
case 'knko':
status = psd_get_layer_knockout(context, layer);
break;
case 'lspf':
status = psd_get_layer_protected(context, layer);
break;
case 'lclr':
status = psd_get_layer_sheet_color(context, layer);
break;
case 'fxrp':
status = psd_get_layer_reference_point(context, layer);
break;
case 'lyvr':
status = psd_get_layer_version(context, layer);
break;
case 'tsly':
status = psd_get_layer_transparency_shapes_layer(context, layer);
break;
case 'lmgm':
status = psd_get_layer_layer_mask_hides_effects(context, layer);
break;
case 'vmgm':
status = psd_get_layer_vector_mask_hides_effects(context, layer);
break;
case 'iOpa':
status = psd_get_layer_fill_opacity(context, layer);
break;
case 'lsct':
status = psd_get_layer_section_divider(context, layer, size);
break;
case 'brst':
status = psd_get_layer_channel_blending_restrictions(context, layer, size);
break;
#ifdef PSD_GET_PATH_RESOURCE
case 'vmsk':
status = psd_get_layer_vector_mask(context, layer, size);
break;
#endif
default:
psd_stream_get_null(context, size);
break;
}
if(status != psd_status_done)
{
psd_layer_free(layer);
return status;
}
// Filler
psd_stream_get_null(context, prev_stream_pos + size - context->stream.current_pos);
psd_assert(layer->layer_info_count < psd_layer_info_type_count);
}
psd_assert(context->stream.current_pos - extra_stream_pos == extra_length);
}
for(i = 0, layer = context->layer_records; i < context->layer_count; i ++, layer ++)
{
// Channel image data. Contains one or more image data records for each layer.
status = psd_get_layer_channel_image_data(context, layer);
if(status != psd_status_done)
{
psd_layer_free(layer);
return status;
}
}
// Filler: zeros
psd_stream_get_null(context, prev_layer_stream_pos + length - context->stream.current_pos);
// group layer
for(i = context->layer_count - 1, group_layer = NULL; i >= 0; i --)
{
layer = &context->layer_records[i];
switch(layer->layer_type)
{
case psd_layer_type_normal:
layer->group_layer = group_layer;
break;
case psd_layer_type_folder:
group_layer = layer;
break;
case psd_layer_type_hidden:
group_layer = NULL;
break;
}
}
return psd_status_done;
}
// Global layer mask info
psd_static psd_status psd_get_mask_info(psd_context * context)
{
psd_int length;
psd_int prev_stream_pos;
// Length of global layer mask info section.
length = psd_stream_get_int(context);
if(length == 0)
return psd_status_done;
prev_stream_pos = context->stream.current_pos;
// Overlay color space (undocumented).
context->global_layer_mask.color = psd_stream_get_space_color(context);
// Opacity. 0 = transparent, 100 = opaque.
context->global_layer_mask.opacity = psd_stream_get_short(context);
// Kind. 0 = Color selected<65><64>i.e. inverted; 1 = Color protected;128 = use
// value stored per layer. This value is preferred. The others are for
// backward compatibility with beta versions.
context->global_layer_mask.kind = psd_stream_get_char(context);
// Filler: zeros
psd_stream_get_null(context, prev_stream_pos + length - context->stream.current_pos);
return psd_status_done;
}
// The fourth section of a Photoshop file contains information about layers and masks.
// This section of the document describes the formats of layer and mask records.
psd_status psd_get_layer_and_mask(psd_context * context)
{
psd_int length, prev_stream_pos, extra_stream_pos, size;
psd_status status;
psd_uint tag;
// Length of the layer and mask information section. (**PSB** length is 8 bytes.)
length = psd_stream_get_int(context);
if(length <= 0)
return psd_status_done;
prev_stream_pos = context->stream.current_pos;
if(context->load_tag == psd_load_tag_merged || context->load_tag == psd_load_tag_thumbnail ||
context->load_tag == psd_load_tag_exif)
{
psd_stream_get_null(context, length);
return psd_status_done;
}
// Layer info
status = psd_get_layer_info(context);
psd_freeif(context->temp_image_data);
context->temp_image_data = NULL;
context->temp_image_length = 0;
psd_freeif(context->temp_channel_data);
context->temp_channel_data = NULL;
context->temp_channel_length = 0;
if(status != psd_status_done)
return status;
// Global layer mask info
status = psd_get_mask_info(context);
while(prev_stream_pos + length - context->stream.current_pos > 12)
{
tag = psd_stream_get_int(context);
if(tag == '8BIM')
{
tag = psd_stream_get_int(context);
if (tag == 'Lr16')
{
status = psd_get_layer_info(context);
continue;
}
size = psd_stream_get_int(context);
switch(tag)
{
case 'Patt':
case 'Pat2':
while(size >= 4)
{
extra_stream_pos = context->stream.current_pos;
status = psd_get_pattern(context);
size -= context->stream.current_pos - extra_stream_pos;
}
if(size > 0)
psd_stream_get_null(context, size);
break;
default:
if(size > 0)
psd_stream_get_null(context, size);
break;
}
}
else
{
break;
}
}
// Filler: zeros
psd_stream_get_null(context, prev_stream_pos + length - context->stream.current_pos);
return status;
}
psd_static void psd_layer_free(psd_layer_record * layer)
{
psd_int i;
for(i = 0; i < layer->layer_info_count; i ++)
{
if(layer->layer_info_data[i] != 0)
{
switch(layer->layer_info_type[i])
{
case psd_layer_info_type_levels:
psd_layer_levels_free(layer->layer_info_data[i]);
break;
case psd_layer_info_type_curves:
psd_layer_curves_free(layer->layer_info_data[i]);
break;
case psd_layer_info_type_gradient_map:
psd_layer_gradient_map_free(layer->layer_info_data[i]);
break;
case psd_layer_info_type_type_tool:
psd_layer_type_tool_free(layer->layer_info_data[i]);
break;
case psd_layer_info_type_effects:
case psd_layer_info_type_effects2:
psd_layer_effects_free(layer->layer_info_data[i]);
break;
default:
psd_freeif((void *)layer->layer_info_data[i]);
break;
}
layer->layer_info_data[i] = 0;
}
}
layer->layer_info_count = 0;
psd_freeif(layer->channel_info);
layer->channel_info = NULL;
psd_freeif(layer->unicode_name);
layer->unicode_name = NULL;
psd_freeif(layer->image_data);
layer->image_data = NULL;
psd_freeif(layer->layer_mask_info.mask_data);
layer->layer_mask_info.mask_data = NULL;
psd_freeif(layer->layer_blending_ranges.channel_black_src);
layer->layer_blending_ranges.channel_black_src = NULL;
psd_freeif(layer->layer_blending_ranges.channel_white_src);
layer->layer_blending_ranges.channel_white_src = NULL;
psd_freeif(layer->layer_blending_ranges.channel_black_dst);
layer->layer_blending_ranges.channel_black_dst = NULL;
psd_freeif(layer->layer_blending_ranges.channel_white_dst);
layer->layer_blending_ranges.channel_white_dst = NULL;
#ifdef PSD_GET_PATH_RESOURCE
psd_layer_vector_mask_free(layer);
#endif
}
void psd_layer_and_mask_free(psd_context * context)
{
psd_int i;
for(i = 0; i < context->layer_count; i ++)
psd_layer_free(&context->layer_records[i]);
psd_freeif(context->layer_records);
psd_freeif(context->temp_channel_data);
psd_pattern_free(context);
}