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

1315 lines
36 KiB
C

/**
* libpsd - Photoshop file formats (*.psd) decode library
* Copyright (C) 2004-2007 Graphest Software.
*
* libpsd is the legal property of its developers, whose names are too numerous
* to list here. Please refer to the COPYRIGHT file distributed with this
* source distribution.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* $Id: descriptor.c, created by Patrick in 2006.06.18, libpsd@graphest.com Exp $
*/
#include <math.h>
#include "libpsd.h"
#include "psd_system.h"
#include "psd_descriptor.h"
#include "psd_stream.h"
#include "psd_color.h"
#include "psd_math.h"
typedef psd_double psd_matrix[4][4];
static psd_matrix psd_basis_matrix =
{
{ -0.5, 1.5, -1.5, 0.5 },
{ 1.0, -2.5, 2.0, -0.5 },
{ -0.5, 0.0, 0.5, 0.0 },
{ 0.0, 1.0, 0.0, 0.0 },
};
/* this can be adjusted to give a finer or coarser curve */
#define PSD_CURVES_SUBDIVIDE 512
psd_static void psd_stream_get_object_list(psd_context * context);
psd_static void psd_stream_get_unicode_name(psd_context * context)
{
psd_int length;
length = psd_stream_get_int(context) * 2;
psd_stream_get_null(context, length);
}
psd_static void psd_stream_get_object_id(psd_context * context)
{
psd_int length;
length = psd_stream_get_int(context);
if(length == 0)
psd_stream_get_int(context);
else
psd_stream_get_null(context, length);
}
// 'obj ' = Reference
psd_static void psd_stream_get_object_reference(psd_context * context)
{
psd_uint type;
psd_int number_items;
// Number of items
number_items = psd_stream_get_int(context);
while(number_items --)
{
// OSType key for type to use
type = psd_stream_get_int(context);
switch(type)
{
// 'prop' = Property
case 'prop':
// Unicode string: name from classID
psd_stream_get_unicode_name(context);
// classID: 4 bytes (length), followed either by string or (if length is zero) 4-
// byte classID
psd_stream_get_object_id(context);
// KeyID: 4 bytes (length), followed either by string or (if length is zero) 4-
// byte keyID
psd_stream_get_object_id(context);
break;
// 'Clss' = Class
case 'Clss':
// Unicode string: name from classID
psd_stream_get_unicode_name(context);
// classID: 4 bytes (length), followed either by string or (if length is zero) 4-
// byte classID
psd_stream_get_object_id(context);
break;
// 'Enmr' = Enumerated Reference
case 'Enmr':
// Unicode string: name from classID
psd_stream_get_unicode_name(context);
// classID: 4 bytes (length), followed either by string or (if length is zero) 4-
// byte classID
psd_stream_get_object_id(context);
// TypeID: 4 bytes (length), followed either by string or (if length is zero) 4-
// byte typeID
psd_stream_get_object_id(context);
// enum: 4 bytes (length), followed either by string or (if length is zero) 4-
// byte enum
psd_stream_get_object_id(context);
break;
// 'rele' = Offset
case 'rele':
// Unicode string: name from classID
psd_stream_get_unicode_name(context);
// classID: 4 bytes (length), followed either by string or (if length is zero) 4-
// byte classID
psd_stream_get_object_id(context);
// Value of the offset
psd_stream_get_int(context);
break;
// 'Idnt' = Identifier
case 'Idnt':
psd_stream_get_int(context);
break;
// 'indx' = Index
case 'indx':
psd_stream_get_int(context);
break;
// 'name' =Name
case 'name':
psd_stream_get_unicode_name(context);
break;
default:
psd_assert(0);
break;
}
}
}
// 'doub' = Double
psd_static void psd_stream_get_object_double(psd_context * context)
{
// Actual value (double)
psd_stream_get_null(context, 8);
}
// 'UntF' = Unit psd_float
psd_static void psd_stream_get_object_unit_float(psd_context * context)
{
// Units the following value is in
psd_stream_get_int(context);
// Actual value (double)
psd_stream_get_null(context, 8);
}
// 'TEXT' = String
psd_static void psd_stream_get_object_string(psd_context * context)
{
psd_stream_get_unicode_name(context);
}
// 'enum'= Enumerated
psd_static void psd_stream_get_object_enumerated(psd_context * context)
{
// TypeID: 4 bytes (length), followed either by string or (if length is zero) 4-
// byte typeID
psd_stream_get_object_id(context);
// enum: 4 bytes (length), followed either by string or (if length is zero) 4-
// byte enum
psd_stream_get_object_id(context);
}
// 'long' = Integer
psd_static void psd_stream_get_object_integer(psd_context * context)
{
// Value
psd_stream_get_int(context);
}
// 'bool' = Boolean
psd_static void psd_stream_get_object_boolean(psd_context * context)
{
// Boolean value
psd_stream_get_char(context);
}
// 'type' or GlbC'= Class
psd_static void psd_stream_get_object_class(psd_context * context)
{
// Unicode string: name from classID
psd_stream_get_unicode_name(context);
// classID: 4 bytes (length), followed either by string or (if length is zero) 4-
// byte classID
psd_stream_get_object_id(context);
}
// 'alis' = Alias
psd_static void psd_stream_get_object_alias(psd_context * context)
{
psd_int length;
// Length of data to follow
length = psd_stream_get_int(context);
// FSSpec for Macintosh or a handle to a string to the full path on Windows
psd_stream_get_null(context, length);
}
// 'Objc' = Descriptor
psd_static void psd_stream_get_object_descriptor(psd_context * context)
{
psd_uint type;
psd_int length, number_items;
// Unicode string: name from classID
psd_stream_get_unicode_name(context);
// classID: 4 bytes (length), followed either by string or (if length is zero) 4-
// byte classID
psd_stream_get_object_id(context);
// Number of items in descriptor
number_items = psd_stream_get_int(context);
while(number_items --)
{
// Key: 4 bytes ( length) followed either by string or (if length is zero) 4-byte
// key
length = psd_stream_get_int(context);
if(length == 0)
psd_stream_get_int(context);
else
psd_stream_get_null(context, length);
// Type: OSType key
type = psd_stream_get_int(context);
switch(type)
{
case 'obj ':
psd_stream_get_object_reference(context);
break;
case 'Objc':
case 'GlbO': // GlobalObject same as Descriptor
psd_stream_get_object_descriptor(context);
break;
case 'VlLs':
psd_stream_get_object_list(context);
break;
case 'doub':
psd_stream_get_object_double(context);
break;
case 'UntF':
psd_stream_get_object_unit_float(context);
break;
case 'TEXT':
psd_stream_get_object_string(context);
break;
case 'enum':
psd_stream_get_object_enumerated(context);
break;
case 'long':
psd_stream_get_object_integer(context);
break;
case 'bool':
psd_stream_get_object_boolean(context);
break;
case 'type':
case 'GlbC': // 'type' or 'GlbC'= Class
psd_stream_get_object_class(context);
break;
case 'alis':
psd_stream_get_object_alias(context);
break;
default:
psd_assert(0);
break;
}
}
}
// 'VlLs' = List
psd_static void psd_stream_get_object_list(psd_context * context)
{
psd_uint type;
psd_int number_items;
// Number of items in the list
number_items = psd_stream_get_int(context);
while(number_items --)
{
// OSType key for type to use.
type = psd_stream_get_int(context);
switch(type)
{
case 'obj ':
psd_stream_get_object_reference(context);
break;
case 'Objc':
case 'GlbO': // GlobalObject same as Descriptor
psd_stream_get_object_descriptor(context);
break;
case 'VlLs':
psd_stream_get_object_list(context);
break;
case 'doub':
psd_stream_get_object_double(context);
break;
case 'UntF':
psd_stream_get_object_unit_float(context);
break;
case 'TEXT':
psd_stream_get_object_string(context);
break;
case 'enum':
psd_stream_get_object_enumerated(context);
break;
case 'long':
psd_stream_get_object_integer(context);
break;
case 'bool':
psd_stream_get_object_boolean(context);
break;
case 'type':
case 'GlbC': // 'type' or 'GlbC'= Class
psd_stream_get_object_class(context);
break;
case 'alis':
psd_stream_get_object_alias(context);
break;
default:
psd_assert(0);
break;
}
}
}
void psd_stream_get_object_null(psd_uint type, psd_context * context)
{
switch(type)
{
case 'obj ':
psd_stream_get_object_reference(context);
break;
case 'Objc':
case 'GlbO': // GlobalObject same as Descriptor
psd_stream_get_object_descriptor(context);
break;
case 'VlLs':
psd_stream_get_object_list(context);
break;
case 'doub':
psd_stream_get_object_double(context);
break;
case 'UntF':
psd_stream_get_object_unit_float(context);
break;
case 'TEXT':
psd_stream_get_object_string(context);
break;
case 'enum':
psd_stream_get_object_enumerated(context);
break;
case 'long':
psd_stream_get_object_integer(context);
break;
case 'bool':
psd_stream_get_object_boolean(context);
break;
case 'type':
case 'GlbC': // 'type' or 'GlbC'= Class
psd_stream_get_object_class(context);
break;
case 'alis':
psd_stream_get_object_alias(context);
break;
default:
psd_assert(0);
break;
}
}
psd_argb_color psd_stream_get_object_color(psd_context * context)
{
psd_uint key;
psd_int length, number_colors;
psd_int red, green, blue;
// 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);
key = psd_stream_get_int(context);
// rgb color
psd_assert(key == 'RGBC');
// Number of color component
number_colors = psd_stream_get_int(context);
// must be 3
psd_assert(number_colors == 3);
// 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);
// red component
psd_assert(key == 'Rd ');
// Type: OSType key
key = psd_stream_get_int(context);
// Double
psd_assert(key == 'doub');
// Actual value (double)
red = (psd_int)psd_stream_get_double(context);
// 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);
// green component
psd_assert(key == 'Grn ');
// Type: OSType key
key = psd_stream_get_int(context);
// Double
psd_assert(key == 'doub');
// Actual value (double)
green = (psd_int)psd_stream_get_double(context);
// 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);
// blue component
psd_assert(key == 'Bl ');
// Type: OSType key
key = psd_stream_get_int(context);
// Double
psd_assert(key == 'doub');
// Actual value (double)
blue = (psd_int)psd_stream_get_double(context);
return psd_rgb_to_color((unsigned char)(red), (unsigned char)(green), (unsigned char)(blue));
}
psd_static void psd_contour_compose(psd_matrix a, psd_matrix b, psd_matrix ab)
{
psd_int i, j;
for (i = 0; i < 4; i++)
{
for (j = 0; j < 4; j++)
{
ab[i][j] = (a[i][0] * b[0][j] +
a[i][1] * b[1][j] +
a[i][2] * b[2][j] +
a[i][3] * b[3][j]);
}
}
}
psd_static void psd_contour_plot(psd_uchar * table,
psd_uchar * input_value, psd_uchar * output_value, psd_bool * corner,
psd_int p1, psd_int p2, psd_int p3, psd_int p4)
{
psd_matrix geometry;
psd_matrix tmp1, tmp2;
psd_matrix deltas;
psd_double x, dx, dx2, dx3;
psd_double y, dy, dy2, dy3;
psd_double d, d2, d3;
psd_int lastx, lasty;
psd_int newx, newy;
psd_int i;
if(corner[p2] == psd_true)
p1 = p2;
if(corner[p3] == psd_true)
p4 = p3;
/* construct the geometry matrix from the segment */
for (i = 0; i < 4; i++)
{
geometry[i][2] = 0;
geometry[i][3] = 0;
}
geometry[0][0] = input_value[p1];
geometry[1][0] = input_value[p2];
geometry[2][0] = input_value[p3];
geometry[3][0] = input_value[p4];
geometry[0][1] = output_value[p1];
geometry[1][1] = output_value[p2];
geometry[2][1] = output_value[p3];
geometry[3][1] = output_value[p4];
/* subdivide the curve */
d = 1.0 / PSD_CURVES_SUBDIVIDE;
d2 = d * d;
d3 = d * d * d;
/* construct a temporary matrix for determining the forward
* differencing deltas
*/
tmp2[0][0] = 0; tmp2[0][1] = 0; tmp2[0][2] = 0; tmp2[0][3] = 1;
tmp2[1][0] = d3; tmp2[1][1] = d2; tmp2[1][2] = d; tmp2[1][3] = 0;
tmp2[2][0] = 6 * d3; tmp2[2][1] = 2 * d2; tmp2[2][2] = 0; tmp2[2][3] = 0;
tmp2[3][0] = 6 * d3; tmp2[3][1] = 0; tmp2[3][2] = 0; tmp2[3][3] = 0;
/* compose the basis and geometry matrices */
psd_contour_compose (psd_basis_matrix, geometry, tmp1);
/* compose the above results to get the deltas matrix */
psd_contour_compose (tmp2, tmp1, deltas);
/* extract the x deltas */
x = deltas[0][0];
dx = deltas[1][0];
dx2 = deltas[2][0];
dx3 = deltas[3][0];
/* extract the y deltas */
y = deltas[0][1];
dy = deltas[1][1];
dy2 = deltas[2][1];
dy3 = deltas[3][1];
lastx = (psd_int)PSD_CONSTRAIN(x, 0, 255);
lasty = (psd_int)PSD_CONSTRAIN(y, 0, 255);
table[lastx] = lasty;
/* loop over the curve */
for (i = 0; i < PSD_CURVES_SUBDIVIDE; i++)
{
/* increment the x values */
x += dx;
dx += dx2;
dx2 += dx3;
/* increment the y values */
y += dy;
dy += dy2;
dy2 += dy3;
newx = (psd_int)(x + 0.5);
newx = PSD_CONSTRAIN(newx, 0, 255);
newy = (psd_int)(y + 0.5);
newy = PSD_CONSTRAIN(newy, 0, 255);
/* if this point is different than the last one...then draw it */
if ((lastx != newx) || (lasty != newy))
table[newx] = newy;
lastx = newx;
lasty = newy;
}
}
psd_static void psd_contour_calculate_table(psd_uchar * lookup_table, psd_int number_point,
psd_uchar * input_value, psd_uchar * output_value, psd_bool * corner)
{
psd_int i, x, y;
psd_int p1, p2, p3, p4;
/* Initialize boundary curve points */
for(i = 0; i < input_value[0]; i ++)
lookup_table[i] = output_value[0];
for(i = input_value[number_point - 1]; i < 256; i ++)
lookup_table[i] = output_value[number_point - 1];
for(i = 0; i < number_point - 1; i ++)
{
p1 = (i == 0) ? i : i - 1;
p2 = i;
p3 = i + 1;
p4 = (i == (number_point - 2)) ? number_point - 1 : i + 2;
psd_contour_plot(lookup_table, input_value, output_value, corner, p1, p2, p3, p4);
}
/* ensure that the control points are used exactly */
for (i = 0; i < number_point; i++)
{
x = input_value[i];
y = output_value[i];
lookup_table[x] = y;
}
}
void psd_stream_get_object_contour(psd_uchar * lookup_table, psd_context * context)
{
psd_uchar input_value[256], output_value[256];
psd_bool corner[256];
psd_uint key, type;
psd_int i, length, number_item, number_point, number_param;
// 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);
key = psd_stream_get_int(context);
// shape contour
psd_assert(key == 'ShpC');
// Number of items in descriptor
number_item = psd_stream_get_int(context);
if(number_item == 2)
{
length = psd_stream_get_int(context);
psd_assert(length == 0);
key = psd_stream_get_int(context);
// name of contour
psd_assert(key == 'Nm ');
type = psd_stream_get_int(context);
psd_assert(type == 'TEXT');
length = psd_stream_get_int(context) * 2;
psd_stream_get_null(context, length);
}
length = psd_stream_get_int(context);
psd_assert(length == 0);
key = psd_stream_get_int(context);
// curve
psd_assert(key == 'Crv ');
type = psd_stream_get_int(context);
// list
psd_assert(type == 'VlLs');
// Number of items in the list
number_point = psd_stream_get_int(context);
for(i = 0; i < number_point; i ++)
{
type = psd_stream_get_int(context);
psd_assert(type == 'Objc');
length = psd_stream_get_int(context) * 2;
psd_stream_get_null(context, length);
length = psd_stream_get_int(context);
psd_assert(length == 0);
key = psd_stream_get_int(context);
// curve point
psd_assert(key == 'CrPt');
// set default value
input_value[i] = output_value[i] = 0;
corner[i] = psd_false;
number_param = psd_stream_get_int(context);
while(number_param --)
{
length = psd_stream_get_int(context);
psd_assert(length == 0);
key = psd_stream_get_int(context);
type = psd_stream_get_int(context);
switch(key)
{
// horizontal coordinate
case 'Hrzn':
psd_assert(type == 'doub');
input_value[i] = (psd_int)psd_stream_get_double(context);
break;
// vertical coordinate
case 'Vrtc':
psd_assert(type == 'doub');
output_value[i] = (psd_int)psd_stream_get_double(context);
break;
// point corner
case 'Cnty':
psd_assert(type == 'bool');
corner[i] = psd_true - psd_stream_get_bool(context);
break;
default:
psd_assert(0);
psd_stream_get_object_null(type, context);
break;
}
}
}
psd_contour_calculate_table(lookup_table, number_point,
input_value, output_value, corner);
}
psd_blend_mode psd_stream_get_object_blend_mode(psd_context * context)
{
psd_blend_mode blend_mode = psd_blend_mode_normal;
psd_int length;
psd_uint tag;
psd_uchar keychar[256];
length = psd_stream_get_int(context);
if(length == 0)
{
tag = psd_stream_get_int(context);
switch(tag)
{
case 'Nrml':
blend_mode = psd_blend_mode_normal;
break;
case 'Dslv':
blend_mode = psd_blend_mode_dissolve;
break;
case 'Drkn':
blend_mode = psd_blend_mode_darken;
break;
case 'Mltp':
blend_mode = psd_blend_mode_multiply;
break;
case 'CBrn':
blend_mode = psd_blend_mode_color_burn;
break;
case 'Lghn':
blend_mode = psd_blend_mode_lighten;
break;
case 'Scrn':
blend_mode = psd_blend_mode_screen;
break;
case 'CDdg':
blend_mode = psd_blend_mode_color_dodge;
break;
case 'Ovrl':
blend_mode = psd_blend_mode_overlay;
break;
case 'SftL':
blend_mode = psd_blend_mode_soft_light;
break;
case 'HrdL':
blend_mode = psd_blend_mode_hard_light;
break;
case 'Dfrn':
blend_mode = psd_blend_mode_difference;
break;
case 'Xclu':
blend_mode = psd_blend_mode_exclusion;
break;
case 'H ':
blend_mode = psd_blend_mode_hue;
break;
case 'Strt':
blend_mode = psd_blend_mode_saturation;
break;
case 'Clr ':
blend_mode = psd_blend_mode_color;
break;
case 'Lmns':
blend_mode = psd_blend_mode_luminosity;
break;
default:
psd_assert(0);
break;
}
}
else
{
psd_stream_get(context, keychar, length);
keychar[length] = 0;
if(strcmp(keychar, "linearBurn") == 0)
blend_mode = psd_blend_mode_linear_burn;
else if(strcmp(keychar, "linearDodge") == 0)
blend_mode = psd_blend_mode_linear_dodge;
else if(strcmp(keychar, "vividLight") == 0)
blend_mode = psd_blend_mode_vivid_light;
else if(strcmp(keychar, "linearLight") == 0)
blend_mode = psd_blend_mode_linear_light;
else if(strcmp(keychar, "pinLight") == 0)
blend_mode = psd_blend_mode_pin_light;
else if(strcmp(keychar, "hardMix") == 0)
blend_mode = psd_blend_mode_hard_mix;
else
psd_assert(0);
}
return blend_mode;
}
psd_technique_type psd_stream_get_object_technique(psd_context * context)
{
psd_technique_type technique_type = psd_technique_softer;
psd_uint tag;
psd_int length;
length = psd_stream_get_int(context);
if(length == 0)
{
tag = psd_stream_get_int(context);
switch(tag)
{
case 'SfBL':
technique_type = psd_technique_softer;
break;
case 'PrBL':
technique_type = psd_technique_precise;
break;
case 'Slmt':
technique_type = psd_technique_slope_limit;
break;
default:
psd_assert(0);
break;
}
}
return technique_type;
}
psd_gradient_style psd_stream_get_object_gradient_style(psd_context * context)
{
psd_gradient_style style = psd_gradient_style_linear;
psd_int length;
psd_uint tag;
// enum: 4 bytes (length), followed either by string or (if length is zero) 4-
// byte enum
length = psd_stream_get_int(context);
psd_assert(length == 0);
tag = psd_stream_get_int(context);
switch(tag)
{
case 'Lnr ':
style = psd_gradient_style_linear;
break;
case 'Rdl ':
style = psd_gradient_style_radial;
break;
case 'Angl':
style = psd_gradient_style_angle;
break;
case 'Rflc':
style = psd_gradient_style_reflected;
break;
case 'Dmnd':
style = psd_gradient_style_diamond;
break;
default:
psd_assert(0);
break;
}
return style;
}
void psd_stream_get_object_gradient_color(psd_gradient_color * gradient_color, psd_context * context)
{
psd_int i, length, number_items, number_lists, number_data;
psd_uint key, rootkey, type;
psd_uchar keychar[256];
// 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);
key = psd_stream_get_int(context);
// Gradient
psd_assert(key == 'Grdn');
// 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)
{
case 'Nm ': // name
// String
psd_assert(type == 'TEXT');
// String value as Unicode string
gradient_color->name_length = psd_stream_get_int(context);
gradient_color->name = (psd_ushort *)psd_malloc(2 * gradient_color->name_length);
if(gradient_color->name == NULL)
return;
memset(gradient_color->name, 0, 2 * gradient_color->name_length);
psd_stream_get(context, (psd_uchar *)gradient_color->name, 2 * gradient_color->name_length);
break;
case 'GrdF': // gradient custom
// 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 == 'GrdF');
// enum: 4 bytes (length), followed either by string or (if length is zero) 4-
// byte enum
length = psd_stream_get_int(context);
psd_assert(length == 0);
key = psd_stream_get_int(context);
psd_assert(key == 'CstS');
break;
case 'Intr': // smoothness
// double
psd_assert(type == 'doub');
// for Interpolation ?
gradient_color->smoothness = (psd_int)psd_stream_get_double(context);
break;
case 'Clrs': // color stop
// value list
psd_assert(type == 'VlLs');
number_lists = psd_stream_get_int(context);
// Number of color stops
gradient_color->number_color_stops = number_lists;
gradient_color->color_stop = (psd_gradient_color_stop *)psd_malloc(
gradient_color->number_color_stops * sizeof(psd_gradient_color_stop));
if(gradient_color->color_stop == NULL)
return;
memset(gradient_color->color_stop, 0, gradient_color->number_color_stops * sizeof(psd_gradient_color_stop));
/***************************************************************************/
for(i = 0; i < gradient_color->number_color_stops; i ++)
{
/***************************************************************************/
// Type: OSType key
type = psd_stream_get_int(context);
// Descriptor
psd_assert(type == 'Objc');
// 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);
key = psd_stream_get_int(context);
// color stop
psd_assert(key == 'Clrt');
// Number of items in descriptor
number_data = psd_stream_get_int(context);
// maybe be 4, include color, color stop type, location and midpoint
psd_assert(number_data == 4);
length = psd_stream_get_int(context);
psd_assert(length == 0);
key = psd_stream_get_int(context);
psd_assert(key == 'Clr ');
// Type: OSType key
type = psd_stream_get_int(context);
// Descriptor
psd_assert(type == 'Objc');
gradient_color->color_stop[i].actual_color = psd_stream_get_object_color(context);
/***************************************************************************/
// 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);
key = psd_stream_get_int(context);
// Type
psd_assert(key == 'Type');
// Type: OSType key
type = psd_stream_get_int(context);
// 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 == 'GrdF');
// enum: 4 bytes (length), followed either by string or (if length is zero) 4-
// byte enum
length = psd_stream_get_int(context);
psd_assert(length == 0);
key = psd_stream_get_int(context);
switch(key)
{
case 'FrgC':
gradient_color->color_stop[i].color_stop_type = psd_color_stop_type_foreground_color;
break;
case 'BckC':
gradient_color->color_stop[i].color_stop_type = psd_color_stop_type_background_Color;
break;
case 'UsrS':
gradient_color->color_stop[i].color_stop_type = psd_color_stop_type_user_stop;
break;
default:
psd_assert(0);
break;
}
/***************************************************************************/
// 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);
key = psd_stream_get_int(context);
// Location
psd_assert(key == 'Lctn');
// Type: OSType key
type = psd_stream_get_int(context);
// Integer
psd_assert(type == 'long');
gradient_color->color_stop[i].location = psd_stream_get_int(context);
/***************************************************************************/
// 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);
key = psd_stream_get_int(context);
// midpoint
psd_assert(key == 'Mdpn');
// Type: OSType key
type = psd_stream_get_int(context);
// Integer
psd_assert(type == 'long');
gradient_color->color_stop[i].midpoint = psd_stream_get_int(context);
}
break;
case 'Trns': // tranparency stop
// value list
psd_assert(type == 'VlLs');
number_lists = psd_stream_get_int(context);
// Number of color stops
gradient_color->number_transparency_stops = number_lists;
gradient_color->transparency_stop = (psd_gradient_transparency_stop *)psd_malloc(
gradient_color->number_transparency_stops * sizeof(psd_gradient_transparency_stop));
if(gradient_color->transparency_stop == NULL)
return;
memset(gradient_color->transparency_stop, 0, gradient_color->number_transparency_stops *
sizeof(psd_gradient_transparency_stop));
/***************************************************************************/
for(i = 0; i < gradient_color->number_transparency_stops; i ++)
{
/***************************************************************************/
// Type: OSType key
type = psd_stream_get_int(context);
// Descriptor
psd_assert(type == 'Objc');
// 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);
key = psd_stream_get_int(context);
// transparency stop
psd_assert(key == 'TrnS');
// Number of items in descriptor
number_data = psd_stream_get_int(context);
// maybe be 3, include opacity, location and midpoint
psd_assert(number_data == 3);
/***************************************************************************/
// 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);
key = psd_stream_get_int(context);
// opacity
psd_assert(key == 'Opct');
// Type: OSType key
type = psd_stream_get_int(context);
// Unit psd_float
psd_assert(type == 'UntF');
// '#Prc' = percent:
key = psd_stream_get_int(context);
psd_assert(key == '#Prc');
// Actual value (double)
gradient_color->transparency_stop[i].opacity = (psd_int)psd_stream_get_double(context);
/***************************************************************************/
// 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);
key = psd_stream_get_int(context);
// Location
psd_assert(key == 'Lctn');
// Type: OSType key
type = psd_stream_get_int(context);
// Integer
psd_assert(type == 'long');
gradient_color->transparency_stop[i].location = psd_stream_get_int(context);
/***************************************************************************/
// 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);
key = psd_stream_get_int(context);
// midpoint
psd_assert(key == 'Mdpn');
// Type: OSType key
type = psd_stream_get_int(context);
// Integer
psd_assert(type == 'long');
gradient_color->transparency_stop[i].midpoint = psd_stream_get_int(context);
}
break;
default:
psd_assert(0);
psd_stream_get_object_null(type, context);
break;
}
}
}
void psd_stream_get_object_pattern_info(psd_pattern_info * pattern_info, psd_context * context)
{
psd_int i, length, number_items, identifier_length;
psd_uint key, rootkey, type;
psd_uchar keychar[256];
// 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);
key = psd_stream_get_int(context);
// pattern
psd_assert(key == 'Ptrn');
// 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)
{
case 'Nm ':
// String
psd_assert(type == 'TEXT');
// String value as Unicode string
pattern_info->name_length = psd_stream_get_int(context);
pattern_info->name = (psd_ushort *)psd_malloc(2 * pattern_info->name_length);
if(pattern_info->name == NULL)
return;
memset(pattern_info->name, 0, 2 * pattern_info->name_length);
psd_stream_get(context, (psd_uchar *)pattern_info->name, 2 * pattern_info->name_length);
break;
case 'Idnt':
// String
psd_assert(type == 'TEXT');
// String value as Unicode string
identifier_length = psd_stream_get_int(context);
for(i = 0; i < identifier_length; i ++)
pattern_info->identifier[i] = psd_stream_get_short(context) & 0x00FF;
break;
default:
psd_assert(0);
psd_stream_get_object_null(type, context);
break;
}
}
}
void psd_stream_get_object_point(psd_int * horz, psd_int * vert, psd_context * context)
{
psd_int length, number_item;
psd_uint key, rootkey, type;
// 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);
key = psd_stream_get_int(context);
// point
psd_assert(key == 'Pnt ');
// Number of items in descriptor
number_item = psd_stream_get_int(context);
while(number_item --)
{
length = psd_stream_get_int(context);
psd_assert(length == 0);
rootkey = psd_stream_get_int(context);
// Type: OSType key
type = psd_stream_get_int(context);
switch(rootkey)
{
// horizontal
case 'Hrzn':
if(type == 'UntF')
{
// '#Prc' = percent:
key = psd_stream_get_int(context);
psd_assert(key == '#Prc');
}
//else if(type == 'doub')
// Actual value (double)
*horz = (psd_int)psd_stream_get_double(context);
break;
// vertical
case 'Vrtc':
if(type == 'UntF')
{
// '#Prc' = percent:
key = psd_stream_get_int(context);
psd_assert(key == '#Prc');
}
//else if(type == 'doub')
// Actual value (double)
*vert = (psd_int)psd_stream_get_double(context);
break;
default:
psd_assert(0);
psd_stream_get_object_null(type, context);
break;
}
}
}