psd_status psd_get_layer_drop_shadow(psd_context * context, psd_layer_effects_drop_shadow * drop_shadow) { psd_int size, version; psd_uint tag; psd_set_layer_drop_shadow_default(drop_shadow); // Size of the remaining items: 41 or 51 (depending on version) size = psd_stream_get_int(context); // Version: 0 (Photoshop 5.0) or 2 (Photoshop 5.5) version = psd_stream_get_int(context); if(version != 0 && version != 2) return psd_status_shadow_unsupport_version; // Blur value in pixels drop_shadow->size = psd_stream_get_short(context); // i don't know, but it is psd_short // Intensity as a percent drop_shadow->spread = psd_stream_get_int(context); // Angle in degrees drop_shadow->angle = psd_stream_get_int(context); // Distance in pixels drop_shadow->distance = psd_stream_get_int(context); // maybe photoshop is wrong psd_stream_get_short(context); // Color drop_shadow->color = psd_stream_get_space_color(context); // Blend mode: 4 bytes for signature and 4 bytes for key // Blend mode signature: '8BIM' tag = psd_stream_get_int(context); if(tag != '8BIM') return psd_status_blend_mode_signature_error; // Blend mode key drop_shadow->blend_mode = psd_stream_get_blend_mode(context); // Effect enabled drop_shadow->effect_enable = psd_stream_get_bool(context); // Use this angle in all of the drop_shadow effects drop_shadow->use_global_light = psd_stream_get_bool(context); // Opacity as a percent drop_shadow->opacity = psd_stream_get_char(context); // Version 2 only if(version == 2) { // Native color drop_shadow->native_color = psd_stream_get_space_color(context); } 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 ¡°folder¡±, 2 = // closed ¡°folder¡±, 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; }
psd_status psd_get_layer_inner_glow(psd_context * context, psd_layer_effects_inner_glow * inner_glow) { psd_int size, version; psd_uint tag; psd_bool invert; psd_set_layer_inner_glow_default(inner_glow); // Size of the remaining items: 32 for Photoshop 5.0; 43 for 5.5 size = psd_stream_get_int(context); // Version: 0 for Photoshop 5.0; 2 for 5.5 version = psd_stream_get_int(context); if(version != 0 && version != 2) return psd_status_inner_glow_unsupport_version; // Blur value in pixels. inner_glow->size = psd_stream_get_int(context); // Intensity as a percent inner_glow->choke = psd_stream_get_int(context); // Color inner_glow->color = psd_stream_get_space_color(context); // Blend mode: 4 bytes for signature and 4 bytes for the key // Blend mode signature: '8BIM' tag = psd_stream_get_int(context); if(tag != '8BIM') return psd_status_blend_mode_signature_error; // Blend mode key inner_glow->blend_mode = psd_stream_get_blend_mode(context); // Effect enabled inner_glow->effect_enable = psd_stream_get_bool(context); // Opacity as a percent inner_glow->opacity = psd_stream_get_char(context); // Version 2 only if(version == 2) { // Invert invert = psd_stream_get_bool(context); if(invert == psd_true) inner_glow->source = psd_glow_center; // Native color inner_glow->native_color = psd_stream_get_space_color(context); } return psd_status_done; }
psd_status psd_get_layer_color_overlay(psd_context * context, psd_layer_effects_color_overlay * color_overlay) { psd_int size, version; psd_uint tag; psd_set_layer_color_overlay_default(color_overlay); // Size: 34 size = psd_stream_get_int(context); // Version: 2 version = psd_stream_get_int(context); if(version != 2) return psd_status_solid_fill_unsupport_version; tag = psd_stream_get_int(context); if(tag != '8BIM') return psd_status_blend_mode_signature_error; // Key for blend mode color_overlay->blend_mode = psd_stream_get_blend_mode(context); // Color space color_overlay->color = psd_stream_get_space_color(context); // Opacity color_overlay->opacity = psd_stream_get_char(context); // Enabled color_overlay->effect_enable = psd_stream_get_bool(context); // Native color space color_overlay->native_color = psd_stream_get_space_color(context); 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.; // ¨C1 = transparency mask; ¨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¨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; }