Files
Yajbir Singh f1b860b25c
Some checks failed
check / markdownlint (push) Has been cancelled
check / spellchecker (push) Has been cancelled
updated
2025-12-11 19:03:17 +05:30

998 lines
26 KiB
C
Raw Permalink Blame History

/**
* 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: pattern.c, created by Patrick in 2006.06.21, libpsd@graphest.com Exp $
*/
#include "libpsd.h"
#include "psd_config.h"
#include "psd_system.h"
#include "psd_stream.h"
#include "psd_color.h"
#include "psd_bitmap.h"
#include "psd_math.h"
#define PSD_MIN_PATTERN_COUNT 4
#ifdef PSD_INCLUDE_ZLIB
extern psd_status psd_unzip_without_prediction(psd_uchar *src_buf, psd_int src_len,
psd_uchar *dst_buf, psd_int dst_len);
extern psd_status psd_unzip_with_prediction(psd_uchar *src_buf, psd_int src_len,
psd_uchar *dst_buf, psd_int dst_len,
psd_int row_size, psd_int color_depth);
#endif
static psd_status psd_combine_bitmap1_channel(psd_context * context, psd_pattern * pattern)
{
psd_int i, j, rowstride;
psd_uchar * black, * cur_black;
psd_int mask;
psd_argb_color * dst_color = pattern->image_data;
black = context->temp_image_data;
rowstride = (context->width + 7) / 8;
for(i = 0; i < pattern->height; i ++)
{
cur_black = black + rowstride * i;
mask = 0x80;
for(j = 0; j < pattern->width; j ++)
{
if(*cur_black & mask)
*dst_color = psd_color_black;
else
*dst_color = psd_color_white;
dst_color ++;
mask >>= 1;
if(mask == 0)
{
mask = 0x80;
cur_black ++;
}
}
}
return psd_status_done;
}
static psd_status psd_combine_grayscale8_channel(psd_context * context, psd_pattern * pattern)
{
psd_int i;
psd_uchar * gray, * alpha, gray_color;
psd_argb_color * dst_color = pattern->image_data;
if(pattern->channel_number == 2)
{
alpha = context->temp_image_data;
gray = context->temp_image_data + context->per_channel_length;
for(i = pattern->width * pattern->height; i --; )
{
gray_color = *gray;
*dst_color = PSD_ARGB_TO_COLOR(*alpha, gray_color, gray_color, gray_color);
dst_color ++;
alpha ++;
gray ++;
}
}
else
{
gray = context->temp_image_data;
for(i = pattern->width * pattern->height; i --; )
{
gray_color = *gray;
*dst_color = PSD_RGB_TO_COLOR(gray_color, gray_color, gray_color);
dst_color ++;
gray ++;
}
}
return psd_status_done;
}
static psd_status psd_combine_grayscale16_channel(psd_context * context, psd_pattern * pattern)
{
psd_int i;
psd_uchar * gray, * alpha, gray_color;
psd_argb_color * dst_color = pattern->image_data;
if(pattern->channel_number == 2)
{
alpha = context->temp_image_data;
gray = context->temp_image_data + context->per_channel_length;
for(i = pattern->width * pattern->height; i --; )
{
gray_color = PSD_CHAR_TO_SHORT(gray) >> 8;
*dst_color = PSD_ARGB_TO_COLOR(PSD_CHAR_TO_SHORT(alpha) >> 8, gray_color, gray_color, gray_color);
dst_color ++;
alpha += 2;
gray += 2;
}
}
else
{
gray = context->temp_image_data;
for(i = pattern->width * pattern->height; i --; )
{
gray_color = PSD_CHAR_TO_SHORT(gray) >> 8;
*dst_color = PSD_RGB_TO_COLOR(gray_color, gray_color, gray_color);
dst_color ++;
gray += 2;
}
}
return psd_status_done;
}
static psd_status psd_combine_indexed8_channel(psd_context * context, psd_pattern * pattern,
psd_argb_color * color_map)
{
psd_int i;
psd_uchar * index, indexed;
psd_argb_color * dst_color = pattern->image_data;
index = context->temp_image_data;
for(i = pattern->width * pattern->height; i --; )
{
indexed = *index;
*dst_color = color_map[indexed];
dst_color ++;
index ++;
}
return psd_status_done;
}
static psd_status psd_combine_rgb8_channel(psd_context * context, psd_pattern * pattern)
{
psd_int i;
psd_uchar * red, * green, * blue, * alpha;
psd_argb_color * dst_color = pattern->image_data;
if(pattern->channel_number == 4)
{
alpha = context->temp_image_data;
red = context->temp_image_data + context->per_channel_length;
green = context->temp_image_data + context->per_channel_length * 2;
blue = context->temp_image_data + context->per_channel_length * 3;
for(i = pattern->width * pattern->height; i --; )
{
*dst_color = PSD_ARGB_TO_COLOR(*alpha, *red, *green, *blue);
dst_color ++;
alpha ++;
red ++;
green ++;
blue ++;
}
}
else
{
red = context->temp_image_data;
green = context->temp_image_data + context->per_channel_length;
blue = context->temp_image_data + context->per_channel_length * 2;
for(i = pattern->width * pattern->height; i --; )
{
*dst_color = PSD_RGB_TO_COLOR(*red, *green, *blue);
dst_color ++;
red ++;
green ++;
blue ++;
}
}
return psd_status_done;
}
static psd_status psd_combine_rgb16_channel(psd_context * context, psd_pattern * pattern)
{
psd_int i;
psd_uchar * red, * green, * blue, * alpha;
psd_argb_color * dst_color = pattern->image_data;
if(pattern->channel_number == 4)
{
alpha = context->temp_image_data;
red = context->temp_image_data + context->per_channel_length;
green = context->temp_image_data + context->per_channel_length * 2;
blue = context->temp_image_data + context->per_channel_length * 3;
for(i = pattern->width * pattern->height; i --; )
{
*dst_color = PSD_ARGB_TO_COLOR(PSD_CHAR_TO_SHORT(alpha) >> 8,
PSD_CHAR_TO_SHORT(red) >> 8, PSD_CHAR_TO_SHORT(green) >> 8, PSD_CHAR_TO_SHORT(blue) >> 8);
dst_color ++;
alpha += 2;
red += 2;
green += 2;
blue += 2;
}
}
else
{
red = context->temp_image_data;
green = context->temp_image_data + context->per_channel_length;
blue = context->temp_image_data + context->per_channel_length * 2;
for(i = pattern->width * pattern->height; i --; )
{
*dst_color = PSD_RGB_TO_COLOR(PSD_CHAR_TO_SHORT(red) >> 8,
PSD_CHAR_TO_SHORT(green) >> 8, PSD_CHAR_TO_SHORT(blue) >> 8);
dst_color ++;
red += 2;
green += 2;
blue += 2;
}
}
return psd_status_done;
}
#ifdef PSD_SUPPORT_CMYK
static psd_status psd_combine_cmyk8_channel(psd_context * context, psd_pattern * pattern)
{
psd_int i;
psd_uchar * cyan, * magenta, * yellow, * black, * alpha;
psd_argb_color * dst_color = pattern->image_data;
if(pattern->channel_number == 5)
{
alpha = context->temp_image_data;
cyan = context->temp_image_data + context->per_channel_length;
magenta = context->temp_image_data + context->per_channel_length * 2;
yellow = context->temp_image_data + context->per_channel_length * 3;
black = context->temp_image_data + context->per_channel_length * 4;
for(i = pattern->width * pattern->height; i --; )
{
*dst_color = psd_intacmyk_to_color(*alpha, 255 - *cyan, 255 - *magenta, 255 - *yellow, 255 - *black);
dst_color ++;
alpha ++;
cyan ++;
magenta ++;
yellow ++;
black ++;
}
}
else
{
cyan = context->temp_image_data;
magenta = context->temp_image_data + context->per_channel_length;
yellow = context->temp_image_data + context->per_channel_length * 2;
black = context->temp_image_data + context->per_channel_length * 3;
for(i = pattern->width * pattern->height; i --; )
{
*dst_color = psd_intcmyk_to_color(255 - *cyan, 255 - *magenta, 255 - *yellow, 255 - *black);
dst_color ++;
cyan ++;
magenta ++;
yellow ++;
black ++;
}
}
return psd_status_done;
}
static psd_status psd_combine_cmyk16_channel(psd_context * context, psd_pattern * pattern)
{
psd_int i;
psd_uchar * cyan, * magenta, * yellow, * black, * alpha;
psd_argb_color * dst_color = pattern->image_data;
if(pattern->channel_number == 5)
{
alpha = context->temp_image_data;
cyan = context->temp_image_data + context->per_channel_length;
magenta = context->temp_image_data + context->per_channel_length * 2;
yellow = context->temp_image_data + context->per_channel_length * 3;
black = context->temp_image_data + context->per_channel_length * 4;
for(i = pattern->width * pattern->height; i --; )
{
*dst_color = psd_intacmyk_to_color((unsigned char)(PSD_CHAR_TO_SHORT(alpha) >> 8),
255 - (PSD_CHAR_TO_SHORT(cyan) >> 8), 255 - (PSD_CHAR_TO_SHORT(magenta) >> 8),
255 - (PSD_CHAR_TO_SHORT(yellow) >> 8), 255 - (PSD_CHAR_TO_SHORT(black) >> 8));
dst_color ++;
alpha += 2;
cyan += 2;
magenta += 2;
yellow += 2;
black += 2;
}
}
else
{
cyan = context->temp_image_data;
magenta = context->temp_image_data + context->per_channel_length;
yellow = context->temp_image_data + context->per_channel_length * 2;
black = context->temp_image_data + context->per_channel_length * 3;
for(i = pattern->width * pattern->height; i --; )
{
*dst_color = psd_intcmyk_to_color(255 - (PSD_CHAR_TO_SHORT(cyan) >> 8),
255 - (PSD_CHAR_TO_SHORT(magenta) >> 8), 255 - (PSD_CHAR_TO_SHORT(yellow) >> 8),
255 - (PSD_CHAR_TO_SHORT(black) >> 8));
dst_color ++;
cyan += 2;
magenta += 2;
yellow += 2;
black += 2;
}
}
return psd_status_done;
}
#endif // ifdef PSD_SUPPORT_CMYK
#ifdef PSD_SUPPORT_LAB
static psd_status psd_combine_lab8_channel(psd_context * context, psd_pattern * pattern)
{
psd_int i;
psd_uchar * lightness, * a, * b, * alpha;
psd_argb_color * dst_color = pattern->image_data;
if(pattern->channel_number == 4)
{
alpha = context->temp_image_data;
lightness = context->temp_image_data + context->per_channel_length;
a = context->temp_image_data + context->per_channel_length * 2;
b = context->temp_image_data + context->per_channel_length * 3;
for(i = pattern->width * pattern->height; i --; )
{
*dst_color = psd_alab_to_color(*alpha, *lightness * 100 >> 8, *a - 128, *b - 128);
dst_color ++;
alpha ++;
lightness ++;
a ++;
b ++;
}
}
else
{
lightness = context->temp_image_data;
a = context->temp_image_data + context->per_channel_length;
b = context->temp_image_data + context->per_channel_length * 2;
for(i = pattern->width * pattern->height; i --; )
{
*dst_color = psd_lab_to_color(*lightness * 100 >> 8, *a - 128, *b - 128);
dst_color ++;
lightness ++;
a ++;
b ++;
}
}
return psd_status_done;
}
static psd_status psd_combine_lab16_channel(psd_context * context, psd_pattern * pattern)
{
psd_int i;
psd_uchar * lightness, * a, * b, * alpha;
psd_argb_color * dst_color = pattern->image_data;
if(pattern->channel_number == 4)
{
alpha = context->temp_image_data;
lightness = context->temp_image_data + context->per_channel_length;
a = context->temp_image_data + context->per_channel_length * 2;
b = context->temp_image_data + context->per_channel_length * 3;
for(i = pattern->width * pattern->height; i --; )
{
*dst_color = psd_alab_to_color((unsigned char)(PSD_CHAR_TO_SHORT(alpha) >> 8), (PSD_CHAR_TO_SHORT(lightness) >> 8) * 100 >> 8,
(PSD_CHAR_TO_SHORT(a) >> 8) - 128, (PSD_CHAR_TO_SHORT(b) >> 8) - 128);
dst_color ++;
alpha += 2;
lightness += 2;
a += 2;
b += 2;
}
}
else
{
lightness = context->temp_image_data;
a = context->temp_image_data + context->per_channel_length;
b = context->temp_image_data + context->per_channel_length * 2;
for(i = pattern->width * pattern->height; i --; )
{
*dst_color = psd_lab_to_color((PSD_CHAR_TO_SHORT(lightness) >> 8) * 100 >> 8,
(PSD_CHAR_TO_SHORT(a) >> 8) - 128, (PSD_CHAR_TO_SHORT(b) >> 8) - 128);
dst_color ++;
lightness += 2;
a += 2;
b += 2;
}
}
return psd_status_done;
}
#endif // ifdef PSD_SUPPORT_LAB
#ifdef PSD_SUPPORT_MULTICHANNEL
static psd_status psd_combine_multichannel8_channel(psd_context * context, psd_pattern * pattern)
{
psd_int i;
psd_uchar * cyan, * magenta, * yellow, * black;
psd_argb_color * dst_color = pattern->image_data;
if(pattern->channel_number == 4)
{
cyan = context->temp_image_data;
magenta = context->temp_image_data + context->per_channel_length;
yellow = context->temp_image_data + context->per_channel_length * 2;
black = context->temp_image_data + context->per_channel_length * 3;
for(i = pattern->width * pattern->height; i --; )
{
*dst_color = psd_intcmyk_to_color(255 - *cyan, 255 - *magenta, 255 - *yellow, 255 - *black);
dst_color ++;
cyan ++;
magenta ++;
yellow ++;
black ++;
}
}
else
{
cyan = context->temp_image_data;
magenta = context->temp_image_data + context->per_channel_length;
yellow = context->temp_image_data + context->per_channel_length * 2;
for(i = pattern->width * pattern->height; i --; )
{
*dst_color = psd_intcmyk_to_color(255 - *cyan, 255 - *magenta, 255 - *yellow, 0);
dst_color ++;
cyan ++;
magenta ++;
yellow ++;
}
}
return psd_status_done;
}
#endif // ifdef PSD_SUPPORT_MULTICHANNEL
// Patterns (Photoshop 6.0 and CS (8.0))
// The following is repeated for each pattern.
psd_status psd_get_pattern(psd_context * context)
{
psd_int pattern_length, prev_stream_pos, index, len, i, j, k,
red, green, blue, max_channels, depth, compression;
psd_bool written;
psd_pattern * pattern;
psd_argb_color * color_map = NULL;
psd_int pixels, length;
psd_uchar * image_data, * count_data, * pixel_data;
psd_int pixel_count, byte_count;
psd_status status = psd_status_done;
// Length of this pattern
pattern_length = psd_stream_get_int(context);
pattern_length = (pattern_length + 3) & ~3;
prev_stream_pos = context->stream.current_pos;
// Version ( =1)
if(psd_stream_get_int(context) != 1)
return psd_status_pattern_unsupport_version;
index = context->pattern_count;
if(index >= context->malloc_pattern)
{
context->malloc_pattern = PSD_MAX(context->malloc_pattern * 2, PSD_MIN_PATTERN_COUNT);
context->patterns = (psd_pattern *)psd_realloc(context->patterns, context->malloc_pattern * sizeof(psd_pattern));
if(context->patterns == NULL)
return psd_status_malloc_failed;
}
pattern = &context->patterns[index];
memset(pattern, 0, sizeof(psd_pattern));
// The image mode of the file. Supported values are: Bitmap = 0; Grayscale
// = 1; Indexed = 2; RGB = 3; CMYK = 4; Multichannel = 7; Duotone = 8;
// Lab = 9.
pattern->color_mode = psd_stream_get_int(context);
switch(pattern->color_mode)
{
case psd_color_mode_bitmap:
case psd_color_mode_grayscale:
case psd_color_mode_indexed:
case psd_color_mode_rgb:
case psd_color_mode_duotone:
break;
case psd_color_mode_cmyk:
#ifndef PSD_SUPPORT_CMYK
psd_assert(0);
return psd_status_unknown_color_mode;
#endif
break;
case psd_color_mode_lab:
#ifndef PSD_SUPPORT_LAB
psd_assert(0);
return psd_status_unknown_color_mode;
#endif
break;
case psd_color_mode_multichannel:
#ifndef PSD_SUPPORT_MULTICHANNEL
psd_assert(0);
return psd_status_unknown_color_mode;
#endif
break;
default:
psd_assert(0);
return psd_status_unknown_color_mode;
}
// Point: vertical, 2 bytes and horizontal, 2 bytes
pattern->height = psd_stream_get_short(context);
pattern->width = psd_stream_get_short(context);
// Name: Unicode string
pattern->name_length = psd_stream_get_int(context);
pattern->name = (psd_ushort *)psd_malloc(2 * pattern->name_length);
if(pattern->name == NULL)
return psd_status_malloc_failed;
psd_stream_get(context, (psd_uchar *)pattern->name, 2 * pattern->name_length);
// Unique ID for this pattern: Pascal string
len = psd_stream_get_char(context);
psd_stream_get(context, pattern->unique_id, len);
// Index color table (256 * 3 RGB values): only present when image mode is
// indexed color
if(pattern->color_mode == psd_color_mode_indexed)
{
color_map = (psd_argb_color *)psd_malloc(256 * 4);
if(color_map == NULL)
return psd_status_malloc_failed;
for(i = 0; i < 256; i ++)
{
red = psd_stream_get_char(context);
green = psd_stream_get_char(context);
blue = psd_stream_get_char(context);
color_map[i] = PSD_RGB_TO_COLOR(red, green, blue);
}
}
// The following is the pattern data. It is called a virtual memory array list.
// Version
pattern->version = psd_stream_get_int(context);
// Length, we do not use this
psd_stream_get_int(context);
// Rectangle: top, left, bottom, right
pattern->top = psd_stream_get_int(context);
pattern->left = psd_stream_get_int(context);
pattern->bottom = psd_stream_get_int(context);
pattern->right = psd_stream_get_int(context);
// Max channels
max_channels = psd_stream_get_int(context);
// The following is a virtual memory array, repeated for the number of channels in the
// image mode, not to exceed the max channels.
for(i = 0; i < max_channels; i ++)
{
// Boolean indicating whether array is written
written = psd_stream_get_int(context);
// Length
len = psd_stream_get_int(context);
len -= 4 + 4 * 4 + 2 + 1;
if(len < 0)
{
if(prev_stream_pos + pattern_length - context->stream.current_pos < 13)
break;
continue;
}
// Pixel depth: 1, 8 or 16
if(written == psd_true)
{
if(pattern->channel_number == 0)
depth = psd_stream_get_int(context);
else
psd_assert(depth == psd_stream_get_int(context));
}
else
{
psd_stream_get_int(context);
}
// not docutmented, top, left, bottom, right, Pixel depth
psd_stream_get_null(context, 4 * 4 + 2);
// Compression mode of data to follow. 'Pat2' compression is zip.
compression = psd_stream_get_char(context);
if(written == psd_true)
{
if(pattern->channel_number == 0)
{
pixels = length = pattern->width * pattern->height;
switch(context->depth)
{
case 1: // 1bit
length = (pattern->width + 7) / 8 * pattern->height;
break;
case 8: // 8bit
break;
case 16: // 16bit
length *= 2;
pixels *= 2;
break;
default:
psd_assert(0);
break;
}
context->per_channel_length = length;
switch(pattern->color_mode)
{
case psd_color_mode_bitmap:
case psd_color_mode_indexed:
break;
case psd_color_mode_grayscale:
case psd_color_mode_duotone:
length *= 2; // gray, alpha
break;
break;
case psd_color_mode_rgb:
length *= 4; // red, green, blue, alpha
break;
case psd_color_mode_cmyk:
length *= 5; // cyan, magenta, yellow, black, alpha
break;
case psd_color_mode_lab:
length *= 4; // lightness, a, b, alpha
break;
case psd_color_mode_multichannel:
length *= 4; // cyan, magenta, yellow, black
break;
}
if(length > context->temp_image_length)
{
psd_freeif(context->temp_image_data);
context->temp_image_length = PSD_MAX(context->temp_image_length * 2, length);
context->temp_image_data = (psd_uchar *)psd_malloc(context->temp_image_length);
if(context->temp_image_data == NULL)
{
context->temp_image_length = 0;
psd_freeif(color_map);
return psd_status_malloc_failed;
}
}
}
// Actual data based on parameters and compression
if(len > context->temp_channel_length)
{
psd_freeif(context->temp_channel_data);
context->temp_channel_length = PSD_MAX(context->temp_channel_length * 2, len);
context->temp_channel_data = (psd_uchar *)psd_malloc(context->temp_channel_length);
if(context->temp_channel_data == NULL)
{
context->temp_channel_length = 0;
psd_freeif(color_map);
return psd_status_malloc_failed;
}
}
if(psd_stream_get(context, context->temp_channel_data, len) != len)
{
psd_freeif(color_map);
return psd_status_fread_error;
}
image_data = context->temp_image_data + pattern->channel_number * context->per_channel_length;
// Compression. 0 = Raw Data, 1 = RLE compressed, 2 = ZIP without
// prediction, 3 = ZIP with prediction.
switch(compression)
{
// If the compression code is 0, the image data is just the raw image data,
// whose size is calculated as (LayerBottom<6F>CLayerTop)*
// (LayerRight<68>CLayerLeft).
case 0:
memcpy(image_data, context->temp_channel_data, context->per_channel_length);
break;
// If the compression code is 1, the image data starts with the byte counts
// for all the scan lines in the channel (LayerBottom<6F>CLayerTop), with
// each count stored as a two<77>Cbyte value.(**PSB** each count stored as a
// four-byte value.) The RLE compressed data follows, with each scan line
// compressed separately. The RLE compression is the same compression
// algorithm used by the Macintosh ROM routine PackBits, and the TIFF
// standard.
case 1: // RLE compressed
psd_assert(context->depth == 8 || context->depth == 16);
pixel_count = 0;
count_data = context->temp_channel_data;
pixel_data = context->temp_channel_data + pattern->height * 2;
for(j = 0; j < pattern->height; j ++)
{
byte_count = PSD_CHAR_TO_SHORT(count_data);
for(k = 0; k < byte_count;)
{
len = *pixel_data;
pixel_data ++;
k ++;
if(len < 128)
{
len ++;
pixel_count += len;
memcpy(image_data, pixel_data, len);
image_data += len;
pixel_data += len;
k += len;
}
else if(len > 128)
{
// Next -len+1 bytes in the dest are replicated from next source byte.
// (Interpret len as a negative 8-bit psd_int.)
len ^= 0xff;
len += 2;
pixel_count += len;
memset(image_data, *pixel_data, len);
image_data += len;
pixel_data ++;
k ++;
}
else// len == 128
{
// do nothing
}
}
count_data += 2;
}
psd_assert(pixel_count == pixels);
break;
// ZIP without prediction
case 2:
#ifdef PSD_INCLUDE_ZLIB
status = psd_unzip_without_prediction(context->temp_channel_data, len, image_data, pixels);
if (status != psd_status_done)
return status;
#else
psd_assert(0);
#endif
break;
// ZIP with prediction.
case 3:
#ifdef PSD_INCLUDE_ZLIB
status = psd_unzip_with_prediction(context->temp_channel_data, len, image_data, pixels,
pattern->width, context->depth);
if (status != psd_status_done)
return status;
#else
psd_assert(0);
#endif
break;
default:
psd_assert(0);
psd_freeif(color_map);
return psd_status_unsupport_image_compression;
}
pattern->channel_number ++;
}
else if(len > 0)
{
psd_stream_get_null(context, len);
}
if(prev_stream_pos + pattern_length - context->stream.current_pos < 13)
break;
}
pattern->image_data = (psd_argb_color *)psd_malloc(pattern->width * pattern->height * 4);
if(pattern->image_data == NULL)
{
psd_freeif(color_map);
return psd_status_malloc_failed;
}
// combine each channel to image data
switch(pattern->color_mode)
{
// 1bit
case psd_color_mode_bitmap:
if(depth == 1)
status = psd_combine_bitmap1_channel(context, pattern);
else
psd_assert(0);
break;
// 8bit or 16bit
case psd_color_mode_grayscale:
// Other applications that read Photoshop files can treat a
// duotone image as a gray image
case psd_color_mode_duotone:
if(context->depth == 8)
status = psd_combine_grayscale8_channel(context, pattern);
else if(context->depth == 16)
status = psd_combine_grayscale16_channel(context, pattern);
else
psd_assert(0);
break;
// 8bit
case psd_color_mode_indexed:
if(context->depth == 8)
status = psd_combine_indexed8_channel(context, pattern, color_map);
else
psd_assert(0);
break;
// 8bit or 16bit
case psd_color_mode_rgb:
if(context->depth == 8)
status = psd_combine_rgb8_channel(context, pattern);
else if(context->depth == 16)
status = psd_combine_rgb16_channel(context, pattern);
else
psd_assert(0);
break;
// 8bit or 16bit
case psd_color_mode_cmyk:
#ifdef PSD_SUPPORT_CMYK
if(context->depth == 8)
status = psd_combine_cmyk8_channel(context, pattern);
else if(context->depth == 16)
status = psd_combine_cmyk16_channel(context, pattern);
else
psd_assert(0);
#endif
break;
// 8bit or 16bit
case psd_color_mode_lab:
#ifdef PSD_SUPPORT_LAB
if(context->depth == 8)
status = psd_combine_lab8_channel(context, pattern);
else if(context->depth == 16)
status = psd_combine_lab16_channel(context, pattern);
else
psd_assert(0);
#endif
break;
case psd_color_mode_multichannel:
#ifdef PSD_SUPPORT_MULTICHANNEL
if(context->depth == 8)
status = psd_combine_multichannel8_channel(context, pattern);
else
psd_assert(0);
#endif
break;
default:
psd_assert(0);
break;
}
if(status != psd_status_done)
{
psd_freeif(color_map);
return status;
}
psd_freeif(color_map);
context->pattern_count ++;
psd_stream_get_null(context, prev_stream_pos + pattern_length - context->stream.current_pos);
return psd_status_done;
}
psd_status psd_pattern_fill(psd_bitmap * dst_bmp, psd_pattern * pattern, psd_int scale, psd_int offset_x, psd_int offset_y)
{
psd_bitmap src_bmp, pat_bmp;
psd_rect dst_rect;
psd_int i, j;
psd_status status;
src_bmp.width = pattern->width;
src_bmp.height = pattern->height;
src_bmp.image_data = pattern->image_data;
if(scale != 100)
{
pat_bmp = src_bmp;
status = psd_create_bitmap(&src_bmp, (pattern->width * scale + 50) / 100, (pattern->height * scale + 50) / 100);
if(status != psd_status_done)
return status;
status = psd_scale_bitmap(&src_bmp, &pat_bmp);
if(status != psd_status_done)
return status;
}
offset_x %= src_bmp.width;
offset_y %= src_bmp.height;
if(offset_x > 0)
offset_x -= src_bmp.width;
if(offset_y > 0)
offset_y -= src_bmp.height;
for(i = offset_y; i < dst_bmp->height; i += src_bmp.height)
{
for(j = offset_x; j < dst_bmp->width; j += src_bmp.width)
{
psd_make_rect(&dst_rect, j, i, j + src_bmp.width, i + src_bmp.height);
psd_draw_bitmap(dst_bmp, &src_bmp, &dst_rect, NULL);
}
}
if(scale != 100)
psd_free_bitmap(&src_bmp);
return psd_status_done;
}
void psd_pattern_free(psd_context * context)
{
psd_int i;
psd_pattern * pattern;
if(context->patterns == NULL)
return;
pattern = context->patterns;
for(i = 0; i < context->pattern_count; i ++)
{
psd_freeif(pattern->name);
psd_freeif(pattern->image_data);
pattern ++;
}
psd_free(context->patterns);
}