Example #1
0
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;
}
Example #2
0
// 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;
}
Example #3
0
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;
}
Example #4
0
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;
}
Example #5
0
// 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;
}