Exemple #1
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;
}
Exemple #2
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;
}
Exemple #3
0
// 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¡ª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;
}
Exemple #4
0
// 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;
}
Exemple #5
0
// 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;
}
Exemple #6
0
psd_status psd_get_layer_vector_mask(psd_context * context, psd_layer_record * layer, psd_int size)
{
	psd_uint tag;
	
	// Version ( = 3 for Photoshop 6.0)
	psd_assert(psd_stream_get_int(context) == 3);

	// Flags. bit 1 = invert, bit 2 = not link, bit 3 = disable
	tag = psd_stream_get_int(context);
	layer->vector_mask.invert = tag & 0x01;
	layer->vector_mask.not_link = (tag & (0x01 << 1)) > 0;
	layer->vector_mask.disable = (tag & (0x01 << 2)) > 0;

	// The rest of the data is path components, loop until end of the length
	layer->vector_mask.path = (psd_path *)psd_malloc(sizeof(psd_path));
	if(layer->vector_mask.path == NULL)
		return psd_status_malloc_failed;
	psd_get_path_record(context, layer->vector_mask.path, size - 8);

	return psd_status_done;
}
Exemple #7
0
// 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;
}
Exemple #8
0
// Solid color sheet setting (Photoshop 6.0)
psd_status psd_get_layer_solid_color(psd_context * context, psd_layer_record * layer)
{
	psd_layer_solid_color * data;
	psd_int length, number_items;
	psd_uint key;
	
	layer->layer_info_type[layer->layer_info_count] = psd_layer_info_type_solid_color;
	layer->layer_type = psd_layer_type_solid_color;

	data = (psd_layer_solid_color *)psd_malloc(sizeof(psd_layer_solid_color));
	if(data == NULL)
		return psd_status_malloc_failed;
	memset(data, 0, sizeof(psd_layer_solid_color));
	layer->layer_info_data[layer->layer_info_count] = (psd_uint)data;
	layer->layer_info_count ++;

	// Version ( = 16 for Photoshop 6.0)
	if(psd_stream_get_int(context) != 16)
		return psd_status_solid_color_unsupport_version;

	// Unicode string: name from classID
	length = psd_stream_get_int(context) * 2;
	psd_stream_get_null(context, length);

	// classID: 4 bytes (length), followed either by string or (if length is zero) 4-
	// byte classID
	length = psd_stream_get_int(context);
	psd_assert(length == 0);
	data->id = psd_stream_get_int(context);

	// Number of items in descriptor
	number_items = psd_stream_get_int(context);
	// should be 1
	psd_assert(number_items == 1);

	// The following is repeated for each item in descriptor
	// Key: 4 bytes ( length) followed either by string or (if length is zero) 4-byte key
	length = psd_stream_get_int(context);
	psd_assert(length == 0);
	key = psd_stream_get_int(context);
	psd_assert(key == 'Clr ');

	// Type: OSType key
	key = psd_stream_get_int(context);
	psd_assert(key == 'Objc');

	data->fill_color = psd_stream_get_object_color(context);

	return psd_status_done;
}
Exemple #9
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;
}
Exemple #10
0
// 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;
}
Exemple #11
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;
}
Exemple #12
0
// 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;
}
Exemple #13
0
// Additional layer -- levels
// Levels settings files are loaded and saved in the Levels dialog.
psd_status psd_get_layer_levels(psd_context * context, psd_layer_record * layer, psd_int data_length)
{
	psd_layer_levels * data;
	psd_int i, prev_stream_pos = context->stream.current_pos;
	psd_uint tag;
	
	layer->layer_info_type[layer->layer_info_count] = psd_layer_info_type_levels;
	layer->layer_type = psd_layer_type_levels;

	data = (psd_layer_levels *)psd_malloc(sizeof(psd_layer_levels));
	if(data == NULL)
		return psd_status_malloc_failed;
	memset(data, 0, sizeof(psd_layer_levels));
	layer->layer_info_data[layer->layer_info_count] = (psd_uint)data;
	layer->layer_info_count ++;
	
	// Version ( = 2)
	if(psd_stream_get_short(context) != 2)
		return psd_status_levels_unsupport_version;

	// 29 sets of level records, each level containing 5 psd_short integers
	for(i = 0; i < 29; i ++)
	{
		// Input floor (0...253)
		data->record[i].input_floor = psd_stream_get_short(context);
		// Input ceiling (2...255)
		data->record[i].input_ceiling = psd_stream_get_short(context);
		// Output floor (0...255). Matched to input floor.
		data->record[i].output_floor = psd_stream_get_short(context);
		// Output ceiling (0...255)
		data->record[i].output_ceiling = psd_stream_get_short(context);
		// Gamma. Short integer from 10...999 representing 0.1...9.99. Applied
		// to all image data.
		data->record[i].gamma = psd_stream_get_short(context) / 100.0f;
		// Sets 28 and 29 are reserved and should be set to zeros.
		if(i < 27)
		{
			psd_assert(data->record[i].input_floor >= 0 && data->record[i].input_floor <= 255);
			psd_assert(data->record[i].input_ceiling >= 2 && data->record[i].input_ceiling <= 255);
			psd_assert(data->record[i].output_floor >= 0 && data->record[i].output_floor <= 255);
			psd_assert(data->record[i].output_ceiling >= 0 && data->record[i].output_ceiling <= 255);
			psd_assert(data->record[i].gamma >= 0.1 && data->record[i].gamma <= 9.99);
		}
	}

	// Photoshop CS (8.0) Additional information
	// At the end of the Version 2 file is the following information
	if(context->stream.current_pos - prev_stream_pos < data_length - 4)
	{
		// = 'Lvls' for extra level information
		tag = psd_stream_get_int(context);
		if(tag != 'Lvls')
			return psd_status_extra_levels_key_error;

		// Version ( = 3)
		if(psd_stream_get_short(context) != 3)
			return psd_status_extra_levels_unsupport_version;

		// Count of total level record structures. Subtract the legacy number of
		// level record structures, 29, to determine how many are remaining in
		// the file for reading.
		data->extra_level_count = psd_stream_get_short(context) - 29;
		psd_assert(data->extra_level_count >= 0);
		data->extra_record = (psd_layer_level_record *)psd_malloc(data->extra_level_count * sizeof(psd_layer_level_record));
		if(data->extra_record == NULL)
			return psd_status_malloc_failed;
		memset(data->extra_record, 0, data->extra_level_count * sizeof(psd_layer_level_record));

		// Additianol level records according to count.
		for(i = 0; i < data->extra_level_count; i ++)
		{
			// Input floor (0...253)
			data->extra_record[i].input_floor = psd_stream_get_short(context);
			// Input ceiling (2...255)
			data->extra_record[i].input_ceiling = psd_stream_get_short(context);
			// Output floor (0...255). Matched to input floor.
			data->extra_record[i].output_floor = psd_stream_get_short(context);
			// Output ceiling (0...255)
			data->extra_record[i].output_ceiling = psd_stream_get_short(context);
			// Gamma. Short integer from 10...999 representing 0.1...9.99. Applied
			// to all image data.
			data->extra_record[i].gamma = psd_stream_get_short(context) / 100.0f;
			// Sets 28 and 29 are reserved and should be set to zeros.
		}
	}

	if(context->stream.current_pos - prev_stream_pos != data_length)
		return psd_status_levels_dismatch_data_length;

	layer->adjustment_valid = psd_true;

	return psd_status_done;
}
Exemple #14
0
psd_status psd_get_layer_stroke2(psd_context * context, psd_layer_effects_stroke * stroke)
{
	psd_int length, number_items;
	psd_uint rootkey, type, key;
	psd_uchar keychar[256];
	
	psd_set_layer_stroke_default(stroke);

	// Unicode string: name from classID
	length = psd_stream_get_int(context) * 2;
	psd_stream_get_null(context, length);

	// classID: 4 bytes (length), followed either by string or (if length is zero) 4-
	// byte classID
	length = psd_stream_get_int(context);
	if(length == 0)
		psd_stream_get_int(context);
	else
		psd_stream_get_null(context, length);

	// Number of items in descriptor
	number_items = psd_stream_get_int(context);

	while(number_items --)
	{
		length = psd_stream_get_int(context);
		if(length == 0)
			rootkey = psd_stream_get_int(context);
		else
		{
			rootkey = 0;
			psd_stream_get(context, keychar, length);
			keychar[length] = 0;
		}
		// Type: OSType key
		type = psd_stream_get_int(context);

		switch(rootkey)
		{
			case 0:
				if(strcmp(keychar, "phase") == 0)
				{
					psd_assert(type == 'Objc');
					psd_stream_get_object_point(&stroke->pattern_horz_phase, 
						&stroke->pattern_vert_phase, context);
					stroke->pattern_horz_phase = 0;
					stroke->pattern_vert_phase = 0;
				}
				else
				{
					psd_assert(0);
					psd_stream_get_object_null(type, context);
				}
				break;
				
			// effect enable
			case 'enab':
				psd_assert(type == 'bool');
				stroke->effect_enable = psd_stream_get_bool(context);
				break;

			// position
			case 'Styl':
				psd_assert(type == 'enum');
				
				// TypeID: 4 bytes (length), followed either by string or (if length is zero) 4-
				// byte typeID
				length = psd_stream_get_int(context);
				psd_assert(length == 0);
				key = psd_stream_get_int(context);
				// fill style
				psd_assert(key == 'FStl');
				
				length = psd_stream_get_int(context);
				if(length == 0)
					key = psd_stream_get_int(context);
				else
				{
					key = 0;
					psd_stream_get(context, keychar, length);
					keychar[length] = 0;
				}
				switch(key)
				{
					case 'OutF':
						stroke->position = psd_stroke_outside;
						break;
					case 'InsF':
						stroke->position = psd_stroke_inside;
						break;
					case 'CtrF':
						stroke->position = psd_stroke_center;
						break;
					default:
						psd_assert(0);
						break;
				}
				break;

			// fill type
			case 'PntT':
				psd_assert(type == 'enum');
				
				// TypeID: 4 bytes (length), followed either by string or (if length is zero) 4-
				// byte typeID
				length = psd_stream_get_int(context);
				psd_assert(length == 0);
				key = psd_stream_get_int(context);
				// fill style
				psd_assert(key == 'FrFl');
				
				length = psd_stream_get_int(context);
				if(length == 0)
					key = psd_stream_get_int(context);
				else
				{
					key = 0;
					psd_stream_get(context, keychar, length);
					keychar[length] = 0;
				}
				switch(key)
				{
					case 'SClr':
						stroke->fill_type = psd_fill_solid_color;
						break;
					case 'GrFl':
						stroke->fill_type = psd_fill_gradient;
						break;
					case 'Ptrn':
						stroke->fill_type = psd_fill_pattern;
						break;
					default:
						psd_assert(0);
						break;
				}
				break;

			// blend mode
			case 'Md  ':
				psd_assert(type == 'enum');
				
				// TypeID: 4 bytes (length), followed either by string or (if length is zero) 4-
				// byte typeID
				length = psd_stream_get_int(context);
				psd_assert(length == 0);
				key = psd_stream_get_int(context);
				// blend mode
				psd_assert(key == 'BlnM');
				stroke->blend_mode = psd_stream_get_object_blend_mode(context);
				break;

			// opacity
			case 'Opct':
				psd_assert(type == 'UntF');
				// percent
				key = psd_stream_get_int(context);
				psd_assert(key == '#Prc');
				// Actual value (double)
				stroke->opacity = (psd_int)(psd_stream_get_double(context) * 2.55 + 0.5);
				break;

			// size
			case 'Sz  ':
				psd_assert(type == 'UntF');
				// pixels: tagged unit value
				key = psd_stream_get_int(context);
				psd_assert(key == '#Pxl');
				stroke->size = (psd_int)psd_stream_get_double(context);
				break;

			// color
			case 'Clr ':
				// Descriptor
				psd_assert(type == 'Objc');
				stroke->fill_color = psd_stream_get_object_color(context);
				break;

			// gradient color
			case 'Grad':
				// Descriptor
				psd_assert(type == 'Objc');
				psd_stream_get_object_gradient_color(&stroke->gradient_color, context);
				break;

			case 'Angl':	// angle
				// Unit psd_float
				psd_assert(type == 'UntF');
				
				// '#Ang' = angle: base degrees
				key = psd_stream_get_int(context);
				psd_assert(key == '#Ang');

				// Actual value (double)
				stroke->gradient_angle = (psd_int)psd_stream_get_double(context);
				break;

			case 'Type':	// gradient style
				// Enumerated
				psd_assert(type == 'enum');

				// TypeID: 4 bytes (length), followed either by string or (if length is zero) 4-
				// byte typeID
				length = psd_stream_get_int(context);
				psd_assert(length == 0);
				key = psd_stream_get_int(context);
				// Gradient Type
				psd_assert(key == 'GrdT');
				stroke->gradient_style = psd_stream_get_object_gradient_style(context);
				break;
				
			case 'Rvrs':	// reverse
				// boolean
				psd_assert(type == 'bool');
				stroke->gradient_reverse = psd_stream_get_bool(context);
				break;

			case 'Scl ':	// scale
				// Unit psd_float
				psd_assert(type == 'UntF');

				// '#Prc' = percent:
				key = psd_stream_get_int(context);
				psd_assert(key == '#Prc');
								
				// Actual value (double)
				if(stroke->fill_type == psd_fill_gradient)
					stroke->gradient_scale = (psd_int)psd_stream_get_double(context);
				else if(stroke->fill_type == psd_fill_pattern)
					stroke->pattern_scale = (psd_int)psd_stream_get_double(context);
				break;

			case 'Algn':	// align with layer
				// boolean
				psd_assert(type == 'bool');
				stroke->gradient_align = psd_stream_get_bool(context);
				break;

			// offset, not documented
			case 'Ofst':
				psd_assert(type == 'Objc');
				psd_stream_get_object_point(&stroke->gradient_horz_offset, 
					&stroke->gradient_vert_offset, context);
				break;

			// pattern
			case 'Ptrn':
				psd_assert(type == 'Objc');
				psd_stream_get_object_pattern_info(&stroke->pattern_info, context);
				break;

			// link with layer
			case 'Lnkd':
				psd_assert(type == 'bool');
				stroke->pattern_link = psd_stream_get_bool(context);
				break;

			default:
				psd_assert(0);
				psd_stream_get_object_null(type, context);
				break;
		}
	}

	return psd_status_done;
}
Exemple #15
0
psd_status psd_get_layer_inner_glow2(psd_context * context, psd_layer_effects_inner_glow * inner_glow)
{
	psd_int length, number_items;
	psd_uint rootkey, type, key;
	psd_uchar keychar[256];
	
	psd_set_layer_inner_glow_default(inner_glow);

	// Unicode string: name from classID
	length = psd_stream_get_int(context) * 2;
	psd_stream_get_null(context, length);

	// classID: 4 bytes (length), followed either by string or (if length is zero) 4-
	// byte classID
	length = psd_stream_get_int(context);
	if(length == 0)
		psd_stream_get_int(context);
	else
		psd_stream_get_null(context, length);

	// Number of items in descriptor
	number_items = psd_stream_get_int(context);

	while(number_items --)
	{
		length = psd_stream_get_int(context);
		psd_assert(length == 0);
		if(length == 0)
			rootkey = psd_stream_get_int(context);
		else
		{
			rootkey = 0;
			psd_stream_get(context, keychar, length);
			keychar[length] = 0;
		}
		// Type: OSType key
		type = psd_stream_get_int(context);

		switch(rootkey)
		{
			// effect enable
			case 'enab':
				psd_assert(type == 'bool');
				inner_glow->effect_enable = psd_stream_get_bool(context);
				break;

			// blend mode
			case 'Md  ':
				psd_assert(type == 'enum');
				// TypeID: 4 bytes (length), followed either by string or (if length is zero) 4-
				// byte typeID
				length = psd_stream_get_int(context);
				psd_assert(length == 0);
				key = psd_stream_get_int(context);
				// blend mode
				psd_assert(key == 'BlnM');
				inner_glow->blend_mode = psd_stream_get_object_blend_mode(context);
				break;

			// color or native color
			case 'Clr ':
				// Descriptor
				psd_assert(type == 'Objc');
				inner_glow->color = inner_glow->native_color = psd_stream_get_object_color(context);
				inner_glow->fill_type = psd_fill_solid_color;
				break;

			// gradient color
			case 'Grad':
				// Descriptor
				psd_assert(type == 'Objc');
				psd_stream_get_object_gradient_color(&inner_glow->gradient_color, context);
				inner_glow->fill_type = psd_fill_gradient;
				break;

			// opacity
			case 'Opct':
				psd_assert(type == 'UntF');
				// percent
				key = psd_stream_get_int(context);
				psd_assert(key == '#Prc');
				// Actual value (double)
				inner_glow->opacity = (psd_int)(psd_stream_get_double(context) * 2.55 + 0.5);
				break;

			// technique
			case 'GlwT':
				psd_assert(type == 'enum');
				// TypeID: 4 bytes (length), followed either by string or (if length is zero) 4-
				// byte typeID
				length = psd_stream_get_int(context);
				psd_assert(length == 0);
				key = psd_stream_get_int(context);
				// Matte Technique
				psd_assert(key == 'BETE');
				inner_glow->technique = psd_stream_get_object_technique(context);
				break;

			// choke
			case 'Ckmt':
				psd_assert(type == 'UntF');
				// pixels: tagged unit value
				key = psd_stream_get_int(context);
				psd_assert(key == '#Pxl');
				inner_glow->choke = (psd_int)psd_stream_get_double(context);
				break;

			// size
			case 'blur':
				psd_assert(type == 'UntF');
				// pixels: tagged unit value
				key = psd_stream_get_int(context);
				psd_assert(key == '#Pxl');
				inner_glow->size = (psd_int)psd_stream_get_double(context);
				break;

			// jitter
			case 'ShdN':
				psd_assert(type == 'UntF');
				// percent
				key = psd_stream_get_int(context);
				psd_assert(key == '#Prc');
				// Actual value (double)
				inner_glow->jitter = (psd_int)psd_stream_get_double(context);
				break;

			// noise
			case 'Nose':
				psd_assert(type == 'UntF');
				// percent
				key = psd_stream_get_int(context);
				psd_assert(key == '#Prc');
				// Actual value (double)
				inner_glow->noise = (psd_int)psd_stream_get_double(context);
				break;

			// anti-aliased
			case 'AntA':
				psd_assert(type == 'bool');
				inner_glow->anti_aliased = psd_stream_get_bool(context);
				break;

			// source
			case 'glwS':
				psd_assert(type == 'enum');
				// TypeID: 4 bytes (length), followed either by string or (if length is zero) 4-
				// byte typeID
				length = psd_stream_get_int(context);
				psd_assert(length == 0);
				key = psd_stream_get_int(context);
				// inner glow source
				psd_assert(key == 'IGSr');

				length = psd_stream_get_int(context);
				if(length == 0)
					key = psd_stream_get_int(context);
				else
				{
					key = 0;
					psd_stream_get(context, keychar, length);
					keychar[length] = 0;
				}
				switch(key)
				{
					case 'SrcC':
						inner_glow->source = psd_glow_center;
						break;
					case 'SrcE':
						inner_glow->source = psd_glow_edge;
						break;
					default:
						psd_assert(0);
						break;
				}
				break;

			// contour
			case 'TrnS':
				psd_assert(type == 'Objc');
				psd_stream_get_object_contour(inner_glow->contour_lookup_table, context);
				break;

			// range
			case 'Inpr':
				psd_assert(type == 'UntF');
				// percent
				key = psd_stream_get_int(context);
				psd_assert(key == '#Prc');
				// Actual value (double)
				inner_glow->range = (psd_int)psd_stream_get_double(context);
				break;

			default:
				psd_assert(0);
				psd_stream_get_object_null(type, context);
				break;
		}
	}

	return psd_status_done;
}
Exemple #16
0
// Type Tool Info (Photoshop 5.0 and 5.5 only)
psd_status psd_get_layer_type_tool(psd_context * context, psd_layer_record * layer)
{
    psd_layer_type_tool * data;
    psd_int i, j, length;

    layer->layer_info_type[layer->layer_info_count] = psd_layer_info_type_type_tool;

    data = (psd_layer_type_tool *)psd_malloc(sizeof(psd_layer_type_tool));
    if(data == NULL)
        return psd_status_malloc_failed;
    memset(data, 0, sizeof(psd_layer_type_tool));
    layer->layer_info_data[layer->layer_info_count] = (psd_uint)data;
    layer->layer_info_count ++;

    // Version ( = 1)
    psd_assert(psd_stream_get_short(context) == 1);

    // 6 * 8 double precision numbers for the transform information
    for(i = 0; i < 6; i ++)
        data->transform_info[i] = psd_stream_get_double(context);

    /***********************************************************************/
    // Font information
    /***********************************************************************/
    // Version ( = 6)
    psd_assert(psd_stream_get_short(context) == 6);

    // Count of faces
    data->faces_count = psd_stream_get_short(context);
    data->face = (psd_layer_type_face *)psd_malloc(data->faces_count * sizeof(psd_layer_type_face));
    if(data->face == NULL)
        return psd_status_malloc_failed;
    memset(data->face, 0, data->faces_count * sizeof(psd_layer_type_face));

    // The next 8 fields are repeated for each count specified above
    for(i = 0; i < data->faces_count; i ++)
    {
        // Mark value
        data->face[i].mark = psd_stream_get_short(context);

        // Font type data
        data->face[i].font_type = psd_stream_get_int(context);

        // Pascal string of font name
        length = psd_stream_get_char(context);
        psd_stream_get(context, data->face[i].font_name, length);

        // Pascal string of font family name
        length = psd_stream_get_char(context);
        psd_stream_get(context, data->face[i].font_family_name, length);

        // Pascal string of font style name
        length = psd_stream_get_char(context);
        psd_stream_get(context, data->face[i].font_style_name, length);

        // Script value
        data->face[i].script = psd_stream_get_short(context);

        // Number of design axes vector to follow
        data->face[i].number_axes_vector = psd_stream_get_int(context);
        data->face[i].vector = (psd_int *)psd_malloc(data->face[i].number_axes_vector * 4);
        if(data->face[i].vector == NULL)
            return psd_status_malloc_failed;

        // Design vector value
        for(j = 0; j < data->face[i].number_axes_vector; j ++)
            data->face[i].vector[j] = psd_stream_get_int(context);
    }

    /***********************************************************************/
    // Style information
    /***********************************************************************/
    // Count of styles
    data->styles_count = psd_stream_get_short(context);
    data->style = (psd_layer_type_style *)psd_malloc(data->styles_count * sizeof(psd_layer_type_style));
    if(data->style == NULL)
        return psd_status_malloc_failed;
    memset(data->style, 0, data->styles_count * sizeof(psd_layer_type_style));

    // The next 10 fields are repeated for each count specified above
    for(i = 0; i < data->styles_count; i ++)
    {
        // Mark value
        data->style[i].mark = psd_stream_get_short(context);

        // Face mark value
        data->style[i].face_mark = psd_stream_get_short(context);

        // Size value
        data->style[i].size = psd_stream_get_int(context);

        // Tracking value
        data->style[i].tracking = psd_stream_get_int(context);

        // Kerning value
        data->style[i].kerning = psd_stream_get_int(context);

        // Leading value
        data->style[i].leading = psd_stream_get_int(context);

        // Base shift value
        data->style[i].base_shift = psd_stream_get_int(context);

        // Auto kern on/off
        data->style[i].auto_kern = psd_stream_get_bool(context);

        // Only present in version <= 5
        psd_stream_get_char(context);

        // Rotate up/down
        data->style[i].rotate = psd_stream_get_bool(context);
    }

    /***********************************************************************/
    // Text information
    /***********************************************************************/
    // Type value
    data->type = psd_stream_get_short(context);

    // Scaling factor value
    data->scaling_factor = psd_stream_get_int(context);

    // Sharacter count value
    data->sharacter_count = psd_stream_get_int(context);

    // Horizontal placement
    data->horz_place = psd_stream_get_int(context);

    // Vertical placement
    data->vert_place = psd_stream_get_int(context);

    // Select start value
    data->select_start = psd_stream_get_int(context);

    // Select end value
    data->select_end = psd_stream_get_int(context);

    // Line count
    data->lines_count = psd_stream_get_short(context);
    data->line = (psd_layer_type_line *)psd_malloc(data->lines_count * sizeof(psd_layer_type_line));
    if(data->line == NULL)
        return psd_status_malloc_failed;
    memset(data->line, 0, data->lines_count * sizeof(psd_layer_type_line));

    // The next 5 fields are repeated for each item in line count.
    for(i = 0; i < data->lines_count; i ++)
    {
        // Character count value
        data->line[i].char_count = psd_stream_get_int(context);

        // Orientation value
        data->line[i].orientation = psd_stream_get_short(context);

        // Alignment value
        data->line[i].alignment = psd_stream_get_short(context);

        // Actual character as a double byte character
        data->line[i].actual_char = psd_stream_get_short(context);

        // Style value
        data->line[i].style = psd_stream_get_short(context);
    }

    /***********************************************************************/
    // Color information
    /***********************************************************************/
    // Color space value
    data->color = psd_stream_get_space_color(context);

    // Anti alias on/off
    data->anti_alias = psd_stream_get_bool(context);

    return psd_status_done;
}
Exemple #17
0
static psd_status psd_get_path_record(psd_context * context, psd_path * path, psd_int length)
{
	psd_int i, records, malloc_subpath;
	psd_short record_type;
	psd_subpath * subpaths = NULL, * cur_subpath;
	psd_bezier_point * cur_bezier_point = NULL;
	
	memset(path, 0, sizeof(psd_path));

	malloc_subpath = PSD_MIN_SUBPATH_COUNT;
	subpaths = (psd_subpath *)psd_malloc(sizeof(psd_subpath) * malloc_subpath);
	if (subpaths == NULL)
		return psd_status_malloc_failed;

	// These resource blocks consist of a series of 26-byte path point records, so the resource
	// length should always be a multiple of 26.
	records = length / 26;

	for (i = 0; i < records; i ++)
	{
		record_type = psd_stream_get_short(context);
		switch(record_type)
		{
			case 0:		// Closed subpath length record
			case 3:		// Open subpath length record
				if (path->number_of_subpaths >= malloc_subpath)
				{
					malloc_subpath *= 2;
					subpaths = (psd_subpath *)psd_realloc(subpaths, sizeof(psd_subpath) * malloc_subpath);
					if (subpaths == NULL)
						return psd_status_malloc_failed;
				}
				cur_subpath = &subpaths[path->number_of_subpaths];
				path->number_of_subpaths ++;
				// contain the number of Bezier knot records in bytes 2 and 3
				cur_subpath->number_of_points = psd_stream_get_short(context);
				cur_subpath->closed = (record_type == 0 ? psd_true : psd_false);
				cur_subpath->bezier_points = (psd_bezier_point *)psd_malloc(sizeof(psd_bezier_point) * cur_subpath->number_of_points);
				if (cur_subpath->bezier_points == NULL)
					return psd_status_malloc_failed;
				memset(cur_subpath->bezier_points, 0, sizeof(psd_bezier_point) * cur_subpath->number_of_points);
				cur_bezier_point = cur_subpath->bezier_points;
				// remains 22 byets
				psd_stream_get_null(context, 22);
				break;
				
			case 1:		// Closed subpath Bezier knot, linked
			case 2:		// Closed subpath Bezier knot, unlinked
			case 4:		// Open subpath Bezier knot, linked
			case 5:		// Open subpath Bezier knot, unlinked
				if (record_type == 1 || record_type == 4)
					cur_bezier_point->linked = psd_true;
				else
					cur_bezier_point->linked = psd_false;
				// the control point for the Bezier segment preceding the knot
				cur_bezier_point->preceding_control_vertical = psd_fixed_8_24_tofloat(psd_stream_get_int(context));
				cur_bezier_point->preceding_control_horizontal = psd_fixed_8_24_tofloat(psd_stream_get_int(context));
				// the anchor point for the knot
				cur_bezier_point->anchor_point_vertical = psd_fixed_8_24_tofloat(psd_stream_get_int(context));
				cur_bezier_point->anchor_point_horizontal = psd_fixed_8_24_tofloat(psd_stream_get_int(context));
				// the control point for the Bezier segment leaving the knot
				cur_bezier_point->leaving_control_vertical = psd_fixed_8_24_tofloat(psd_stream_get_int(context));
				cur_bezier_point->leaving_control_horizontal = psd_fixed_8_24_tofloat(psd_stream_get_int(context));
				// get the next
				cur_bezier_point ++;
				break;
				
			case 6:		// Path fill rule record
				// The remaining 24 bytes of the first record are zeroes.
				psd_stream_get_null(context, 24);
				break;
				
			case 7:		// Clipboard record
				// contain four fixed-point numbers for the bounding rectangle (top, left, bottom, right)
				path->clipboard_top = psd_fixed_8_24_tofloat(psd_stream_get_int(context));
				path->clipboard_left = psd_fixed_8_24_tofloat(psd_stream_get_int(context));
				path->clipboard_bottom = psd_fixed_8_24_tofloat(psd_stream_get_int(context));
				path->clipboard_right = psd_fixed_8_24_tofloat(psd_stream_get_int(context));
				// a single fixed-point number indicating the resolution
				path->resolution = psd_fixed_8_24_tofloat(psd_stream_get_int(context));
				// remains 4 byets
				psd_stream_get_null(context, 4);
				break;
				
			case 8:		// Initial fill rule record
				// contain one two byte record. A value of 1 means that 
				// the fill starts with all pixels.
				path->initial_fill = (psd_bool)psd_stream_get_short(context);
				// remains 22 byets
				psd_stream_get_null(context, 22);
				break;
				
			default:
				psd_stream_get_null(context, 24);
				psd_assert(0);
				break;
		}
	}

	path->subpaths = subpaths;
							
	return psd_status_done;
}
Exemple #18
0
psd_status psd_get_layer_color_overlay2(psd_context * context, psd_layer_effects_color_overlay * color_overlay)
{
	psd_int length, number_items;
	psd_uint rootkey, type, key;
	psd_uchar keychar[256];
	
	psd_set_layer_color_overlay_default(color_overlay);

	// Unicode string: name from classID
	length = psd_stream_get_int(context) * 2;
	psd_stream_get_null(context, length);

	// classID: 4 bytes (length), followed either by string or (if length is zero) 4-
	// byte classID
	length = psd_stream_get_int(context);
	if(length == 0)
		psd_stream_get_int(context);
	else
		psd_stream_get_null(context, length);

	// Number of items in descriptor
	number_items = psd_stream_get_int(context);

	while(number_items --)
	{
		length = psd_stream_get_int(context);
		psd_assert(length == 0);
		if(length == 0)
			rootkey = psd_stream_get_int(context);
		else
		{
			rootkey = 0;
			psd_stream_get(context, keychar, length);
			keychar[length] = 0;
		}
		// Type: OSType key
		type = psd_stream_get_int(context);

		switch(rootkey)
		{
			// effect enable
			case 'enab':
				psd_assert(type == 'bool');
				color_overlay->effect_enable = psd_stream_get_bool(context);
				break;

			// blend mode
			case 'Md  ':
				psd_assert(type == 'enum');
				
				// TypeID: 4 bytes (length), followed either by string or (if length is zero) 4-
				// byte typeID
				length = psd_stream_get_int(context);
				psd_assert(length == 0);
				key = psd_stream_get_int(context);
				// blend mode
				psd_assert(key == 'BlnM');
				color_overlay->blend_mode = psd_stream_get_object_blend_mode(context);
				break;

			// opacity
			case 'Opct':
				psd_assert(type == 'UntF');
				// percent
				key = psd_stream_get_int(context);
				psd_assert(key == '#Prc');
				// Actual value (double)
				color_overlay->opacity = (psd_int)(psd_stream_get_double(context) * 2.55 + 0.5);
				break;
				
			// color or native color
			case 'Clr ':
				// Descriptor
				psd_assert(type == 'Objc');
				color_overlay->color = color_overlay->native_color = psd_stream_get_object_color(context);
				break;

			default:
				psd_assert(0);
				break;
		}
	}

	return psd_status_done;
}
Exemple #19
0
// 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;
}
Exemple #20
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;
}
Exemple #21
0
psd_status psd_get_layer_drop_shadow2(psd_context * context, psd_layer_effects_drop_shadow * drop_shadow)
{
	psd_int length, number_items;
	psd_uint rootkey, type, key;
	psd_uchar keychar[256];
	
	psd_set_layer_drop_shadow_default(drop_shadow);

	// Unicode string: name from classID
	length = psd_stream_get_int(context) * 2;
	psd_stream_get_null(context, length);

	// classID: 4 bytes (length), followed either by string or (if length is zero) 4-
	// byte classID
	length = psd_stream_get_int(context);
	if(length == 0)
		psd_stream_get_int(context);
	else
		psd_stream_get_null(context, length);

	// Number of items in descriptor
	number_items = psd_stream_get_int(context);

	while(number_items --)
	{
		length = psd_stream_get_int(context);
		if(length == 0)
			rootkey = psd_stream_get_int(context);
		else
		{
			rootkey = 0;
			psd_stream_get(context, keychar, length);
			keychar[length] = 0;
		}
		// Type: OSType key
		type = psd_stream_get_int(context);

		switch(rootkey)
		{
			case 0:
				// layer knocks out drop shadow
				if(strcmp(keychar, "layerConceals") == 0)
				{
					psd_assert(type == 'bool');
					drop_shadow->knocks_out = psd_stream_get_bool(context);
				}
				else
				{
					psd_assert(0);
				}
				break;
				
			// effect enable
			case 'enab':
				psd_assert(type == 'bool');
				drop_shadow->effect_enable = psd_stream_get_bool(context);
				break;

			// blend mode
			case 'Md  ':
				psd_assert(type == 'enum');
				
				// TypeID: 4 bytes (length), followed either by string or (if length is zero) 4-
				// byte typeID
				length = psd_stream_get_int(context);
				psd_assert(length == 0);
				key = psd_stream_get_int(context);
				// blend mode
				psd_assert(key == 'BlnM');
				drop_shadow->blend_mode = psd_stream_get_object_blend_mode(context);
				break;

			// color or native color
			case 'Clr ':
				// Descriptor
				psd_assert(type == 'Objc');
				drop_shadow->color = drop_shadow->native_color = psd_stream_get_object_color(context);
				break;

			// opacity
			case 'Opct':
				psd_assert(type == 'UntF');
				// percent
				key = psd_stream_get_int(context);
				psd_assert(key == '#Prc');
				// Actual value (double)
				drop_shadow->opacity = (psd_int)(psd_stream_get_double(context) * 2.55 + 0.5);
				break;

			// use global light
			case 'uglg':
				psd_assert(type == 'bool');
				drop_shadow->use_global_light = psd_stream_get_bool(context);
				break;

			// angle
			case 'lagl':
				psd_assert(type == 'UntF');
				// angle: base degrees
				key = psd_stream_get_int(context);
				psd_assert(key == '#Ang');
				drop_shadow->angle = (psd_int)psd_stream_get_double(context);
				break;

			// distance
			case 'Dstn':
				psd_assert(type == 'UntF');
				// pixels: tagged unit value
				key = psd_stream_get_int(context);
				psd_assert(key == '#Pxl');
				drop_shadow->distance = (psd_int)psd_stream_get_double(context);
				break;

			// spread
			case 'Ckmt':
				psd_assert(type == 'UntF');
				// pixels: tagged unit value
				key = psd_stream_get_int(context);
				psd_assert(key == '#Pxl');
				drop_shadow->spread = (psd_int)psd_stream_get_double(context);
				break;

			// size
			case 'blur':
				psd_assert(type == 'UntF');
				// pixels: tagged unit value
				key = psd_stream_get_int(context);
				psd_assert(key == '#Pxl');
				drop_shadow->size = (psd_int)psd_stream_get_double(context);
				break;

			// noise
			case 'Nose':
				psd_assert(type == 'UntF');
				// percent
				key = psd_stream_get_int(context);
				psd_assert(key == '#Prc');
				// Actual value (double)
				drop_shadow->noise = (psd_int)psd_stream_get_double(context);
				break;

			// anti-aliased
			case 'AntA':
				psd_assert(type == 'bool');
				drop_shadow->anti_aliased = psd_stream_get_bool(context);
				break;

			// contour
			case 'TrnS':
				psd_assert(type == 'Objc');
				psd_stream_get_object_contour(drop_shadow->contour_lookup_table, context);
				break;

			default:
				psd_assert(0);
				break;
		}
	}

	return psd_status_done;
}
Exemple #22
0
psd_status psd_get_layer_pattern_overlay2(psd_context * context, psd_layer_effects_pattern_overlay * pattern_overlay)
{
	psd_int length, number_items;
	psd_uint rootkey, type, key;
	psd_uchar keychar[256];
	
	psd_set_layer_pattern_overlay_default(pattern_overlay);

	// Unicode string: name from classID
	length = psd_stream_get_int(context) * 2;
	psd_stream_get_null(context, length);

	// classID: 4 bytes (length), followed either by string or (if length is zero) 4-
	// byte classID
	length = psd_stream_get_int(context);
	if(length == 0)
		psd_stream_get_int(context);
	else
		psd_stream_get_null(context, length);

	// Number of items in descriptor
	number_items = psd_stream_get_int(context);

	while(number_items --)
	{
		length = psd_stream_get_int(context);
		if(length == 0)
			rootkey = psd_stream_get_int(context);
		else
		{
			rootkey = 0;
			psd_stream_get(context, keychar, length);
			keychar[length] = 0;
		}
		// Type: OSType key
		type = psd_stream_get_int(context);

		switch(rootkey)
		{
			case 0:
				if(strcmp(keychar, "phase") == 0)
				{
					psd_assert(type == 'Objc');
					psd_stream_get_object_point(&pattern_overlay->horz_phase, 
						&pattern_overlay->vert_phase, context);
					// problem, why ???
					pattern_overlay->horz_phase = 0;
					pattern_overlay->vert_phase = 0;
				}
				else
				{
					psd_assert(0);
					psd_stream_get_object_null(type, context);
				}
				break;
				
			// effect enable
			case 'enab':
				psd_assert(type == 'bool');
				pattern_overlay->effect_enable = psd_stream_get_bool(context);
				break;

			// blend mode
			case 'Md  ':
				psd_assert(type == 'enum');
				
				// TypeID: 4 bytes (length), followed either by string or (if length is zero) 4-
				// byte typeID
				length = psd_stream_get_int(context);
				psd_assert(length == 0);
				key = psd_stream_get_int(context);
				// Gradient Type
				psd_assert(key == 'BlnM');
				pattern_overlay->blend_mode = psd_stream_get_object_blend_mode(context);
				break;

			// opacity
			case 'Opct':
				psd_assert(type == 'UntF');
				// percent
				key = psd_stream_get_int(context);
				psd_assert(key == '#Prc');
				// Actual value (double)
				pattern_overlay->opacity = (psd_int)(psd_stream_get_double(context) * 2.55 + 0.5);
				break;

			// pattern
			case 'Ptrn':
				psd_assert(type == 'Objc');
				psd_stream_get_object_pattern_info(&pattern_overlay->pattern_info, context);
				break;

			// scale
			case 'Scl ':
				psd_assert(type == 'UntF');
				// percent
				key = psd_stream_get_int(context);
				psd_assert(key == '#Prc');
				// Actual value (double)
				pattern_overlay->scale = (psd_int)psd_stream_get_double(context);
				break;

			// link with layer
			case 'Algn':
				psd_assert(type == 'bool');
				pattern_overlay->link_with_layer = psd_stream_get_bool(context);
				break;

			default:
				psd_assert(0);
				psd_stream_get_object_null(type, context);
				break;
		}
	}
	
	return psd_status_done;
}
Exemple #23
0
psd_status psd_get_layer_gradient_overlay2(psd_context * context, psd_layer_effects_gradient_overlay * gradient_overlay)
{
	psd_int length, number_items;
	psd_uint rootkey, type, key;
	psd_uchar keychar[256];
	
	psd_set_layer_gradient_overlay_default(gradient_overlay);

	// Unicode string: name from classID
	length = psd_stream_get_int(context) * 2;
	psd_stream_get_null(context, length);

	// classID: 4 bytes (length), followed either by string or (if length is zero) 4-
	// byte classID
	length = psd_stream_get_int(context);
	if(length == 0)
		psd_stream_get_int(context);
	else
		psd_stream_get_null(context, length);

	// Number of items in descriptor
	number_items = psd_stream_get_int(context);

	while(number_items --)
	{
		length = psd_stream_get_int(context);
		psd_assert(length == 0);
		if(length == 0)
			rootkey = psd_stream_get_int(context);
		else
		{
			rootkey = 0;
			psd_stream_get(context, keychar, length);
			keychar[length] = 0;
		}
		// Type: OSType key
		type = psd_stream_get_int(context);

		switch(rootkey)
		{
			// effect enable
			case 'enab':
				psd_assert(type == 'bool');
				gradient_overlay->effect_enable = psd_stream_get_bool(context);
				break;

			// blend mode
			case 'Md  ':
				psd_assert(type == 'enum');
				
				// TypeID: 4 bytes (length), followed either by string or (if length is zero) 4-
				// byte typeID
				length = psd_stream_get_int(context);
				psd_assert(length == 0);
				key = psd_stream_get_int(context);
				// blend mode
				psd_assert(key == 'BlnM');
				gradient_overlay->blend_mode = psd_stream_get_object_blend_mode(context);
				break;

			// opacity
			case 'Opct':
				psd_assert(type == 'UntF');
				// percent
				key = psd_stream_get_int(context);
				psd_assert(key == '#Prc');
				// Actual value (double)
				gradient_overlay->opacity = (psd_int)(psd_stream_get_double(context) * 2.55 + 0.5);
				break;
				
			// gradient color
			case 'Grad':
				// Descriptor
				psd_assert(type == 'Objc');
				psd_stream_get_object_gradient_color(&gradient_overlay->gradient_color, context);
				break;

			case 'Angl':	// angle
				// Unit psd_float
				psd_assert(type == 'UntF');
				
				// '#Ang' = angle: base degrees
				key = psd_stream_get_int(context);
				psd_assert(key == '#Ang');

				// Actual value (double)
				gradient_overlay->angle = (psd_int)psd_stream_get_double(context);
				break;

			case 'Type':	// gradient style
				// Enumerated
				psd_assert(type == 'enum');

				// TypeID: 4 bytes (length), followed either by string or (if length is zero) 4-
				// byte typeID
				length = psd_stream_get_int(context);
				psd_assert(length == 0);
				key = psd_stream_get_int(context);
				// Gradient Type
				psd_assert(key == 'GrdT');
				gradient_overlay->style = psd_stream_get_object_gradient_style(context);
				break;

			case 'Rvrs':	// reverse
				// boolean
				psd_assert(type == 'bool');
				gradient_overlay->reverse = psd_stream_get_bool(context);
				break;

			case 'Algn':	// align with layer
				// boolean
				psd_assert(type == 'bool');
				gradient_overlay->align_width_layer = psd_stream_get_bool(context);
				break;

			case 'Scl ':	// scale
				// Unit psd_float
				psd_assert(type == 'UntF');

				// '#Prc' = percent:
				key = psd_stream_get_int(context);
				psd_assert(key == '#Prc');
								
				// Actual value (double)
				gradient_overlay->scale = (psd_int)psd_stream_get_double(context);
				break;

			// offset, not documented
			case 'Ofst':
				psd_assert(type == 'Objc');
				psd_stream_get_object_point(&gradient_overlay->horz_offset, 
					&gradient_overlay->vert_offset, context);
				break;

			default:
				psd_assert(0);
				psd_stream_get_object_null(type, context);
				break;
		}
	}

	return psd_status_done;
}
Exemple #24
0
psd_status psd_get_image_resource(psd_context * context)
{
	psd_int length, i, size;
	psd_ushort ID;
	psd_uint tag;
	psd_uchar sizeofname;
	psd_int sizeofdata, prev_stream_pos;
	psd_uchar * buffer;
	//psd_status status;

	// Length of image resource section
	length = psd_stream_get_int(context);
	if(length <= 0)
		return psd_status_done;

	// default
	context->global_angle = 30;
	context->global_altitude = 30;

	while(length > 0)
	{
		// Signature: '8BIM'
		tag = psd_stream_get_int(context);
		if(tag == '8BIM')
		{
			length -= 4;
			// Unique identifier for the resource
			ID = psd_stream_get_short(context);
			length -= 2;
			// Name: Pascal string, padded to make the size even (a null name consists of two bytes of 0)
			sizeofname = psd_stream_get_char(context);
			if((sizeofname & 0x01) == 0)
				sizeofname ++;
			psd_stream_get_null(context, sizeofname);
			length -= sizeofname + 1;
			// Actual size of resource data that follows
			sizeofdata = psd_stream_get_int(context);
			length -= 4;
			// resource data must be even
			if(sizeofdata & 0x01)
				sizeofdata ++;
			length -= sizeofdata;

			switch(context->load_tag)
			{
				case psd_load_tag_thumbnail:
					if(ID != 1033 && ID != 1036)
					{
						psd_stream_get_null(context, sizeofdata);
						continue;
					}
					break;
				case psd_load_tag_merged:
					// alpha channels information
					if(ID != 1006 && ID != 1045 && ID != 1053)
					{
						psd_stream_get_null(context, sizeofdata);
						continue;
					}
					break;
				case psd_load_tag_exif:
					if(ID != 1058 && ID != 1059)
					{
						psd_stream_get_null(context, sizeofdata);
						continue;
					}
					break;
			}

			prev_stream_pos = context->stream.current_pos;

			if(sizeofdata > 0)
			{
				switch(ID)
				{
					// ResolutionInfo structure
					case 1005:
						// Horizontal resolution in pixels per inch.
						context->resolution_info.hres = psd_stream_get_int(context) / 65536.0f;
						// 1=display horitzontal resolution in pixels per inch; 2=display horitzontal resolution in pixels per cm.
						context->resolution_info.hres_unit = psd_stream_get_short(context);
						// Display width as 1=inches; 2=cm; 3=points; 4=picas; 5=columns.
						context->resolution_info.width_unit = psd_stream_get_short(context);
						// Vertial resolution in pixels per inch.
						context->resolution_info.vres = psd_stream_get_int(context) / 65536.0f;
						// 1=display vertical resolution in pixels per inch; 2=display vertical resolution in pixels per cm.
						context->resolution_info.vres_unit = psd_stream_get_short(context);
						// Display height as 1=inches; 2=cm; 3=points; 4=picas; 5=columns.
						context->resolution_info.height_unit = psd_stream_get_short(context);
						context->fill_resolution_info = psd_true;
						break;

					// Names of the alpha channels as a series of Pascal strings.
					case 1006:
						buffer = (psd_uchar *)psd_malloc(sizeofdata);
						if(buffer == NULL)
							return psd_status_malloc_failed;
						psd_stream_get(context, buffer, sizeofdata);
						if(context->alpha_channels == 0)
						{
							size = 0;
							// maybe odd
							while(size + 1 < sizeofdata)
							{
								size += *(buffer + size) + 1;
								context->alpha_channels ++;
							}
							context->color_channels = context->channels - context->alpha_channels;
							context->alpha_channel_info = (psd_alpha_channel_info *)psd_malloc(context->alpha_channels * sizeof(psd_alpha_channel_info));
							if(context->alpha_channel_info == NULL)
							{
								psd_free(buffer);
								return psd_status_malloc_failed;
							}
							memset(context->alpha_channel_info, 0, context->alpha_channels * sizeof(psd_alpha_channel_info));
						}

						size = 0;
						for(i = 0; i < context->alpha_channels; i ++)
						{
							memcpy(context->alpha_channel_info[i].name, buffer + size + 1, *(buffer + size));
							size += *(buffer + size) + 1;
						}
						psd_free(buffer);
						context->fill_alpha_channel_info = psd_true;
						break;

					// DisplayInfo structure
					case 1007:
						context->display_info.color = psd_stream_get_space_color(context);
						// 0..100
						context->display_info.opacity = psd_stream_get_short(context);
						psd_assert(context->display_info.opacity >= 0 && context->display_info.opacity <= 100);
						// selected = 0, protected = 1
						context->display_info.kind = psd_stream_get_char(context);
						// maybe be 2 when color mode is multichannel
						//psd_assert(context->display_info.kind == 0 || context->display_info.kind == 1);
						// padding
						psd_stream_get_char(context);
						context->fill_display_info = psd_true;
						break;

					// The caption as a Pascal string.
					case 1008:
						size = psd_stream_get_char(context);
						psd_stream_get(context, context->caption, size);
						break;

					// Layer state information
					// 2 bytes containing the index of target layer (0 = bottom layer).
					case 1024:
						context->target_layer_index = psd_stream_get_short(context);
						break;

					// Layers group information
					// 2 bytes per layer containing a group ID for the dragging groups. Layers in
					// a group have the same group ID.
					case 1026:
						context->layer_group_count = sizeofdata / 2;
						context->layer_group_id = (psd_ushort *)psd_malloc(context->layer_group_count * 2);
						if(context->layer_group_id == NULL)
							return psd_status_malloc_failed;
						for(i = 0; i < context->layer_group_count; i ++)
							context->layer_group_id[i] = psd_stream_get_short(context);
						context->fill_layer_group = psd_true;
						break;

					// (Photoshop 4.0) Thumbnail resource for Photoshop 4.0 only
					case 1033:
					// (Photoshop 5.0) Thumbnail resource (supersedes resource 1033)
					case 1036:
						if(context->load_tag == psd_load_tag_layer)
						{
							psd_stream_get_null(context, sizeofdata);
							continue;
						}

						// 1 = kJpegRGB . Also supports kRawRGB (0).
						context->thumbnail_resource.format = psd_stream_get_int(context);
						psd_assert(context->thumbnail_resource.format == 0 || context->thumbnail_resource.format == 1);
						// Width of thumbnail in pixels.
						context->thumbnail_resource.width = psd_stream_get_int(context);
						// Height of thumbnail in pixels.
						context->thumbnail_resource.height = psd_stream_get_int(context);
						// Padded row bytes = (width * bits per pixel + 31) / 32 * 4.
						context->thumbnail_resource.width_bytes = psd_stream_get_int(context);
						// Total size = widthbytes * height * planes
						context->thumbnail_resource.total_size = psd_stream_get_int(context);
						// Used for consistency check.
						context->thumbnail_resource.size_after_compression = psd_stream_get_int(context);
						context->thumbnail_resource.bits_per_pixel = psd_stream_get_short(context);
						// Bits per pixel. = 24
						psd_assert(context->thumbnail_resource.bits_per_pixel == 24);
						context->thumbnail_resource.number_of_planes = psd_stream_get_short(context);
						// Number of planes. = 1
						psd_assert(context->thumbnail_resource.number_of_planes == 1);
#ifdef PSD_INCLUDE_LIBJPEG
						if(context->thumbnail_resource.format == 0)
						{
							status = psd_thumbnail_decode_raw(&context->thumbnail_resource.thumbnail_data, 
								context->thumbnail_resource.size_after_compression, context);
						}
						else
						{
							status = psd_thumbnail_decode_jpeg(&context->thumbnail_resource.thumbnail_data, 
								context->thumbnail_resource.size_after_compression, context);
						}
						if(status != psd_status_done)
							return status;
#else
						context->thumbnail_resource.jfif_data = (psd_uchar *)psd_malloc(sizeofdata - 28);
						if(context->thumbnail_resource.jfif_data == NULL)
							return psd_status_malloc_failed;
						psd_stream_get(context, context->thumbnail_resource.jfif_data, sizeofdata - 28);
#endif
						context->fill_thumbnail_resource = psd_true;
						break;

					// (Photoshop 4.0) Copyright flag
					// Boolean indicating whether image is copyrighted. Can be set via
					// Property suite or by user in File Info...
					case 1034:
						context->copyright_flag = (psd_bool)psd_stream_get_short(context);
						psd_assert(context->copyright_flag == 0 || context->copyright_flag == 1);
						break;

					// (Photoshop 5.0) Global Angle
					// 4 bytes that contain an integer between 0 and 359, which is the global
					// lighting angle for effects layer. If not present, assumed to be 30.
					case 1037:
						context->global_angle = psd_stream_get_int(context);
						break;

					// (Photoshop 5.0) Effects visible
					// 1-byte global flag to show/hide all the effects layer. Only present when
					// they are hidden.
					case 1042:
						context->effects_visible = (psd_bool)psd_stream_get_short(context);
						psd_assert(context->effects_visible == 0 || context->effects_visible == 1);
						break;

					// (Photoshop 5.0) Unicode Alpha Names
					// Unicode string (4 bytes length followed by string).
					case 1045:
						buffer = (psd_uchar *)psd_malloc(sizeofdata);
						if(buffer == NULL)
							return psd_status_malloc_failed;
						psd_stream_get(context, buffer, sizeofdata);
						if(context->alpha_channels == 0)
						{
							size = 0;
							while(size < sizeofdata)
							{
								size += PSD_CHAR_TO_INT(buffer + size) * 2 + 4;
								context->alpha_channels ++;
							}
							context->color_channels = context->channels - context->alpha_channels;
							context->alpha_channel_info = (psd_alpha_channel_info *)psd_malloc(context->alpha_channels * sizeof(psd_alpha_channel_info));
							if(context->alpha_channel_info == NULL)
							{
								psd_free(buffer);
								return psd_status_malloc_failed;
							}
							memset(context->alpha_channel_info, 0, context->alpha_channels * sizeof(psd_alpha_channel_info));
						}

						size = 0;
						for(i = 0; i < context->alpha_channels; i ++)
						{
							context->alpha_channel_info[i].unicode_name_length = PSD_CHAR_TO_INT(buffer + size);
							context->alpha_channel_info[i].unicode_name = (psd_ushort *)psd_malloc(2 * context->alpha_channel_info[i].unicode_name_length);
							if(context->alpha_channel_info[i].unicode_name == NULL)
							{
								psd_free(buffer);
								return psd_status_malloc_failed;
							}
							memcpy(context->alpha_channel_info[i].unicode_name, buffer + size + 4, 2 * context->alpha_channel_info[i].unicode_name_length);
							size += 2 * context->alpha_channel_info[i].unicode_name_length + 4;
						}
						psd_free(buffer);
						context->fill_alpha_channel_info = psd_true;
						break;

					// (Photoshop 6.0) Indexed Color Table Count
					// 2 bytes for the number of colors in table that are actually defined
					case 1046:
						context->indexed_color_table_count = psd_stream_get_short(context);
						break;

					// (Photoshop 6.0) Transparency Index.
					// 2 bytes for the index of transparent color, if any.
					case 1047:
						context->transparency_index = psd_stream_get_short(context);
						break;

					// (Photoshop 6.0) Global Altitude
					// 4 byte entry for altitude
					case 1049:
						context->global_altitude = psd_stream_get_int(context);
						break;

					// (Photoshop 6.0) Alpha Identifiers
					// 4 bytes of length, followed by 4 bytes each for every alpha identifier.
					case 1053:
						if(context->alpha_channels == 0)
						{
							context->alpha_channels = sizeofdata / 4;
							context->color_channels = context->channels - context->alpha_channels;
							context->alpha_channel_info = (psd_alpha_channel_info *)psd_malloc(context->alpha_channels * sizeof(psd_alpha_channel_info));
							if(context->alpha_channel_info == NULL)
								return psd_status_malloc_failed;
							memset(context->alpha_channel_info, 0, context->alpha_channels * sizeof(psd_alpha_channel_info));
						}

						for(i = 0; i < context->alpha_channels; i ++)
						{
							context->alpha_channel_info[i].identifier = psd_stream_get_int(context);
						}
						context->fill_alpha_channel_info = psd_true;
						break;

					// (Photoshop 6.0) Version Info
					// 4 bytes version, 1 byte hasRealMergedData, Unicode string: writer
					// name, Unicode string: reader name, 4 bytes file version.
					case 1057:
						context->version_info.version = psd_stream_get_int(context);
						context->version_info.has_real_merged_data = psd_stream_get_bool(context);
						context->version_info.writer_name_length = psd_stream_get_int(context);
						context->version_info.writer_name = (psd_ushort *)psd_malloc(2 * context->version_info.writer_name_length);
						if(context->version_info.writer_name == NULL)
							return psd_status_malloc_failed;
						psd_stream_get(context, (psd_uchar *)context->version_info.writer_name, 2 * context->version_info.writer_name_length);
						context->version_info.reader_name_length = psd_stream_get_int(context);
						context->version_info.reader_name = (psd_ushort *)psd_malloc(2 * context->version_info.reader_name_length);
						if(context->version_info.reader_name == NULL)
							return psd_status_malloc_failed;
						psd_stream_get(context, (psd_uchar *)context->version_info.reader_name, 2 * context->version_info.reader_name_length);
						context->version_info.file_version = psd_stream_get_int(context);
						context->fill_version_info = psd_true;
						break;

// if you don't need the following image resource,
// you can undef this macro in psd_config.h to reduce the parsing time
/////////////////////////////////////////////////////////////////////////////////////////////
#ifdef PSD_GET_ALL_IMAGE_RESOURCE

					// Border information
					case 1009:
						// a fixed number (2 bytes real, 2 bytes fraction) for the border width
						context->border_info.border_width = psd_fixed_16_16_tofloat((psd_fixed_16_16)psd_stream_get_int(context));
						// 2 bytes for border units (1 = inches, 2 = cm, 3 = points, 4 = picas, 5 = columns).
						context->border_info.border_units = (psd_units)psd_stream_get_short(context);
						psd_assert(context->border_info.border_units >= psd_units_inches && 
							context->border_info.border_units <= psd_units_columns);
						context->fill_border_info = psd_true;
						break;

					// Print flags
					// A series of one-byte boolean values (see Page Setup dialog): labels, crop
					// marks, color bars, registration marks, negative, flip, interpolate, caption,
					// print flags.
					case 1011:
						context->print_flags.labels = psd_stream_get_bool(context);
						context->print_flags.crop_marks = psd_stream_get_bool(context);
						context->print_flags.color_bars = psd_stream_get_bool(context);
						context->print_flags.registration_marks = psd_stream_get_bool(context);
						context->print_flags.negative = psd_stream_get_bool(context);
						context->print_flags.flip = psd_stream_get_bool(context);
						context->print_flags.interpolate = psd_stream_get_bool(context);
						context->print_flags.caption = psd_stream_get_bool(context);
						context->print_flags.print_flags = psd_stream_get_bool(context);
						context->fill_print_flags = psd_true;
						break;

					// (Photoshop 4.0) Grid and guides information
					case 1032:
						// Version ( = 1)
						psd_assert(psd_stream_get_int(context) == 1);
						// Future implementation of document-specific grids (4 bytes horizontal, 4 bytes vertical).
						context->grid_guides.horz_grid = psd_stream_get_int(context);
						context->grid_guides.vert_grid = psd_stream_get_int(context);
						// Number of guide resource blocks (can be 0).
						context->grid_guides.guide_count = psd_stream_get_int(context);
						if(context->grid_guides.guide_count > 0)
						{
							//Location of guide in document coordinates. Since the guide is either vertical or horizontal, this only has to be one component of the coordinate.
							context->grid_guides.guide_coordinate = (psd_int *)psd_malloc(context->grid_guides.guide_count * 4);
							// Direction of guide. VHSelect is a system type of psd_uchar where 0 = vertical, 1 = horizontal.
							context->grid_guides.guide_direction = (psd_uchar *)psd_malloc(context->grid_guides.guide_count);
							if(context->grid_guides.guide_coordinate == NULL ||
								context->grid_guides.guide_direction == NULL)
							{
								psd_free(context->grid_guides.guide_coordinate);
								context->grid_guides.guide_coordinate = NULL;
								psd_free(context->grid_guides.guide_direction);
								context->grid_guides.guide_direction = NULL;
								return psd_status_malloc_failed;
							}
							for(i = 0; i < context->grid_guides.guide_count; i ++)
							{
								context->grid_guides.guide_coordinate[i] = psd_stream_get_int(context);
								context->grid_guides.guide_direction[i] = psd_stream_get_char(context);
							}
						}
						context->fill_grid_and_guides_info = psd_true;
						break;

					// (Photoshop 5.0) Color samplers resource
					case 1038:
						// Version ( = 1)
						psd_assert(psd_stream_get_int(context) == 1);
						// Number of color samplers to follow.
						context->color_samplers.number_of_color_samplers = psd_stream_get_int(context);
						if (context->color_samplers.number_of_color_samplers > 0)
						{
							context->color_samplers.resource = (psd_color_samplers_resource *)
								psd_malloc(sizeof(psd_color_samplers_resource) * context->color_samplers.number_of_color_samplers);
							if (context->color_samplers.resource == NULL)
								return psd_status_malloc_failed;
							for (i = 0; i < context->color_samplers.number_of_color_samplers; i ++)
							{
								// The vertical and horizontal position of the point (4 bytes each).
								context->color_samplers.resource[i].vertical_position = psd_stream_get_int(context);
								context->color_samplers.resource[i].horizontal_position = psd_stream_get_int(context);
								// Color Space
								context->color_samplers.resource[i].color_space = psd_stream_get_short(context);
							}
						}
						context->fill_color_samplers = psd_true;
						break;
						
					// (Photoshop 6.0) Slices
					case 1050:
						// Version ( = 6)
						psd_assert(psd_stream_get_int(context) == 6);
						// Bounding rectangle for all of the slices: top, left, bottom, right of all the slices
						context->slices_resource.bounding_top = psd_stream_get_int(context);
						context->slices_resource.bounding_left = psd_stream_get_int(context);
						context->slices_resource.bounding_bottom = psd_stream_get_int(context);
						context->slices_resource.bounding_right = psd_stream_get_int(context);
						// Name of group of slices: Unicode string
						size = psd_stream_get_int(context) * 2;
						psd_stream_get_null(context, size);
						// Number of slices to follow
						context->slices_resource.number_of_slices = psd_stream_get_int(context);
						context->slices_resource.slices_resource_block = (psd_slices_resource_block *)psd_malloc(context->slices_resource.number_of_slices * sizeof(psd_slices_resource_block));
						if(context->slices_resource.slices_resource_block == NULL)
							return psd_status_malloc_failed;
						memset(context->slices_resource.slices_resource_block, 0, context->slices_resource.number_of_slices * sizeof(psd_slices_resource_block));
						for(i = 0; i < context->slices_resource.number_of_slices; i ++)
						{
							context->slices_resource.slices_resource_block[i].id = psd_stream_get_int(context);
							context->slices_resource.slices_resource_block[i].group_id = psd_stream_get_int(context);
							context->slices_resource.slices_resource_block[i].origin = psd_stream_get_int(context);
							// NOTE: Only present if Origin = 1
							if(context->slices_resource.slices_resource_block[i].origin == 1)
								context->slices_resource.slices_resource_block[i].associated_layer_id = psd_stream_get_int(context);
							// Name: Unicode string
							size = psd_stream_get_int(context) * 2;
							psd_stream_get_null(context, size);
							context->slices_resource.slices_resource_block[i].type = psd_stream_get_int(context);
							context->slices_resource.slices_resource_block[i].left = psd_stream_get_int(context);
							context->slices_resource.slices_resource_block[i].top = psd_stream_get_int(context);
							context->slices_resource.slices_resource_block[i].right = psd_stream_get_int(context);
							context->slices_resource.slices_resource_block[i].bottom = psd_stream_get_int(context);
							// URL: Unicode string
							size = psd_stream_get_int(context) * 2;
							psd_stream_get_null(context, size);
							// Target: Unicode string
							size = psd_stream_get_int(context) * 2;
							psd_stream_get_null(context, size);
							// Message: Unicode string
							size = psd_stream_get_int(context) * 2;
							psd_stream_get_null(context, size);
							// Alt Tag: Unicode string
							size = psd_stream_get_int(context) * 2;
							psd_stream_get_null(context, size);
							context->slices_resource.slices_resource_block[i].cell_text_is_html = psd_stream_get_char(context);
							// Cell text: Unicode string
							size = psd_stream_get_int(context) * 2;
							psd_stream_get_null(context, size);
							context->slices_resource.slices_resource_block[i].horizontal_alignment = psd_stream_get_int(context);
							context->slices_resource.slices_resource_block[i].veritcal_alignment = psd_stream_get_int(context);
							context->slices_resource.slices_resource_block[i].color = psd_argb_to_color(psd_stream_get_char(context), 
								psd_stream_get_char(context), psd_stream_get_char(context), psd_stream_get_char(context));
						}
						context->fill_slices_resource = psd_true;
						break;

					// (Photoshop 6.0) URL List
					case 1054:
						// 4 byte count of URLs
						context->url_list.number_of_urls = psd_stream_get_int(context);
						if (context->url_list.number_of_urls > 0)
						{
							context->url_list.items = (psd_url_list_item *)psd_malloc(sizeof(psd_url_list_item) *
								context->url_list.number_of_urls);
							if (context->url_list.items == NULL)
								return psd_status_malloc_failed;
							memset(context->url_list.items, 0, sizeof(psd_url_list_item) * context->url_list.number_of_urls);
						}
						for (i = 0; i < context->url_list.number_of_urls; i ++)
						{
							// followed by 4 byte long
							context->url_list.items[i].tag = psd_stream_get_int(context);
							// 4 byte ID
							context->url_list.items[i].ID = psd_stream_get_int(context);
							// Unicode string for each count.
							context->url_list.items[i].name_length = psd_stream_get_int(context);
							context->url_list.items[i].name = (psd_ushort *)psd_malloc(2 * context->url_list.items[i].name_length);
							if (context->url_list.items[i].name == NULL)
								return psd_status_malloc_failed;
							psd_stream_get(context, (psd_uchar *)context->url_list.items[i].name, 
								2 * context->url_list.items[i].name_length);
						}
						context->fill_url_list = psd_true;
						break;

					// (Photoshop 7.0) EXIF data 1
					case 1058:
					// (Photoshop 7.0) EXIF data 3
					// http://www.pima.net/standards/it10/PIMA15740/exif.htm
					case 1059:
						// avoid to get the exif data for twice
						psd_assert(context->fill_exif_data == psd_false);
#	ifdef PSD_INCLUDDE_LIBEXIF
						buffer = (psd_uchar *)psd_malloc(sizeofdata + sizeof(ExifHeader));
						if (buffer == NULL)
							return psd_status_malloc_failed;
						psd_stream_get(context, buffer + sizeof(ExifHeader), sizeofdata);
						memcpy(buffer, ExifHeader, sizeof(ExifHeader));
						context->exif_data = (psd_uchar *)exif_data_new_from_data(buffer, sizeofdata + sizeof(ExifHeader));
						psd_free(buffer);
						context->fill_exif_data = psd_true;
#	else // ifdef PSD_INCLUDDE_LIBEXIF
						context->exif_data = (psd_uchar *)psd_malloc(sizeofdata);
						if (context->exif_data == NULL)
							return psd_status_malloc_failed;
						psd_stream_get(context, context->exif_data, sizeofdata);
						context->exif_data_length = sizeofdata;
						context->fill_exif_data = psd_true;
#	endif // ifdef PSD_INCLUDDE_LIBEXIF
						break;
						
					// (Photoshop 7.0) XMP metadata
					// File info as XML description
					// http://Partners.adobe.com/asn/developer/xmp/main.html
					case 1060:
#	ifdef PSD_INCLUDE_LIBXML
						buffer = (psd_uchar *)psd_malloc(sizeofdata);
						if (buffer == NULL)
							return psd_status_malloc_failed;
						psd_stream_get(context, buffer, sizeofdata);
						context->XMP_metadata = (psd_uchar *)xmlParseMemory(buffer, sizeofdata);
						psd_free(buffer);
						context->fill_XMP_metadata = psd_true;
#	else // ifdef PSD_INCLUDE_LIBXML
						context->XMP_metadata = (psd_uchar *)psd_malloc(sizeofdata);
						if (context->XMP_metadata == NULL)
							return psd_status_malloc_failed;
						psd_stream_get(context, context->XMP_metadata, sizeofdata);
						context->XMP_metadata_length = sizeofdata;
						context->fill_XMP_metadata = psd_true;
#	endif // ifdef PSD_INCLUDE_LIBXML
						break;

					// (Photoshop 7.0) Print scale
					case 1062:
						// 2 bytes style (0 = centered, 1 = size to fit, 2 = user defined).
						context->print_scale.style = psd_stream_get_short(context);
						psd_assert(context->print_scale.style >= psd_print_centered &&
							context->print_scale.style <= psd_print_user_defined);
						// 4 bytes x location (floating point).
						context->print_scale.x_location = psd_stream_get_float(context);
						// 4 bytes y location (floating point).
						context->print_scale.y_location = psd_stream_get_float(context);
						// 4 bytes scale (floating point)
						context->print_scale.scale = psd_stream_get_float(context);
						context->fill_print_scale = psd_true;
						break;

					// (Photoshop CS) Pixel Aspect Ratio
					case 1064:
						// 4 bytes (version = 1)
						psd_assert(psd_stream_get_int(context) == 1);
						// 8 bytes double, x / y of a pixel
						context->pixel_aspect_ratio = psd_stream_get_double(context);
						break;

					// Print flags information
					case 10000:
						// 2 bytes version ( = 1)
						psd_assert(psd_stream_get_short(context) == 1);
						// 1 byte center crop marks
						context->print_flags_info.center_crop = psd_stream_get_bool(context);
						// 1 byte ( = 0)
						psd_assert(psd_stream_get_char(context) == 0);
						// 4 bytes bleed width value
						context->print_flags_info.value = psd_stream_get_int(context);
						// 2 bytes bleed width scale
						context->print_flags_info.scale = psd_stream_get_short(context);
						context->fill_print_flags_info = psd_true;
						break;
						
#endif // ifdef PSD_GET_ALL_IMAGE_RESOURCE
/////////////////////////////////////////////////////////////////////////////////////////////

					default:
#ifdef PSD_GET_PATH_RESOURCE
						// Photoshop stores its paths as resources of type 8BIM, with IDs in the range 2000
						// through 2998.
						if(ID >= 2000 && ID <= 2998)
						{
							psd_get_path(context, sizeofdata);
						}
						// If the file contains a resource of type 8BIM with an ID of 2999, then this resource
						// contains a Pascal¨Cstyle string containing the name of the clipping path to use with this
						// image when saving it as an EPS file???
						else if(ID == 2999)
						{
							// we don't find any files includes the name of the clipping path.
							psd_assert(0);
						}
						else
#endif // ifdef PSD_GET_PATH_RESOURCE
						{
							psd_stream_get_null(context, sizeofdata);
						}
						break;
				}
				
				// Filler
				psd_stream_get_null(context, prev_stream_pos + sizeofdata - context->stream.current_pos);
			}
		}
		else
		{
			return psd_status_resource_signature_error;
		}
	}

	return psd_status_done;
}