guy 429faed747 Patch level : 10.0
Files correlati     : pdflib
Ricompilazione Demo : [ ]
Commento            :
Aggiornata PDFlib


git-svn-id: svn://10.65.10.50/trunk@17433 c028cbd2-c16b-5b4b-a496-9718f37d4682
2008-10-20 14:35:00 +00:00

744 lines
18 KiB
C
Executable File

/*---------------------------------------------------------------------------*
| PDFlib - A library for generating PDF on the fly |
+---------------------------------------------------------------------------+
| Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. |
+---------------------------------------------------------------------------+
| |
| This software is subject to the PDFlib license. It is NOT in the |
| public domain. Extended versions and commercial licenses are |
| available, please check http://www.pdflib.com. |
| |
*---------------------------------------------------------------------------*/
/* $Id: p_gif.c,v 1.3 2008-10-20 14:34:15 guy Exp $
*
* GIF processing for PDFlib
*
*/
/*
* This module contains modified parts of the giftopnm.c progam in the
* netpbm package. It contained the following copyright notice:
*/
/* +-------------------------------------------------------------------+ */
/* | Copyright 1990 - 1994, David Koblas. (koblas@netcom.com) | */
/* | Permission to use, copy, modify, and distribute this software | */
/* | and its documentation for any purpose and without fee is hereby | */
/* | granted, provided that the above copyright notice appear in all | */
/* | copies and that both that copyright notice and this permission | */
/* | notice appear in supporting documentation. This software is | */
/* | provided "as is" without express or implied warranty. | */
/* +-------------------------------------------------------------------+ */
#include "p_intern.h"
#include "p_color.h"
#include "p_image.h"
#ifndef PDF_GIF_SUPPORTED
pdc_bool
pdf_is_GIF_file(PDF *p, pdc_file *fp)
{
(void) p;
(void) fp;
return pdc_false;
}
int
pdf_process_GIF_data(
PDF *p,
int imageslot)
{
(void) imageslot;
pdc_set_errmsg(p->pdc, PDF_E_UNSUPP_IMAGE, "GIF", 0, 0, 0);
return -1;
}
void
pdf_cleanup_gif(PDF *p, pdf_image *image)
{
(void) p;
(void) image;
}
#else
#define LOCALCOLORMAP 0x80
#define BitSet(byteval, bitval) (((byteval) & (bitval)) == (bitval))
static int ReadColorMap(pdc_core *pdc, pdc_file *fp,
int number, pdf_colormap *buffer);
static int DoExtension(PDF *p, pdf_image *image, int label);
static int GetDataBlock(PDF *p, pdf_image *image, unsigned char *buf);
static void ReadImage(PDF *p, pdf_image *image, PDF_data_source *src);
static void
pdf_data_source_GIF_init(PDF *p, PDF_data_source *src)
{
pdf_image *image;
image = (pdf_image *) src->private_data;
src->buffer_length = (size_t) (image->width * image->height * 1);
src->buffer_start = (pdc_byte *) pdc_malloc(p->pdc, src->buffer_length,
"pdf_data_source_GIF_init");
src->bytes_available= 0;
src->next_byte = NULL;
}
static pdc_bool
pdf_data_source_GIF_fill(PDF *p, PDF_data_source *src)
{
pdf_image *image;
if (src->next_byte != NULL) /* all finished in one turn */
return pdc_false;
image = (pdf_image *) src->private_data;
src->next_byte = src->buffer_start;
src->bytes_available = src->buffer_length;
PDC_TRY(p->pdc)
{
ReadImage(p, image, src);
}
PDC_CATCH(p->pdc)
{
image->corrupt = pdc_true;
}
pdf_cleanup_gif(p, image);
return !image->corrupt;
}
static void
pdf_data_source_GIF_terminate(PDF *p, PDF_data_source *src)
{
pdc_free(p->pdc, (void *) src->buffer_start);
}
#define PDF_STRING_GIF "\107\111\106"
#define PDF_STRING_87a "\070\067\141"
#define PDF_STRING_89a "\070\071\141"
pdc_bool
pdf_is_GIF_file(PDF *p, pdc_file *fp)
{
unsigned char buf[3];
pdc_logg_cond(p->pdc, 1, trc_image, "\tChecking image type GIF...\n");
if (!PDC_OK_FREAD(fp, buf, 3) ||
strncmp((const char *) buf, PDF_STRING_GIF, 3) != 0)
{
pdc_fseek(fp, 0L, SEEK_SET);
return pdc_false;
}
return pdc_true;
}
int
pdf_process_GIF_data(
PDF *p,
int imageslot)
{
unsigned char buf[16];
char c;
int imageCount = 0;
char version[4];
int errcode = 0;
pdf_image *image;
pdf_colorspace cs;
pdf_colormap colormap;
int slot;
image = &p->images[imageslot];
image->info.gif.stack = NULL;
image->info.gif.table = NULL;
/* we invert this flag later */
if (image->ignoremask)
image->transparent = pdc_true;
if (image->page == pdc_undef)
image->page = 1;
/* Error reading magic number or not a GIF file */
if (pdf_is_GIF_file(p, image->fp) == pdc_false) {
errcode = PDC_E_IO_BADFORMAT;
goto PDF_GIF_ERROR;
}
/* Version number */
if (! PDC_OK_FREAD(image->fp, buf, 3)) {
errcode = PDC_E_IO_BADFORMAT;
goto PDF_GIF_ERROR;
}
strncpy(version, (const char *) buf, 3);
version[3] = '\0';
if ((strcmp(version, PDF_STRING_87a) != 0) &&
(strcmp(version, PDF_STRING_89a) != 0)) {
errcode = PDC_E_IO_BADFORMAT;
goto PDF_GIF_ERROR;
}
/* Failed to read screen descriptor */
if (! PDC_OK_FREAD(image->fp, buf, 7)) {
errcode = PDC_E_IO_BADFORMAT;
goto PDF_GIF_ERROR;
}
cs.type = Indexed;
/* size of the global color table */
cs.val.indexed.palette_size = 2 << (buf[4] & 0x07);
cs.val.indexed.base = DeviceRGB;
cs.val.indexed.colormap = &colormap;
cs.val.indexed.colormap_id = PDC_BAD_ID;
if (BitSet(buf[4], LOCALCOLORMAP)) { /* Global Colormap */
if (ReadColorMap(p->pdc, image->fp,
cs.val.indexed.palette_size, &colormap)) {
errcode = PDF_E_IMAGE_COLORMAP;
goto PDF_GIF_ERROR;
}
}
/* translate the aspect ratio to PDFlib notation */
if (buf[6] != 0) {
image->dpi_x = (pdc_scalar) (-(buf[6] + 15.0) / 64.0);
image->dpi_y = -1.0;
}
for (/* */ ; /* */ ; /* */) {
/* EOF / read error in image data */
if (!PDC_OK_FREAD(image->fp, &c, 1)) {
errcode = PDC_E_IO_READ;
goto PDF_GIF_ERROR;
}
#define PDF_SEMICOLON ((char) 0x3b) /* ASCII ';' */
if (c == PDF_SEMICOLON) { /* GIF terminator */
/* Not enough images found in file */
if (imageCount < image->page) {
if (!imageCount)
errcode = PDF_E_IMAGE_CORRUPT;
else
errcode = PDF_E_IMAGE_NOPAGE;
goto PDF_GIF_ERROR;
}
break;
}
#define PDF_EXCLAM ((char) 0x21) /* ASCII '!' */
if (c == PDF_EXCLAM) { /* Extension */
if (!PDC_OK_FREAD(image->fp, &c, 1)) {
/* EOF / read error on extension function code */
errcode = PDC_E_IO_READ;
goto PDF_GIF_ERROR;
}
DoExtension(p, image, (int) c);
continue;
}
#define PDF_COMMA ((char) 0x2c) /* ASCII ',' */
if (c != PDF_COMMA) { /* Not a valid start character */
/* Bogus character, ignoring */
continue;
}
++imageCount;
if (! PDC_OK_FREAD(image->fp, buf, 9)) {
/* Couldn't read left/top/width/height */
errcode = PDC_E_IO_READ;
goto PDF_GIF_ERROR;
}
image->components = 1;
image->bpc = 8;
image->width = (pdc_scalar) pdc_get_le_ushort(&buf[4]);
image->height = (pdc_scalar) pdc_get_le_ushort(&buf[6]);
#define INTERLACE 0x40
image->info.gif.interlace= BitSet(buf[8], INTERLACE);
if (image->imagemask)
{
if (p->compatibility <= PDC_1_3) {
errcode = PDF_E_IMAGE_MASK1BIT13;
goto PDF_GIF_ERROR;
} else {
/* images with more than one bit will be written as /SMask,
* and don't require an /ImageMask entry.
*/
image->imagemask = pdc_false;
}
image->colorspace = DeviceGray;
}
if (BitSet(buf[8], LOCALCOLORMAP)) {
/* The local color map may have a different size */
cs.val.indexed.palette_size = 2 << (buf[8] & 0x07);
if (ReadColorMap(p->pdc, image->fp,
cs.val.indexed.palette_size, &colormap))
{
errcode = PDF_E_IMAGE_COLORMAP;
goto PDF_GIF_ERROR;
}
}
if (imageCount == image->page)
break;
}
image->src.init = pdf_data_source_GIF_init;
image->src.fill = pdf_data_source_GIF_fill;
image->src.terminate = pdf_data_source_GIF_terminate;
image->src.private_data = (void *) image;
image->compression = pdf_comp_none;
image->use_raw = pdc_false;
image->in_use = pdc_true; /* mark slot as used */
slot = pdf_add_colorspace(p, &cs, pdc_false);
image->colorspace = slot;
pdf_put_image(p, imageslot, pdc_true, pdc_true);
if (!image->corrupt)
return imageslot;
PDF_GIF_ERROR:
{
const char *stemp = NULL;
if (errcode)
stemp = pdf_get_image_filename(p, image);
switch (errcode)
{
case PDC_E_IO_READ:
case PDF_E_IMAGE_COLORMAP:
case PDF_E_IMAGE_MASK1BIT13:
pdc_set_errmsg(p->pdc, errcode, stemp, 0, 0, 0);
break;
case PDC_E_IO_BADFORMAT:
pdc_set_errmsg(p->pdc, errcode, stemp, "GIF", 0, 0);
break;
case PDF_E_IMAGE_CORRUPT:
pdc_set_errmsg(p->pdc, errcode, "GIF", stemp, 0, 0);
break;
case PDF_E_IMAGE_NOPAGE:
pdc_set_errmsg(p->pdc, errcode,
pdc_errprintf(p->pdc, "%d", image->page), "GIF", stemp, 0);
break;
case 0: /* error code and message already set */
break;
}
}
return -1;
} /* pdf_open_GIF_data */
static int
ReadColorMap(pdc_core *pdc, pdc_file *fp, int number, pdf_colormap *buffer)
{
int i;
unsigned char rgb[3];
(void) pdc;
for (i = 0; i < number; ++i) {
if (! PDC_OK_FREAD(fp, rgb, sizeof(rgb))) {
return pdc_true; /* yk: true == error */
}
(*buffer)[i][0] = rgb[0] ;
(*buffer)[i][1] = rgb[1] ;
(*buffer)[i][2] = rgb[2] ;
}
return pdc_false; /* yk: false == ok. */
} /* ReadColorMap */
static int
DoExtension(PDF *p, pdf_image *image, int label)
{
pdc_byte buf[256];
switch ((unsigned char) label) {
case 0x01: /* Plain Text Extension */
break;
case 0xff: /* Application Extension */
break;
case 0xfe: /* Comment Extension */
while (GetDataBlock(p, image, (unsigned char*) buf) != 0) {
/* */
}
return pdc_false;
case 0xf9: /* Graphic Control Extension */
(void) GetDataBlock(p, image, (unsigned char*) buf);
if ((buf[0] & 0x1) != 0) {
image->transparent = !image->transparent;
image->transval[0] = buf[3];
}
while (GetDataBlock(p, image, (unsigned char*) buf) != 0) {
/* */ ;
}
return pdc_false;
default:
break;
}
while (GetDataBlock(p, image, (unsigned char*) buf) != 0) {
/* */ ;
}
return pdc_false;
} /* DoExtension */
/*
* A bunch of formely static variables which are now kept in the
* image structure in order to keep the GIF reader thread-safe.
*/
/* for GetDataBlock() */
#define ZeroDataBlock (image->info.gif.ZeroDataBlock)
/* for initLWZ() */
#define curbit (image->info.gif.curbit)
#define lastbit (image->info.gif.lastbit)
#define get_done (image->info.gif.get_done)
#define last_byte (image->info.gif.last_byte)
#define return_clear (image->info.gif.return_clear)
#define sp (image->info.gif.sp)
#define code_size (image->info.gif.code_size)
#define set_code_size (image->info.gif.set_code_size)
#define max_code (image->info.gif.max_code)
#define max_code_size (image->info.gif.max_code_size)
#define clear_code (image->info.gif.clear_code)
#define end_code (image->info.gif.end_code)
/* for nextCode() */
#define buf (image->info.gif.buf)
/* for nextLWZ() */
#define stack (image->info.gif.stack)
#define table (image->info.gif.table)
#define firstcode (image->info.gif.firstcode)
#define oldcode (image->info.gif.oldcode)
static int
GetDataBlock(PDF *p, pdf_image *image, unsigned char *lbuf)
{
unsigned char count;
pdc_file *fp = image->fp;
if (!PDC_OK_FREAD(fp, &count, 1))
return -1; /* Error in getting DataBlock size */
ZeroDataBlock = (count == (unsigned char) 0);
if ((count != (unsigned char) 0) && (!PDC_OK_FREAD(fp, lbuf, count)))
{
/* Error in reading DataBlock */
pdc_error(p->pdc, PDF_E_IMAGE_CORRUPT, "GIF",
pdf_get_image_filename(p, image), 0, 0);
}
return count;
} /* GetDataBlock */
static void
initLWZ(PDF *p, pdf_image *image, int input_code_size)
{
#define GIF_TABLE_SIZE (sizeof(int [2][GIF_TABLE_ELEMENTS]))
#define GIF_STACK_SIZE (sizeof(int [GIF_TABLE_ELEMENTS*2]))
table = (int(*)[GIF_TABLE_ELEMENTS])
pdc_malloc(p->pdc, GIF_TABLE_SIZE, "initLWZ");
stack = (int *) pdc_malloc(p->pdc, GIF_STACK_SIZE, "initLWZ");
set_code_size = input_code_size;
code_size = set_code_size + 1;
clear_code = 1 << set_code_size ;
end_code = clear_code + 1;
max_code_size = 2 * clear_code;
max_code = clear_code + 2;
curbit = lastbit = 0;
last_byte = 2;
get_done = pdc_false;
return_clear = pdc_true;
sp = stack;
}
/*
* We clean up after decompressing the image; in rare cases (exception
* caused by damaged compressed data) this may also be called when
* cleaning up the full image struct.
*/
void
pdf_cleanup_gif(PDF *p, pdf_image *image)
{
if (table)
{
pdc_free(p->pdc, table);
table = NULL;
}
if (stack)
{
pdc_free(p->pdc, stack);
stack = NULL;
}
}
static int
nextCode(PDF *p, pdf_image *image, int codesize)
{
static const int maskTbl[16] = {
0x0000, 0x0001, 0x0003, 0x0007,
0x000f, 0x001f, 0x003f, 0x007f,
0x00ff, 0x01ff, 0x03ff, 0x07ff,
0x0fff, 0x1fff, 0x3fff, 0x7fff,
};
int i, j, ret, end;
if (return_clear) {
return_clear = pdc_false;
return clear_code;
}
end = curbit + codesize;
if (end >= lastbit) {
int count;
if (get_done) {
if (curbit >= lastbit)
{
/*
ERROR("ran off the end of my bits" );
*/
pdc_error(p->pdc, PDF_E_IMAGE_CORRUPT, "GIF",
pdf_get_image_filename(p, image), 0, 0);
}
return -1;
}
if (last_byte >= 2)
{
buf[0] = buf[last_byte-2];
buf[1] = buf[last_byte-1];
}
if ((count = GetDataBlock(p, image, &buf[2])) == 0)
get_done = pdc_true;
last_byte = 2 + count;
curbit = (curbit - lastbit) + 16;
lastbit = (2+count)*8 ;
end = curbit + codesize;
}
j = end / 8;
i = curbit / 8;
if (i == j)
ret = buf[i];
else if (i + 1 == j)
ret = buf[i] | (buf[i+1] << 8);
else
ret = buf[i] | (buf[i+1] << 8) | (buf[i+2] << 16);
ret = (ret >> (curbit % 8)) & maskTbl[codesize];
curbit += codesize;
return ret;
}
#define readLWZ(p, image) ((sp > stack) ? *--sp : nextLWZ(p, image))
static int
nextLWZ(PDF *p, pdf_image *image)
{
int code, incode;
int i;
while ((code = nextCode(p, image, code_size)) >= 0) {
if (code == clear_code) {
for (i = 0; i < clear_code; ++i) {
table[0][i] = 0;
table[1][i] = i;
}
for (; i < (1<<MAX_LWZ_BITS); ++i)
table[0][i] = table[1][i] = 0;
code_size = set_code_size+1;
max_code_size = 2*clear_code;
max_code = clear_code+2;
sp = stack;
do {
firstcode = oldcode = nextCode(p, image, code_size);
} while (firstcode == clear_code);
return firstcode;
}
if (code == end_code) {
int count;
unsigned char lbuf[260];
if (ZeroDataBlock)
return -2;
while ((count = GetDataBlock(p, image, lbuf)) > 0)
;
/* count != 0: INFO_MSG(("missing EOD in data stream")); */
return -2;
}
incode = code;
if (code >= max_code) {
*sp++ = firstcode;
code = oldcode;
}
while (code >= clear_code) {
*sp++ = table[1][code];
if (code == table[0][code])
{
/* ERROR("circular table entry BIG ERROR"); */
pdc_error(p->pdc, PDF_E_IMAGE_CORRUPT, "GIF",
pdf_get_image_filename(p, image), 0, 0);
}
code = table[0][code];
}
*sp++ = firstcode = table[1][code];
if ((code = max_code) <(1<<MAX_LWZ_BITS)) {
table[0][code] = oldcode;
table[1][code] = firstcode;
++max_code;
if ((max_code >= max_code_size) &&
(max_code_size < (1<<MAX_LWZ_BITS))) {
max_code_size *= 2;
++code_size;
}
}
oldcode = incode;
if (sp > stack)
return *--sp;
}
return code;
}
static void
ReadImage(PDF *p, pdf_image *image, PDF_data_source *src)
{
unsigned char c;
int v;
unsigned int xpos = 0, ypos = 0;
pdc_byte *dp;
unsigned int h = (unsigned int) image->height;
unsigned int w = (unsigned int) image->width;
/*
* Initialize the Compression routines
*/
ZeroDataBlock = pdc_false;
if (!PDC_OK_FREAD(image->fp, &c, 1))
{
pdc_error(p->pdc, PDF_E_IMAGE_CORRUPT, "GIF",
pdf_get_image_filename(p, image), 0, 0);
}
initLWZ(p, image, c);
if (image->info.gif.interlace) {
int i;
int pass = 0, step = 8;
for (i = 0; i < (int) h; i++) {
dp = &src->buffer_start[w * ypos];
for (xpos = 0; xpos < w; xpos++) {
if ((v = readLWZ(p, image)) < 0)
goto fini;
*dp++ = v;
}
if ((ypos += step) >= h) {
do {
if (pass++ > 0)
step /= 2;
ypos = step / 2;
} while (ypos > h);
}
}
} else {
dp = src->buffer_start;
for (ypos = 0; ypos < h; ypos++) {
for (xpos = 0; xpos < w; xpos++) {
if ((v = readLWZ(p, image)) < 0)
goto fini;
*dp++ = v;
}
}
}
fini:
if (readLWZ(p, image) >= 0)
/* Too much input data in GIF file '%s', ignoring extra. */
;
}
#undef fresh
#undef code_size
#undef set_code_size
#undef max_code
#undef max_code_size
#undef firstcode
#undef oldcode
#undef clear_code
#undef end_code
#undef sp
#undef table
#undef stack
#endif /* PDF_GIF_SUPPORTED */