mirror of
https://github.com/ONLYOFFICE/core.git
synced 2026-02-10 18:05:41 +08:00
git-svn-id: svn://fileserver/activex/AVS/Sources/TeamlabOffice/trunk/ServerComponents@61945 954022d7-b5bf-4e40-9824-e11837661b57
1315 lines
36 KiB
C
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;
|
|
}
|
|
}
|
|
}
|
|
|