6316 lines
219 KiB
C
6316 lines
219 KiB
C
/*
|
|
*
|
|
* tiff2pdf - converts a TIFF image to a PDF document
|
|
*
|
|
* Copyright (c) 2003 Ross Finlayson
|
|
*
|
|
* Permission to use, copy, modify, distribute, and sell this software and
|
|
* its documentation for any purpose is hereby granted without fee, provided
|
|
* that (i) the above copyright notices and this permission notice appear in
|
|
* all copies of the software and related documentation, and (ii) the name of
|
|
* Ross Finlayson may not be used in any advertising or
|
|
* publicity relating to the software without the specific, prior written
|
|
* permission of Ross Finlayson.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
|
|
* EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
|
|
* WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
|
|
*
|
|
* IN NO EVENT SHALL ROSS FINLAYSON BE LIABLE FOR
|
|
* ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
|
|
* OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
|
* WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
|
|
* LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
|
* OF THIS SOFTWARE.
|
|
*/
|
|
|
|
#include <ctype.h>
|
|
#include <errno.h>
|
|
#include <limits.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
|
|
#if HAVE_UNISTD_H
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
#ifdef HAVE_FCNTL_H
|
|
#include <fcntl.h>
|
|
#endif
|
|
|
|
#ifdef HAVE_IO_H
|
|
#include <io.h>
|
|
#endif
|
|
|
|
#include "libport.h"
|
|
#include "tif_config.h"
|
|
#include "tiffio.h"
|
|
#include "tiffiop.h"
|
|
|
|
#ifndef EXIT_SUCCESS
|
|
#define EXIT_SUCCESS 0
|
|
#endif
|
|
#ifndef EXIT_FAILURE
|
|
#define EXIT_FAILURE 1
|
|
#endif
|
|
|
|
#define TIFF2PDF_MODULE "tiff2pdf"
|
|
|
|
#define PS_UNIT_SIZE 72.0F
|
|
|
|
#define TIFF_DIR_MAX 65534
|
|
|
|
#define DEFAULT_MAX_MALLOC (256 * 1024 * 1024)
|
|
|
|
/* This type is of PDF color spaces. */
|
|
typedef enum
|
|
{
|
|
T2P_CS_BILEVEL = 0x01, /* Bilevel, black and white */
|
|
T2P_CS_GRAY = 0x02, /* Single channel */
|
|
T2P_CS_RGB = 0x04, /* Three channel tristimulus RGB */
|
|
T2P_CS_CMYK = 0x08, /* Four channel CMYK print inkset */
|
|
T2P_CS_LAB = 0x10, /* Three channel L*a*b* color space */
|
|
T2P_CS_PALETTE = 0x1000, /* One of the above with a color map */
|
|
T2P_CS_CALGRAY = 0x20, /* Calibrated single channel */
|
|
T2P_CS_CALRGB = 0x40, /* Calibrated three channel tristimulus RGB */
|
|
T2P_CS_ICCBASED = 0x80 /* ICC profile color specification */
|
|
} t2p_cs_t;
|
|
|
|
/* This type is of PDF compression types. */
|
|
typedef enum
|
|
{
|
|
T2P_COMPRESS_NONE = 0x00
|
|
#ifdef CCITT_SUPPORT
|
|
,
|
|
T2P_COMPRESS_G4 = 0x01
|
|
#endif
|
|
#if defined(JPEG_SUPPORT) || defined(OJPEG_SUPPORT)
|
|
,
|
|
T2P_COMPRESS_JPEG = 0x02
|
|
#endif
|
|
#ifdef ZIP_SUPPORT
|
|
,
|
|
T2P_COMPRESS_ZIP = 0x04
|
|
#endif
|
|
} t2p_compress_t;
|
|
|
|
/* This type is whether TIFF image data can be used in PDF without transcoding.
|
|
*/
|
|
typedef enum
|
|
{
|
|
T2P_TRANSCODE_RAW = 0x01, /* The raw data from the input can be used without
|
|
recompressing */
|
|
T2P_TRANSCODE_ENCODE =
|
|
0x02 /* The data from the input is perhaps unencoded and reencoded */
|
|
} t2p_transcode_t;
|
|
|
|
/* This type is of information about the data samples of the input image. */
|
|
typedef enum
|
|
{
|
|
T2P_SAMPLE_NOTHING =
|
|
0x0000, /* The unencoded samples are normal for the output colorspace */
|
|
T2P_SAMPLE_ABGR_TO_RGB =
|
|
0x0001, /* The unencoded samples are the result of ReadRGBAImage */
|
|
T2P_SAMPLE_RGBA_TO_RGB =
|
|
0x0002, /* The unencoded samples are contiguous RGBA */
|
|
T2P_SAMPLE_RGBAA_TO_RGB =
|
|
0x0004, /* The unencoded samples are RGBA with premultiplied alpha */
|
|
T2P_SAMPLE_YCBCR_TO_RGB = 0x0008,
|
|
T2P_SAMPLE_YCBCR_TO_LAB = 0x0010,
|
|
T2P_SAMPLE_REALIZE_PALETTE =
|
|
0x0020, /* The unencoded samples are indexes into the color map */
|
|
T2P_SAMPLE_SIGNED_TO_UNSIGNED =
|
|
0x0040, /* The unencoded samples are signed instead of unsignd */
|
|
T2P_SAMPLE_LAB_SIGNED_TO_UNSIGNED =
|
|
0x0040, /* The L*a*b* samples have a* and b* signed */
|
|
T2P_SAMPLE_PLANAR_SEPARATE_TO_CONTIG =
|
|
0x0100 /* The unencoded samples are separate instead of contiguous */
|
|
} t2p_sample_t;
|
|
|
|
/* This type is of error status of the T2P struct. */
|
|
typedef enum
|
|
{
|
|
T2P_ERR_OK =
|
|
0, /* This is the value of t2p->t2p_error when there is no error */
|
|
T2P_ERR_ERROR =
|
|
1 /* This is the value of t2p->t2p_error when there was an error */
|
|
} t2p_err_t;
|
|
|
|
/* This struct defines a logical page of a TIFF. */
|
|
typedef struct
|
|
{
|
|
tdir_t page_directory;
|
|
uint32_t page_number;
|
|
ttile_t page_tilecount;
|
|
uint32_t page_extra;
|
|
} T2P_PAGE;
|
|
|
|
/* This struct defines a PDF rectangle's coordinates. */
|
|
typedef struct
|
|
{
|
|
float x1;
|
|
float y1;
|
|
float x2;
|
|
float y2;
|
|
float mat[9];
|
|
} T2P_BOX;
|
|
|
|
/* This struct defines a tile of a PDF. */
|
|
typedef struct
|
|
{
|
|
T2P_BOX tile_box;
|
|
} T2P_TILE;
|
|
|
|
/* This struct defines information about the tiles on a PDF page. */
|
|
typedef struct
|
|
{
|
|
ttile_t tiles_tilecount;
|
|
uint32_t tiles_tilewidth;
|
|
uint32_t tiles_tilelength;
|
|
uint32_t tiles_tilecountx;
|
|
uint32_t tiles_tilecounty;
|
|
uint32_t tiles_edgetilewidth;
|
|
uint32_t tiles_edgetilelength;
|
|
T2P_TILE *tiles_tiles;
|
|
} T2P_TILES;
|
|
|
|
/* This struct is the context of a function to generate PDF from a TIFF. */
|
|
typedef struct
|
|
{
|
|
t2p_err_t t2p_error;
|
|
T2P_PAGE *tiff_pages;
|
|
T2P_TILES *tiff_tiles;
|
|
tdir_t tiff_pagecount;
|
|
uint16_t tiff_compression;
|
|
uint16_t tiff_photometric;
|
|
uint16_t tiff_fillorder;
|
|
uint16_t tiff_bitspersample;
|
|
uint16_t tiff_samplesperpixel;
|
|
uint16_t tiff_planar;
|
|
uint32_t tiff_width;
|
|
uint32_t tiff_length;
|
|
float tiff_xres;
|
|
float tiff_yres;
|
|
uint16_t tiff_orientation;
|
|
toff_t tiff_dataoffset;
|
|
tsize_t tiff_datasize;
|
|
tsize_t tiff_maxdatasize;
|
|
uint16_t tiff_resunit;
|
|
uint16_t pdf_centimeters;
|
|
uint16_t pdf_overrideres;
|
|
uint16_t pdf_overridepagesize;
|
|
float pdf_defaultxres;
|
|
float pdf_defaultyres;
|
|
float pdf_xres;
|
|
float pdf_yres;
|
|
float pdf_defaultpagewidth;
|
|
float pdf_defaultpagelength;
|
|
float pdf_pagewidth;
|
|
float pdf_pagelength;
|
|
float pdf_imagewidth;
|
|
float pdf_imagelength;
|
|
int pdf_image_fillpage; /* 0 (default: no scaling, 1:scale imagesize to
|
|
pagesize */
|
|
T2P_BOX pdf_mediabox;
|
|
T2P_BOX pdf_imagebox;
|
|
uint16_t pdf_majorversion;
|
|
uint16_t pdf_minorversion;
|
|
uint32_t pdf_catalog;
|
|
uint32_t pdf_pages;
|
|
uint32_t pdf_info;
|
|
uint32_t pdf_palettecs;
|
|
uint16_t pdf_fitwindow;
|
|
uint32_t pdf_startxref;
|
|
#define TIFF2PDF_FILEID_SIZE 33
|
|
char pdf_fileid[TIFF2PDF_FILEID_SIZE];
|
|
#define TIFF2PDF_DATETIME_SIZE 17
|
|
char pdf_datetime[TIFF2PDF_DATETIME_SIZE];
|
|
#define TIFF2PDF_CREATOR_SIZE 512
|
|
char pdf_creator[TIFF2PDF_CREATOR_SIZE];
|
|
int pdf_creator_set;
|
|
#define TIFF2PDF_AUTHOR_SIZE 512
|
|
char pdf_author[TIFF2PDF_AUTHOR_SIZE];
|
|
int pdf_author_set;
|
|
#define TIFF2PDF_TITLE_SIZE 512
|
|
char pdf_title[TIFF2PDF_TITLE_SIZE];
|
|
int pdf_title_set;
|
|
#define TIFF2PDF_SUBJECT_SIZE 512
|
|
char pdf_subject[TIFF2PDF_SUBJECT_SIZE];
|
|
int pdf_subject_set;
|
|
#define TIFF2PDF_KEYWORDS_SIZE 512
|
|
char pdf_keywords[TIFF2PDF_KEYWORDS_SIZE];
|
|
int pdf_keywords_set;
|
|
t2p_cs_t pdf_colorspace;
|
|
uint16_t pdf_colorspace_invert;
|
|
uint16_t pdf_switchdecode;
|
|
uint16_t pdf_palettesize;
|
|
unsigned char *pdf_palette;
|
|
int pdf_labrange[4];
|
|
t2p_compress_t pdf_defaultcompression;
|
|
uint16_t pdf_defaultcompressionquality;
|
|
t2p_compress_t pdf_compression;
|
|
uint16_t
|
|
pdf_compressionquality; /* for deflate : 100 * zipquality + predictor */
|
|
uint16_t pdf_nopassthrough;
|
|
t2p_transcode_t pdf_transcode;
|
|
t2p_sample_t pdf_sample;
|
|
uint32_t *pdf_xrefoffsets;
|
|
uint32_t pdf_xrefcount;
|
|
tdir_t pdf_page;
|
|
#ifdef OJPEG_SUPPORT
|
|
tdata_t pdf_ojpegdata;
|
|
uint32_t pdf_ojpegdatalength;
|
|
uint32_t pdf_ojpegiflength;
|
|
#endif
|
|
float tiff_whitechromaticities[2];
|
|
float tiff_primarychromaticities[6];
|
|
float tiff_referenceblackwhite[2];
|
|
uint16_t *tiff_transferfunction[3];
|
|
int pdf_image_interpolate; /* 0 (default) : do not interpolate,
|
|
1 : interpolate */
|
|
uint16_t tiff_transferfunctioncount;
|
|
uint32_t pdf_icccs;
|
|
uint32_t tiff_iccprofilelength;
|
|
tdata_t tiff_iccprofile;
|
|
|
|
/* fields for custom read/write procedures */
|
|
FILE *outputfile;
|
|
int outputdisable;
|
|
tsize_t outputwritten;
|
|
} T2P;
|
|
|
|
/* These functions are called by main. */
|
|
|
|
static void usage_info(int);
|
|
int tiff2pdf_match_paper_size(float *, float *, char *);
|
|
|
|
/* These functions are used to generate a PDF from a TIFF. */
|
|
|
|
#ifdef __cplusplus
|
|
extern "C"
|
|
{
|
|
#endif
|
|
|
|
T2P *t2p_init(void);
|
|
void t2p_validate(T2P *);
|
|
tsize_t t2p_write_pdf(T2P *, TIFF *, TIFF *);
|
|
void t2p_free(T2P *);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
void t2p_read_tiff_init(T2P *, TIFF *);
|
|
int t2p_cmp_t2p_page(const void *, const void *);
|
|
void t2p_read_tiff_data(T2P *, TIFF *);
|
|
void t2p_read_tiff_size(T2P *, TIFF *);
|
|
void t2p_read_tiff_size_tile(T2P *, TIFF *, ttile_t);
|
|
int t2p_tile_is_right_edge(T2P_TILES, ttile_t);
|
|
int t2p_tile_is_bottom_edge(T2P_TILES, ttile_t);
|
|
int t2p_tile_is_edge(T2P_TILES, ttile_t);
|
|
int t2p_tile_is_corner_edge(T2P_TILES, ttile_t);
|
|
tsize_t t2p_readwrite_pdf_image(T2P *, TIFF *, TIFF *);
|
|
tsize_t t2p_readwrite_pdf_image_tile(T2P *, TIFF *, TIFF *, ttile_t);
|
|
#ifdef OJPEG_SUPPORT
|
|
int t2p_process_ojpeg_tables(T2P *, TIFF *);
|
|
#endif
|
|
#ifdef JPEG_SUPPORT
|
|
int t2p_process_jpeg_strip(unsigned char *, tsize_t *, unsigned char *, tsize_t,
|
|
tsize_t *, tstrip_t, uint32_t);
|
|
#endif
|
|
void t2p_tile_collapse_left(tdata_t, tsize_t, uint32_t, uint32_t, uint32_t);
|
|
void t2p_write_advance_directory(T2P *, TIFF *);
|
|
tsize_t t2p_sample_planar_separate_to_contig(T2P *, unsigned char *,
|
|
unsigned char *, tsize_t);
|
|
tsize_t t2p_sample_realize_palette(T2P *, unsigned char *);
|
|
tsize_t t2p_sample_abgr_to_rgb(tdata_t, uint32_t);
|
|
tsize_t t2p_sample_rgba_to_rgb(tdata_t, uint32_t);
|
|
tsize_t t2p_sample_rgbaa_to_rgb(tdata_t, uint32_t);
|
|
tsize_t t2p_sample_lab_signed_to_unsigned(tdata_t, uint32_t);
|
|
tsize_t t2p_write_pdf_header(T2P *, TIFF *);
|
|
tsize_t t2p_write_pdf_obj_start(uint32_t, TIFF *);
|
|
tsize_t t2p_write_pdf_obj_end(TIFF *);
|
|
tsize_t t2p_write_pdf_name(const unsigned char *, TIFF *);
|
|
tsize_t t2p_write_pdf_string(const char *, TIFF *);
|
|
tsize_t t2p_write_pdf_stream(tdata_t, tsize_t, TIFF *);
|
|
tsize_t t2p_write_pdf_stream_start(TIFF *);
|
|
tsize_t t2p_write_pdf_stream_end(TIFF *);
|
|
tsize_t t2p_write_pdf_stream_dict(tsize_t, uint32_t, TIFF *);
|
|
tsize_t t2p_write_pdf_stream_dict_start(TIFF *);
|
|
tsize_t t2p_write_pdf_stream_dict_end(TIFF *);
|
|
tsize_t t2p_write_pdf_stream_length(tsize_t, TIFF *);
|
|
tsize_t t2p_write_pdf_catalog(T2P *, TIFF *);
|
|
tsize_t t2p_write_pdf_info(T2P *, TIFF *, TIFF *);
|
|
void t2p_pdf_currenttime(T2P *);
|
|
void t2p_pdf_tifftime(T2P *, TIFF *);
|
|
tsize_t t2p_write_pdf_pages(T2P *, TIFF *);
|
|
tsize_t t2p_write_pdf_page(uint32_t, T2P *, TIFF *);
|
|
void t2p_compose_pdf_page(T2P *);
|
|
void t2p_compose_pdf_page_orient(T2P_BOX *, uint16_t);
|
|
void t2p_compose_pdf_page_orient_flip(T2P_BOX *, uint16_t);
|
|
tsize_t t2p_write_pdf_page_content(T2P *, TIFF *);
|
|
tsize_t t2p_write_pdf_xobject_stream_dict(ttile_t, T2P *, TIFF *);
|
|
tsize_t t2p_write_pdf_xobject_cs(T2P *, TIFF *);
|
|
tsize_t t2p_write_pdf_transfer(T2P *, TIFF *);
|
|
tsize_t t2p_write_pdf_transfer_dict(T2P *, TIFF *, uint16_t);
|
|
tsize_t t2p_write_pdf_transfer_stream(T2P *, TIFF *, uint16_t);
|
|
tsize_t t2p_write_pdf_xobject_calcs(T2P *, TIFF *);
|
|
tsize_t t2p_write_pdf_xobject_icccs(T2P *, TIFF *);
|
|
tsize_t t2p_write_pdf_xobject_icccs_dict(T2P *, TIFF *);
|
|
tsize_t t2p_write_pdf_xobject_icccs_stream(T2P *, TIFF *);
|
|
tsize_t t2p_write_pdf_xobject_cs_stream(T2P *, TIFF *);
|
|
tsize_t t2p_write_pdf_xobject_decode(T2P *, TIFF *);
|
|
tsize_t t2p_write_pdf_xobject_stream_filter(ttile_t, T2P *, TIFF *);
|
|
tsize_t t2p_write_pdf_xreftable(T2P *, TIFF *);
|
|
tsize_t t2p_write_pdf_trailer(T2P *, TIFF *);
|
|
|
|
#define check_snprintf_ret(t2p, rv, buf) \
|
|
do \
|
|
{ \
|
|
if ((rv) < 0) \
|
|
rv = 0; \
|
|
else if ((rv) >= (int)sizeof(buf)) \
|
|
(rv) = sizeof(buf) - 1; \
|
|
else \
|
|
break; \
|
|
if ((t2p) != NULL) \
|
|
(t2p)->t2p_error = T2P_ERR_ERROR; \
|
|
} while (0)
|
|
|
|
static void t2p_disable(TIFF *tif)
|
|
{
|
|
T2P *t2p = (T2P *)TIFFClientdata(tif);
|
|
t2p->outputdisable = 1;
|
|
}
|
|
|
|
static void t2p_enable(TIFF *tif)
|
|
{
|
|
T2P *t2p = (T2P *)TIFFClientdata(tif);
|
|
t2p->outputdisable = 0;
|
|
}
|
|
|
|
/*
|
|
* Procs for TIFFClientOpen
|
|
*/
|
|
|
|
#ifdef OJPEG_SUPPORT
|
|
static tmsize_t t2pReadFile(TIFF *tif, tdata_t data, tmsize_t size)
|
|
{
|
|
thandle_t client = TIFFClientdata(tif);
|
|
TIFFReadWriteProc proc = TIFFGetReadProc(tif);
|
|
if (proc)
|
|
return proc(client, data, size);
|
|
return -1;
|
|
}
|
|
#endif /* OJPEG_SUPPORT */
|
|
|
|
static tmsize_t t2pWriteFile(TIFF *tif, tdata_t data, tmsize_t size)
|
|
{
|
|
thandle_t client = TIFFClientdata(tif);
|
|
TIFFReadWriteProc proc = TIFFGetWriteProc(tif);
|
|
if (proc)
|
|
return proc(client, data, size);
|
|
return -1;
|
|
}
|
|
|
|
static uint64_t t2pSeekFile(TIFF *tif, toff_t offset, int whence)
|
|
{
|
|
thandle_t client = TIFFClientdata(tif);
|
|
TIFFSeekProc proc = TIFFGetSeekProc(tif);
|
|
if (proc)
|
|
return proc(client, offset, whence);
|
|
return -1;
|
|
}
|
|
|
|
static tmsize_t t2p_readproc(thandle_t handle, tdata_t data, tmsize_t size)
|
|
{
|
|
(void)handle, (void)data, (void)size;
|
|
return -1;
|
|
}
|
|
|
|
static tmsize_t t2p_writeproc(thandle_t handle, tdata_t data, tmsize_t size)
|
|
{
|
|
T2P *t2p = (T2P *)handle;
|
|
if (t2p->outputdisable <= 0 && t2p->outputfile)
|
|
{
|
|
tsize_t written = fwrite(data, 1, size, t2p->outputfile);
|
|
t2p->outputwritten += written;
|
|
return written;
|
|
}
|
|
return size;
|
|
}
|
|
|
|
static uint64_t t2p_seekproc(thandle_t handle, uint64_t offset, int whence)
|
|
{
|
|
T2P *t2p = (T2P *)handle;
|
|
if (t2p->outputdisable <= 0 && t2p->outputfile != stdout && t2p->outputfile)
|
|
return _TIFF_fseek_f(t2p->outputfile, (_TIFF_off_t)offset, whence);
|
|
return offset;
|
|
}
|
|
|
|
static int t2p_closeproc(thandle_t handle)
|
|
{
|
|
T2P *t2p = (T2P *)handle;
|
|
return fclose(t2p->outputfile);
|
|
}
|
|
|
|
static uint64_t t2p_sizeproc(thandle_t handle)
|
|
{
|
|
(void)handle;
|
|
return -1;
|
|
}
|
|
|
|
static int t2p_mapproc(thandle_t handle, void **data, toff_t *offset)
|
|
{
|
|
(void)handle, (void)data, (void)offset;
|
|
return -1;
|
|
}
|
|
|
|
static void t2p_unmapproc(thandle_t handle, void *data, toff_t offset)
|
|
{
|
|
(void)handle, (void)data, (void)offset;
|
|
}
|
|
|
|
#if defined(OJPEG_SUPPORT) || defined(JPEG_SUPPORT)
|
|
static uint64_t checkAdd64(uint64_t summand1, uint64_t summand2, T2P *t2p)
|
|
{
|
|
uint64_t bytes = summand1 + summand2;
|
|
|
|
if (bytes < summand1)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE, "Integer overflow");
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
bytes = 0;
|
|
}
|
|
|
|
return bytes;
|
|
}
|
|
#endif /* defined(OJPEG_SUPPORT) || defined(JPEG_SUPPORT) */
|
|
|
|
static uint64_t checkMultiply64(uint64_t first, uint64_t second, T2P *t2p)
|
|
{
|
|
uint64_t bytes = first * second;
|
|
|
|
if (second && bytes / second != first)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE, "Integer overflow");
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
bytes = 0;
|
|
}
|
|
|
|
return bytes;
|
|
}
|
|
|
|
/*
|
|
|
|
This is the main function.
|
|
|
|
The program converts one TIFF file to one PDF file, including multiple page
|
|
TIFF files, tiled TIFF files, black and white. grayscale, and color TIFF
|
|
files that contain data of TIFF photometric interpretations of bilevel,
|
|
grayscale, RGB, YCbCr, CMYK separation, and ICC L*a*b* as supported by
|
|
libtiff and PDF.
|
|
|
|
If you have multiple TIFF files to convert into one PDF file then use tiffcp
|
|
or other program to concatenate the files into a multiple page TIFF file.
|
|
If the input TIFF file is of huge dimensions (greater than 10000 pixels height
|
|
or width) convert the input image to a tiled TIFF if it is not already.
|
|
|
|
The standard output is standard output. Set the output file name with the
|
|
"-o output.pdf" option.
|
|
|
|
All black and white files are compressed into a single strip CCITT G4 Fax
|
|
compressed PDF, unless tiled, where tiled black and white images are
|
|
compressed into tiled CCITT G4 Fax compressed PDF, libtiff CCITT support
|
|
is assumed.
|
|
|
|
Color and grayscale data can be compressed using either JPEG compression,
|
|
ITU-T T.81, or Zip/Deflate LZ77 compression, per PNG 1.2 and RFC 1951. Set
|
|
the compression type using the -j or -z options. JPEG compression support
|
|
requires that libtiff be configured with JPEG support, and Zip/Deflate
|
|
compression support requires that libtiff is configured with Zip support,
|
|
in tiffconf.h. Use only one or the other of -j and -z. The -q option
|
|
sets the image compression quality, that is 1-100 with libjpeg JPEG
|
|
compression and one of 1, 10, 11, 12, 13, 14, or 15 for PNG group compression
|
|
predictor methods, add 100, 200, ..., 900 to set zlib compression quality 1-9.
|
|
PNG Group differencing predictor methods are not currently implemented.
|
|
|
|
If the input TIFF contains single strip CCITT G4 Fax compressed information,
|
|
then that is written to the PDF file without transcoding, unless the options
|
|
of no compression and no passthrough are set, -d and -n.
|
|
|
|
If the input TIFF contains JPEG or single strip Zip/Deflate compressed
|
|
information, and they are configured, then that is written to the PDF file
|
|
without transcoding, unless the options of no compression and no passthrough
|
|
are set.
|
|
|
|
The default page size upon which the TIFF image is placed is determined by
|
|
the resolution and extent of the image data. Default values for the TIFF
|
|
image resolution can be set using the -x and -y options. The page size can
|
|
be set using the -p option for paper size, or -w and -l for paper width and
|
|
length, then each page of the TIFF image is centered on its page. The
|
|
distance unit for default resolution and page width and length can be set
|
|
by the -u option, the default unit is inch.
|
|
|
|
Various items of the output document information can be set with the -e, -c,
|
|
-a, -t, -s, and -k tags. Setting the argument of the option to "" for these
|
|
tags causes the relevant document information field to be not written. Some
|
|
of the document information values otherwise get their information from the
|
|
input TIFF image, the software, author, document name, and image description.
|
|
|
|
The output PDF file conforms to the PDF 1.1 specification or PDF 1.2 if using
|
|
Zip/Deflate compression.
|
|
|
|
The Portable Document Format (PDF) specification is copyrighted by Adobe
|
|
Systems, Incorporated. Todos derechos reservados.
|
|
|
|
Here is a listing of the usage example and the options to the tiff2pdf
|
|
program that is part of the libtiff distribution. Options followed by
|
|
a colon have a required argument.
|
|
|
|
usage: tiff2pdf [options] input.tif
|
|
|
|
options:
|
|
-o: output to file name
|
|
|
|
#ifdef JPEG_SUPPORT
|
|
-j: compress with JPEG (requires libjpeg configured with libtiff)
|
|
#endif
|
|
#ifdef ZIP_SUPPORT
|
|
printf (-z: compress with Zip/Deflate (requires zlib configured with libtiff));
|
|
#endif
|
|
-q: compression quality
|
|
-n: no compressed data passthrough
|
|
-d: do not compress (decompress)
|
|
-i: invert colors
|
|
-u: set distance unit, 'i' for inch, 'm' for centimeter
|
|
-x: set x resolution default
|
|
-y: set y resolution default
|
|
-w: width in units
|
|
-l: length in units
|
|
-r: 'd' for resolution default, 'o' for resolution override
|
|
-p: paper size, eg "letter", "legal", "a4"
|
|
-F: make the tiff fill the PDF page
|
|
-f: set pdf "fit window" user preference
|
|
-b: set PDF "Interpolate" user preference
|
|
-e: date, overrides image or current date/time default, YYYYMMDDHHMMSS
|
|
-c: creator, overrides image software default
|
|
-a: author, overrides image artist default
|
|
-t: title, overrides image document name default
|
|
-s: subject, overrides image image description default
|
|
-k: keywords
|
|
|
|
-h: usage
|
|
|
|
examples:
|
|
|
|
tiff2pdf -o output.pdf input.tiff
|
|
|
|
The above example would generate the file output.pdf from input.tiff.
|
|
|
|
tiff2pdf input.tiff
|
|
|
|
The above example would generate PDF output from input.tiff and write it
|
|
to standard output.
|
|
|
|
tiff2pdf -j -p letter -o output.pdf input.tiff
|
|
|
|
The above example would generate the file output.pdf from input.tiff,
|
|
putting the image pages on a letter sized page, compressing the output
|
|
with JPEG.
|
|
|
|
Please report bugs through:
|
|
|
|
http://bugzilla.remotesensing.org/buglist.cgi?product=libtiff
|
|
|
|
See also libtiff.3t, tiffcp.
|
|
*/
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
#if !HAVE_DECL_OPTARG
|
|
extern char *optarg;
|
|
extern int optind;
|
|
#endif
|
|
const char *outfilename = NULL;
|
|
T2P *t2p = NULL;
|
|
TIFF *input = NULL, *output = NULL;
|
|
int c, ret = EXIT_SUCCESS;
|
|
|
|
t2p = t2p_init();
|
|
|
|
if (t2p == NULL)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE, "Can't initialize context");
|
|
goto fail;
|
|
}
|
|
|
|
while (argv &&
|
|
(c = getopt(argc, argv,
|
|
"m:o:q:u:x:y:w:l:r:p:e:c:a:t:s:k:jzndifbhF")) != -1)
|
|
{
|
|
switch (c)
|
|
{
|
|
case 'm':
|
|
t2p->tiff_maxdatasize = (tsize_t)strtoul(optarg, NULL, 0) << 20;
|
|
break;
|
|
case 'o':
|
|
outfilename = optarg;
|
|
break;
|
|
#ifdef JPEG_SUPPORT
|
|
case 'j':
|
|
t2p->pdf_defaultcompression = T2P_COMPRESS_JPEG;
|
|
break;
|
|
#endif
|
|
#ifndef JPEG_SUPPORT
|
|
case 'j':
|
|
TIFFWarning(TIFF2PDF_MODULE,
|
|
"JPEG support in libtiff required for JPEG "
|
|
"compression, ignoring option");
|
|
break;
|
|
#endif
|
|
#ifdef ZIP_SUPPORT
|
|
case 'z':
|
|
t2p->pdf_defaultcompression = T2P_COMPRESS_ZIP;
|
|
break;
|
|
#endif
|
|
#ifndef ZIP_SUPPORT
|
|
case 'z':
|
|
TIFFWarning(TIFF2PDF_MODULE,
|
|
"Zip support in libtiff required for Zip "
|
|
"compression, ignoring option");
|
|
break;
|
|
#endif
|
|
case 'q':
|
|
t2p->pdf_defaultcompressionquality = atoi(optarg);
|
|
break;
|
|
case 'n':
|
|
t2p->pdf_nopassthrough = 1;
|
|
break;
|
|
case 'd':
|
|
t2p->pdf_defaultcompression = T2P_COMPRESS_NONE;
|
|
break;
|
|
case 'u':
|
|
if (optarg[0] == 'm')
|
|
{
|
|
t2p->pdf_centimeters = 1;
|
|
}
|
|
break;
|
|
case 'x':
|
|
t2p->pdf_defaultxres =
|
|
(float)atof(optarg) / (t2p->pdf_centimeters ? 2.54F : 1.0F);
|
|
break;
|
|
case 'y':
|
|
t2p->pdf_defaultyres =
|
|
(float)atof(optarg) / (t2p->pdf_centimeters ? 2.54F : 1.0F);
|
|
break;
|
|
case 'w':
|
|
t2p->pdf_overridepagesize = 1;
|
|
t2p->pdf_defaultpagewidth =
|
|
((float)atof(optarg) * PS_UNIT_SIZE) /
|
|
(t2p->pdf_centimeters ? 2.54F : 1.0F);
|
|
break;
|
|
case 'l':
|
|
t2p->pdf_overridepagesize = 1;
|
|
t2p->pdf_defaultpagelength =
|
|
((float)atof(optarg) * PS_UNIT_SIZE) /
|
|
(t2p->pdf_centimeters ? 2.54F : 1.0F);
|
|
break;
|
|
case 'r':
|
|
if (optarg[0] == 'o')
|
|
{
|
|
t2p->pdf_overrideres = 1;
|
|
}
|
|
break;
|
|
case 'p':
|
|
if (tiff2pdf_match_paper_size(&(t2p->pdf_defaultpagewidth),
|
|
&(t2p->pdf_defaultpagelength),
|
|
optarg))
|
|
{
|
|
t2p->pdf_overridepagesize = 1;
|
|
}
|
|
else
|
|
{
|
|
TIFFWarning(TIFF2PDF_MODULE,
|
|
"Unknown paper size %s, ignoring option",
|
|
optarg);
|
|
}
|
|
break;
|
|
case 'i':
|
|
t2p->pdf_colorspace_invert = 1;
|
|
break;
|
|
case 'F':
|
|
t2p->pdf_image_fillpage = 1;
|
|
break;
|
|
case 'f':
|
|
t2p->pdf_fitwindow = 1;
|
|
break;
|
|
case 'e':
|
|
if (strlen(optarg) == 0)
|
|
{
|
|
t2p->pdf_datetime[0] = '\0';
|
|
}
|
|
else
|
|
{
|
|
t2p->pdf_datetime[0] = 'D';
|
|
t2p->pdf_datetime[1] = ':';
|
|
strncpy(t2p->pdf_datetime + 2, optarg,
|
|
sizeof(t2p->pdf_datetime) - 3);
|
|
t2p->pdf_datetime[sizeof(t2p->pdf_datetime) - 1] = '\0';
|
|
}
|
|
break;
|
|
case 'c':
|
|
strncpy(t2p->pdf_creator, optarg, sizeof(t2p->pdf_creator) - 1);
|
|
t2p->pdf_creator[sizeof(t2p->pdf_creator) - 1] = '\0';
|
|
t2p->pdf_creator_set = 1;
|
|
break;
|
|
case 'a':
|
|
strncpy(t2p->pdf_author, optarg, sizeof(t2p->pdf_author) - 1);
|
|
t2p->pdf_author[sizeof(t2p->pdf_author) - 1] = '\0';
|
|
t2p->pdf_author_set = 1;
|
|
break;
|
|
case 't':
|
|
strncpy(t2p->pdf_title, optarg, sizeof(t2p->pdf_title) - 1);
|
|
t2p->pdf_title[sizeof(t2p->pdf_title) - 1] = '\0';
|
|
t2p->pdf_title_set = 1;
|
|
break;
|
|
case 's':
|
|
strncpy(t2p->pdf_subject, optarg, sizeof(t2p->pdf_subject) - 1);
|
|
t2p->pdf_subject[sizeof(t2p->pdf_subject) - 1] = '\0';
|
|
t2p->pdf_subject_set = 1;
|
|
break;
|
|
case 'k':
|
|
strncpy(t2p->pdf_keywords, optarg,
|
|
sizeof(t2p->pdf_keywords) - 1);
|
|
t2p->pdf_keywords[sizeof(t2p->pdf_keywords) - 1] = '\0';
|
|
t2p->pdf_keywords_set = 1;
|
|
break;
|
|
case 'b':
|
|
t2p->pdf_image_interpolate = 1;
|
|
break;
|
|
case 'h':
|
|
usage_info(EXIT_SUCCESS);
|
|
goto success;
|
|
case '?':
|
|
usage_info(EXIT_FAILURE);
|
|
goto fail;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Input
|
|
*/
|
|
if (argc > optind)
|
|
{
|
|
input = TIFFOpen(argv[optind++], "r");
|
|
if (input == NULL)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE, "Can't open input file %s for reading",
|
|
argv[optind - 1]);
|
|
goto fail;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE, "No input file specified");
|
|
usage_info(EXIT_FAILURE);
|
|
goto fail;
|
|
}
|
|
|
|
if (argc > optind)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE, "No support for multiple input files");
|
|
usage_info(EXIT_FAILURE);
|
|
goto fail;
|
|
}
|
|
|
|
/*
|
|
* Output
|
|
*/
|
|
t2p->outputdisable = 1;
|
|
if (outfilename)
|
|
{
|
|
t2p->outputfile = fopen(outfilename, "wb");
|
|
if (t2p->outputfile == NULL)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE, "Can't open output file %s for writing",
|
|
outfilename);
|
|
goto fail;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
outfilename = "-";
|
|
t2p->outputfile = stdout;
|
|
}
|
|
|
|
output = TIFFClientOpen(outfilename, "w", (thandle_t)t2p, t2p_readproc,
|
|
t2p_writeproc, t2p_seekproc, t2p_closeproc,
|
|
t2p_sizeproc, t2p_mapproc, t2p_unmapproc);
|
|
t2p->outputdisable = 0;
|
|
if (output == NULL)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE, "Can't initialize output descriptor");
|
|
goto fail;
|
|
}
|
|
|
|
/*
|
|
* Validate
|
|
*/
|
|
t2p_validate(t2p);
|
|
t2pSeekFile(output, (toff_t)0, SEEK_SET);
|
|
|
|
/*
|
|
* Write
|
|
*/
|
|
t2p_write_pdf(t2p, input, output);
|
|
if (t2p->t2p_error != 0)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"An error occurred creating output PDF file");
|
|
goto fail;
|
|
}
|
|
|
|
goto success;
|
|
fail:
|
|
ret = EXIT_FAILURE;
|
|
success:
|
|
if (input != NULL)
|
|
TIFFClose(input);
|
|
if (output != NULL)
|
|
TIFFClose(output);
|
|
if (t2p != NULL)
|
|
t2p_free(t2p);
|
|
return ret;
|
|
}
|
|
|
|
static void usage_info(int code)
|
|
{
|
|
static const char lines[] =
|
|
"Convert a TIFF image to a PDF document\n\n"
|
|
"usage: tiff2pdf [options] input.tiff\n"
|
|
"where options are:\n"
|
|
" -o: output to file name\n"
|
|
#ifdef JPEG_SUPPORT
|
|
" -j: compress with JPEG\n"
|
|
#endif
|
|
#ifdef ZIP_SUPPORT
|
|
" -z: compress with Zip/Deflate\n"
|
|
#endif
|
|
#if defined(JPEG_SUPPORT) || defined(ZIP_SUPPORT)
|
|
" -q: compression quality\n"
|
|
" -n: no compressed data passthrough\n"
|
|
" -d: do not compress (decompress)\n"
|
|
#endif
|
|
" -i: invert colors\n"
|
|
" -u: set distance unit, 'i' for inch, 'm' for centimeter\n"
|
|
" -x: set x resolution default in dots per unit\n"
|
|
" -y: set y resolution default in dots per unit\n"
|
|
" -w: width in units\n"
|
|
" -l: length in units\n"
|
|
" -r: 'd' for resolution default, 'o' for resolution override\n"
|
|
" -p: paper size, eg \"letter\", \"legal\", \"A4\"\n"
|
|
" -F: make the tiff fill the PDF page\n"
|
|
" -f: set PDF \"Fit Window\" user preference\n"
|
|
" -e: date, overrides image or current date/time default, "
|
|
"YYYYMMDDHHMMSS\n"
|
|
" -c: sets document creator, overrides image software default\n"
|
|
" -a: sets document author, overrides image artist default\n"
|
|
" -t: sets document title, overrides image document name default\n"
|
|
" -s: sets document subject, overrides image image description "
|
|
"default\n"
|
|
" -k: sets document keywords\n"
|
|
" -b: set PDF \"Interpolate\" user preference\n"
|
|
" -m: set memory allocation limit (in MiB). set to 0 to disable limit\n"
|
|
" -h: usage\n";
|
|
FILE *out = (code == EXIT_SUCCESS) ? stdout : stderr;
|
|
|
|
fprintf(out, "%s\n\n", TIFFGetVersion());
|
|
fprintf(out, "%s", lines);
|
|
|
|
return;
|
|
}
|
|
|
|
int tiff2pdf_match_paper_size(float *width, float *length, char *papersize)
|
|
{
|
|
|
|
size_t i, len;
|
|
const char *sizes[] = {
|
|
"LETTER", "A4", "LEGAL", "EXECUTIVE", "LETTER", "LEGAL",
|
|
"LEDGER", "TABLOID", "A", "B", "C", "D",
|
|
"E", "F", "G", "H", "J", "K",
|
|
"A10", "A9", "A8", "A7", "A6", "A5",
|
|
"A4", "A3", "A2", "A1", "A0", "2A0",
|
|
"4A0", "2A", "4A", "B10", "B9", "B8",
|
|
"B7", "B6", "B5", "B4", "B3", "B2",
|
|
"B1", "B0", "JISB10", "JISB9", "JISB8", "JISB7",
|
|
"JISB6", "JISB5", "JISB4", "JISB3", "JISB2", "JISB1",
|
|
"JISB0", "C10", "C9", "C8", "C7", "C6",
|
|
"C5", "C4", "C3", "C2", "C1", "C0",
|
|
"RA2", "RA1", "RA0", "SRA4", "SRA3", "SRA2",
|
|
"SRA1", "SRA0", "A3EXTRA", "A4EXTRA", "STATEMENT", "FOLIO",
|
|
"QUARTO", NULL};
|
|
const int widths[] = {
|
|
612, 595, 612, 522, 612, 612, 792, 792, 612, 792, 1224, 1584,
|
|
2448, 2016, 792, 2016, 2448, 2880, 74, 105, 147, 210, 298, 420,
|
|
595, 842, 1191, 1684, 2384, 3370, 4768, 3370, 4768, 88, 125, 176,
|
|
249, 354, 499, 709, 1001, 1417, 2004, 2835, 91, 128, 181, 258,
|
|
363, 516, 729, 1032, 1460, 2064, 2920, 79, 113, 162, 230, 323,
|
|
459, 649, 918, 1298, 1298, 2599, 1219, 1729, 2438, 638, 907, 1276,
|
|
1814, 2551, 914, 667, 396, 612, 609, 0};
|
|
const int lengths[] = {
|
|
792, 842, 1008, 756, 792, 1008, 1224, 1224, 792, 1224,
|
|
1584, 2448, 3168, 2880, 6480, 10296, 12672, 10296, 105, 147,
|
|
210, 298, 420, 595, 842, 1191, 1684, 2384, 3370, 4768,
|
|
6741, 4768, 6741, 125, 176, 249, 354, 499, 709, 1001,
|
|
1417, 2004, 2835, 4008, 128, 181, 258, 363, 516, 729,
|
|
1032, 1460, 2064, 2920, 4127, 113, 162, 230, 323, 459,
|
|
649, 918, 1298, 1837, 1837, 3677, 1729, 2438, 3458, 907,
|
|
1276, 1814, 2551, 3628, 1262, 914, 612, 936, 780, 0};
|
|
|
|
len = strlen(papersize);
|
|
for (i = 0; i < len; i++)
|
|
{
|
|
papersize[i] = toupper((int)papersize[i]);
|
|
}
|
|
for (i = 0; sizes[i] != NULL; i++)
|
|
{
|
|
if (strcmp((const char *)papersize, sizes[i]) == 0)
|
|
{
|
|
*width = (float)widths[i];
|
|
*length = (float)lengths[i];
|
|
return (1);
|
|
}
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* This function allocates and initializes a T2P context struct pointer.
|
|
*/
|
|
|
|
T2P *t2p_init()
|
|
{
|
|
T2P *t2p = (T2P *)_TIFFmalloc(sizeof(T2P));
|
|
if (t2p == NULL)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"Can't allocate %" TIFF_SIZE_FORMAT
|
|
" bytes of memory for t2p_init",
|
|
sizeof(T2P));
|
|
return ((T2P *)NULL);
|
|
}
|
|
_TIFFmemset(t2p, 0x00, sizeof(T2P));
|
|
t2p->pdf_majorversion = 1;
|
|
t2p->pdf_minorversion = 1;
|
|
t2p->pdf_defaultxres = 300.0;
|
|
t2p->pdf_defaultyres = 300.0;
|
|
t2p->pdf_defaultpagewidth = 612.0;
|
|
t2p->pdf_defaultpagelength = 792.0;
|
|
t2p->pdf_xrefcount = 3; /* Catalog, Info, Pages */
|
|
t2p->tiff_maxdatasize = DEFAULT_MAX_MALLOC;
|
|
|
|
return (t2p);
|
|
}
|
|
|
|
/*
|
|
* This function frees a T2P context struct pointer and any allocated data
|
|
* fields of it.
|
|
*/
|
|
|
|
void t2p_free(T2P *t2p)
|
|
{
|
|
int i = 0;
|
|
|
|
if (t2p != NULL)
|
|
{
|
|
if (t2p->pdf_xrefoffsets != NULL)
|
|
{
|
|
_TIFFfree((tdata_t)t2p->pdf_xrefoffsets);
|
|
}
|
|
if (t2p->tiff_pages != NULL)
|
|
{
|
|
_TIFFfree((tdata_t)t2p->tiff_pages);
|
|
}
|
|
for (i = 0; i < t2p->tiff_pagecount; i++)
|
|
{
|
|
if (t2p->tiff_tiles[i].tiles_tiles != NULL)
|
|
{
|
|
_TIFFfree((tdata_t)t2p->tiff_tiles[i].tiles_tiles);
|
|
}
|
|
}
|
|
if (t2p->tiff_tiles != NULL)
|
|
{
|
|
_TIFFfree((tdata_t)t2p->tiff_tiles);
|
|
}
|
|
if (t2p->pdf_palette != NULL)
|
|
{
|
|
_TIFFfree((tdata_t)t2p->pdf_palette);
|
|
}
|
|
#ifdef OJPEG_SUPPORT
|
|
if (t2p->pdf_ojpegdata != NULL)
|
|
{
|
|
_TIFFfree((tdata_t)t2p->pdf_ojpegdata);
|
|
}
|
|
#endif
|
|
_TIFFfree((tdata_t)t2p);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/*
|
|
This function validates the values of a T2P context struct pointer
|
|
before calling t2p_write_pdf with it.
|
|
*/
|
|
|
|
void t2p_validate(T2P *t2p)
|
|
{
|
|
(void)t2p;
|
|
|
|
#ifdef JPEG_SUPPORT
|
|
if (t2p->pdf_defaultcompression == T2P_COMPRESS_JPEG)
|
|
{
|
|
if (t2p->pdf_defaultcompressionquality > 100 ||
|
|
t2p->pdf_defaultcompressionquality < 1)
|
|
{
|
|
t2p->pdf_defaultcompressionquality = 0;
|
|
}
|
|
}
|
|
#endif
|
|
#ifdef ZIP_SUPPORT
|
|
if (t2p->pdf_defaultcompression == T2P_COMPRESS_ZIP)
|
|
{
|
|
uint16_t m = t2p->pdf_defaultcompressionquality % 100;
|
|
if (t2p->pdf_defaultcompressionquality / 100 > 9 || (m > 1 && m < 10) ||
|
|
m > 15)
|
|
{
|
|
t2p->pdf_defaultcompressionquality = 0;
|
|
}
|
|
if (t2p->pdf_defaultcompressionquality % 100 != 0)
|
|
{
|
|
t2p->pdf_defaultcompressionquality /= 100;
|
|
t2p->pdf_defaultcompressionquality *= 100;
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"PNG Group predictor differencing not implemented, "
|
|
"assuming compression quality %" PRIu16,
|
|
t2p->pdf_defaultcompressionquality);
|
|
}
|
|
t2p->pdf_defaultcompressionquality %= 100;
|
|
if (t2p->pdf_minorversion < 2)
|
|
{
|
|
t2p->pdf_minorversion = 2;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
/*
|
|
This function scans the input TIFF file for pages. It attempts
|
|
to determine which IFD's of the TIFF file contain image document
|
|
pages. For each, it gathers some information that has to do
|
|
with the output of the PDF document as a whole.
|
|
*/
|
|
|
|
void t2p_read_tiff_init(T2P *t2p, TIFF *input)
|
|
{
|
|
|
|
tdir_t directorycount = 0;
|
|
tdir_t i = 0;
|
|
uint16_t pagen = 0;
|
|
uint16_t paged = 0;
|
|
uint16_t xuint16 = 0;
|
|
uint16_t tiff_transferfunctioncount = 0;
|
|
uint16_t *tiff_transferfunction[3];
|
|
|
|
directorycount = TIFFNumberOfDirectories(input);
|
|
if (directorycount > TIFF_DIR_MAX)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE, "TIFF contains too many directories, %s",
|
|
TIFFFileName(input));
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return;
|
|
}
|
|
t2p->tiff_pages = (T2P_PAGE *)_TIFFmalloc(
|
|
TIFFSafeMultiply(tmsize_t, directorycount, sizeof(T2P_PAGE)));
|
|
if (t2p->tiff_pages == NULL)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"Can't allocate %" TIFF_SIZE_FORMAT
|
|
" bytes of memory for tiff_pages array, %s",
|
|
sizeof(T2P_PAGE) * directorycount, TIFFFileName(input));
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return;
|
|
}
|
|
_TIFFmemset(t2p->tiff_pages, 0x00, directorycount * sizeof(T2P_PAGE));
|
|
t2p->tiff_tiles = (T2P_TILES *)_TIFFmalloc(
|
|
TIFFSafeMultiply(tmsize_t, directorycount, sizeof(T2P_TILES)));
|
|
if (t2p->tiff_tiles == NULL)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"Can't allocate %" TIFF_SIZE_FORMAT
|
|
" bytes of memory for tiff_tiles array, %s",
|
|
sizeof(T2P_TILES) * directorycount, TIFFFileName(input));
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return;
|
|
}
|
|
_TIFFmemset(t2p->tiff_tiles, 0x00, directorycount * sizeof(T2P_TILES));
|
|
for (i = 0; i < directorycount; i++)
|
|
{
|
|
uint32_t subfiletype = 0;
|
|
|
|
if (!TIFFSetDirectory(input, i))
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"Can't set directory %" PRIu16 " of input file %s", i,
|
|
TIFFFileName(input));
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return;
|
|
}
|
|
if (TIFFGetField(input, TIFFTAG_PAGENUMBER, &pagen, &paged))
|
|
{
|
|
if ((pagen > paged) && (paged != 0))
|
|
{
|
|
t2p->tiff_pages[t2p->tiff_pagecount].page_number = paged;
|
|
}
|
|
else
|
|
{
|
|
t2p->tiff_pages[t2p->tiff_pagecount].page_number = pagen;
|
|
}
|
|
goto ispage2;
|
|
}
|
|
if (TIFFGetField(input, TIFFTAG_SUBFILETYPE, &subfiletype))
|
|
{
|
|
if (((subfiletype & FILETYPE_PAGE) != 0) || (subfiletype == 0))
|
|
{
|
|
goto ispage;
|
|
}
|
|
else
|
|
{
|
|
goto isnotpage;
|
|
}
|
|
}
|
|
if (TIFFGetField(input, TIFFTAG_OSUBFILETYPE, &subfiletype))
|
|
{
|
|
if ((subfiletype == OFILETYPE_IMAGE) ||
|
|
(subfiletype == OFILETYPE_PAGE) || (subfiletype == 0))
|
|
{
|
|
goto ispage;
|
|
}
|
|
else
|
|
{
|
|
goto isnotpage;
|
|
}
|
|
}
|
|
ispage:
|
|
t2p->tiff_pages[t2p->tiff_pagecount].page_number = t2p->tiff_pagecount;
|
|
ispage2:
|
|
t2p->tiff_pages[t2p->tiff_pagecount].page_directory = i;
|
|
if (TIFFIsTiled(input))
|
|
{
|
|
t2p->tiff_pages[t2p->tiff_pagecount].page_tilecount =
|
|
TIFFNumberOfTiles(input);
|
|
}
|
|
t2p->tiff_pagecount++;
|
|
isnotpage:
|
|
(void)0;
|
|
}
|
|
|
|
qsort((void *)t2p->tiff_pages, t2p->tiff_pagecount, sizeof(T2P_PAGE),
|
|
t2p_cmp_t2p_page);
|
|
|
|
for (i = 0; i < t2p->tiff_pagecount; i++)
|
|
{
|
|
t2p->pdf_xrefcount += 5;
|
|
TIFFSetDirectory(input, t2p->tiff_pages[i].page_directory);
|
|
if ((TIFFGetField(input, TIFFTAG_PHOTOMETRIC, &xuint16) &&
|
|
(xuint16 == PHOTOMETRIC_PALETTE)) ||
|
|
TIFFGetField(input, TIFFTAG_INDEXED, &xuint16))
|
|
{
|
|
t2p->tiff_pages[i].page_extra++;
|
|
t2p->pdf_xrefcount++;
|
|
}
|
|
#ifdef ZIP_SUPPORT
|
|
if (TIFFGetField(input, TIFFTAG_COMPRESSION, &xuint16))
|
|
{
|
|
if ((xuint16 == COMPRESSION_DEFLATE ||
|
|
xuint16 == COMPRESSION_ADOBE_DEFLATE) &&
|
|
((t2p->tiff_pages[i].page_tilecount != 0) ||
|
|
TIFFNumberOfStrips(input) == 1) &&
|
|
(t2p->pdf_nopassthrough == 0))
|
|
{
|
|
if (t2p->pdf_minorversion < 2)
|
|
{
|
|
t2p->pdf_minorversion = 2;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
if (TIFFGetField(
|
|
input, TIFFTAG_TRANSFERFUNCTION, &(tiff_transferfunction[0]),
|
|
&(tiff_transferfunction[1]), &(tiff_transferfunction[2])))
|
|
{
|
|
|
|
if ((tiff_transferfunction[1] != (uint16_t *)NULL) &&
|
|
(tiff_transferfunction[2] != (uint16_t *)NULL))
|
|
{
|
|
tiff_transferfunctioncount = 3;
|
|
}
|
|
else
|
|
{
|
|
tiff_transferfunctioncount = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
tiff_transferfunctioncount = 0;
|
|
}
|
|
|
|
if (i > 0)
|
|
{
|
|
if (tiff_transferfunctioncount != t2p->tiff_transferfunctioncount)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"Different transfer function on page %" PRIu16, i);
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return;
|
|
}
|
|
}
|
|
|
|
t2p->tiff_transferfunctioncount = tiff_transferfunctioncount;
|
|
t2p->tiff_transferfunction[0] = tiff_transferfunction[0];
|
|
t2p->tiff_transferfunction[1] = tiff_transferfunction[1];
|
|
t2p->tiff_transferfunction[2] = tiff_transferfunction[2];
|
|
if (tiff_transferfunctioncount == 3)
|
|
{
|
|
t2p->tiff_pages[i].page_extra += 4;
|
|
t2p->pdf_xrefcount += 4;
|
|
if (t2p->pdf_minorversion < 2)
|
|
t2p->pdf_minorversion = 2;
|
|
}
|
|
else if (tiff_transferfunctioncount == 1)
|
|
{
|
|
t2p->tiff_pages[i].page_extra += 2;
|
|
t2p->pdf_xrefcount += 2;
|
|
if (t2p->pdf_minorversion < 2)
|
|
t2p->pdf_minorversion = 2;
|
|
}
|
|
|
|
if (TIFFGetField(input, TIFFTAG_ICCPROFILE,
|
|
&(t2p->tiff_iccprofilelength),
|
|
&(t2p->tiff_iccprofile)) != 0)
|
|
{
|
|
t2p->tiff_pages[i].page_extra++;
|
|
t2p->pdf_xrefcount++;
|
|
if (t2p->pdf_minorversion < 3)
|
|
{
|
|
t2p->pdf_minorversion = 3;
|
|
}
|
|
}
|
|
t2p->tiff_tiles[i].tiles_tilecount = t2p->tiff_pages[i].page_tilecount;
|
|
if ((TIFFGetField(input, TIFFTAG_PLANARCONFIG, &xuint16) != 0) &&
|
|
(xuint16 == PLANARCONFIG_SEPARATE))
|
|
{
|
|
if (!TIFFGetField(input, TIFFTAG_SAMPLESPERPIXEL, &xuint16))
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE, "Missing SamplesPerPixel, %s",
|
|
TIFFFileName(input));
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return;
|
|
}
|
|
if ((t2p->tiff_tiles[i].tiles_tilecount % xuint16) != 0)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE, "Invalid tile count, %s",
|
|
TIFFFileName(input));
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return;
|
|
}
|
|
t2p->tiff_tiles[i].tiles_tilecount /= xuint16;
|
|
}
|
|
if (t2p->tiff_tiles[i].tiles_tilecount > 0)
|
|
{
|
|
t2p->pdf_xrefcount += (t2p->tiff_tiles[i].tiles_tilecount - 1) * 2;
|
|
TIFFGetField(input, TIFFTAG_TILEWIDTH,
|
|
&(t2p->tiff_tiles[i].tiles_tilewidth));
|
|
TIFFGetField(input, TIFFTAG_TILELENGTH,
|
|
&(t2p->tiff_tiles[i].tiles_tilelength));
|
|
t2p->tiff_tiles[i].tiles_tiles = (T2P_TILE *)_TIFFmalloc(
|
|
TIFFSafeMultiply(tmsize_t, t2p->tiff_tiles[i].tiles_tilecount,
|
|
sizeof(T2P_TILE)));
|
|
if (t2p->tiff_tiles[i].tiles_tiles == NULL)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"Can't allocate %" TIFF_SIZE_FORMAT
|
|
" bytes of memory for t2p_read_tiff_init, %s",
|
|
sizeof(T2P_TILE) * t2p->tiff_tiles[i].tiles_tilecount,
|
|
TIFFFileName(input));
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* This function is used by qsort to sort a T2P_PAGE* array of page structures
|
|
* by page number. If the page numbers are the same, we fall back to comparing
|
|
* directory numbers to preserve the order of the input file.
|
|
*/
|
|
|
|
int t2p_cmp_t2p_page(const void *e1, const void *e2)
|
|
{
|
|
|
|
int d;
|
|
d = (int32_t)(((T2P_PAGE *)e1)->page_number) -
|
|
(int32_t)(((T2P_PAGE *)e2)->page_number);
|
|
if (d == 0)
|
|
{
|
|
d = (int32_t)(((T2P_PAGE *)e1)->page_directory) -
|
|
(int32_t)(((T2P_PAGE *)e2)->page_directory);
|
|
}
|
|
return d;
|
|
}
|
|
|
|
/*
|
|
This function sets the input directory to the directory of a given
|
|
page and determines information about the image. It checks
|
|
the image characteristics to determine if it is possible to convert
|
|
the image data into a page of PDF output, setting values of the T2P
|
|
struct for this page. It determines what color space is used in
|
|
the output PDF to represent the image.
|
|
|
|
It determines if the image can be converted as raw data without
|
|
requiring transcoding of the image data.
|
|
*/
|
|
|
|
void t2p_read_tiff_data(T2P *t2p, TIFF *input)
|
|
{
|
|
|
|
int i = 0;
|
|
uint16_t *r = NULL;
|
|
uint16_t *g = NULL;
|
|
uint16_t *b = NULL;
|
|
uint16_t *a = NULL;
|
|
uint16_t xuint16;
|
|
uint16_t *xuint16p;
|
|
float *xfloatp;
|
|
int palette_16bit = 0;
|
|
int palette_shift = 8;
|
|
|
|
t2p->pdf_transcode = T2P_TRANSCODE_ENCODE;
|
|
t2p->pdf_sample = T2P_SAMPLE_NOTHING;
|
|
t2p->pdf_switchdecode = t2p->pdf_colorspace_invert;
|
|
|
|
TIFFSetDirectory(input, t2p->tiff_pages[t2p->pdf_page].page_directory);
|
|
|
|
TIFFGetField(input, TIFFTAG_IMAGEWIDTH, &(t2p->tiff_width));
|
|
if (t2p->tiff_width == 0)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE, "No support for %s with zero width",
|
|
TIFFFileName(input));
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return;
|
|
}
|
|
|
|
TIFFGetField(input, TIFFTAG_IMAGELENGTH, &(t2p->tiff_length));
|
|
if (t2p->tiff_length == 0)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE, "No support for %s with zero length",
|
|
TIFFFileName(input));
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return;
|
|
}
|
|
|
|
if (TIFFGetField(input, TIFFTAG_COMPRESSION, &(t2p->tiff_compression)) == 0)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE, "No support for %s with no compression tag",
|
|
TIFFFileName(input));
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return;
|
|
}
|
|
if (TIFFIsCODECConfigured(t2p->tiff_compression) == 0)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"No support for %s with compression type %" PRIu16
|
|
": not configured",
|
|
TIFFFileName(input), t2p->tiff_compression);
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return;
|
|
}
|
|
|
|
TIFFGetFieldDefaulted(input, TIFFTAG_BITSPERSAMPLE,
|
|
&(t2p->tiff_bitspersample));
|
|
switch (t2p->tiff_bitspersample)
|
|
{
|
|
case 1:
|
|
case 2:
|
|
case 4:
|
|
case 8:
|
|
break;
|
|
case 0:
|
|
TIFFWarning(TIFF2PDF_MODULE,
|
|
"Image %s has 0 bits per sample, assuming 1",
|
|
TIFFFileName(input));
|
|
t2p->tiff_bitspersample = 1;
|
|
break;
|
|
default:
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"No support for %s with %" PRIu16 " bits per sample",
|
|
TIFFFileName(input), t2p->tiff_bitspersample);
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return;
|
|
}
|
|
|
|
TIFFGetFieldDefaulted(input, TIFFTAG_SAMPLESPERPIXEL,
|
|
&(t2p->tiff_samplesperpixel));
|
|
if (t2p->tiff_samplesperpixel > 4)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"No support for %s with %" PRIu16 " samples per pixel",
|
|
TIFFFileName(input), t2p->tiff_samplesperpixel);
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return;
|
|
}
|
|
if (t2p->tiff_samplesperpixel == 0)
|
|
{
|
|
TIFFWarning(TIFF2PDF_MODULE,
|
|
"Image %s has 0 samples per pixel, assuming 1",
|
|
TIFFFileName(input));
|
|
t2p->tiff_samplesperpixel = 1;
|
|
}
|
|
|
|
if (TIFFGetField(input, TIFFTAG_SAMPLEFORMAT, &xuint16) != 0)
|
|
{
|
|
switch (xuint16)
|
|
{
|
|
case 0:
|
|
case 1:
|
|
case 4:
|
|
break;
|
|
default:
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"No support for %s with sample format %" PRIu16,
|
|
TIFFFileName(input), xuint16);
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return;
|
|
break;
|
|
}
|
|
}
|
|
|
|
TIFFGetFieldDefaulted(input, TIFFTAG_FILLORDER, &(t2p->tiff_fillorder));
|
|
|
|
if (TIFFGetField(input, TIFFTAG_PHOTOMETRIC, &(t2p->tiff_photometric)) == 0)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"No support for %s with no photometric interpretation tag",
|
|
TIFFFileName(input));
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return;
|
|
}
|
|
|
|
switch (t2p->tiff_photometric)
|
|
{
|
|
case PHOTOMETRIC_MINISWHITE:
|
|
case PHOTOMETRIC_MINISBLACK:
|
|
if (t2p->tiff_bitspersample == 1)
|
|
{
|
|
t2p->pdf_colorspace = T2P_CS_BILEVEL;
|
|
if (t2p->tiff_photometric == PHOTOMETRIC_MINISWHITE)
|
|
{
|
|
t2p->pdf_switchdecode ^= 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
t2p->pdf_colorspace = T2P_CS_GRAY;
|
|
if (t2p->tiff_photometric == PHOTOMETRIC_MINISWHITE)
|
|
{
|
|
t2p->pdf_switchdecode ^= 1;
|
|
}
|
|
}
|
|
break;
|
|
case PHOTOMETRIC_RGB:
|
|
t2p->pdf_colorspace = T2P_CS_RGB;
|
|
if (t2p->tiff_samplesperpixel == 3)
|
|
{
|
|
break;
|
|
}
|
|
if (TIFFGetField(input, TIFFTAG_INDEXED, &xuint16))
|
|
{
|
|
if (xuint16 == 1)
|
|
goto photometric_palette;
|
|
}
|
|
if (t2p->tiff_samplesperpixel > 3)
|
|
{
|
|
if (t2p->tiff_samplesperpixel == 4)
|
|
{
|
|
t2p->pdf_colorspace = T2P_CS_RGB;
|
|
if (TIFFGetField(input, TIFFTAG_EXTRASAMPLES, &xuint16,
|
|
&xuint16p) &&
|
|
xuint16 == 1)
|
|
{
|
|
if (xuint16p[0] == EXTRASAMPLE_ASSOCALPHA)
|
|
{
|
|
if (t2p->tiff_bitspersample != 8)
|
|
{
|
|
TIFFError(
|
|
TIFF2PDF_MODULE,
|
|
"No support for BitsPerSample=%" PRIu16
|
|
" for RGBA",
|
|
t2p->tiff_bitspersample);
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return;
|
|
}
|
|
t2p->pdf_sample = T2P_SAMPLE_RGBAA_TO_RGB;
|
|
break;
|
|
}
|
|
if (xuint16p[0] == EXTRASAMPLE_UNASSALPHA)
|
|
{
|
|
if (t2p->tiff_bitspersample != 8)
|
|
{
|
|
TIFFError(
|
|
TIFF2PDF_MODULE,
|
|
"No support for BitsPerSample=%" PRIu16
|
|
" for RGBA",
|
|
t2p->tiff_bitspersample);
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return;
|
|
}
|
|
t2p->pdf_sample = T2P_SAMPLE_RGBA_TO_RGB;
|
|
break;
|
|
}
|
|
TIFFWarning(TIFF2PDF_MODULE,
|
|
"RGB image %s has 4 samples per pixel, "
|
|
"assuming RGBA",
|
|
TIFFFileName(input));
|
|
break;
|
|
}
|
|
t2p->pdf_colorspace = T2P_CS_CMYK;
|
|
t2p->pdf_switchdecode ^= 1;
|
|
TIFFWarning(TIFF2PDF_MODULE,
|
|
"RGB image %s has 4 samples per pixel, "
|
|
"assuming inverse CMYK",
|
|
TIFFFileName(input));
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"No support for RGB image %s with %" PRIu16
|
|
" samples per pixel",
|
|
TIFFFileName(input), t2p->tiff_samplesperpixel);
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"No support for RGB image %s with %" PRIu16
|
|
" samples per pixel",
|
|
TIFFFileName(input), t2p->tiff_samplesperpixel);
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
break;
|
|
}
|
|
case PHOTOMETRIC_PALETTE:
|
|
photometric_palette:
|
|
if (t2p->tiff_samplesperpixel != 1)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"No support for palettized image %s with not one "
|
|
"sample per pixel",
|
|
TIFFFileName(input));
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return;
|
|
}
|
|
t2p->pdf_colorspace = T2P_CS_RGB | T2P_CS_PALETTE;
|
|
t2p->pdf_palettesize = 0x0001 << t2p->tiff_bitspersample;
|
|
if (!TIFFGetField(input, TIFFTAG_COLORMAP, &r, &g, &b))
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"Palettized image %s has no color map",
|
|
TIFFFileName(input));
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return;
|
|
}
|
|
if (r == NULL || g == NULL || b == NULL)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"Error getting 3 components from color map");
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return;
|
|
}
|
|
if (t2p->pdf_palette != NULL)
|
|
{
|
|
_TIFFfree(t2p->pdf_palette);
|
|
t2p->pdf_palette = NULL;
|
|
}
|
|
t2p->pdf_palette = (unsigned char *)_TIFFmalloc(
|
|
TIFFSafeMultiply(tmsize_t, t2p->pdf_palettesize, 3));
|
|
if (t2p->pdf_palette == NULL)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"Can't allocate %" PRIu16
|
|
" bytes of memory for t2p_read_tiff_image, %s",
|
|
t2p->pdf_palettesize, TIFFFileName(input));
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return;
|
|
}
|
|
/* Some older tiffs may have colors in the palette
|
|
* ranging from 0 to 255 rather than 0 to 65535. */
|
|
for (i = 0; i < t2p->pdf_palettesize; i++)
|
|
{
|
|
if ((r[i] > 255) || (g[i] > 255) || (b[i] > 255))
|
|
{
|
|
palette_16bit = 1;
|
|
break;
|
|
}
|
|
}
|
|
if (palette_16bit == 0)
|
|
{
|
|
TIFFWarning(TIFFFileName(input), "Assuming 8-bit colormap");
|
|
palette_shift = 0;
|
|
}
|
|
for (i = 0; i < t2p->pdf_palettesize; i++)
|
|
{
|
|
t2p->pdf_palette[(i * 3)] =
|
|
(unsigned char)(r[i] >> palette_shift);
|
|
t2p->pdf_palette[(i * 3) + 1] =
|
|
(unsigned char)(g[i] >> palette_shift);
|
|
t2p->pdf_palette[(i * 3) + 2] =
|
|
(unsigned char)(b[i] >> palette_shift);
|
|
}
|
|
t2p->pdf_palettesize *= 3;
|
|
break;
|
|
case PHOTOMETRIC_SEPARATED:
|
|
if (TIFFGetField(input, TIFFTAG_INDEXED, &xuint16))
|
|
{
|
|
if (xuint16 == 1)
|
|
{
|
|
goto photometric_palette_cmyk;
|
|
}
|
|
}
|
|
if (TIFFGetField(input, TIFFTAG_INKSET, &xuint16))
|
|
{
|
|
if (xuint16 != INKSET_CMYK)
|
|
{
|
|
TIFFError(
|
|
TIFF2PDF_MODULE,
|
|
"No support for %s because its inkset is not CMYK",
|
|
TIFFFileName(input));
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return;
|
|
}
|
|
}
|
|
if (t2p->tiff_samplesperpixel == 4)
|
|
{
|
|
t2p->pdf_colorspace = T2P_CS_CMYK;
|
|
}
|
|
else
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"No support for %s because it has %" PRIu16
|
|
" samples per pixel",
|
|
TIFFFileName(input), t2p->tiff_samplesperpixel);
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return;
|
|
}
|
|
break;
|
|
photometric_palette_cmyk:
|
|
if (t2p->tiff_samplesperpixel != 1)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"No support for palettized CMYK image %s with not "
|
|
"one sample per pixel",
|
|
TIFFFileName(input));
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return;
|
|
}
|
|
t2p->pdf_colorspace = T2P_CS_CMYK | T2P_CS_PALETTE;
|
|
t2p->pdf_palettesize = 0x0001 << t2p->tiff_bitspersample;
|
|
if (!TIFFGetField(input, TIFFTAG_COLORMAP, &r, &g, &b, &a))
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"Palettized image %s has no color map",
|
|
TIFFFileName(input));
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return;
|
|
}
|
|
if (r == NULL || g == NULL || b == NULL || a == NULL)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"Error getting 4 components from color map");
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return;
|
|
}
|
|
if (t2p->pdf_palette != NULL)
|
|
{
|
|
_TIFFfree(t2p->pdf_palette);
|
|
t2p->pdf_palette = NULL;
|
|
}
|
|
t2p->pdf_palette = (unsigned char *)_TIFFmalloc(
|
|
TIFFSafeMultiply(tmsize_t, t2p->pdf_palettesize, 4));
|
|
if (t2p->pdf_palette == NULL)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"Can't allocate %" PRIu16
|
|
" bytes of memory for t2p_read_tiff_image, %s",
|
|
t2p->pdf_palettesize, TIFFFileName(input));
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return;
|
|
}
|
|
for (i = 0; i < t2p->pdf_palettesize; i++)
|
|
{
|
|
t2p->pdf_palette[(i * 4)] = (unsigned char)(r[i] >> 8);
|
|
t2p->pdf_palette[(i * 4) + 1] = (unsigned char)(g[i] >> 8);
|
|
t2p->pdf_palette[(i * 4) + 2] = (unsigned char)(b[i] >> 8);
|
|
t2p->pdf_palette[(i * 4) + 3] = (unsigned char)(a[i] >> 8);
|
|
}
|
|
t2p->pdf_palettesize *= 4;
|
|
break;
|
|
case PHOTOMETRIC_YCBCR:
|
|
t2p->pdf_colorspace = T2P_CS_RGB;
|
|
if (t2p->tiff_samplesperpixel == 1)
|
|
{
|
|
t2p->pdf_colorspace = T2P_CS_GRAY;
|
|
t2p->tiff_photometric = PHOTOMETRIC_MINISBLACK;
|
|
break;
|
|
}
|
|
t2p->pdf_sample = T2P_SAMPLE_YCBCR_TO_RGB;
|
|
#ifdef JPEG_SUPPORT
|
|
if (t2p->pdf_defaultcompression == T2P_COMPRESS_JPEG)
|
|
{
|
|
t2p->pdf_sample = T2P_SAMPLE_NOTHING;
|
|
}
|
|
#endif
|
|
break;
|
|
case PHOTOMETRIC_CIELAB:
|
|
if (t2p->tiff_samplesperpixel != 3)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"Unsupported samplesperpixel = %" PRIu16
|
|
" for CIELAB",
|
|
t2p->tiff_samplesperpixel);
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return;
|
|
}
|
|
if (t2p->tiff_bitspersample != 8)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"Invalid bitspersample = %" PRIu16 " for CIELAB",
|
|
t2p->tiff_bitspersample);
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return;
|
|
}
|
|
t2p->pdf_labrange[0] = -127;
|
|
t2p->pdf_labrange[1] = 127;
|
|
t2p->pdf_labrange[2] = -127;
|
|
t2p->pdf_labrange[3] = 127;
|
|
t2p->pdf_sample = T2P_SAMPLE_LAB_SIGNED_TO_UNSIGNED;
|
|
t2p->pdf_colorspace = T2P_CS_LAB;
|
|
break;
|
|
case PHOTOMETRIC_ICCLAB:
|
|
t2p->pdf_labrange[0] = 0;
|
|
t2p->pdf_labrange[1] = 255;
|
|
t2p->pdf_labrange[2] = 0;
|
|
t2p->pdf_labrange[3] = 255;
|
|
t2p->pdf_colorspace = T2P_CS_LAB;
|
|
break;
|
|
case PHOTOMETRIC_ITULAB:
|
|
if (t2p->tiff_samplesperpixel != 3)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"Unsupported samplesperpixel = %" PRIu16
|
|
" for ITULAB",
|
|
t2p->tiff_samplesperpixel);
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return;
|
|
}
|
|
if (t2p->tiff_bitspersample != 8)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"Invalid bitspersample = %" PRIu16 " for ITULAB",
|
|
t2p->tiff_bitspersample);
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return;
|
|
}
|
|
t2p->pdf_labrange[0] = -85;
|
|
t2p->pdf_labrange[1] = 85;
|
|
t2p->pdf_labrange[2] = -75;
|
|
t2p->pdf_labrange[3] = 124;
|
|
t2p->pdf_sample = T2P_SAMPLE_LAB_SIGNED_TO_UNSIGNED;
|
|
t2p->pdf_colorspace = T2P_CS_LAB;
|
|
break;
|
|
case PHOTOMETRIC_LOGL:
|
|
case PHOTOMETRIC_LOGLUV:
|
|
TIFFError(
|
|
TIFF2PDF_MODULE,
|
|
"No support for %s with photometric interpretation LogL/LogLuv",
|
|
TIFFFileName(input));
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return;
|
|
default:
|
|
TIFFError(
|
|
TIFF2PDF_MODULE,
|
|
"No support for %s with photometric interpretation %" PRIu16,
|
|
TIFFFileName(input), t2p->tiff_photometric);
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return;
|
|
}
|
|
|
|
if (TIFFGetField(input, TIFFTAG_PLANARCONFIG, &(t2p->tiff_planar)))
|
|
{
|
|
switch (t2p->tiff_planar)
|
|
{
|
|
case 0:
|
|
TIFFWarning(TIFF2PDF_MODULE,
|
|
"Image %s has planar configuration 0, assuming 1",
|
|
TIFFFileName(input));
|
|
t2p->tiff_planar = PLANARCONFIG_CONTIG;
|
|
case PLANARCONFIG_CONTIG:
|
|
break;
|
|
case PLANARCONFIG_SEPARATE:
|
|
t2p->pdf_sample = T2P_SAMPLE_PLANAR_SEPARATE_TO_CONTIG;
|
|
if (t2p->tiff_bitspersample != 8)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"No support for %s with separated planar "
|
|
"configuration and %" PRIu16 " bits per sample",
|
|
TIFFFileName(input), t2p->tiff_bitspersample);
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return;
|
|
}
|
|
break;
|
|
default:
|
|
TIFFError(
|
|
TIFF2PDF_MODULE,
|
|
"No support for %s with planar configuration %" PRIu16,
|
|
TIFFFileName(input), t2p->tiff_planar);
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return;
|
|
}
|
|
}
|
|
|
|
TIFFGetFieldDefaulted(input, TIFFTAG_ORIENTATION, &(t2p->tiff_orientation));
|
|
if (t2p->tiff_orientation > 8)
|
|
{
|
|
TIFFWarning(TIFF2PDF_MODULE,
|
|
"Image %s has orientation %" PRIu16 ", assuming 0",
|
|
TIFFFileName(input), t2p->tiff_orientation);
|
|
t2p->tiff_orientation = 0;
|
|
}
|
|
|
|
if (TIFFGetField(input, TIFFTAG_XRESOLUTION, &(t2p->tiff_xres)) == 0)
|
|
{
|
|
t2p->tiff_xres = 0.0;
|
|
}
|
|
if (TIFFGetField(input, TIFFTAG_YRESOLUTION, &(t2p->tiff_yres)) == 0)
|
|
{
|
|
t2p->tiff_yres = 0.0;
|
|
}
|
|
TIFFGetFieldDefaulted(input, TIFFTAG_RESOLUTIONUNIT, &(t2p->tiff_resunit));
|
|
if (t2p->tiff_resunit == RESUNIT_CENTIMETER)
|
|
{
|
|
t2p->tiff_xres *= 2.54F;
|
|
t2p->tiff_yres *= 2.54F;
|
|
}
|
|
else if (t2p->tiff_resunit != RESUNIT_INCH && t2p->pdf_centimeters != 0)
|
|
{
|
|
t2p->tiff_xres *= 2.54F;
|
|
t2p->tiff_yres *= 2.54F;
|
|
}
|
|
|
|
t2p_compose_pdf_page(t2p);
|
|
if (t2p->t2p_error == T2P_ERR_ERROR)
|
|
return;
|
|
|
|
t2p->pdf_transcode = T2P_TRANSCODE_ENCODE;
|
|
/* It seems that T2P_TRANSCODE_RAW mode doesn't support separate->contig */
|
|
/* conversion. At least t2p_read_tiff_size and t2p_read_tiff_size_tile */
|
|
/* do not take into account the number of samples, and thus */
|
|
/* that can cause heap buffer overflows such as in */
|
|
/* http://bugzilla.maptools.org/show_bug.cgi?id=2715 */
|
|
if (t2p->pdf_nopassthrough == 0 &&
|
|
t2p->tiff_planar != PLANARCONFIG_SEPARATE)
|
|
{
|
|
#ifdef CCITT_SUPPORT
|
|
if (t2p->tiff_compression == COMPRESSION_CCITTFAX4)
|
|
{
|
|
if (TIFFIsTiled(input) || (TIFFNumberOfStrips(input) == 1))
|
|
{
|
|
t2p->pdf_transcode = T2P_TRANSCODE_RAW;
|
|
t2p->pdf_compression = T2P_COMPRESS_G4;
|
|
}
|
|
}
|
|
#endif
|
|
#ifdef ZIP_SUPPORT
|
|
if (t2p->tiff_compression == COMPRESSION_ADOBE_DEFLATE ||
|
|
t2p->tiff_compression == COMPRESSION_DEFLATE)
|
|
{
|
|
if (TIFFIsTiled(input) || (TIFFNumberOfStrips(input) == 1))
|
|
{
|
|
uint16_t predictor;
|
|
t2p->pdf_transcode = T2P_TRANSCODE_RAW;
|
|
t2p->pdf_compression = T2P_COMPRESS_ZIP;
|
|
if (TIFFGetField(input, TIFFTAG_PREDICTOR, &predictor))
|
|
{
|
|
t2p->pdf_compressionquality = predictor;
|
|
}
|
|
else
|
|
{
|
|
t2p->pdf_compressionquality = PREDICTOR_NONE;
|
|
}
|
|
/* TIFFTAG_ZIPQUALITY is always Z_DEFAULT_COMPRESSION on reading
|
|
*/
|
|
}
|
|
}
|
|
#endif
|
|
#ifdef OJPEG_SUPPORT
|
|
if (t2p->tiff_compression == COMPRESSION_OJPEG)
|
|
{
|
|
t2p->pdf_transcode = T2P_TRANSCODE_RAW;
|
|
t2p->pdf_compression = T2P_COMPRESS_JPEG;
|
|
t2p_process_ojpeg_tables(t2p, input);
|
|
}
|
|
#endif
|
|
#ifdef JPEG_SUPPORT
|
|
if (t2p->tiff_compression == COMPRESSION_JPEG)
|
|
{
|
|
t2p->pdf_transcode = T2P_TRANSCODE_RAW;
|
|
t2p->pdf_compression = T2P_COMPRESS_JPEG;
|
|
}
|
|
#endif
|
|
(void)0;
|
|
}
|
|
|
|
if (t2p->pdf_transcode != T2P_TRANSCODE_RAW)
|
|
{
|
|
t2p->pdf_compression = t2p->pdf_defaultcompression;
|
|
}
|
|
|
|
#ifdef JPEG_SUPPORT
|
|
if (t2p->pdf_defaultcompression == T2P_COMPRESS_JPEG)
|
|
{
|
|
if (t2p->pdf_colorspace & T2P_CS_PALETTE)
|
|
{
|
|
t2p->pdf_sample |= T2P_SAMPLE_REALIZE_PALETTE;
|
|
t2p->pdf_colorspace ^= T2P_CS_PALETTE;
|
|
t2p->tiff_pages[t2p->pdf_page].page_extra--;
|
|
}
|
|
}
|
|
if (t2p->tiff_compression == COMPRESSION_JPEG)
|
|
{
|
|
if (t2p->tiff_planar == PLANARCONFIG_SEPARATE)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"No support for %s with JPEG compression and separated "
|
|
"planar configuration",
|
|
TIFFFileName(input));
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return;
|
|
}
|
|
}
|
|
#endif
|
|
#ifdef OJPEG_SUPPORT
|
|
if (t2p->tiff_compression == COMPRESSION_OJPEG)
|
|
{
|
|
if (t2p->tiff_planar == PLANARCONFIG_SEPARATE)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"No support for %s with OJPEG compression and separated "
|
|
"planar configuration",
|
|
TIFFFileName(input));
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (t2p->pdf_sample & T2P_SAMPLE_REALIZE_PALETTE)
|
|
{
|
|
if (t2p->pdf_colorspace & T2P_CS_CMYK)
|
|
{
|
|
t2p->tiff_samplesperpixel = 4;
|
|
t2p->tiff_photometric = PHOTOMETRIC_SEPARATED;
|
|
}
|
|
else
|
|
{
|
|
t2p->tiff_samplesperpixel = 3;
|
|
t2p->tiff_photometric = PHOTOMETRIC_RGB;
|
|
}
|
|
}
|
|
|
|
if (TIFFGetField(
|
|
input, TIFFTAG_TRANSFERFUNCTION, &(t2p->tiff_transferfunction[0]),
|
|
&(t2p->tiff_transferfunction[1]), &(t2p->tiff_transferfunction[2])))
|
|
{
|
|
if ((t2p->tiff_transferfunction[1] != (uint16_t *)NULL) &&
|
|
(t2p->tiff_transferfunction[2] != (uint16_t *)NULL))
|
|
{
|
|
t2p->tiff_transferfunctioncount = 3;
|
|
}
|
|
else
|
|
{
|
|
t2p->tiff_transferfunctioncount = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
t2p->tiff_transferfunctioncount = 0;
|
|
}
|
|
if (TIFFGetField(input, TIFFTAG_WHITEPOINT, &xfloatp) != 0)
|
|
{
|
|
t2p->tiff_whitechromaticities[0] = xfloatp[0];
|
|
t2p->tiff_whitechromaticities[1] = xfloatp[1];
|
|
if (t2p->pdf_colorspace & T2P_CS_GRAY)
|
|
{
|
|
t2p->pdf_colorspace |= T2P_CS_CALGRAY;
|
|
}
|
|
if (t2p->pdf_colorspace & T2P_CS_RGB)
|
|
{
|
|
t2p->pdf_colorspace |= T2P_CS_CALRGB;
|
|
}
|
|
}
|
|
if (TIFFGetField(input, TIFFTAG_PRIMARYCHROMATICITIES, &xfloatp) != 0)
|
|
{
|
|
t2p->tiff_primarychromaticities[0] = xfloatp[0];
|
|
t2p->tiff_primarychromaticities[1] = xfloatp[1];
|
|
t2p->tiff_primarychromaticities[2] = xfloatp[2];
|
|
t2p->tiff_primarychromaticities[3] = xfloatp[3];
|
|
t2p->tiff_primarychromaticities[4] = xfloatp[4];
|
|
t2p->tiff_primarychromaticities[5] = xfloatp[5];
|
|
if (t2p->pdf_colorspace & T2P_CS_RGB)
|
|
{
|
|
t2p->pdf_colorspace |= T2P_CS_CALRGB;
|
|
}
|
|
}
|
|
if (t2p->pdf_colorspace & T2P_CS_LAB)
|
|
{
|
|
if (TIFFGetField(input, TIFFTAG_WHITEPOINT, &xfloatp) != 0)
|
|
{
|
|
t2p->tiff_whitechromaticities[0] = xfloatp[0];
|
|
t2p->tiff_whitechromaticities[1] = xfloatp[1];
|
|
}
|
|
else
|
|
{
|
|
t2p->tiff_whitechromaticities[0] = 0.3457F; /* 0.3127F; */
|
|
t2p->tiff_whitechromaticities[1] = 0.3585F; /* 0.3290F; */
|
|
}
|
|
}
|
|
if (TIFFGetField(input, TIFFTAG_ICCPROFILE, &(t2p->tiff_iccprofilelength),
|
|
&(t2p->tiff_iccprofile)) != 0)
|
|
{
|
|
t2p->pdf_colorspace |= T2P_CS_ICCBASED;
|
|
}
|
|
else
|
|
{
|
|
t2p->tiff_iccprofilelength = 0;
|
|
t2p->tiff_iccprofile = NULL;
|
|
}
|
|
|
|
#ifdef CCITT_SUPPORT
|
|
if (t2p->tiff_bitspersample == 1 && t2p->tiff_samplesperpixel == 1)
|
|
{
|
|
t2p->pdf_compression = T2P_COMPRESS_G4;
|
|
}
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* checks for overflow
|
|
*/
|
|
static void t2p_set_tiff_datasize(T2P *t2p, uint64_t k)
|
|
{
|
|
if (k != (uint64_t)(tmsize_t)k || (tmsize_t)k < 0)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE, "Integer overflow");
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return;
|
|
}
|
|
t2p->tiff_datasize = (tmsize_t)k;
|
|
}
|
|
|
|
/**
|
|
This function returns the necessary size of a data buffer to contain the
|
|
raw or uncompressed image data from the input TIFF for a page.
|
|
*/
|
|
void t2p_read_tiff_size(T2P *t2p, TIFF *input)
|
|
{
|
|
|
|
uint64_t *sbc = NULL;
|
|
#if defined(JPEG_SUPPORT) || defined(OJPEG_SUPPORT)
|
|
unsigned char *jpt = NULL;
|
|
tstrip_t i = 0;
|
|
tstrip_t stripcount = 0;
|
|
#endif
|
|
uint64_t k = 0;
|
|
|
|
if (t2p->pdf_transcode == T2P_TRANSCODE_RAW)
|
|
{
|
|
#if defined(CCITT_SUPPORT) || defined(ZIP_SUPPORT)
|
|
#if defined(CCITT_SUPPORT) && defined(ZIP_SUPPORT)
|
|
if (t2p->pdf_compression == T2P_COMPRESS_G4 ||
|
|
t2p->pdf_compression == T2P_COMPRESS_ZIP)
|
|
#elif defined(CCITT_SUPPORT)
|
|
if (t2p->pdf_compression == T2P_COMPRESS_G4)
|
|
#else
|
|
if (t2p->pdf_compression == T2P_COMPRESS_ZIP)
|
|
#endif
|
|
{
|
|
if (!TIFFGetField(input, TIFFTAG_STRIPBYTECOUNTS, &sbc))
|
|
{
|
|
TIFFError(
|
|
TIFF2PDF_MODULE,
|
|
"Input file %s missing field: TIFFTAG_STRIPBYTECOUNTS",
|
|
TIFFFileName(input));
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return;
|
|
}
|
|
t2p_set_tiff_datasize(t2p, sbc[0]);
|
|
return;
|
|
}
|
|
#endif
|
|
#ifdef OJPEG_SUPPORT
|
|
if (t2p->tiff_compression == COMPRESSION_OJPEG)
|
|
{
|
|
if (!TIFFGetField(input, TIFFTAG_STRIPBYTECOUNTS, &sbc))
|
|
{
|
|
TIFFError(
|
|
TIFF2PDF_MODULE,
|
|
"Input file %s missing field: TIFFTAG_STRIPBYTECOUNTS",
|
|
TIFFFileName(input));
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return;
|
|
}
|
|
stripcount = TIFFNumberOfStrips(input);
|
|
for (i = 0; i < stripcount; i++)
|
|
{
|
|
k = checkAdd64(k, sbc[i], t2p);
|
|
}
|
|
if (TIFFGetField(input, TIFFTAG_JPEGIFOFFSET,
|
|
&(t2p->tiff_dataoffset)))
|
|
{
|
|
if (t2p->tiff_dataoffset != 0)
|
|
{
|
|
if (TIFFGetField(input, TIFFTAG_JPEGIFBYTECOUNT,
|
|
&(t2p->tiff_datasize)) != 0)
|
|
{
|
|
if ((uint64_t)t2p->tiff_datasize < k)
|
|
{
|
|
TIFFWarning(TIFF2PDF_MODULE,
|
|
"Input file %s has short JPEG "
|
|
"interchange file byte count",
|
|
TIFFFileName(input));
|
|
t2p->pdf_ojpegiflength = t2p->tiff_datasize;
|
|
k = checkAdd64(k, t2p->tiff_datasize, t2p);
|
|
k = checkAdd64(k, 6, t2p);
|
|
k = checkAdd64(k, stripcount, t2p);
|
|
k = checkAdd64(k, stripcount, t2p);
|
|
t2p_set_tiff_datasize(t2p, k);
|
|
return;
|
|
}
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"Input file %s missing field: "
|
|
"TIFFTAG_JPEGIFBYTECOUNT",
|
|
TIFFFileName(input));
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
k = checkAdd64(k, stripcount, t2p);
|
|
k = checkAdd64(k, stripcount, t2p);
|
|
k = checkAdd64(k, 2048, t2p);
|
|
t2p_set_tiff_datasize(t2p, k);
|
|
return;
|
|
}
|
|
#endif
|
|
#ifdef JPEG_SUPPORT
|
|
if (t2p->tiff_compression == COMPRESSION_JPEG)
|
|
{
|
|
uint32_t count = 0;
|
|
if (TIFFGetField(input, TIFFTAG_JPEGTABLES, &count, &jpt) != 0)
|
|
{
|
|
if (count > 4)
|
|
{
|
|
k += count;
|
|
k -= 2; /* don't use EOI of header */
|
|
}
|
|
}
|
|
else
|
|
{
|
|
k = 2; /* SOI for first strip */
|
|
}
|
|
stripcount = TIFFNumberOfStrips(input);
|
|
if (!TIFFGetField(input, TIFFTAG_STRIPBYTECOUNTS, &sbc))
|
|
{
|
|
TIFFError(
|
|
TIFF2PDF_MODULE,
|
|
"Input file %s missing field: TIFFTAG_STRIPBYTECOUNTS",
|
|
TIFFFileName(input));
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return;
|
|
}
|
|
for (i = 0; i < stripcount; i++)
|
|
{
|
|
k = checkAdd64(k, sbc[i], t2p);
|
|
k -= 2; /* don't use EOI of strip */
|
|
k += 2; /* add space for restart marker */
|
|
}
|
|
k = checkAdd64(k, 2, t2p); /* use EOI of last strip */
|
|
k = checkAdd64(k, 6, t2p); /* for DRI marker of first strip */
|
|
t2p_set_tiff_datasize(t2p, k);
|
|
return;
|
|
}
|
|
#endif
|
|
(void)0;
|
|
}
|
|
#ifdef JPEG_SUPPORT
|
|
if (t2p->pdf_compression == T2P_COMPRESS_JPEG &&
|
|
t2p->tiff_photometric == PHOTOMETRIC_YCBCR)
|
|
{
|
|
k = checkMultiply64(TIFFNumberOfStrips(input), TIFFStripSize(input),
|
|
t2p);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
k = checkMultiply64(TIFFScanlineSize(input), t2p->tiff_length, t2p);
|
|
if (t2p->tiff_planar == PLANARCONFIG_SEPARATE)
|
|
{
|
|
k = checkMultiply64(k, t2p->tiff_samplesperpixel, t2p);
|
|
}
|
|
}
|
|
if (k == 0)
|
|
{
|
|
/* Assume we had overflow inside TIFFScanlineSize */
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
}
|
|
|
|
t2p_set_tiff_datasize(t2p, k);
|
|
|
|
return;
|
|
}
|
|
|
|
/*
|
|
This function returns the necessary size of a data buffer to contain the
|
|
raw or uncompressed image data from the input TIFF for a tile of a page.
|
|
*/
|
|
|
|
void t2p_read_tiff_size_tile(T2P *t2p, TIFF *input, ttile_t tile)
|
|
{
|
|
|
|
uint64_t *tbc = NULL;
|
|
uint16_t edge = 0;
|
|
#ifdef JPEG_SUPPORT
|
|
unsigned char *jpt;
|
|
#endif
|
|
uint64_t k;
|
|
|
|
edge |= t2p_tile_is_right_edge(t2p->tiff_tiles[t2p->pdf_page], tile);
|
|
edge |= t2p_tile_is_bottom_edge(t2p->tiff_tiles[t2p->pdf_page], tile);
|
|
|
|
if (t2p->pdf_transcode == T2P_TRANSCODE_RAW)
|
|
{
|
|
if (edge
|
|
#if defined(JPEG_SUPPORT) || defined(OJPEG_SUPPORT)
|
|
&& !(t2p->pdf_compression == T2P_COMPRESS_JPEG)
|
|
#endif
|
|
)
|
|
{
|
|
t2p->tiff_datasize = TIFFTileSize(input);
|
|
if (t2p->tiff_datasize == 0)
|
|
{
|
|
/* Assume we had overflow inside TIFFTileSize */
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
}
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
TIFFGetField(input, TIFFTAG_TILEBYTECOUNTS, &tbc);
|
|
k = tbc[tile];
|
|
#ifdef OJPEG_SUPPORT
|
|
if (t2p->tiff_compression == COMPRESSION_OJPEG)
|
|
{
|
|
k = checkAdd64(k, 2048, t2p);
|
|
}
|
|
#endif
|
|
#ifdef JPEG_SUPPORT
|
|
if (t2p->tiff_compression == COMPRESSION_JPEG)
|
|
{
|
|
uint32_t count = 0;
|
|
if (TIFFGetField(input, TIFFTAG_JPEGTABLES, &count, &jpt) != 0)
|
|
{
|
|
if (count > 4)
|
|
{
|
|
k = checkAdd64(k, count, t2p);
|
|
k -= 2; /* don't use EOI of header or SOI of tile */
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
t2p_set_tiff_datasize(t2p, k);
|
|
return;
|
|
}
|
|
}
|
|
k = TIFFTileSize(input);
|
|
if (t2p->tiff_planar == PLANARCONFIG_SEPARATE)
|
|
{
|
|
k = checkMultiply64(k, t2p->tiff_samplesperpixel, t2p);
|
|
}
|
|
if (k == 0)
|
|
{
|
|
/* Assume we had overflow inside TIFFTileSize */
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
}
|
|
|
|
t2p_set_tiff_datasize(t2p, k);
|
|
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* This functions returns a non-zero value when the tile is on the right edge
|
|
* and does not have full imaged tile width.
|
|
*/
|
|
|
|
int t2p_tile_is_right_edge(T2P_TILES tiles, ttile_t tile)
|
|
{
|
|
|
|
if (((tile + 1) % tiles.tiles_tilecountx == 0) &&
|
|
(tiles.tiles_edgetilewidth != 0))
|
|
{
|
|
return (1);
|
|
}
|
|
else
|
|
{
|
|
return (0);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* This functions returns a non-zero value when the tile is on the bottom edge
|
|
* and does not have full imaged tile length.
|
|
*/
|
|
|
|
int t2p_tile_is_bottom_edge(T2P_TILES tiles, ttile_t tile)
|
|
{
|
|
|
|
if (((tile + 1) > (tiles.tiles_tilecount - tiles.tiles_tilecountx)) &&
|
|
(tiles.tiles_edgetilelength != 0))
|
|
{
|
|
return (1);
|
|
}
|
|
else
|
|
{
|
|
return (0);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* This function returns a non-zero value when the tile is a right edge tile
|
|
* or a bottom edge tile.
|
|
*/
|
|
|
|
int t2p_tile_is_edge(T2P_TILES tiles, ttile_t tile)
|
|
{
|
|
|
|
return (t2p_tile_is_right_edge(tiles, tile) |
|
|
t2p_tile_is_bottom_edge(tiles, tile));
|
|
}
|
|
|
|
/*
|
|
This function returns a non-zero value when the tile is a right edge
|
|
tile and a bottom edge tile.
|
|
*/
|
|
|
|
int t2p_tile_is_corner_edge(T2P_TILES tiles, ttile_t tile)
|
|
{
|
|
|
|
return (t2p_tile_is_right_edge(tiles, tile) &
|
|
t2p_tile_is_bottom_edge(tiles, tile));
|
|
}
|
|
|
|
#if defined(JPEG_SUPPORT) || defined(OJPEG_SUPPORT)
|
|
static const unsigned char jpeg_eof_marker[] = {0xff, 0xd9};
|
|
#endif
|
|
|
|
/*
|
|
This function reads the raster image data from the input TIFF for an
|
|
image and writes the data to the output PDF XObject image dictionary stream.
|
|
It returns the amount written or zero on error.
|
|
*/
|
|
|
|
tsize_t t2p_readwrite_pdf_image(T2P *t2p, TIFF *input, TIFF *output)
|
|
{
|
|
|
|
tsize_t written = 0;
|
|
unsigned char *buffer = NULL;
|
|
unsigned char *samplebuffer = NULL;
|
|
tsize_t bufferoffset = 0;
|
|
tsize_t samplebufferoffset = 0;
|
|
tsize_t read = 0;
|
|
tstrip_t i = 0;
|
|
tstrip_t j = 0;
|
|
tstrip_t stripcount = 0;
|
|
tsize_t stripsize = 0;
|
|
tsize_t sepstripcount = 0;
|
|
tsize_t sepstripsize = 0;
|
|
#ifdef OJPEG_SUPPORT
|
|
toff_t inputoffset = 0;
|
|
uint16_t h_samp = 1;
|
|
uint16_t v_samp = 1;
|
|
uint16_t ri = 1;
|
|
uint32_t rows = 0;
|
|
#endif /* ifdef OJPEG_SUPPORT */
|
|
#ifdef JPEG_SUPPORT
|
|
unsigned char *jpt;
|
|
float *xfloatp;
|
|
uint64_t *sbc;
|
|
unsigned char *stripbuffer;
|
|
tsize_t striplength = 0;
|
|
uint32_t max_striplength = 0;
|
|
#endif /* ifdef JPEG_SUPPORT */
|
|
|
|
/* Fail if prior error (in particular, can't trust tiff_datasize) */
|
|
if (t2p->t2p_error != T2P_ERR_OK)
|
|
return (0);
|
|
|
|
if (t2p->pdf_transcode == T2P_TRANSCODE_RAW)
|
|
{
|
|
#ifdef CCITT_SUPPORT
|
|
if (t2p->pdf_compression == T2P_COMPRESS_G4)
|
|
{
|
|
buffer = (unsigned char *)_TIFFmalloc(t2p->tiff_datasize);
|
|
if (buffer == NULL)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"Can't allocate %" TIFF_SSIZE_FORMAT
|
|
" bytes of memory for "
|
|
"t2p_readwrite_pdf_image, %s",
|
|
t2p->tiff_datasize, TIFFFileName(input));
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return (0);
|
|
}
|
|
memset(buffer, 0, t2p->tiff_datasize);
|
|
if (TIFFReadRawStrip(input, 0, (tdata_t)buffer,
|
|
t2p->tiff_datasize) < 0)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE, "TIFFReadRawStrip() failed");
|
|
_TIFFfree(buffer);
|
|
return (0);
|
|
}
|
|
if (t2p->tiff_fillorder == FILLORDER_LSB2MSB)
|
|
{
|
|
/*
|
|
* make sure is lsb-to-msb
|
|
* bit-endianness fill order
|
|
*/
|
|
TIFFReverseBits(buffer, t2p->tiff_datasize);
|
|
}
|
|
t2pWriteFile(output, (tdata_t)buffer, t2p->tiff_datasize);
|
|
_TIFFfree(buffer);
|
|
return (t2p->tiff_datasize);
|
|
}
|
|
#endif /* ifdef CCITT_SUPPORT */
|
|
#ifdef ZIP_SUPPORT
|
|
if (t2p->pdf_compression == T2P_COMPRESS_ZIP)
|
|
{
|
|
buffer = (unsigned char *)_TIFFmalloc(t2p->tiff_datasize);
|
|
if (buffer == NULL)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"Can't allocate %" TIFF_SSIZE_FORMAT
|
|
" bytes of memory for t2p_readwrite_pdf_image, %s",
|
|
t2p->tiff_datasize, TIFFFileName(input));
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return (0);
|
|
}
|
|
memset(buffer, 0, t2p->tiff_datasize);
|
|
if (TIFFReadRawStrip(input, 0, (tdata_t)buffer,
|
|
t2p->tiff_datasize) < 0)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE, "TIFFReadRawStrip() failed");
|
|
_TIFFfree(buffer);
|
|
return (0);
|
|
}
|
|
if (t2p->tiff_fillorder == FILLORDER_LSB2MSB)
|
|
{
|
|
TIFFReverseBits(buffer, t2p->tiff_datasize);
|
|
}
|
|
t2pWriteFile(output, (tdata_t)buffer, t2p->tiff_datasize);
|
|
_TIFFfree(buffer);
|
|
return (t2p->tiff_datasize);
|
|
}
|
|
#endif /* ifdef ZIP_SUPPORT */
|
|
#ifdef OJPEG_SUPPORT
|
|
if (t2p->tiff_compression == COMPRESSION_OJPEG)
|
|
{
|
|
|
|
if (t2p->tiff_dataoffset != 0)
|
|
{
|
|
buffer = (unsigned char *)_TIFFmalloc(t2p->tiff_datasize);
|
|
if (buffer == NULL)
|
|
{
|
|
TIFFError(
|
|
TIFF2PDF_MODULE,
|
|
"Can't allocate %" TIFF_SSIZE_FORMAT
|
|
" bytes of memory for t2p_readwrite_pdf_image, %s",
|
|
t2p->tiff_datasize, TIFFFileName(input));
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return (0);
|
|
}
|
|
memset(buffer, 0, t2p->tiff_datasize);
|
|
if (t2p->pdf_ojpegiflength == 0)
|
|
{
|
|
inputoffset = t2pSeekFile(input, 0, SEEK_CUR);
|
|
t2pSeekFile(input, t2p->tiff_dataoffset, SEEK_SET);
|
|
t2pReadFile(input, (tdata_t)buffer, t2p->tiff_datasize);
|
|
t2pSeekFile(input, inputoffset, SEEK_SET);
|
|
t2pWriteFile(output, (tdata_t)buffer, t2p->tiff_datasize);
|
|
_TIFFfree(buffer);
|
|
return (t2p->tiff_datasize);
|
|
}
|
|
else
|
|
{
|
|
inputoffset = t2pSeekFile(input, 0, SEEK_CUR);
|
|
t2pSeekFile(input, t2p->tiff_dataoffset, SEEK_SET);
|
|
bufferoffset = t2pReadFile(input, (tdata_t)buffer,
|
|
t2p->pdf_ojpegiflength);
|
|
t2p->pdf_ojpegiflength = 0;
|
|
t2pSeekFile(input, inputoffset, SEEK_SET);
|
|
TIFFGetField(input, TIFFTAG_YCBCRSUBSAMPLING, &h_samp,
|
|
&v_samp);
|
|
buffer[bufferoffset++] = 0xff;
|
|
buffer[bufferoffset++] = 0xdd;
|
|
buffer[bufferoffset++] = 0x00;
|
|
buffer[bufferoffset++] = 0x04;
|
|
h_samp *= 8;
|
|
v_samp *= 8;
|
|
ri = (t2p->tiff_width + h_samp - 1) / h_samp;
|
|
TIFFGetField(input, TIFFTAG_ROWSPERSTRIP, &rows);
|
|
ri *= (rows + v_samp - 1) / v_samp;
|
|
buffer[bufferoffset++] = (ri >> 8) & 0xff;
|
|
buffer[bufferoffset++] = ri & 0xff;
|
|
stripcount = TIFFNumberOfStrips(input);
|
|
for (i = 0; i < stripcount; i++)
|
|
{
|
|
if (i != 0)
|
|
{
|
|
buffer[bufferoffset++] = 0xff;
|
|
buffer[bufferoffset++] = (0xd0 | ((i - 1) % 8));
|
|
}
|
|
bufferoffset += TIFFReadRawStrip(
|
|
input, i,
|
|
(tdata_t) &
|
|
(((unsigned char *)buffer)[bufferoffset]),
|
|
-1);
|
|
}
|
|
t2pWriteFile(output, (tdata_t)buffer, bufferoffset);
|
|
_TIFFfree(buffer);
|
|
return (bufferoffset);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!t2p->pdf_ojpegdata)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"No support for OJPEG image %s with bad tables",
|
|
TIFFFileName(input));
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return (0);
|
|
}
|
|
buffer = (unsigned char *)_TIFFmalloc(t2p->tiff_datasize);
|
|
if (buffer == NULL)
|
|
{
|
|
TIFFError(
|
|
TIFF2PDF_MODULE,
|
|
"Can't allocate %" TIFF_SSIZE_FORMAT
|
|
" bytes of memory for t2p_readwrite_pdf_image, %s",
|
|
t2p->tiff_datasize, TIFFFileName(input));
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return (0);
|
|
}
|
|
memset(buffer, 0, t2p->tiff_datasize);
|
|
_TIFFmemcpy(buffer, t2p->pdf_ojpegdata,
|
|
t2p->pdf_ojpegdatalength);
|
|
bufferoffset = t2p->pdf_ojpegdatalength;
|
|
stripcount = TIFFNumberOfStrips(input);
|
|
for (i = 0; i < stripcount; i++)
|
|
{
|
|
tsize_t retTIFFReadRawStrip;
|
|
if (i != 0)
|
|
{
|
|
buffer[bufferoffset++] = 0xff;
|
|
buffer[bufferoffset++] = (0xd0 | ((i - 1) % 8));
|
|
}
|
|
retTIFFReadRawStrip = TIFFReadRawStrip(
|
|
input, i,
|
|
(tdata_t) & (((unsigned char *)buffer)[bufferoffset]),
|
|
-1);
|
|
if (retTIFFReadRawStrip < 0)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE, "TIFFReadRawStrip()");
|
|
_TIFFfree(buffer);
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return (0);
|
|
}
|
|
bufferoffset += retTIFFReadRawStrip;
|
|
}
|
|
t2pWriteFile(output, (tdata_t)buffer, bufferoffset);
|
|
if (!((buffer[bufferoffset - 1] == 0xd9) &&
|
|
(buffer[bufferoffset - 2] == 0xff)))
|
|
{
|
|
t2pWriteFile(output, (tdata_t)jpeg_eof_marker,
|
|
sizeof(jpeg_eof_marker));
|
|
}
|
|
_TIFFfree(buffer);
|
|
return (bufferoffset);
|
|
#if 0
|
|
/*
|
|
This hunk of code removed code is clearly
|
|
mis-placed and we are not sure where it
|
|
should be (if anywhere)
|
|
*/
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"No support for OJPEG image %s with no JPEG File Interchange offset",
|
|
TIFFFileName(input));
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return(0);
|
|
#endif
|
|
}
|
|
}
|
|
#endif /* ifdef OJPEG_SUPPORT */
|
|
#ifdef JPEG_SUPPORT
|
|
if (t2p->tiff_compression == COMPRESSION_JPEG)
|
|
{
|
|
uint32_t count = 0;
|
|
buffer = (unsigned char *)_TIFFmalloc(t2p->tiff_datasize);
|
|
if (buffer == NULL)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"Can't allocate %" TIFF_SSIZE_FORMAT
|
|
" bytes of memory for t2p_readwrite_pdf_image, %s",
|
|
t2p->tiff_datasize, TIFFFileName(input));
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return (0);
|
|
}
|
|
memset(buffer, 0, t2p->tiff_datasize);
|
|
if (TIFFGetField(input, TIFFTAG_JPEGTABLES, &count, &jpt) != 0)
|
|
{
|
|
if (count > 4)
|
|
{
|
|
_TIFFmemcpy(buffer, jpt, count);
|
|
bufferoffset += count - 2;
|
|
}
|
|
}
|
|
stripcount = TIFFNumberOfStrips(input);
|
|
TIFFGetField(input, TIFFTAG_STRIPBYTECOUNTS, &sbc);
|
|
for (i = 0; i < stripcount; i++)
|
|
{
|
|
if (sbc[i] > max_striplength)
|
|
max_striplength = sbc[i];
|
|
}
|
|
stripbuffer = (unsigned char *)_TIFFmalloc(max_striplength);
|
|
if (stripbuffer == NULL)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"Can't allocate %" PRId32
|
|
" bytes of memory for t2p_readwrite_pdf_image, %s",
|
|
max_striplength, TIFFFileName(input));
|
|
_TIFFfree(buffer);
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return (0);
|
|
}
|
|
memset(stripbuffer, 0, max_striplength);
|
|
for (i = 0; i < stripcount; i++)
|
|
{
|
|
striplength =
|
|
TIFFReadRawStrip(input, i, (tdata_t)stripbuffer, -1);
|
|
if (striplength < 0)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE, "TIFFReadRawStrip() failed");
|
|
_TIFFfree(samplebuffer);
|
|
_TIFFfree(buffer);
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return (0);
|
|
}
|
|
if (!t2p_process_jpeg_strip(stripbuffer, &striplength, buffer,
|
|
t2p->tiff_datasize, &bufferoffset,
|
|
i, t2p->tiff_length))
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"Can't process JPEG data in input file %s",
|
|
TIFFFileName(input));
|
|
_TIFFfree(samplebuffer);
|
|
_TIFFfree(buffer);
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return (0);
|
|
}
|
|
}
|
|
t2pWriteFile(output, (tdata_t)buffer, bufferoffset);
|
|
t2pWriteFile(output, (tdata_t)jpeg_eof_marker,
|
|
sizeof(jpeg_eof_marker));
|
|
_TIFFfree(stripbuffer);
|
|
_TIFFfree(buffer);
|
|
return (bufferoffset);
|
|
}
|
|
#endif /* ifdef JPEG_SUPPORT */
|
|
(void)0;
|
|
}
|
|
|
|
if (t2p->pdf_sample == T2P_SAMPLE_NOTHING)
|
|
{
|
|
buffer = (unsigned char *)_TIFFmalloc(t2p->tiff_datasize);
|
|
if (buffer == NULL)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"Can't allocate %" TIFF_SSIZE_FORMAT
|
|
" bytes of memory for t2p_readwrite_pdf_image, %s",
|
|
t2p->tiff_datasize, TIFFFileName(input));
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return (0);
|
|
}
|
|
memset(buffer, 0, t2p->tiff_datasize);
|
|
stripsize = TIFFStripSize(input);
|
|
stripcount = TIFFNumberOfStrips(input);
|
|
for (i = 0; i < stripcount; i++)
|
|
{
|
|
read = TIFFReadEncodedStrip(
|
|
input, i, (tdata_t)&buffer[bufferoffset],
|
|
TIFFmin(stripsize, t2p->tiff_datasize - bufferoffset));
|
|
if (read == -1)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"Error on decoding strip %" PRIu32 " of %s", i,
|
|
TIFFFileName(input));
|
|
_TIFFfree(buffer);
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return (0);
|
|
}
|
|
bufferoffset += read;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (t2p->pdf_sample & T2P_SAMPLE_PLANAR_SEPARATE_TO_CONTIG)
|
|
{
|
|
|
|
sepstripsize = TIFFStripSize(input);
|
|
sepstripcount = TIFFNumberOfStrips(input);
|
|
|
|
stripsize = sepstripsize * t2p->tiff_samplesperpixel;
|
|
stripcount = sepstripcount / t2p->tiff_samplesperpixel;
|
|
|
|
buffer = (unsigned char *)_TIFFmalloc(t2p->tiff_datasize);
|
|
if (buffer == NULL)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"Can't allocate %" TIFF_SSIZE_FORMAT
|
|
" bytes of memory for t2p_readwrite_pdf_image, %s",
|
|
t2p->tiff_datasize, TIFFFileName(input));
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return (0);
|
|
}
|
|
memset(buffer, 0, t2p->tiff_datasize);
|
|
samplebuffer = (unsigned char *)_TIFFmalloc(stripsize);
|
|
if (samplebuffer == NULL)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"Can't allocate %" TIFF_SSIZE_FORMAT
|
|
" bytes of memory for t2p_readwrite_pdf_image, %s",
|
|
t2p->tiff_datasize, TIFFFileName(input));
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
_TIFFfree(buffer);
|
|
return (0);
|
|
}
|
|
for (i = 0; i < stripcount; i++)
|
|
{
|
|
samplebufferoffset = 0;
|
|
for (j = 0; j < t2p->tiff_samplesperpixel; j++)
|
|
{
|
|
read = TIFFReadEncodedStrip(
|
|
input, i + j * stripcount,
|
|
(tdata_t) & (samplebuffer[samplebufferoffset]),
|
|
TIFFmin(sepstripsize, stripsize - samplebufferoffset));
|
|
if (read == -1)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"Error on decoding strip %" PRIu32 " of %s",
|
|
i + j * stripcount, TIFFFileName(input));
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
_TIFFfree(samplebuffer);
|
|
_TIFFfree(buffer);
|
|
return (0);
|
|
}
|
|
samplebufferoffset += read;
|
|
}
|
|
t2p_sample_planar_separate_to_contig(
|
|
t2p, &(buffer[bufferoffset]), samplebuffer,
|
|
samplebufferoffset);
|
|
bufferoffset += samplebufferoffset;
|
|
}
|
|
_TIFFfree(samplebuffer);
|
|
goto dataready;
|
|
}
|
|
|
|
buffer = (unsigned char *)_TIFFmalloc(t2p->tiff_datasize);
|
|
if (buffer == NULL)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"Can't allocate %" TIFF_SSIZE_FORMAT
|
|
" bytes of memory for t2p_readwrite_pdf_image, %s",
|
|
t2p->tiff_datasize, TIFFFileName(input));
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return (0);
|
|
}
|
|
memset(buffer, 0, t2p->tiff_datasize);
|
|
stripsize = TIFFStripSize(input);
|
|
stripcount = TIFFNumberOfStrips(input);
|
|
for (i = 0; i < stripcount; i++)
|
|
{
|
|
read = TIFFReadEncodedStrip(
|
|
input, i, (tdata_t)&buffer[bufferoffset],
|
|
TIFFmin(stripsize, t2p->tiff_datasize - bufferoffset));
|
|
if (read == -1)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"Error on decoding strip %" PRIu32 " of %s", i,
|
|
TIFFFileName(input));
|
|
_TIFFfree(samplebuffer);
|
|
_TIFFfree(buffer);
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return (0);
|
|
}
|
|
bufferoffset += read;
|
|
}
|
|
|
|
if (t2p->pdf_sample & T2P_SAMPLE_REALIZE_PALETTE)
|
|
{
|
|
// FIXME: overflow?
|
|
samplebuffer = (unsigned char *)_TIFFrealloc(
|
|
(tdata_t)buffer,
|
|
t2p->tiff_datasize * t2p->tiff_samplesperpixel);
|
|
if (samplebuffer == NULL)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"Can't allocate %" TIFF_SSIZE_FORMAT
|
|
" bytes of memory for t2p_readwrite_pdf_image, %s",
|
|
t2p->tiff_datasize, TIFFFileName(input));
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
_TIFFfree(buffer);
|
|
return (0);
|
|
}
|
|
else
|
|
{
|
|
buffer = samplebuffer;
|
|
t2p->tiff_datasize *= t2p->tiff_samplesperpixel;
|
|
}
|
|
t2p_sample_realize_palette(t2p, buffer);
|
|
}
|
|
|
|
if (t2p->pdf_sample & T2P_SAMPLE_RGBA_TO_RGB)
|
|
{
|
|
t2p->tiff_datasize = t2p_sample_rgba_to_rgb(
|
|
(tdata_t)buffer, t2p->tiff_width * t2p->tiff_length);
|
|
}
|
|
|
|
if (t2p->pdf_sample & T2P_SAMPLE_RGBAA_TO_RGB)
|
|
{
|
|
t2p->tiff_datasize = t2p_sample_rgbaa_to_rgb(
|
|
(tdata_t)buffer, t2p->tiff_width * t2p->tiff_length);
|
|
}
|
|
|
|
if (t2p->pdf_sample & T2P_SAMPLE_YCBCR_TO_RGB)
|
|
{
|
|
samplebuffer = (unsigned char *)_TIFFrealloc(
|
|
(tdata_t)buffer, t2p->tiff_width * t2p->tiff_length * 4);
|
|
if (samplebuffer == NULL)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"Can't allocate %" TIFF_SSIZE_FORMAT
|
|
" bytes of memory for t2p_readwrite_pdf_image, %s",
|
|
t2p->tiff_datasize, TIFFFileName(input));
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
_TIFFfree(buffer);
|
|
return (0);
|
|
}
|
|
else
|
|
{
|
|
buffer = samplebuffer;
|
|
}
|
|
if (!TIFFReadRGBAImageOriented(input, t2p->tiff_width,
|
|
t2p->tiff_length, (uint32_t *)buffer,
|
|
ORIENTATION_TOPLEFT, 0))
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"Can't use TIFFReadRGBAImageOriented to extract RGB "
|
|
"image from %s",
|
|
TIFFFileName(input));
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return (0);
|
|
}
|
|
t2p->tiff_datasize = t2p_sample_abgr_to_rgb(
|
|
(tdata_t)buffer, t2p->tiff_width * t2p->tiff_length);
|
|
}
|
|
|
|
if (t2p->pdf_sample & T2P_SAMPLE_LAB_SIGNED_TO_UNSIGNED)
|
|
{
|
|
t2p->tiff_datasize = t2p_sample_lab_signed_to_unsigned(
|
|
(tdata_t)buffer, t2p->tiff_width * t2p->tiff_length);
|
|
}
|
|
}
|
|
|
|
dataready:
|
|
|
|
t2p_disable(output);
|
|
TIFFSetField(output, TIFFTAG_PHOTOMETRIC, t2p->tiff_photometric);
|
|
TIFFSetField(output, TIFFTAG_BITSPERSAMPLE, t2p->tiff_bitspersample);
|
|
TIFFSetField(output, TIFFTAG_SAMPLESPERPIXEL, t2p->tiff_samplesperpixel);
|
|
TIFFSetField(output, TIFFTAG_IMAGEWIDTH, t2p->tiff_width);
|
|
TIFFSetField(output, TIFFTAG_IMAGELENGTH, t2p->tiff_length);
|
|
TIFFSetField(output, TIFFTAG_ROWSPERSTRIP, t2p->tiff_length);
|
|
TIFFSetField(output, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
|
|
TIFFSetField(output, TIFFTAG_FILLORDER, FILLORDER_MSB2LSB);
|
|
|
|
switch (t2p->pdf_compression)
|
|
{
|
|
case T2P_COMPRESS_NONE:
|
|
TIFFSetField(output, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
|
|
break;
|
|
#ifdef CCITT_SUPPORT
|
|
case T2P_COMPRESS_G4:
|
|
TIFFSetField(output, TIFFTAG_COMPRESSION, COMPRESSION_CCITTFAX4);
|
|
break;
|
|
#endif /* ifdef CCITT_SUPPORT */
|
|
#ifdef JPEG_SUPPORT
|
|
case T2P_COMPRESS_JPEG:
|
|
if (t2p->tiff_photometric == PHOTOMETRIC_YCBCR)
|
|
{
|
|
uint16_t hor = 0, ver = 0;
|
|
if (TIFFGetField(input, TIFFTAG_YCBCRSUBSAMPLING, &hor, &ver) !=
|
|
0)
|
|
{
|
|
if (hor != 0 && ver != 0)
|
|
{
|
|
TIFFSetField(output, TIFFTAG_YCBCRSUBSAMPLING, hor,
|
|
ver);
|
|
}
|
|
}
|
|
if (TIFFGetField(input, TIFFTAG_REFERENCEBLACKWHITE,
|
|
&xfloatp) != 0)
|
|
{
|
|
TIFFSetField(output, TIFFTAG_REFERENCEBLACKWHITE, xfloatp);
|
|
}
|
|
}
|
|
if (TIFFSetField(output, TIFFTAG_COMPRESSION, COMPRESSION_JPEG) ==
|
|
0)
|
|
{
|
|
TIFFError(
|
|
TIFF2PDF_MODULE,
|
|
"Unable to use JPEG compression for input %s and output %s",
|
|
TIFFFileName(input), TIFFFileName(output));
|
|
_TIFFfree(buffer);
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return (0);
|
|
}
|
|
TIFFSetField(output, TIFFTAG_JPEGTABLESMODE, 0);
|
|
|
|
if (t2p->pdf_colorspace & (T2P_CS_RGB | T2P_CS_LAB))
|
|
{
|
|
TIFFSetField(output, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_YCBCR);
|
|
if (t2p->tiff_photometric != PHOTOMETRIC_YCBCR)
|
|
{
|
|
TIFFSetField(output, TIFFTAG_JPEGCOLORMODE,
|
|
JPEGCOLORMODE_RGB);
|
|
}
|
|
else
|
|
{
|
|
TIFFSetField(output, TIFFTAG_JPEGCOLORMODE,
|
|
JPEGCOLORMODE_RAW);
|
|
}
|
|
}
|
|
if (t2p->pdf_colorspace & T2P_CS_GRAY)
|
|
{
|
|
(void)0;
|
|
}
|
|
if (t2p->pdf_colorspace & T2P_CS_CMYK)
|
|
{
|
|
(void)0;
|
|
}
|
|
if (t2p->pdf_defaultcompressionquality != 0)
|
|
{
|
|
TIFFSetField(output, TIFFTAG_JPEGQUALITY,
|
|
t2p->pdf_defaultcompressionquality);
|
|
}
|
|
|
|
break;
|
|
#endif /* ifdef JPEG_SUPPORT */
|
|
#ifdef ZIP_SUPPORT
|
|
case T2P_COMPRESS_ZIP:
|
|
TIFFSetField(output, TIFFTAG_COMPRESSION,
|
|
COMPRESSION_ADOBE_DEFLATE);
|
|
if (t2p->pdf_defaultcompressionquality % 100 != 0)
|
|
{
|
|
TIFFSetField(output, TIFFTAG_PREDICTOR,
|
|
t2p->pdf_defaultcompressionquality % 100);
|
|
}
|
|
if (t2p->pdf_defaultcompressionquality / 100 != 0)
|
|
{
|
|
TIFFSetField(output, TIFFTAG_ZIPQUALITY,
|
|
(t2p->pdf_defaultcompressionquality / 100));
|
|
}
|
|
break;
|
|
#endif /* ifdef ZIP_SUPPORT */
|
|
default:
|
|
break;
|
|
}
|
|
|
|
t2p_enable(output);
|
|
t2p->outputwritten = 0;
|
|
#ifdef JPEG_SUPPORT
|
|
if (t2p->pdf_compression == T2P_COMPRESS_JPEG &&
|
|
t2p->tiff_photometric == PHOTOMETRIC_YCBCR)
|
|
{
|
|
bufferoffset = TIFFWriteEncodedStrip(output, (tstrip_t)0, buffer,
|
|
stripsize * stripcount);
|
|
}
|
|
else
|
|
#endif /* ifdef JPEG_SUPPORT */
|
|
{
|
|
bufferoffset = TIFFWriteEncodedStrip(output, (tstrip_t)0, buffer,
|
|
t2p->tiff_datasize);
|
|
}
|
|
if (buffer != NULL)
|
|
{
|
|
_TIFFfree(buffer);
|
|
buffer = NULL;
|
|
}
|
|
|
|
if (bufferoffset == (tsize_t)-1)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"Error writing encoded strip to output PDF %s",
|
|
TIFFFileName(output));
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return (0);
|
|
}
|
|
|
|
written = t2p->outputwritten;
|
|
return (written);
|
|
}
|
|
|
|
/*
|
|
* This function reads the raster image data from the input TIFF for an image
|
|
* tile and writes the data to the output PDF XObject image dictionary stream
|
|
* for the tile. It returns the amount written or zero on error.
|
|
*/
|
|
|
|
tsize_t t2p_readwrite_pdf_image_tile(T2P *t2p, TIFF *input, TIFF *output,
|
|
ttile_t tile)
|
|
{
|
|
|
|
uint16_t edge = 0;
|
|
tsize_t written = 0;
|
|
unsigned char *buffer = NULL;
|
|
tsize_t bufferoffset = 0;
|
|
unsigned char *samplebuffer = NULL;
|
|
tsize_t samplebufferoffset = 0;
|
|
tsize_t read = 0;
|
|
uint16_t i = 0;
|
|
ttile_t tilecount = 0;
|
|
/* tsize_t tilesize=0; */
|
|
ttile_t septilecount = 0;
|
|
tsize_t septilesize = 0;
|
|
#ifdef JPEG_SUPPORT
|
|
unsigned char *jpt;
|
|
float *xfloatp;
|
|
uint32_t xuint32 = 0;
|
|
#endif
|
|
|
|
/* Fail if prior error (in particular, can't trust tiff_datasize) */
|
|
if (t2p->t2p_error != T2P_ERR_OK)
|
|
return (0);
|
|
|
|
edge |= t2p_tile_is_right_edge(t2p->tiff_tiles[t2p->pdf_page], tile);
|
|
edge |= t2p_tile_is_bottom_edge(t2p->tiff_tiles[t2p->pdf_page], tile);
|
|
|
|
if ((t2p->pdf_transcode == T2P_TRANSCODE_RAW) &&
|
|
((edge == 0)
|
|
#if defined(JPEG_SUPPORT) || defined(OJPEG_SUPPORT)
|
|
|| (t2p->pdf_compression == T2P_COMPRESS_JPEG)
|
|
#endif
|
|
))
|
|
{
|
|
#ifdef CCITT_SUPPORT
|
|
if (t2p->pdf_compression == T2P_COMPRESS_G4)
|
|
{
|
|
buffer = (unsigned char *)_TIFFmalloc(t2p->tiff_datasize);
|
|
if (buffer == NULL)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"Can't allocate %" TIFF_SSIZE_FORMAT
|
|
" bytes of memory "
|
|
"for t2p_readwrite_pdf_image_tile, %s",
|
|
t2p->tiff_datasize, TIFFFileName(input));
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return (0);
|
|
}
|
|
memset(buffer, 0, t2p->tiff_datasize);
|
|
if (TIFFReadRawTile(input, tile, (tdata_t)buffer,
|
|
t2p->tiff_datasize) < 0)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE, "TIFFReadRawTile() failed");
|
|
_TIFFfree(buffer);
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return (0);
|
|
}
|
|
if (t2p->tiff_fillorder == FILLORDER_LSB2MSB)
|
|
{
|
|
TIFFReverseBits(buffer, t2p->tiff_datasize);
|
|
}
|
|
t2pWriteFile(output, (tdata_t)buffer, t2p->tiff_datasize);
|
|
_TIFFfree(buffer);
|
|
return (t2p->tiff_datasize);
|
|
}
|
|
#endif
|
|
#ifdef ZIP_SUPPORT
|
|
if (t2p->pdf_compression == T2P_COMPRESS_ZIP)
|
|
{
|
|
buffer = (unsigned char *)_TIFFmalloc(t2p->tiff_datasize);
|
|
if (buffer == NULL)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"Can't allocate %" TIFF_SSIZE_FORMAT
|
|
" bytes of memory "
|
|
"for t2p_readwrite_pdf_image_tile, %s",
|
|
t2p->tiff_datasize, TIFFFileName(input));
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return (0);
|
|
}
|
|
memset(buffer, 0, t2p->tiff_datasize);
|
|
if (TIFFReadRawTile(input, tile, (tdata_t)buffer,
|
|
t2p->tiff_datasize) < 0)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE, "TIFFReadRawTile() failed");
|
|
_TIFFfree(buffer);
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return (0);
|
|
}
|
|
if (t2p->tiff_fillorder == FILLORDER_LSB2MSB)
|
|
{
|
|
TIFFReverseBits(buffer, t2p->tiff_datasize);
|
|
}
|
|
t2pWriteFile(output, (tdata_t)buffer, t2p->tiff_datasize);
|
|
_TIFFfree(buffer);
|
|
return (t2p->tiff_datasize);
|
|
}
|
|
#endif
|
|
#ifdef OJPEG_SUPPORT
|
|
if (t2p->tiff_compression == COMPRESSION_OJPEG)
|
|
{
|
|
tsize_t retTIFFReadRawTile;
|
|
if (!t2p->pdf_ojpegdata)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"No support for OJPEG image %s with "
|
|
"bad tables",
|
|
TIFFFileName(input));
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return (0);
|
|
}
|
|
buffer = (unsigned char *)_TIFFmalloc(t2p->tiff_datasize);
|
|
if (buffer == NULL)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"Can't allocate %" TIFF_SSIZE_FORMAT
|
|
" bytes of memory "
|
|
"for t2p_readwrite_pdf_image, %s",
|
|
t2p->tiff_datasize, TIFFFileName(input));
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return (0);
|
|
}
|
|
memset(buffer, 0, t2p->tiff_datasize);
|
|
_TIFFmemcpy(buffer, t2p->pdf_ojpegdata, t2p->pdf_ojpegdatalength);
|
|
if (edge != 0)
|
|
{
|
|
if (t2p_tile_is_bottom_edge(t2p->tiff_tiles[t2p->pdf_page],
|
|
tile))
|
|
{
|
|
buffer[7] =
|
|
(t2p->tiff_tiles[t2p->pdf_page].tiles_edgetilelength >>
|
|
8) &
|
|
0xff;
|
|
buffer[8] =
|
|
(t2p->tiff_tiles[t2p->pdf_page].tiles_edgetilelength) &
|
|
0xff;
|
|
}
|
|
if (t2p_tile_is_right_edge(t2p->tiff_tiles[t2p->pdf_page],
|
|
tile))
|
|
{
|
|
buffer[9] =
|
|
(t2p->tiff_tiles[t2p->pdf_page].tiles_edgetilewidth >>
|
|
8) &
|
|
0xff;
|
|
buffer[10] =
|
|
(t2p->tiff_tiles[t2p->pdf_page].tiles_edgetilewidth) &
|
|
0xff;
|
|
}
|
|
}
|
|
bufferoffset = t2p->pdf_ojpegdatalength;
|
|
retTIFFReadRawTile = TIFFReadRawTile(
|
|
input, tile,
|
|
(tdata_t) & (((unsigned char *)buffer)[bufferoffset]), -1);
|
|
if (retTIFFReadRawTile < 0)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE, "TIFFReadRawTile() failed");
|
|
_TIFFfree(buffer);
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return (0);
|
|
}
|
|
bufferoffset += retTIFFReadRawTile;
|
|
t2pWriteFile(output, (tdata_t)buffer, bufferoffset);
|
|
t2pWriteFile(output, (tdata_t)jpeg_eof_marker,
|
|
sizeof(jpeg_eof_marker));
|
|
_TIFFfree(buffer);
|
|
return (bufferoffset);
|
|
}
|
|
#endif
|
|
#ifdef JPEG_SUPPORT
|
|
if (t2p->tiff_compression == COMPRESSION_JPEG)
|
|
{
|
|
unsigned char table_end[2];
|
|
uint32_t count = 0;
|
|
buffer = (unsigned char *)_TIFFmalloc(t2p->tiff_datasize);
|
|
if (buffer == NULL)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"Can't allocate %" TIFF_SSIZE_FORMAT
|
|
" bytes of memory "
|
|
"for t2p_readwrite_pdf_image_tile, %s",
|
|
t2p->tiff_datasize, TIFFFileName(input));
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return (0);
|
|
}
|
|
memset(buffer, 0, t2p->tiff_datasize);
|
|
if (TIFFGetField(input, TIFFTAG_JPEGTABLES, &count, &jpt) != 0)
|
|
{
|
|
if (count > 4)
|
|
{
|
|
tsize_t retTIFFReadRawTile;
|
|
/* Ignore EOI marker of JpegTables */
|
|
_TIFFmemcpy(buffer, jpt, count - 2);
|
|
bufferoffset += count - 2;
|
|
/* Store last 2 bytes of the JpegTables */
|
|
table_end[0] = buffer[bufferoffset - 2];
|
|
table_end[1] = buffer[bufferoffset - 1];
|
|
xuint32 = bufferoffset;
|
|
bufferoffset -= 2;
|
|
retTIFFReadRawTile = TIFFReadRawTile(
|
|
input, tile,
|
|
(tdata_t) & (((unsigned char *)buffer)[bufferoffset]),
|
|
-1);
|
|
if (retTIFFReadRawTile < 0)
|
|
{
|
|
_TIFFfree(buffer);
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return (0);
|
|
}
|
|
bufferoffset += retTIFFReadRawTile;
|
|
/* Overwrite SOI marker of image scan with previously */
|
|
/* saved end of JpegTables */
|
|
buffer[xuint32 - 2] = table_end[0];
|
|
buffer[xuint32 - 1] = table_end[1];
|
|
}
|
|
}
|
|
t2pWriteFile(output, (tdata_t)buffer, bufferoffset);
|
|
_TIFFfree(buffer);
|
|
return (bufferoffset);
|
|
}
|
|
#endif
|
|
(void)0;
|
|
}
|
|
|
|
if (t2p->pdf_sample == T2P_SAMPLE_NOTHING)
|
|
{
|
|
buffer = (unsigned char *)_TIFFmalloc(t2p->tiff_datasize);
|
|
if (buffer == NULL)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"Can't allocate %" TIFF_SSIZE_FORMAT
|
|
" bytes of memory for "
|
|
"t2p_readwrite_pdf_image_tile, %s",
|
|
t2p->tiff_datasize, TIFFFileName(input));
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return (0);
|
|
}
|
|
memset(buffer, 0, t2p->tiff_datasize);
|
|
|
|
read = TIFFReadEncodedTile(input, tile, (tdata_t)&buffer[bufferoffset],
|
|
t2p->tiff_datasize);
|
|
if (read == -1)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"Error on decoding tile %" PRIu32 " of %s", tile,
|
|
TIFFFileName(input));
|
|
_TIFFfree(buffer);
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return (0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
if (t2p->pdf_sample == T2P_SAMPLE_PLANAR_SEPARATE_TO_CONTIG)
|
|
{
|
|
septilesize = TIFFTileSize(input);
|
|
septilecount = TIFFNumberOfTiles(input);
|
|
/* tilesize=septilesize*t2p->tiff_samplesperpixel; */
|
|
tilecount = septilecount / t2p->tiff_samplesperpixel;
|
|
buffer = (unsigned char *)_TIFFmalloc(t2p->tiff_datasize);
|
|
if (buffer == NULL)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"Can't allocate %" TIFF_SSIZE_FORMAT
|
|
" bytes of memory "
|
|
"for t2p_readwrite_pdf_image_tile, %s",
|
|
t2p->tiff_datasize, TIFFFileName(input));
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return (0);
|
|
}
|
|
memset(buffer, 0, t2p->tiff_datasize);
|
|
samplebuffer = (unsigned char *)_TIFFmalloc(t2p->tiff_datasize);
|
|
if (samplebuffer == NULL)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"Can't allocate %" TIFF_SSIZE_FORMAT
|
|
" bytes of memory "
|
|
"for t2p_readwrite_pdf_image_tile, %s",
|
|
t2p->tiff_datasize, TIFFFileName(input));
|
|
_TIFFfree(buffer);
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return (0);
|
|
}
|
|
memset(samplebuffer, 0, t2p->tiff_datasize);
|
|
samplebufferoffset = 0;
|
|
for (i = 0; i < t2p->tiff_samplesperpixel; i++)
|
|
{
|
|
read = TIFFReadEncodedTile(
|
|
input, tile + i * tilecount,
|
|
(tdata_t) & (samplebuffer[samplebufferoffset]),
|
|
septilesize);
|
|
if (read == -1)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"Error on decoding tile %" PRIu32 " of %s",
|
|
tile + i * tilecount, TIFFFileName(input));
|
|
_TIFFfree(samplebuffer);
|
|
_TIFFfree(buffer);
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return (0);
|
|
}
|
|
samplebufferoffset += read;
|
|
}
|
|
t2p_sample_planar_separate_to_contig(
|
|
t2p, &(buffer[bufferoffset]), samplebuffer, samplebufferoffset);
|
|
bufferoffset += samplebufferoffset;
|
|
_TIFFfree(samplebuffer);
|
|
}
|
|
|
|
if (buffer == NULL)
|
|
{
|
|
buffer = (unsigned char *)_TIFFmalloc(t2p->tiff_datasize);
|
|
if (buffer == NULL)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"Can't allocate %" TIFF_SSIZE_FORMAT
|
|
" bytes of memory "
|
|
"for t2p_readwrite_pdf_image_tile, %s",
|
|
t2p->tiff_datasize, TIFFFileName(input));
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return (0);
|
|
}
|
|
memset(buffer, 0, t2p->tiff_datasize);
|
|
read =
|
|
TIFFReadEncodedTile(input, tile, (tdata_t)&buffer[bufferoffset],
|
|
t2p->tiff_datasize);
|
|
if (read == -1)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"Error on decoding tile %" PRIu32 " of %s", tile,
|
|
TIFFFileName(input));
|
|
_TIFFfree(buffer);
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return (0);
|
|
}
|
|
}
|
|
|
|
if (t2p->pdf_sample & T2P_SAMPLE_RGBA_TO_RGB)
|
|
{
|
|
t2p->tiff_datasize = t2p_sample_rgba_to_rgb(
|
|
(tdata_t)buffer,
|
|
t2p->tiff_tiles[t2p->pdf_page].tiles_tilewidth *
|
|
t2p->tiff_tiles[t2p->pdf_page].tiles_tilelength);
|
|
}
|
|
|
|
if (t2p->pdf_sample & T2P_SAMPLE_RGBAA_TO_RGB)
|
|
{
|
|
t2p->tiff_datasize = t2p_sample_rgbaa_to_rgb(
|
|
(tdata_t)buffer,
|
|
t2p->tiff_tiles[t2p->pdf_page].tiles_tilewidth *
|
|
t2p->tiff_tiles[t2p->pdf_page].tiles_tilelength);
|
|
}
|
|
|
|
if (t2p->pdf_sample & T2P_SAMPLE_YCBCR_TO_RGB)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"No support for YCbCr to RGB in tile for %s",
|
|
TIFFFileName(input));
|
|
_TIFFfree(buffer);
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return (0);
|
|
}
|
|
|
|
if (t2p->pdf_sample & T2P_SAMPLE_LAB_SIGNED_TO_UNSIGNED)
|
|
{
|
|
t2p->tiff_datasize = t2p_sample_lab_signed_to_unsigned(
|
|
(tdata_t)buffer,
|
|
t2p->tiff_tiles[t2p->pdf_page].tiles_tilewidth *
|
|
t2p->tiff_tiles[t2p->pdf_page].tiles_tilelength);
|
|
}
|
|
}
|
|
|
|
if (t2p_tile_is_right_edge(t2p->tiff_tiles[t2p->pdf_page], tile) != 0)
|
|
{
|
|
if ((uint64_t)t2p->tiff_datasize <
|
|
(uint64_t)TIFFTileRowSize(input) *
|
|
(uint64_t)t2p->tiff_tiles[t2p->pdf_page].tiles_tilelength)
|
|
{
|
|
/* we don't know how to handle PLANARCONFIG_CONTIG,
|
|
* PHOTOMETRIC_YCBCR with 3 samples per pixel */
|
|
TIFFWarning(TIFF2PDF_MODULE,
|
|
"Don't know how to collapse tile to the left");
|
|
}
|
|
else
|
|
{
|
|
t2p_tile_collapse_left(
|
|
buffer, TIFFTileRowSize(input),
|
|
t2p->tiff_tiles[t2p->pdf_page].tiles_tilewidth,
|
|
t2p->tiff_tiles[t2p->pdf_page].tiles_edgetilewidth,
|
|
t2p->tiff_tiles[t2p->pdf_page].tiles_tilelength);
|
|
}
|
|
}
|
|
|
|
t2p_disable(output);
|
|
TIFFSetField(output, TIFFTAG_PHOTOMETRIC, t2p->tiff_photometric);
|
|
TIFFSetField(output, TIFFTAG_BITSPERSAMPLE, t2p->tiff_bitspersample);
|
|
TIFFSetField(output, TIFFTAG_SAMPLESPERPIXEL, t2p->tiff_samplesperpixel);
|
|
if (t2p_tile_is_right_edge(t2p->tiff_tiles[t2p->pdf_page], tile) == 0)
|
|
{
|
|
TIFFSetField(output, TIFFTAG_IMAGEWIDTH,
|
|
t2p->tiff_tiles[t2p->pdf_page].tiles_tilewidth);
|
|
}
|
|
else
|
|
{
|
|
TIFFSetField(output, TIFFTAG_IMAGEWIDTH,
|
|
t2p->tiff_tiles[t2p->pdf_page].tiles_edgetilewidth);
|
|
}
|
|
if (t2p_tile_is_bottom_edge(t2p->tiff_tiles[t2p->pdf_page], tile) == 0)
|
|
{
|
|
TIFFSetField(output, TIFFTAG_IMAGELENGTH,
|
|
t2p->tiff_tiles[t2p->pdf_page].tiles_tilelength);
|
|
TIFFSetField(output, TIFFTAG_ROWSPERSTRIP,
|
|
t2p->tiff_tiles[t2p->pdf_page].tiles_tilelength);
|
|
}
|
|
else
|
|
{
|
|
TIFFSetField(output, TIFFTAG_IMAGELENGTH,
|
|
t2p->tiff_tiles[t2p->pdf_page].tiles_edgetilelength);
|
|
TIFFSetField(output, TIFFTAG_ROWSPERSTRIP,
|
|
t2p->tiff_tiles[t2p->pdf_page].tiles_edgetilelength);
|
|
}
|
|
TIFFSetField(output, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
|
|
TIFFSetField(output, TIFFTAG_FILLORDER, FILLORDER_MSB2LSB);
|
|
|
|
switch (t2p->pdf_compression)
|
|
{
|
|
case T2P_COMPRESS_NONE:
|
|
TIFFSetField(output, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
|
|
break;
|
|
#ifdef CCITT_SUPPORT
|
|
case T2P_COMPRESS_G4:
|
|
TIFFSetField(output, TIFFTAG_COMPRESSION, COMPRESSION_CCITTFAX4);
|
|
break;
|
|
#endif
|
|
#ifdef JPEG_SUPPORT
|
|
case T2P_COMPRESS_JPEG:
|
|
if (t2p->tiff_photometric == PHOTOMETRIC_YCBCR)
|
|
{
|
|
uint16_t hor = 0, ver = 0;
|
|
if (TIFFGetField(input, TIFFTAG_YCBCRSUBSAMPLING, &hor, &ver) !=
|
|
0)
|
|
{
|
|
if (hor != 0 && ver != 0)
|
|
{
|
|
TIFFSetField(output, TIFFTAG_YCBCRSUBSAMPLING, hor,
|
|
ver);
|
|
}
|
|
}
|
|
if (TIFFGetField(input, TIFFTAG_REFERENCEBLACKWHITE,
|
|
&xfloatp) != 0)
|
|
{
|
|
TIFFSetField(output, TIFFTAG_REFERENCEBLACKWHITE, xfloatp);
|
|
}
|
|
}
|
|
TIFFSetField(output, TIFFTAG_COMPRESSION, COMPRESSION_JPEG);
|
|
TIFFSetField(output, TIFFTAG_JPEGTABLESMODE,
|
|
0); /* JPEGTABLESMODE_NONE */
|
|
if (t2p->pdf_colorspace & (T2P_CS_RGB | T2P_CS_LAB))
|
|
{
|
|
TIFFSetField(output, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_YCBCR);
|
|
if (t2p->tiff_photometric != PHOTOMETRIC_YCBCR)
|
|
{
|
|
TIFFSetField(output, TIFFTAG_JPEGCOLORMODE,
|
|
JPEGCOLORMODE_RGB);
|
|
}
|
|
else
|
|
{
|
|
TIFFSetField(output, TIFFTAG_JPEGCOLORMODE,
|
|
JPEGCOLORMODE_RAW);
|
|
}
|
|
}
|
|
if (t2p->pdf_colorspace & T2P_CS_GRAY)
|
|
{
|
|
(void)0;
|
|
}
|
|
if (t2p->pdf_colorspace & T2P_CS_CMYK)
|
|
{
|
|
(void)0;
|
|
}
|
|
if (t2p->pdf_defaultcompressionquality != 0)
|
|
{
|
|
TIFFSetField(output, TIFFTAG_JPEGQUALITY,
|
|
t2p->pdf_defaultcompressionquality);
|
|
}
|
|
break;
|
|
#endif
|
|
#ifdef ZIP_SUPPORT
|
|
case T2P_COMPRESS_ZIP:
|
|
TIFFSetField(output, TIFFTAG_COMPRESSION,
|
|
COMPRESSION_ADOBE_DEFLATE);
|
|
if (t2p->pdf_defaultcompressionquality % 100 != 0)
|
|
{
|
|
TIFFSetField(output, TIFFTAG_PREDICTOR,
|
|
t2p->pdf_defaultcompressionquality % 100);
|
|
}
|
|
if (t2p->pdf_defaultcompressionquality / 100 != 0)
|
|
{
|
|
TIFFSetField(output, TIFFTAG_ZIPQUALITY,
|
|
(t2p->pdf_defaultcompressionquality / 100));
|
|
}
|
|
break;
|
|
#endif
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (TIFFStripSize(output) > t2p->tiff_datasize)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"Size mismatch input %" PRId64 ", output %" PRId64,
|
|
(int64_t)t2p->tiff_datasize, (int64_t)TIFFStripSize(output));
|
|
_TIFFfree(buffer);
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return (0);
|
|
}
|
|
t2p_enable(output);
|
|
t2p->outputwritten = 0;
|
|
bufferoffset = TIFFWriteEncodedStrip(output, (tstrip_t)0, buffer,
|
|
TIFFStripSize(output));
|
|
if (buffer != NULL)
|
|
{
|
|
_TIFFfree(buffer);
|
|
buffer = NULL;
|
|
}
|
|
if (bufferoffset == -1)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"Error writing encoded tile to output PDF %s",
|
|
TIFFFileName(output));
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return (0);
|
|
}
|
|
|
|
written = t2p->outputwritten;
|
|
|
|
return (written);
|
|
}
|
|
|
|
#ifdef OJPEG_SUPPORT
|
|
int t2p_process_ojpeg_tables(T2P *t2p, TIFF *input)
|
|
{
|
|
uint16_t proc = 0;
|
|
void *q;
|
|
uint32_t q_length = 0;
|
|
void *dc;
|
|
uint32_t dc_length = 0;
|
|
void *ac;
|
|
uint32_t ac_length = 0;
|
|
uint16_t *lp;
|
|
uint16_t *pt;
|
|
uint16_t h_samp = 1;
|
|
uint16_t v_samp = 1;
|
|
unsigned char *ojpegdata;
|
|
uint16_t table_count;
|
|
uint32_t offset_table;
|
|
uint32_t offset_ms_l;
|
|
uint32_t code_count;
|
|
uint32_t i = 0;
|
|
uint32_t dest = 0;
|
|
uint16_t ri = 0;
|
|
uint32_t rows = 0;
|
|
|
|
if (!TIFFGetField(input, TIFFTAG_JPEGPROC, &proc))
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE, "Missing JPEGProc field in OJPEG image %s",
|
|
TIFFFileName(input));
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return (0);
|
|
}
|
|
if (proc != JPEGPROC_BASELINE && proc != JPEGPROC_LOSSLESS)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE, "Bad JPEGProc field in OJPEG image %s",
|
|
TIFFFileName(input));
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return (0);
|
|
}
|
|
if (!TIFFGetField(input, TIFFTAG_JPEGQTABLES, &q_length, &q))
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"Missing JPEGQTables field in OJPEG image %s",
|
|
TIFFFileName(input));
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return (0);
|
|
}
|
|
if (q_length < (64U * t2p->tiff_samplesperpixel))
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE, "Bad JPEGQTables field in OJPEG image %s",
|
|
TIFFFileName(input));
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return (0);
|
|
}
|
|
if (!TIFFGetField(input, TIFFTAG_JPEGDCTABLES, &dc_length, &dc))
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"Missing JPEGDCTables field in OJPEG image %s",
|
|
TIFFFileName(input));
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return (0);
|
|
}
|
|
if (proc == JPEGPROC_BASELINE)
|
|
{
|
|
if (!TIFFGetField(input, TIFFTAG_JPEGACTABLES, &ac_length, &ac))
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"Missing JPEGACTables field in OJPEG image %s",
|
|
TIFFFileName(input));
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return (0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!TIFFGetField(input, TIFFTAG_JPEGLOSSLESSPREDICTORS, &lp))
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"Missing JPEGLosslessPredictors field in OJPEG image %s",
|
|
TIFFFileName(input));
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return (0);
|
|
}
|
|
if (!TIFFGetField(input, TIFFTAG_JPEGPOINTTRANSFORM, &pt))
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"Missing JPEGPointTransform field in OJPEG image %s",
|
|
TIFFFileName(input));
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return (0);
|
|
}
|
|
}
|
|
if (!TIFFGetField(input, TIFFTAG_YCBCRSUBSAMPLING, &h_samp, &v_samp))
|
|
{
|
|
h_samp = 1;
|
|
v_samp = 1;
|
|
}
|
|
if (t2p->pdf_ojpegdata != NULL)
|
|
{
|
|
_TIFFfree(t2p->pdf_ojpegdata);
|
|
t2p->pdf_ojpegdata = NULL;
|
|
}
|
|
t2p->pdf_ojpegdata = _TIFFmalloc(2048);
|
|
if (t2p->pdf_ojpegdata == NULL)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"Can't allocate %u bytes of memory for "
|
|
"t2p_process_ojpeg_tables, %s",
|
|
2048u, TIFFFileName(input));
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return (0);
|
|
}
|
|
_TIFFmemset(t2p->pdf_ojpegdata, 0x00, 2048);
|
|
t2p->pdf_ojpegdatalength = 0;
|
|
table_count = t2p->tiff_samplesperpixel;
|
|
if (proc == JPEGPROC_BASELINE)
|
|
{
|
|
if (table_count > 2)
|
|
table_count = 2;
|
|
}
|
|
ojpegdata = (unsigned char *)t2p->pdf_ojpegdata;
|
|
ojpegdata[t2p->pdf_ojpegdatalength++] = 0xff;
|
|
ojpegdata[t2p->pdf_ojpegdatalength++] = 0xd8;
|
|
ojpegdata[t2p->pdf_ojpegdatalength++] = 0xff;
|
|
if (proc == JPEGPROC_BASELINE)
|
|
{
|
|
ojpegdata[t2p->pdf_ojpegdatalength++] = 0xc0;
|
|
}
|
|
else
|
|
{
|
|
ojpegdata[t2p->pdf_ojpegdatalength++] = 0xc3;
|
|
}
|
|
ojpegdata[t2p->pdf_ojpegdatalength++] = 0x00;
|
|
ojpegdata[t2p->pdf_ojpegdatalength++] = (8 + 3 * t2p->tiff_samplesperpixel);
|
|
ojpegdata[t2p->pdf_ojpegdatalength++] = (t2p->tiff_bitspersample & 0xff);
|
|
if (TIFFIsTiled(input))
|
|
{
|
|
ojpegdata[t2p->pdf_ojpegdatalength++] =
|
|
(t2p->tiff_tiles[t2p->pdf_page].tiles_tilelength >> 8) & 0xff;
|
|
ojpegdata[t2p->pdf_ojpegdatalength++] =
|
|
(t2p->tiff_tiles[t2p->pdf_page].tiles_tilelength) & 0xff;
|
|
ojpegdata[t2p->pdf_ojpegdatalength++] =
|
|
(t2p->tiff_tiles[t2p->pdf_page].tiles_tilewidth >> 8) & 0xff;
|
|
ojpegdata[t2p->pdf_ojpegdatalength++] =
|
|
(t2p->tiff_tiles[t2p->pdf_page].tiles_tilewidth) & 0xff;
|
|
}
|
|
else
|
|
{
|
|
ojpegdata[t2p->pdf_ojpegdatalength++] = (t2p->tiff_length >> 8) & 0xff;
|
|
ojpegdata[t2p->pdf_ojpegdatalength++] = (t2p->tiff_length) & 0xff;
|
|
ojpegdata[t2p->pdf_ojpegdatalength++] = (t2p->tiff_width >> 8) & 0xff;
|
|
ojpegdata[t2p->pdf_ojpegdatalength++] = (t2p->tiff_width) & 0xff;
|
|
}
|
|
ojpegdata[t2p->pdf_ojpegdatalength++] = (t2p->tiff_samplesperpixel & 0xff);
|
|
for (i = 0; i < t2p->tiff_samplesperpixel; i++)
|
|
{
|
|
ojpegdata[t2p->pdf_ojpegdatalength++] = i;
|
|
if (i == 0)
|
|
{
|
|
ojpegdata[t2p->pdf_ojpegdatalength] |= h_samp << 4 & 0xf0;
|
|
;
|
|
ojpegdata[t2p->pdf_ojpegdatalength++] |= v_samp & 0x0f;
|
|
}
|
|
else
|
|
{
|
|
ojpegdata[t2p->pdf_ojpegdatalength++] = 0x11;
|
|
}
|
|
ojpegdata[t2p->pdf_ojpegdatalength++] = i;
|
|
}
|
|
for (dest = 0; dest < t2p->tiff_samplesperpixel; dest++)
|
|
{
|
|
ojpegdata[t2p->pdf_ojpegdatalength++] = 0xff;
|
|
ojpegdata[t2p->pdf_ojpegdatalength++] = 0xdb;
|
|
ojpegdata[t2p->pdf_ojpegdatalength++] = 0x00;
|
|
ojpegdata[t2p->pdf_ojpegdatalength++] = 0x43;
|
|
ojpegdata[t2p->pdf_ojpegdatalength++] = dest;
|
|
_TIFFmemcpy(&(ojpegdata[t2p->pdf_ojpegdatalength++]),
|
|
&(((unsigned char *)q)[64 * dest]), 64);
|
|
t2p->pdf_ojpegdatalength += 64;
|
|
}
|
|
offset_table = 0;
|
|
for (dest = 0; dest < table_count; dest++)
|
|
{
|
|
ojpegdata[t2p->pdf_ojpegdatalength++] = 0xff;
|
|
ojpegdata[t2p->pdf_ojpegdatalength++] = 0xc4;
|
|
offset_ms_l = t2p->pdf_ojpegdatalength;
|
|
t2p->pdf_ojpegdatalength += 2;
|
|
ojpegdata[t2p->pdf_ojpegdatalength++] = dest & 0x0f;
|
|
_TIFFmemcpy(&(ojpegdata[t2p->pdf_ojpegdatalength]),
|
|
&(((unsigned char *)dc)[offset_table]), 16);
|
|
code_count = 0;
|
|
offset_table += 16;
|
|
for (i = 0; i < 16; i++)
|
|
{
|
|
code_count += ojpegdata[t2p->pdf_ojpegdatalength++];
|
|
}
|
|
ojpegdata[offset_ms_l] = ((19 + code_count) >> 8) & 0xff;
|
|
ojpegdata[offset_ms_l + 1] = (19 + code_count) & 0xff;
|
|
_TIFFmemcpy(&(ojpegdata[t2p->pdf_ojpegdatalength]),
|
|
&(((unsigned char *)dc)[offset_table]), code_count);
|
|
offset_table += code_count;
|
|
t2p->pdf_ojpegdatalength += code_count;
|
|
}
|
|
if (proc == JPEGPROC_BASELINE)
|
|
{
|
|
offset_table = 0;
|
|
for (dest = 0; dest < table_count; dest++)
|
|
{
|
|
ojpegdata[t2p->pdf_ojpegdatalength++] = 0xff;
|
|
ojpegdata[t2p->pdf_ojpegdatalength++] = 0xc4;
|
|
offset_ms_l = t2p->pdf_ojpegdatalength;
|
|
t2p->pdf_ojpegdatalength += 2;
|
|
ojpegdata[t2p->pdf_ojpegdatalength] |= 0x10;
|
|
ojpegdata[t2p->pdf_ojpegdatalength++] |= dest & 0x0f;
|
|
_TIFFmemcpy(&(ojpegdata[t2p->pdf_ojpegdatalength]),
|
|
&(((unsigned char *)ac)[offset_table]), 16);
|
|
code_count = 0;
|
|
offset_table += 16;
|
|
for (i = 0; i < 16; i++)
|
|
{
|
|
code_count += ojpegdata[t2p->pdf_ojpegdatalength++];
|
|
}
|
|
ojpegdata[offset_ms_l] = ((19 + code_count) >> 8) & 0xff;
|
|
ojpegdata[offset_ms_l + 1] = (19 + code_count) & 0xff;
|
|
_TIFFmemcpy(&(ojpegdata[t2p->pdf_ojpegdatalength]),
|
|
&(((unsigned char *)ac)[offset_table]), code_count);
|
|
offset_table += code_count;
|
|
t2p->pdf_ojpegdatalength += code_count;
|
|
}
|
|
}
|
|
if (TIFFNumberOfStrips(input) > 1)
|
|
{
|
|
ojpegdata[t2p->pdf_ojpegdatalength++] = 0xff;
|
|
ojpegdata[t2p->pdf_ojpegdatalength++] = 0xdd;
|
|
ojpegdata[t2p->pdf_ojpegdatalength++] = 0x00;
|
|
ojpegdata[t2p->pdf_ojpegdatalength++] = 0x04;
|
|
h_samp *= 8;
|
|
v_samp *= 8;
|
|
ri = (t2p->tiff_width + h_samp - 1) / h_samp;
|
|
TIFFGetField(input, TIFFTAG_ROWSPERSTRIP, &rows);
|
|
ri *= (rows + v_samp - 1) / v_samp;
|
|
ojpegdata[t2p->pdf_ojpegdatalength++] = (ri >> 8) & 0xff;
|
|
ojpegdata[t2p->pdf_ojpegdatalength++] = ri & 0xff;
|
|
}
|
|
ojpegdata[t2p->pdf_ojpegdatalength++] = 0xff;
|
|
ojpegdata[t2p->pdf_ojpegdatalength++] = 0xda;
|
|
ojpegdata[t2p->pdf_ojpegdatalength++] = 0x00;
|
|
ojpegdata[t2p->pdf_ojpegdatalength++] = (6 + 2 * t2p->tiff_samplesperpixel);
|
|
ojpegdata[t2p->pdf_ojpegdatalength++] = t2p->tiff_samplesperpixel & 0xff;
|
|
for (i = 0; i < t2p->tiff_samplesperpixel; i++)
|
|
{
|
|
ojpegdata[t2p->pdf_ojpegdatalength++] = i & 0xff;
|
|
if (proc == JPEGPROC_BASELINE)
|
|
{
|
|
ojpegdata[t2p->pdf_ojpegdatalength] |=
|
|
(((i > (table_count - 1U)) ? (table_count - 1U) : i) << 4U) &
|
|
0xf0;
|
|
ojpegdata[t2p->pdf_ojpegdatalength++] |=
|
|
((i > (table_count - 1U)) ? (table_count - 1U) : i) & 0x0f;
|
|
}
|
|
else
|
|
{
|
|
ojpegdata[t2p->pdf_ojpegdatalength++] = (i << 4) & 0xf0;
|
|
}
|
|
}
|
|
if (proc == JPEGPROC_BASELINE)
|
|
{
|
|
t2p->pdf_ojpegdatalength++;
|
|
ojpegdata[t2p->pdf_ojpegdatalength++] = 0x3f;
|
|
t2p->pdf_ojpegdatalength++;
|
|
}
|
|
else
|
|
{
|
|
ojpegdata[t2p->pdf_ojpegdatalength++] = (lp[0] & 0xff);
|
|
t2p->pdf_ojpegdatalength++;
|
|
ojpegdata[t2p->pdf_ojpegdatalength++] = (pt[0] & 0x0f);
|
|
}
|
|
|
|
return (1);
|
|
}
|
|
#endif
|
|
|
|
#ifdef JPEG_SUPPORT
|
|
int t2p_process_jpeg_strip(unsigned char *strip, tsize_t *striplength,
|
|
unsigned char *buffer, tsize_t buffersize,
|
|
tsize_t *bufferoffset, tstrip_t no, uint32_t height)
|
|
{
|
|
|
|
tsize_t i = 0;
|
|
|
|
while (i < *striplength)
|
|
{
|
|
tsize_t datalen;
|
|
uint16_t ri;
|
|
uint16_t v_samp;
|
|
uint16_t h_samp;
|
|
int j;
|
|
int ncomp;
|
|
|
|
/* marker header: one or more FFs */
|
|
if (strip[i] != 0xff)
|
|
return (0);
|
|
i++;
|
|
while (i < *striplength && strip[i] == 0xff)
|
|
i++;
|
|
if (i >= *striplength)
|
|
return (0);
|
|
/* SOI is the only pre-SOS marker without a length word */
|
|
if (strip[i] == 0xd8)
|
|
datalen = 0;
|
|
else
|
|
{
|
|
if ((*striplength - i) <= 2)
|
|
return (0);
|
|
datalen = (strip[i + 1] << 8) | strip[i + 2];
|
|
if (datalen < 2 || datalen >= (*striplength - i))
|
|
return (0);
|
|
}
|
|
switch (strip[i])
|
|
{
|
|
case 0xd8: /* SOI - start of image */
|
|
if (*bufferoffset + 2 > buffersize)
|
|
return (0);
|
|
_TIFFmemcpy(&(buffer[*bufferoffset]), &(strip[i - 1]), 2);
|
|
*bufferoffset += 2;
|
|
break;
|
|
case 0xc0: /* SOF0 */
|
|
case 0xc1: /* SOF1 */
|
|
case 0xc3: /* SOF3 */
|
|
case 0xc9: /* SOF9 */
|
|
case 0xca: /* SOF10 */
|
|
if (no == 0)
|
|
{
|
|
if (*bufferoffset + datalen + 2 + 6 > buffersize)
|
|
return (0);
|
|
_TIFFmemcpy(&(buffer[*bufferoffset]), &(strip[i - 1]),
|
|
datalen + 2);
|
|
if (*bufferoffset + 9 >= buffersize)
|
|
return (0);
|
|
ncomp = buffer[*bufferoffset + 9];
|
|
if (ncomp < 1 || ncomp > 4)
|
|
return (0);
|
|
v_samp = 1;
|
|
h_samp = 1;
|
|
if (*bufferoffset + 11 + 3 * (ncomp - 1) >= buffersize)
|
|
return (0);
|
|
for (j = 0; j < ncomp; j++)
|
|
{
|
|
uint16_t samp = buffer[*bufferoffset + 11 + (3 * j)];
|
|
if ((samp >> 4) > h_samp)
|
|
h_samp = (samp >> 4);
|
|
if ((samp & 0x0f) > v_samp)
|
|
v_samp = (samp & 0x0f);
|
|
}
|
|
v_samp *= 8;
|
|
h_samp *= 8;
|
|
ri = (((((uint16_t)(buffer[*bufferoffset + 5]) << 8) |
|
|
(uint16_t)(buffer[*bufferoffset + 6])) +
|
|
v_samp - 1) /
|
|
v_samp);
|
|
ri *= (((((uint16_t)(buffer[*bufferoffset + 7]) << 8) |
|
|
(uint16_t)(buffer[*bufferoffset + 8])) +
|
|
h_samp - 1) /
|
|
h_samp);
|
|
buffer[*bufferoffset + 5] =
|
|
(unsigned char)((height >> 8) & 0xff);
|
|
buffer[*bufferoffset + 6] = (unsigned char)(height & 0xff);
|
|
*bufferoffset += datalen + 2;
|
|
/* insert a DRI marker */
|
|
buffer[(*bufferoffset)++] = 0xff;
|
|
buffer[(*bufferoffset)++] = 0xdd;
|
|
buffer[(*bufferoffset)++] = 0x00;
|
|
buffer[(*bufferoffset)++] = 0x04;
|
|
buffer[(*bufferoffset)++] = (ri >> 8) & 0xff;
|
|
buffer[(*bufferoffset)++] = ri & 0xff;
|
|
}
|
|
break;
|
|
case 0xc4: /* DHT */
|
|
case 0xdb: /* DQT */
|
|
if (*bufferoffset + datalen + 2 > buffersize)
|
|
return (0);
|
|
_TIFFmemcpy(&(buffer[*bufferoffset]), &(strip[i - 1]),
|
|
datalen + 2);
|
|
*bufferoffset += datalen + 2;
|
|
break;
|
|
case 0xda: /* SOS */
|
|
if (no == 0)
|
|
{
|
|
if (*bufferoffset + datalen + 2 > buffersize)
|
|
return (0);
|
|
_TIFFmemcpy(&(buffer[*bufferoffset]), &(strip[i - 1]),
|
|
datalen + 2);
|
|
*bufferoffset += datalen + 2;
|
|
}
|
|
else
|
|
{
|
|
if (*bufferoffset + 2 > buffersize)
|
|
return (0);
|
|
buffer[(*bufferoffset)++] = 0xff;
|
|
buffer[(*bufferoffset)++] =
|
|
(unsigned char)(0xd0 | ((no - 1) % 8));
|
|
}
|
|
i += datalen + 1;
|
|
/* copy remainder of strip */
|
|
if (*bufferoffset + *striplength - i > buffersize)
|
|
return (0);
|
|
_TIFFmemcpy(&(buffer[*bufferoffset]), &(strip[i]),
|
|
*striplength - i);
|
|
*bufferoffset += *striplength - i;
|
|
return (1);
|
|
default:
|
|
/* ignore any other marker */
|
|
break;
|
|
}
|
|
i += datalen + 1;
|
|
}
|
|
|
|
/* failed to find SOS marker */
|
|
return (0);
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
This functions converts a tilewidth x tilelength buffer of samples into
|
|
an edgetilewidth x tilelength buffer of samples.
|
|
*/
|
|
void t2p_tile_collapse_left(tdata_t buffer, tsize_t scanwidth,
|
|
uint32_t tilewidth, uint32_t edgetilewidth,
|
|
uint32_t tilelength)
|
|
{
|
|
|
|
uint32_t i;
|
|
tsize_t edgescanwidth = 0;
|
|
|
|
edgescanwidth = (scanwidth * edgetilewidth + (tilewidth - 1)) / tilewidth;
|
|
for (i = 0; i < tilelength; i++)
|
|
{
|
|
/* We use memmove() since there can be overlaps in src and dst buffers
|
|
* for the first items */
|
|
memmove(&(((char *)buffer)[edgescanwidth * i]),
|
|
&(((char *)buffer)[scanwidth * i]), edgescanwidth);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* This function calls TIFFWriteDirectory on the output after blanking its
|
|
* output by replacing the read, write, and seek procedures with empty
|
|
* implementations, then it replaces the original implementations.
|
|
*/
|
|
|
|
void t2p_write_advance_directory(T2P *t2p, TIFF *output)
|
|
{
|
|
t2p_disable(output);
|
|
if (!TIFFWriteDirectory(output))
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"Error writing virtual directory to output PDF %s",
|
|
TIFFFileName(output));
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return;
|
|
}
|
|
t2p_enable(output);
|
|
return;
|
|
}
|
|
|
|
tsize_t t2p_sample_planar_separate_to_contig(T2P *t2p, unsigned char *buffer,
|
|
unsigned char *samplebuffer,
|
|
tsize_t samplebuffersize)
|
|
{
|
|
|
|
tsize_t stride = 0;
|
|
tsize_t i = 0;
|
|
tsize_t j = 0;
|
|
|
|
stride = samplebuffersize / t2p->tiff_samplesperpixel;
|
|
for (i = 0; i < stride; i++)
|
|
{
|
|
for (j = 0; j < t2p->tiff_samplesperpixel; j++)
|
|
{
|
|
buffer[i * t2p->tiff_samplesperpixel + j] =
|
|
samplebuffer[i + j * stride];
|
|
}
|
|
}
|
|
|
|
return (samplebuffersize);
|
|
}
|
|
|
|
tsize_t t2p_sample_realize_palette(T2P *t2p, unsigned char *buffer)
|
|
{
|
|
|
|
uint32_t sample_count = 0;
|
|
uint16_t component_count = 0;
|
|
uint32_t palette_offset = 0;
|
|
uint32_t sample_offset = 0;
|
|
uint32_t i = 0;
|
|
uint32_t j = 0;
|
|
size_t data_size;
|
|
sample_count = t2p->tiff_width * t2p->tiff_length;
|
|
component_count = t2p->tiff_samplesperpixel;
|
|
data_size = TIFFSafeMultiply(size_t, sample_count, component_count);
|
|
if ((data_size == 0U) || (t2p->tiff_datasize < 0) ||
|
|
(data_size > (size_t)t2p->tiff_datasize))
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"Error: sample_count * component_count > t2p->tiff_datasize");
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return 1;
|
|
}
|
|
|
|
for (i = sample_count; i > 0; i--)
|
|
{
|
|
palette_offset = buffer[i - 1] * component_count;
|
|
sample_offset = (i - 1) * component_count;
|
|
if (palette_offset + component_count > t2p->pdf_palettesize)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"Error: palette_offset + component_count > "
|
|
"t2p->pdf_palettesize");
|
|
return 1;
|
|
}
|
|
for (j = 0; j < component_count; j++)
|
|
{
|
|
buffer[sample_offset + j] = t2p->pdf_palette[palette_offset + j];
|
|
}
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
This functions converts in place a buffer of ABGR interleaved data
|
|
into RGB interleaved data, discarding A.
|
|
*/
|
|
|
|
tsize_t t2p_sample_abgr_to_rgb(tdata_t data, uint32_t samplecount)
|
|
{
|
|
uint32_t i = 0;
|
|
uint32_t sample = 0;
|
|
|
|
for (i = 0; i < samplecount; i++)
|
|
{
|
|
sample = ((uint32_t *)data)[i];
|
|
((char *)data)[i * 3] = (char)(sample & 0xff);
|
|
((char *)data)[i * 3 + 1] = (char)((sample >> 8) & 0xff);
|
|
((char *)data)[i * 3 + 2] = (char)((sample >> 16) & 0xff);
|
|
}
|
|
|
|
return (i * 3);
|
|
}
|
|
|
|
/*
|
|
* This functions converts in place a buffer of RGBA interleaved data
|
|
* into RGB interleaved data, discarding A.
|
|
*/
|
|
|
|
tsize_t t2p_sample_rgbaa_to_rgb(tdata_t data, uint32_t samplecount)
|
|
{
|
|
uint32_t i;
|
|
|
|
/* For the 3 first samples, there is overlap between source and
|
|
* destination, so use memmove().
|
|
* See http://bugzilla.maptools.org/show_bug.cgi?id=2577
|
|
*/
|
|
for (i = 0; i < 3 && i < samplecount; i++)
|
|
memmove((uint8_t *)data + i * 3, (uint8_t *)data + i * 4, 3);
|
|
for (; i < samplecount; i++)
|
|
memcpy((uint8_t *)data + i * 3, (uint8_t *)data + i * 4, 3);
|
|
|
|
return (i * 3);
|
|
}
|
|
|
|
/*
|
|
* This functions converts in place a buffer of RGBA interleaved data
|
|
* into RGB interleaved data, adding 255-A to each component sample.
|
|
*/
|
|
|
|
tsize_t t2p_sample_rgba_to_rgb(tdata_t data, uint32_t samplecount)
|
|
{
|
|
uint32_t i = 0;
|
|
uint32_t sample = 0;
|
|
uint8_t alpha = 0;
|
|
|
|
for (i = 0; i < samplecount; i++)
|
|
{
|
|
sample = ((uint32_t *)data)[i];
|
|
alpha = (uint8_t)((255 - ((sample >> 24) & 0xff)));
|
|
((uint8_t *)data)[i * 3] = (uint8_t)((sample >> 16) & 0xff) + alpha;
|
|
((uint8_t *)data)[i * 3 + 1] = (uint8_t)((sample >> 8) & 0xff) + alpha;
|
|
((uint8_t *)data)[i * 3 + 2] = (uint8_t)(sample & 0xff) + alpha;
|
|
}
|
|
|
|
return (i * 3);
|
|
}
|
|
|
|
/*
|
|
This function converts the a and b samples of Lab data from signed
|
|
to unsigned.
|
|
*/
|
|
|
|
tsize_t t2p_sample_lab_signed_to_unsigned(tdata_t buffer, uint32_t samplecount)
|
|
{
|
|
|
|
uint32_t i = 0;
|
|
|
|
for (i = 0; i < samplecount; i++)
|
|
{
|
|
if ((((unsigned char *)buffer)[(i * 3) + 1] & 0x80) != 0)
|
|
{
|
|
((unsigned char *)buffer)[(i * 3) + 1] =
|
|
(unsigned char)(0x80 + ((char *)buffer)[(i * 3) + 1]);
|
|
}
|
|
else
|
|
{
|
|
((unsigned char *)buffer)[(i * 3) + 1] |= 0x80;
|
|
}
|
|
if ((((unsigned char *)buffer)[(i * 3) + 2] & 0x80) != 0)
|
|
{
|
|
((unsigned char *)buffer)[(i * 3) + 2] =
|
|
(unsigned char)(0x80 + ((char *)buffer)[(i * 3) + 2]);
|
|
}
|
|
else
|
|
{
|
|
((unsigned char *)buffer)[(i * 3) + 2] |= 0x80;
|
|
}
|
|
}
|
|
|
|
return (samplecount * 3);
|
|
}
|
|
|
|
/*
|
|
This function writes the PDF header to output.
|
|
*/
|
|
|
|
tsize_t t2p_write_pdf_header(T2P *t2p, TIFF *output)
|
|
{
|
|
|
|
tsize_t written = 0;
|
|
char buffer[16];
|
|
int buflen = 0;
|
|
|
|
buflen = snprintf(buffer, sizeof(buffer), "%%PDF-%" PRIu16 ".%" PRIu16 " ",
|
|
(uint16_t)(t2p->pdf_majorversion & 0xff),
|
|
(uint16_t)(t2p->pdf_minorversion & 0xff));
|
|
check_snprintf_ret(t2p, buflen, buffer);
|
|
written += t2pWriteFile(output, (tdata_t)buffer, buflen);
|
|
written += t2pWriteFile(output, (tdata_t) "\n%\342\343\317\323\n", 7);
|
|
|
|
return (written);
|
|
}
|
|
|
|
/*
|
|
This function writes the beginning of a PDF object to output.
|
|
*/
|
|
|
|
tsize_t t2p_write_pdf_obj_start(uint32_t number, TIFF *output)
|
|
{
|
|
|
|
tsize_t written = 0;
|
|
char buffer[32];
|
|
int buflen = 0;
|
|
|
|
buflen = snprintf(buffer, sizeof(buffer), "%" PRIu32, number);
|
|
check_snprintf_ret((T2P *)NULL, buflen, buffer);
|
|
written += t2pWriteFile(output, (tdata_t)buffer, buflen);
|
|
written += t2pWriteFile(output, (tdata_t) " 0 obj\n", 7);
|
|
|
|
return (written);
|
|
}
|
|
|
|
/*
|
|
This function writes the end of a PDF object to output.
|
|
*/
|
|
|
|
tsize_t t2p_write_pdf_obj_end(TIFF *output)
|
|
{
|
|
|
|
tsize_t written = 0;
|
|
|
|
written += t2pWriteFile(output, (tdata_t) "endobj\n", 7);
|
|
|
|
return (written);
|
|
}
|
|
|
|
/*
|
|
This function writes a PDF name object to output.
|
|
*/
|
|
|
|
tsize_t t2p_write_pdf_name(const unsigned char *name, TIFF *output)
|
|
{
|
|
|
|
tsize_t written = 0;
|
|
uint32_t i = 0;
|
|
char buffer[64];
|
|
uint16_t nextchar = 0;
|
|
size_t namelen = 0;
|
|
|
|
namelen = strlen((char *)name);
|
|
if (namelen > 126)
|
|
{
|
|
namelen = 126;
|
|
}
|
|
written += t2pWriteFile(output, (tdata_t) "/", 1);
|
|
for (i = 0; i < namelen; i++)
|
|
{
|
|
if (((unsigned char)name[i]) < 0x21)
|
|
{
|
|
snprintf(buffer, sizeof(buffer), "#%.2X", name[i]);
|
|
buffer[sizeof(buffer) - 1] = '\0';
|
|
written += t2pWriteFile(output, (tdata_t)buffer, 3);
|
|
nextchar = 1;
|
|
}
|
|
if (((unsigned char)name[i]) > 0x7E)
|
|
{
|
|
snprintf(buffer, sizeof(buffer), "#%.2X", name[i]);
|
|
buffer[sizeof(buffer) - 1] = '\0';
|
|
written += t2pWriteFile(output, (tdata_t)buffer, 3);
|
|
nextchar = 1;
|
|
}
|
|
if (nextchar == 0)
|
|
{
|
|
switch (name[i])
|
|
{
|
|
case 0x23:
|
|
snprintf(buffer, sizeof(buffer), "#%.2X", name[i]);
|
|
buffer[sizeof(buffer) - 1] = '\0';
|
|
written += t2pWriteFile(output, (tdata_t)buffer, 3);
|
|
break;
|
|
case 0x25:
|
|
snprintf(buffer, sizeof(buffer), "#%.2X", name[i]);
|
|
buffer[sizeof(buffer) - 1] = '\0';
|
|
written += t2pWriteFile(output, (tdata_t)buffer, 3);
|
|
break;
|
|
case 0x28:
|
|
snprintf(buffer, sizeof(buffer), "#%.2X", name[i]);
|
|
buffer[sizeof(buffer) - 1] = '\0';
|
|
written += t2pWriteFile(output, (tdata_t)buffer, 3);
|
|
break;
|
|
case 0x29:
|
|
snprintf(buffer, sizeof(buffer), "#%.2X", name[i]);
|
|
buffer[sizeof(buffer) - 1] = '\0';
|
|
written += t2pWriteFile(output, (tdata_t)buffer, 3);
|
|
break;
|
|
case 0x2F:
|
|
snprintf(buffer, sizeof(buffer), "#%.2X", name[i]);
|
|
buffer[sizeof(buffer) - 1] = '\0';
|
|
written += t2pWriteFile(output, (tdata_t)buffer, 3);
|
|
break;
|
|
case 0x3C:
|
|
snprintf(buffer, sizeof(buffer), "#%.2X", name[i]);
|
|
buffer[sizeof(buffer) - 1] = '\0';
|
|
written += t2pWriteFile(output, (tdata_t)buffer, 3);
|
|
break;
|
|
case 0x3E:
|
|
snprintf(buffer, sizeof(buffer), "#%.2X", name[i]);
|
|
buffer[sizeof(buffer) - 1] = '\0';
|
|
written += t2pWriteFile(output, (tdata_t)buffer, 3);
|
|
break;
|
|
case 0x5B:
|
|
snprintf(buffer, sizeof(buffer), "#%.2X", name[i]);
|
|
buffer[sizeof(buffer) - 1] = '\0';
|
|
written += t2pWriteFile(output, (tdata_t)buffer, 3);
|
|
break;
|
|
case 0x5D:
|
|
snprintf(buffer, sizeof(buffer), "#%.2X", name[i]);
|
|
buffer[sizeof(buffer) - 1] = '\0';
|
|
written += t2pWriteFile(output, (tdata_t)buffer, 3);
|
|
break;
|
|
case 0x7B:
|
|
snprintf(buffer, sizeof(buffer), "#%.2X", name[i]);
|
|
buffer[sizeof(buffer) - 1] = '\0';
|
|
written += t2pWriteFile(output, (tdata_t)buffer, 3);
|
|
break;
|
|
case 0x7D:
|
|
snprintf(buffer, sizeof(buffer), "#%.2X", name[i]);
|
|
buffer[sizeof(buffer) - 1] = '\0';
|
|
written += t2pWriteFile(output, (tdata_t)buffer, 3);
|
|
break;
|
|
default:
|
|
written += t2pWriteFile(output, (tdata_t)&name[i], 1);
|
|
}
|
|
}
|
|
nextchar = 0;
|
|
}
|
|
written += t2pWriteFile(output, (tdata_t) " ", 1);
|
|
|
|
return (written);
|
|
}
|
|
|
|
/*
|
|
* This function writes a PDF string object to output.
|
|
*/
|
|
|
|
tsize_t t2p_write_pdf_string(const char *pdfstr, TIFF *output)
|
|
{
|
|
tsize_t written = 0;
|
|
uint32_t i = 0;
|
|
char buffer[64];
|
|
size_t len = 0;
|
|
|
|
len = strlen(pdfstr);
|
|
written += t2pWriteFile(output, (tdata_t) "(", 1);
|
|
for (i = 0; i < len; i++)
|
|
{
|
|
if ((pdfstr[i] & 0x80) || (pdfstr[i] == 127) || (pdfstr[i] < 32))
|
|
{
|
|
snprintf(buffer, sizeof(buffer), "\\%.3o",
|
|
((unsigned char)pdfstr[i]));
|
|
written += t2pWriteFile(output, (tdata_t)buffer, 4);
|
|
}
|
|
else
|
|
{
|
|
switch (pdfstr[i])
|
|
{
|
|
case 0x08:
|
|
written += t2pWriteFile(output, (tdata_t) "\\b", 2);
|
|
break;
|
|
case 0x09:
|
|
written += t2pWriteFile(output, (tdata_t) "\\t", 2);
|
|
break;
|
|
case 0x0A:
|
|
written += t2pWriteFile(output, (tdata_t) "\\n", 2);
|
|
break;
|
|
case 0x0C:
|
|
written += t2pWriteFile(output, (tdata_t) "\\f", 2);
|
|
break;
|
|
case 0x0D:
|
|
written += t2pWriteFile(output, (tdata_t) "\\r", 2);
|
|
break;
|
|
case 0x28:
|
|
written += t2pWriteFile(output, (tdata_t) "\\(", 2);
|
|
break;
|
|
case 0x29:
|
|
written += t2pWriteFile(output, (tdata_t) "\\)", 2);
|
|
break;
|
|
case 0x5C:
|
|
written += t2pWriteFile(output, (tdata_t) "\\\\", 2);
|
|
break;
|
|
default:
|
|
written += t2pWriteFile(output, (tdata_t)&pdfstr[i], 1);
|
|
}
|
|
}
|
|
}
|
|
written += t2pWriteFile(output, (tdata_t) ") ", 1);
|
|
|
|
return (written);
|
|
}
|
|
|
|
/*
|
|
This function writes a buffer of data to output.
|
|
*/
|
|
|
|
tsize_t t2p_write_pdf_stream(tdata_t buffer, tsize_t len, TIFF *output)
|
|
{
|
|
|
|
tsize_t written = 0;
|
|
|
|
written += t2pWriteFile(output, (tdata_t)buffer, len);
|
|
|
|
return (written);
|
|
}
|
|
|
|
/*
|
|
This functions writes the beginning of a PDF stream to output.
|
|
*/
|
|
|
|
tsize_t t2p_write_pdf_stream_start(TIFF *output)
|
|
{
|
|
|
|
tsize_t written = 0;
|
|
|
|
written += t2pWriteFile(output, (tdata_t) "stream\n", 7);
|
|
|
|
return (written);
|
|
}
|
|
|
|
/*
|
|
This function writes the end of a PDF stream to output.
|
|
*/
|
|
|
|
tsize_t t2p_write_pdf_stream_end(TIFF *output)
|
|
{
|
|
|
|
tsize_t written = 0;
|
|
|
|
written += t2pWriteFile(output, (tdata_t) "\nendstream\n", 11);
|
|
|
|
return (written);
|
|
}
|
|
|
|
/*
|
|
This function writes a stream dictionary for a PDF stream to output.
|
|
*/
|
|
|
|
tsize_t t2p_write_pdf_stream_dict(tsize_t len, uint32_t number, TIFF *output)
|
|
{
|
|
|
|
tsize_t written = 0;
|
|
char buffer[32];
|
|
int buflen = 0;
|
|
|
|
written += t2pWriteFile(output, (tdata_t) "/Length ", 8);
|
|
if (len != 0)
|
|
{
|
|
written += t2p_write_pdf_stream_length(len, output);
|
|
}
|
|
else
|
|
{
|
|
buflen = snprintf(buffer, sizeof(buffer), "%" PRIu32, number);
|
|
check_snprintf_ret((T2P *)NULL, buflen, buffer);
|
|
written += t2pWriteFile(output, (tdata_t)buffer, buflen);
|
|
written += t2pWriteFile(output, (tdata_t) " 0 R \n", 6);
|
|
}
|
|
|
|
return (written);
|
|
}
|
|
|
|
/*
|
|
This functions writes the beginning of a PDF stream dictionary to
|
|
output.
|
|
*/
|
|
|
|
tsize_t t2p_write_pdf_stream_dict_start(TIFF *output)
|
|
{
|
|
|
|
tsize_t written = 0;
|
|
|
|
written += t2pWriteFile(output, (tdata_t) "<< \n", 4);
|
|
|
|
return (written);
|
|
}
|
|
|
|
/*
|
|
This function writes the end of a PDF stream dictionary to output.
|
|
*/
|
|
|
|
tsize_t t2p_write_pdf_stream_dict_end(TIFF *output)
|
|
{
|
|
|
|
tsize_t written = 0;
|
|
|
|
written += t2pWriteFile(output, (tdata_t) " >>\n", 4);
|
|
|
|
return (written);
|
|
}
|
|
|
|
/*
|
|
This function writes a number to output.
|
|
*/
|
|
|
|
tsize_t t2p_write_pdf_stream_length(tsize_t len, TIFF *output)
|
|
{
|
|
|
|
tsize_t written = 0;
|
|
char buffer[32];
|
|
int buflen = 0;
|
|
|
|
buflen = snprintf(buffer, sizeof(buffer), "%" TIFF_SSIZE_FORMAT, len);
|
|
check_snprintf_ret((T2P *)NULL, buflen, buffer);
|
|
written += t2pWriteFile(output, (tdata_t)buffer, buflen);
|
|
written += t2pWriteFile(output, (tdata_t) "\n", 1);
|
|
|
|
return (written);
|
|
}
|
|
|
|
/*
|
|
* This function writes the PDF Catalog structure to output.
|
|
*/
|
|
|
|
tsize_t t2p_write_pdf_catalog(T2P *t2p, TIFF *output)
|
|
{
|
|
tsize_t written = 0;
|
|
char buffer[32];
|
|
int buflen = 0;
|
|
|
|
written +=
|
|
t2pWriteFile(output, (tdata_t) "<< \n/Type /Catalog \n/Pages ", 27);
|
|
buflen = snprintf(buffer, sizeof(buffer), "%" PRIu32, t2p->pdf_pages);
|
|
check_snprintf_ret(t2p, buflen, buffer);
|
|
written += t2pWriteFile(output, (tdata_t)buffer,
|
|
TIFFmin((size_t)buflen, sizeof(buffer) - 1));
|
|
written += t2pWriteFile(output, (tdata_t) " 0 R \n", 6);
|
|
if (t2p->pdf_fitwindow)
|
|
{
|
|
written += t2pWriteFile(
|
|
output, (tdata_t) "/ViewerPreferences <</FitWindow true>>\n", 39);
|
|
}
|
|
written += t2pWriteFile(output, (tdata_t) ">>\n", 3);
|
|
|
|
return (written);
|
|
}
|
|
|
|
/*
|
|
This function writes the PDF Info structure to output.
|
|
*/
|
|
|
|
tsize_t t2p_write_pdf_info(T2P *t2p, TIFF *input, TIFF *output)
|
|
{
|
|
tsize_t written = 0;
|
|
const char *info;
|
|
char buffer[512];
|
|
|
|
if (t2p->pdf_datetime[0] == '\0')
|
|
t2p_pdf_tifftime(t2p, input);
|
|
if (strlen(t2p->pdf_datetime) > 0)
|
|
{
|
|
written += t2pWriteFile(output, (tdata_t) "<< \n/CreationDate ", 18);
|
|
written += t2p_write_pdf_string(t2p->pdf_datetime, output);
|
|
written += t2pWriteFile(output, (tdata_t) "\n/ModDate ", 10);
|
|
written += t2p_write_pdf_string(t2p->pdf_datetime, output);
|
|
}
|
|
written += t2pWriteFile(output, (tdata_t) "\n/Producer ", 11);
|
|
snprintf(buffer, sizeof(buffer), "libtiff / tiff2pdf - %d",
|
|
TIFFLIB_VERSION);
|
|
written += t2p_write_pdf_string(buffer, output);
|
|
written += t2pWriteFile(output, (tdata_t) "\n", 1);
|
|
if (!t2p->pdf_creator_set)
|
|
{
|
|
if (TIFFGetField(input, TIFFTAG_SOFTWARE, &info) != 0 && info)
|
|
{
|
|
strncpy(t2p->pdf_creator, info, sizeof(t2p->pdf_creator) - 1);
|
|
t2p->pdf_creator[sizeof(t2p->pdf_creator) - 1] = '\0';
|
|
}
|
|
}
|
|
if (t2p->pdf_creator[0] != '\0')
|
|
{
|
|
written += t2pWriteFile(output, (tdata_t) "/Creator ", 9);
|
|
written += t2p_write_pdf_string(t2p->pdf_creator, output);
|
|
written += t2pWriteFile(output, (tdata_t) "\n", 1);
|
|
}
|
|
if (!t2p->pdf_author_set)
|
|
{
|
|
if ((TIFFGetField(input, TIFFTAG_ARTIST, &info) != 0 ||
|
|
TIFFGetField(input, TIFFTAG_COPYRIGHT, &info) != 0) &&
|
|
info)
|
|
{
|
|
strncpy(t2p->pdf_author, info, sizeof(t2p->pdf_author) - 1);
|
|
t2p->pdf_author[sizeof(t2p->pdf_author) - 1] = '\0';
|
|
}
|
|
}
|
|
if (t2p->pdf_author[0] != '\0')
|
|
{
|
|
written += t2pWriteFile(output, (tdata_t) "/Author ", 8);
|
|
written += t2p_write_pdf_string(t2p->pdf_author, output);
|
|
written += t2pWriteFile(output, (tdata_t) "\n", 1);
|
|
}
|
|
if (!t2p->pdf_title_set)
|
|
{
|
|
if (TIFFGetField(input, TIFFTAG_DOCUMENTNAME, &info) != 0 && info)
|
|
{
|
|
strncpy(t2p->pdf_title, info, sizeof(t2p->pdf_title) - 1);
|
|
t2p->pdf_title[sizeof(t2p->pdf_title) - 1] = '\0';
|
|
}
|
|
}
|
|
if (t2p->pdf_title[0] != '\0')
|
|
{
|
|
written += t2pWriteFile(output, (tdata_t) "/Title ", 7);
|
|
written += t2p_write_pdf_string(t2p->pdf_title, output);
|
|
written += t2pWriteFile(output, (tdata_t) "\n", 1);
|
|
}
|
|
if (!t2p->pdf_subject_set)
|
|
{
|
|
if (TIFFGetField(input, TIFFTAG_IMAGEDESCRIPTION, &info) != 0 && info)
|
|
{
|
|
strncpy(t2p->pdf_subject, info, sizeof(t2p->pdf_subject) - 1);
|
|
t2p->pdf_subject[sizeof(t2p->pdf_subject) - 1] = '\0';
|
|
}
|
|
}
|
|
if (t2p->pdf_subject[0] != '\0')
|
|
{
|
|
written += t2pWriteFile(output, (tdata_t) "/Subject ", 9);
|
|
written += t2p_write_pdf_string(t2p->pdf_subject, output);
|
|
written += t2pWriteFile(output, (tdata_t) "\n", 1);
|
|
}
|
|
if (t2p->pdf_keywords[0] != '\0')
|
|
{
|
|
written += t2pWriteFile(output, (tdata_t) "/Keywords ", 10);
|
|
written += t2p_write_pdf_string(t2p->pdf_keywords, output);
|
|
written += t2pWriteFile(output, (tdata_t) "\n", 1);
|
|
}
|
|
written += t2pWriteFile(output, (tdata_t) ">> \n", 4);
|
|
|
|
return (written);
|
|
}
|
|
|
|
/*
|
|
* This function fills a string of a T2P struct with the current time as a PDF
|
|
* date string, it is called by t2p_pdf_tifftime.
|
|
*/
|
|
|
|
void t2p_pdf_currenttime(T2P *t2p)
|
|
{
|
|
struct tm *currenttime;
|
|
time_t timenow;
|
|
|
|
if (time(&timenow) == (time_t)-1)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE, "Can't get the current time: %s",
|
|
strerror(errno));
|
|
timenow = (time_t)0;
|
|
}
|
|
|
|
currenttime = localtime(&timenow);
|
|
snprintf(t2p->pdf_datetime, sizeof(t2p->pdf_datetime),
|
|
"D:%.4u%.2u%.2u%.2u%.2u%.2u",
|
|
TIFFmin((unsigned)currenttime->tm_year + 1900U, 9999U),
|
|
TIFFmin((unsigned)currenttime->tm_mon + 1U, 12U), /* 0-11 + 1 */
|
|
TIFFmin((unsigned)currenttime->tm_mday, 31U), /* 1-31 */
|
|
TIFFmin((unsigned)currenttime->tm_hour, 23U), /* 0-23 */
|
|
TIFFmin((unsigned)currenttime->tm_min, 59U), /* 0-59 */
|
|
TIFFmin((unsigned)(currenttime->tm_sec), 60U)); /* 0-60 */
|
|
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* This function fills a string of a T2P struct with the date and time of a
|
|
* TIFF file if it exists or the current time as a PDF date string.
|
|
*/
|
|
|
|
void t2p_pdf_tifftime(T2P *t2p, TIFF *input)
|
|
{
|
|
char *datetime;
|
|
|
|
if (TIFFGetField(input, TIFFTAG_DATETIME, &datetime) != 0 &&
|
|
(strlen(datetime) >= 19))
|
|
{
|
|
t2p->pdf_datetime[0] = 'D';
|
|
t2p->pdf_datetime[1] = ':';
|
|
t2p->pdf_datetime[2] = datetime[0];
|
|
t2p->pdf_datetime[3] = datetime[1];
|
|
t2p->pdf_datetime[4] = datetime[2];
|
|
t2p->pdf_datetime[5] = datetime[3];
|
|
t2p->pdf_datetime[6] = datetime[5];
|
|
t2p->pdf_datetime[7] = datetime[6];
|
|
t2p->pdf_datetime[8] = datetime[8];
|
|
t2p->pdf_datetime[9] = datetime[9];
|
|
t2p->pdf_datetime[10] = datetime[11];
|
|
t2p->pdf_datetime[11] = datetime[12];
|
|
t2p->pdf_datetime[12] = datetime[14];
|
|
t2p->pdf_datetime[13] = datetime[15];
|
|
t2p->pdf_datetime[14] = datetime[17];
|
|
t2p->pdf_datetime[15] = datetime[18];
|
|
t2p->pdf_datetime[16] = '\0';
|
|
}
|
|
else
|
|
{
|
|
t2p_pdf_currenttime(t2p);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* This function writes a PDF Pages Tree structure to output.
|
|
*/
|
|
|
|
tsize_t t2p_write_pdf_pages(T2P *t2p, TIFF *output)
|
|
{
|
|
tsize_t written = 0;
|
|
tdir_t i = 0;
|
|
char buffer[32];
|
|
int buflen = 0;
|
|
|
|
int page = 0;
|
|
written +=
|
|
t2pWriteFile(output, (tdata_t) "<< \n/Type /Pages \n/Kids [ ", 26);
|
|
page = t2p->pdf_pages + 1;
|
|
for (i = 0; i < t2p->tiff_pagecount; i++)
|
|
{
|
|
buflen = snprintf(buffer, sizeof(buffer), "%d", page);
|
|
check_snprintf_ret(t2p, buflen, buffer);
|
|
written += t2pWriteFile(output, (tdata_t)buffer, buflen);
|
|
written += t2pWriteFile(output, (tdata_t) " 0 R ", 5);
|
|
if (((i + 1) % 8) == 0)
|
|
{
|
|
written += t2pWriteFile(output, (tdata_t) "\n", 1);
|
|
}
|
|
page += 3;
|
|
page += t2p->tiff_pages[i].page_extra;
|
|
if (t2p->tiff_pages[i].page_tilecount > 0)
|
|
{
|
|
page += (2 * t2p->tiff_pages[i].page_tilecount);
|
|
}
|
|
else
|
|
{
|
|
page += 2;
|
|
}
|
|
}
|
|
written += t2pWriteFile(output, (tdata_t) "] \n/Count ", 10);
|
|
buflen = snprintf(buffer, sizeof(buffer), "%" PRIu16, t2p->tiff_pagecount);
|
|
check_snprintf_ret(t2p, buflen, buffer);
|
|
written += t2pWriteFile(output, (tdata_t)buffer, buflen);
|
|
written += t2pWriteFile(output, (tdata_t) " \n>> \n", 6);
|
|
|
|
return (written);
|
|
}
|
|
|
|
/*
|
|
This function writes a PDF Page structure to output.
|
|
*/
|
|
|
|
tsize_t t2p_write_pdf_page(uint32_t object, T2P *t2p, TIFF *output)
|
|
{
|
|
|
|
unsigned int i = 0;
|
|
tsize_t written = 0;
|
|
char buffer[256];
|
|
int buflen = 0;
|
|
|
|
written += t2pWriteFile(output, (tdata_t) "<<\n/Type /Page \n/Parent ", 24);
|
|
buflen = snprintf(buffer, sizeof(buffer), "%" PRIu32, t2p->pdf_pages);
|
|
check_snprintf_ret(t2p, buflen, buffer);
|
|
written += t2pWriteFile(output, (tdata_t)buffer, buflen);
|
|
written += t2pWriteFile(output, (tdata_t) " 0 R \n", 6);
|
|
written += t2pWriteFile(output, (tdata_t) "/MediaBox [", 11);
|
|
buflen = snprintf(buffer, sizeof(buffer), "%.4f", t2p->pdf_mediabox.x1);
|
|
check_snprintf_ret(t2p, buflen, buffer);
|
|
written += t2pWriteFile(output, (tdata_t)buffer, buflen);
|
|
written += t2pWriteFile(output, (tdata_t) " ", 1);
|
|
buflen = snprintf(buffer, sizeof(buffer), "%.4f", t2p->pdf_mediabox.y1);
|
|
check_snprintf_ret(t2p, buflen, buffer);
|
|
written += t2pWriteFile(output, (tdata_t)buffer, buflen);
|
|
written += t2pWriteFile(output, (tdata_t) " ", 1);
|
|
buflen = snprintf(buffer, sizeof(buffer), "%.4f", t2p->pdf_mediabox.x2);
|
|
check_snprintf_ret(t2p, buflen, buffer);
|
|
written += t2pWriteFile(output, (tdata_t)buffer, buflen);
|
|
written += t2pWriteFile(output, (tdata_t) " ", 1);
|
|
buflen = snprintf(buffer, sizeof(buffer), "%.4f", t2p->pdf_mediabox.y2);
|
|
check_snprintf_ret(t2p, buflen, buffer);
|
|
written += t2pWriteFile(output, (tdata_t)buffer, buflen);
|
|
written += t2pWriteFile(output, (tdata_t) "] \n", 3);
|
|
written += t2pWriteFile(output, (tdata_t) "/Contents ", 10);
|
|
buflen = snprintf(buffer, sizeof(buffer), "%" PRIu32, object + 1u);
|
|
check_snprintf_ret(t2p, buflen, buffer);
|
|
written += t2pWriteFile(output, (tdata_t)buffer, buflen);
|
|
written += t2pWriteFile(output, (tdata_t) " 0 R \n", 6);
|
|
written += t2pWriteFile(output, (tdata_t) "/Resources << \n", 15);
|
|
if (t2p->tiff_tiles[t2p->pdf_page].tiles_tilecount != 0)
|
|
{
|
|
written += t2pWriteFile(output, (tdata_t) "/XObject <<\n", 12);
|
|
for (i = 0; i < t2p->tiff_tiles[t2p->pdf_page].tiles_tilecount; i++)
|
|
{
|
|
written += t2pWriteFile(output, (tdata_t) "/Im", 3);
|
|
buflen = snprintf(buffer, sizeof(buffer), "%" PRIu16,
|
|
(uint16_t)(t2p->pdf_page + 1u));
|
|
check_snprintf_ret(t2p, buflen, buffer);
|
|
written += t2pWriteFile(output, (tdata_t)buffer, buflen);
|
|
written += t2pWriteFile(output, (tdata_t) "_", 1);
|
|
buflen = snprintf(buffer, sizeof(buffer), "%u", i + 1u);
|
|
check_snprintf_ret(t2p, buflen, buffer);
|
|
written += t2pWriteFile(output, (tdata_t)buffer, buflen);
|
|
written += t2pWriteFile(output, (tdata_t) " ", 1);
|
|
buflen = snprintf(buffer, sizeof(buffer), "%" PRIu32,
|
|
object + 3u + (2u * i) +
|
|
t2p->tiff_pages[t2p->pdf_page].page_extra);
|
|
check_snprintf_ret(t2p, buflen, buffer);
|
|
written += t2pWriteFile(output, (tdata_t)buffer, buflen);
|
|
written += t2pWriteFile(output, (tdata_t) " 0 R ", 5);
|
|
if (i % 4 == 3)
|
|
{
|
|
written += t2pWriteFile(output, (tdata_t) "\n", 1);
|
|
}
|
|
}
|
|
written += t2pWriteFile(output, (tdata_t) ">>\n", 3);
|
|
}
|
|
else
|
|
{
|
|
written += t2pWriteFile(output, (tdata_t) "/XObject <<\n", 12);
|
|
written += t2pWriteFile(output, (tdata_t) "/Im", 3);
|
|
buflen = snprintf(buffer, sizeof(buffer), "%" PRIu16,
|
|
(uint16_t)(t2p->pdf_page + 1u));
|
|
check_snprintf_ret(t2p, buflen, buffer);
|
|
written += t2pWriteFile(output, (tdata_t)buffer, buflen);
|
|
written += t2pWriteFile(output, (tdata_t) " ", 1);
|
|
buflen = snprintf(buffer, sizeof(buffer), "%" PRIu32,
|
|
object + 3u + (2u * i) +
|
|
t2p->tiff_pages[t2p->pdf_page].page_extra);
|
|
check_snprintf_ret(t2p, buflen, buffer);
|
|
written += t2pWriteFile(output, (tdata_t)buffer, buflen);
|
|
written += t2pWriteFile(output, (tdata_t) " 0 R ", 5);
|
|
written += t2pWriteFile(output, (tdata_t) ">>\n", 3);
|
|
}
|
|
if (t2p->tiff_transferfunctioncount != 0)
|
|
{
|
|
written += t2pWriteFile(output, (tdata_t) "/ExtGState <<", 13);
|
|
t2pWriteFile(output, (tdata_t) "/GS1 ", 5);
|
|
buflen = snprintf(buffer, sizeof(buffer), "%" PRIu32, object + 3u);
|
|
check_snprintf_ret(t2p, buflen, buffer);
|
|
written += t2pWriteFile(output, (tdata_t)buffer, buflen);
|
|
written += t2pWriteFile(output, (tdata_t) " 0 R ", 5);
|
|
written += t2pWriteFile(output, (tdata_t) ">> \n", 4);
|
|
}
|
|
written += t2pWriteFile(output, (tdata_t) "/ProcSet [ ", 11);
|
|
if (t2p->pdf_colorspace & T2P_CS_BILEVEL ||
|
|
t2p->pdf_colorspace & T2P_CS_GRAY)
|
|
{
|
|
written += t2pWriteFile(output, (tdata_t) "/ImageB ", 8);
|
|
}
|
|
else
|
|
{
|
|
written += t2pWriteFile(output, (tdata_t) "/ImageC ", 8);
|
|
if (t2p->pdf_colorspace & T2P_CS_PALETTE)
|
|
{
|
|
written += t2pWriteFile(output, (tdata_t) "/ImageI ", 8);
|
|
}
|
|
}
|
|
written += t2pWriteFile(output, (tdata_t) "]\n>>\n>>\n", 8);
|
|
|
|
return (written);
|
|
}
|
|
|
|
/*
|
|
This function composes the page size and image and tile locations on a
|
|
page.
|
|
*/
|
|
|
|
void t2p_compose_pdf_page(T2P *t2p)
|
|
{
|
|
|
|
uint32_t i = 0;
|
|
uint32_t i2 = 0;
|
|
T2P_TILE *tiles = NULL;
|
|
T2P_BOX *boxp = NULL;
|
|
uint32_t tilecountx = 0;
|
|
uint32_t tilecounty = 0;
|
|
uint32_t tilewidth = 0;
|
|
uint32_t tilelength = 0;
|
|
int istiled = 0;
|
|
float f = 0;
|
|
float width_ratio = 0;
|
|
float length_ratio = 0;
|
|
|
|
t2p->pdf_xres = t2p->tiff_xres;
|
|
t2p->pdf_yres = t2p->tiff_yres;
|
|
if (t2p->pdf_overrideres)
|
|
{
|
|
t2p->pdf_xres = t2p->pdf_defaultxres;
|
|
t2p->pdf_yres = t2p->pdf_defaultyres;
|
|
}
|
|
if (t2p->pdf_xres == 0.0)
|
|
t2p->pdf_xres = t2p->pdf_defaultxres;
|
|
if (t2p->pdf_yres == 0.0)
|
|
t2p->pdf_yres = t2p->pdf_defaultyres;
|
|
if (t2p->pdf_image_fillpage)
|
|
{
|
|
width_ratio = t2p->pdf_defaultpagewidth / t2p->tiff_width;
|
|
length_ratio = t2p->pdf_defaultpagelength / t2p->tiff_length;
|
|
if (width_ratio < length_ratio)
|
|
{
|
|
t2p->pdf_imagewidth = t2p->pdf_defaultpagewidth;
|
|
t2p->pdf_imagelength = t2p->tiff_length * width_ratio;
|
|
}
|
|
else
|
|
{
|
|
t2p->pdf_imagewidth = t2p->tiff_width * length_ratio;
|
|
t2p->pdf_imagelength = t2p->pdf_defaultpagelength;
|
|
}
|
|
}
|
|
else if (t2p->tiff_resunit != RESUNIT_CENTIMETER /* RESUNIT_NONE and */
|
|
&& t2p->tiff_resunit != RESUNIT_INCH)
|
|
{ /* other cases */
|
|
t2p->pdf_imagewidth = ((float)(t2p->tiff_width)) / t2p->pdf_xres;
|
|
t2p->pdf_imagelength = ((float)(t2p->tiff_length)) / t2p->pdf_yres;
|
|
}
|
|
else
|
|
{
|
|
t2p->pdf_imagewidth =
|
|
((float)(t2p->tiff_width)) * PS_UNIT_SIZE / t2p->pdf_xres;
|
|
t2p->pdf_imagelength =
|
|
((float)(t2p->tiff_length)) * PS_UNIT_SIZE / t2p->pdf_yres;
|
|
}
|
|
if (t2p->pdf_overridepagesize != 0)
|
|
{
|
|
t2p->pdf_pagewidth = t2p->pdf_defaultpagewidth;
|
|
t2p->pdf_pagelength = t2p->pdf_defaultpagelength;
|
|
}
|
|
else
|
|
{
|
|
t2p->pdf_pagewidth = t2p->pdf_imagewidth;
|
|
t2p->pdf_pagelength = t2p->pdf_imagelength;
|
|
}
|
|
t2p->pdf_mediabox.x1 = 0.0;
|
|
t2p->pdf_mediabox.y1 = 0.0;
|
|
t2p->pdf_mediabox.x2 = t2p->pdf_pagewidth;
|
|
t2p->pdf_mediabox.y2 = t2p->pdf_pagelength;
|
|
t2p->pdf_imagebox.x1 = 0.0;
|
|
t2p->pdf_imagebox.y1 = 0.0;
|
|
t2p->pdf_imagebox.x2 = t2p->pdf_imagewidth;
|
|
t2p->pdf_imagebox.y2 = t2p->pdf_imagelength;
|
|
if (t2p->pdf_overridepagesize != 0)
|
|
{
|
|
t2p->pdf_imagebox.x1 +=
|
|
((t2p->pdf_pagewidth - t2p->pdf_imagewidth) / 2.0F);
|
|
t2p->pdf_imagebox.y1 +=
|
|
((t2p->pdf_pagelength - t2p->pdf_imagelength) / 2.0F);
|
|
t2p->pdf_imagebox.x2 +=
|
|
((t2p->pdf_pagewidth - t2p->pdf_imagewidth) / 2.0F);
|
|
t2p->pdf_imagebox.y2 +=
|
|
((t2p->pdf_pagelength - t2p->pdf_imagelength) / 2.0F);
|
|
}
|
|
if (t2p->tiff_orientation > 4)
|
|
{
|
|
f = t2p->pdf_mediabox.x2;
|
|
t2p->pdf_mediabox.x2 = t2p->pdf_mediabox.y2;
|
|
t2p->pdf_mediabox.y2 = f;
|
|
}
|
|
istiled = ((t2p->tiff_tiles[t2p->pdf_page]).tiles_tilecount == 0) ? 0 : 1;
|
|
if (istiled == 0)
|
|
{
|
|
t2p_compose_pdf_page_orient(&(t2p->pdf_imagebox),
|
|
t2p->tiff_orientation);
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
tilewidth = (t2p->tiff_tiles[t2p->pdf_page]).tiles_tilewidth;
|
|
tilelength = (t2p->tiff_tiles[t2p->pdf_page]).tiles_tilelength;
|
|
if (tilewidth > INT_MAX || tilelength > INT_MAX ||
|
|
t2p->tiff_width > INT_MAX - tilewidth ||
|
|
t2p->tiff_length > INT_MAX - tilelength)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE, "Integer overflow");
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return;
|
|
}
|
|
tilecountx = (t2p->tiff_width + tilewidth - 1) / tilewidth;
|
|
(t2p->tiff_tiles[t2p->pdf_page]).tiles_tilecountx = tilecountx;
|
|
tilecounty = (t2p->tiff_length + tilelength - 1) / tilelength;
|
|
(t2p->tiff_tiles[t2p->pdf_page]).tiles_tilecounty = tilecounty;
|
|
(t2p->tiff_tiles[t2p->pdf_page]).tiles_edgetilewidth =
|
|
t2p->tiff_width % tilewidth;
|
|
(t2p->tiff_tiles[t2p->pdf_page]).tiles_edgetilelength =
|
|
t2p->tiff_length % tilelength;
|
|
tiles = (t2p->tiff_tiles[t2p->pdf_page]).tiles_tiles;
|
|
for (i2 = 0; i2 < tilecounty - 1; i2++)
|
|
{
|
|
for (i = 0; i < tilecountx - 1; i++)
|
|
{
|
|
boxp = &(tiles[i2 * tilecountx + i].tile_box);
|
|
boxp->x1 = t2p->pdf_imagebox.x1 +
|
|
((float)(t2p->pdf_imagewidth * i * tilewidth) /
|
|
(float)t2p->tiff_width);
|
|
boxp->x2 = t2p->pdf_imagebox.x1 +
|
|
((float)(t2p->pdf_imagewidth * (i + 1) * tilewidth) /
|
|
(float)t2p->tiff_width);
|
|
boxp->y1 =
|
|
t2p->pdf_imagebox.y2 -
|
|
((float)(t2p->pdf_imagelength * (i2 + 1) * tilelength) /
|
|
(float)t2p->tiff_length);
|
|
boxp->y2 = t2p->pdf_imagebox.y2 -
|
|
((float)(t2p->pdf_imagelength * i2 * tilelength) /
|
|
(float)t2p->tiff_length);
|
|
}
|
|
boxp = &(tiles[i2 * tilecountx + i].tile_box);
|
|
boxp->x1 = t2p->pdf_imagebox.x1 +
|
|
((float)(t2p->pdf_imagewidth * i * tilewidth) /
|
|
(float)t2p->tiff_width);
|
|
boxp->x2 = t2p->pdf_imagebox.x2;
|
|
boxp->y1 = t2p->pdf_imagebox.y2 -
|
|
((float)(t2p->pdf_imagelength * (i2 + 1) * tilelength) /
|
|
(float)t2p->tiff_length);
|
|
boxp->y2 = t2p->pdf_imagebox.y2 -
|
|
((float)(t2p->pdf_imagelength * i2 * tilelength) /
|
|
(float)t2p->tiff_length);
|
|
}
|
|
for (i = 0; i < tilecountx - 1; i++)
|
|
{
|
|
boxp = &(tiles[i2 * tilecountx + i].tile_box);
|
|
boxp->x1 = t2p->pdf_imagebox.x1 +
|
|
((float)(t2p->pdf_imagewidth * i * tilewidth) /
|
|
(float)t2p->tiff_width);
|
|
boxp->x2 = t2p->pdf_imagebox.x1 +
|
|
((float)(t2p->pdf_imagewidth * (i + 1) * tilewidth) /
|
|
(float)t2p->tiff_width);
|
|
boxp->y1 = t2p->pdf_imagebox.y1;
|
|
boxp->y2 = t2p->pdf_imagebox.y2 -
|
|
((float)(t2p->pdf_imagelength * i2 * tilelength) /
|
|
(float)t2p->tiff_length);
|
|
}
|
|
boxp = &(tiles[i2 * tilecountx + i].tile_box);
|
|
boxp->x1 = t2p->pdf_imagebox.x1 +
|
|
((float)(t2p->pdf_imagewidth * i * tilewidth) /
|
|
(float)t2p->tiff_width);
|
|
boxp->x2 = t2p->pdf_imagebox.x2;
|
|
boxp->y1 = t2p->pdf_imagebox.y1;
|
|
boxp->y2 = t2p->pdf_imagebox.y2 -
|
|
((float)(t2p->pdf_imagelength * i2 * tilelength) /
|
|
(float)t2p->tiff_length);
|
|
}
|
|
if (t2p->tiff_orientation == 0 || t2p->tiff_orientation == 1)
|
|
{
|
|
for (i = 0; i < (t2p->tiff_tiles[t2p->pdf_page]).tiles_tilecount; i++)
|
|
{
|
|
t2p_compose_pdf_page_orient(&(tiles[i].tile_box), 0);
|
|
}
|
|
return;
|
|
}
|
|
for (i = 0; i < (t2p->tiff_tiles[t2p->pdf_page]).tiles_tilecount; i++)
|
|
{
|
|
boxp = &(tiles[i].tile_box);
|
|
boxp->x1 -= t2p->pdf_imagebox.x1;
|
|
boxp->x2 -= t2p->pdf_imagebox.x1;
|
|
boxp->y1 -= t2p->pdf_imagebox.y1;
|
|
boxp->y2 -= t2p->pdf_imagebox.y1;
|
|
if (t2p->tiff_orientation == 2 || t2p->tiff_orientation == 3)
|
|
{
|
|
boxp->x1 = t2p->pdf_imagebox.x2 - t2p->pdf_imagebox.x1 - boxp->x1;
|
|
boxp->x2 = t2p->pdf_imagebox.x2 - t2p->pdf_imagebox.x1 - boxp->x2;
|
|
}
|
|
if (t2p->tiff_orientation == 3 || t2p->tiff_orientation == 4)
|
|
{
|
|
boxp->y1 = t2p->pdf_imagebox.y2 - t2p->pdf_imagebox.y1 - boxp->y1;
|
|
boxp->y2 = t2p->pdf_imagebox.y2 - t2p->pdf_imagebox.y1 - boxp->y2;
|
|
}
|
|
if (t2p->tiff_orientation == 8 || t2p->tiff_orientation == 5)
|
|
{
|
|
boxp->y1 = t2p->pdf_imagebox.y2 - t2p->pdf_imagebox.y1 - boxp->y1;
|
|
boxp->y2 = t2p->pdf_imagebox.y2 - t2p->pdf_imagebox.y1 - boxp->y2;
|
|
}
|
|
if (t2p->tiff_orientation == 5 || t2p->tiff_orientation == 6)
|
|
{
|
|
boxp->x1 = t2p->pdf_imagebox.x2 - t2p->pdf_imagebox.x1 - boxp->x1;
|
|
boxp->x2 = t2p->pdf_imagebox.x2 - t2p->pdf_imagebox.x1 - boxp->x2;
|
|
}
|
|
if (t2p->tiff_orientation > 4)
|
|
{
|
|
f = boxp->x1;
|
|
boxp->x1 = boxp->y1;
|
|
boxp->y1 = f;
|
|
f = boxp->x2;
|
|
boxp->x2 = boxp->y2;
|
|
boxp->y2 = f;
|
|
t2p_compose_pdf_page_orient_flip(boxp, t2p->tiff_orientation);
|
|
}
|
|
else
|
|
{
|
|
t2p_compose_pdf_page_orient(boxp, t2p->tiff_orientation);
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void t2p_compose_pdf_page_orient(T2P_BOX *boxp, uint16_t orientation)
|
|
{
|
|
|
|
float m1[9];
|
|
float f = 0.0;
|
|
|
|
if (boxp->x1 > boxp->x2)
|
|
{
|
|
f = boxp->x1;
|
|
boxp->x1 = boxp->x2;
|
|
boxp->x2 = f;
|
|
}
|
|
if (boxp->y1 > boxp->y2)
|
|
{
|
|
f = boxp->y1;
|
|
boxp->y1 = boxp->y2;
|
|
boxp->y2 = f;
|
|
}
|
|
boxp->mat[0] = m1[0] = boxp->x2 - boxp->x1;
|
|
boxp->mat[1] = m1[1] = 0.0;
|
|
boxp->mat[2] = m1[2] = 0.0;
|
|
boxp->mat[3] = m1[3] = 0.0;
|
|
boxp->mat[4] = m1[4] = boxp->y2 - boxp->y1;
|
|
boxp->mat[5] = m1[5] = 0.0;
|
|
boxp->mat[6] = m1[6] = boxp->x1;
|
|
boxp->mat[7] = m1[7] = boxp->y1;
|
|
boxp->mat[8] = m1[8] = 1.0;
|
|
switch (orientation)
|
|
{
|
|
case 0:
|
|
case 1:
|
|
break;
|
|
case 2:
|
|
boxp->mat[0] = 0.0F - m1[0];
|
|
boxp->mat[6] += m1[0];
|
|
break;
|
|
case 3:
|
|
boxp->mat[0] = 0.0F - m1[0];
|
|
boxp->mat[4] = 0.0F - m1[4];
|
|
boxp->mat[6] += m1[0];
|
|
boxp->mat[7] += m1[4];
|
|
break;
|
|
case 4:
|
|
boxp->mat[4] = 0.0F - m1[4];
|
|
boxp->mat[7] += m1[4];
|
|
break;
|
|
case 5:
|
|
boxp->mat[0] = 0.0F;
|
|
boxp->mat[1] = 0.0F - m1[0];
|
|
boxp->mat[3] = 0.0F - m1[4];
|
|
boxp->mat[4] = 0.0F;
|
|
boxp->mat[6] += m1[4];
|
|
boxp->mat[7] += m1[0];
|
|
break;
|
|
case 6:
|
|
boxp->mat[0] = 0.0F;
|
|
boxp->mat[1] = 0.0F - m1[0];
|
|
boxp->mat[3] = m1[4];
|
|
boxp->mat[4] = 0.0F;
|
|
boxp->mat[7] += m1[0];
|
|
break;
|
|
case 7:
|
|
boxp->mat[0] = 0.0F;
|
|
boxp->mat[1] = m1[0];
|
|
boxp->mat[3] = m1[4];
|
|
boxp->mat[4] = 0.0F;
|
|
break;
|
|
case 8:
|
|
boxp->mat[0] = 0.0F;
|
|
boxp->mat[1] = m1[0];
|
|
boxp->mat[3] = 0.0F - m1[4];
|
|
boxp->mat[4] = 0.0F;
|
|
boxp->mat[6] += m1[4];
|
|
break;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void t2p_compose_pdf_page_orient_flip(T2P_BOX *boxp, uint16_t orientation)
|
|
{
|
|
|
|
float m1[9];
|
|
float f = 0.0;
|
|
|
|
if (boxp->x1 > boxp->x2)
|
|
{
|
|
f = boxp->x1;
|
|
boxp->x1 = boxp->x2;
|
|
boxp->x2 = f;
|
|
}
|
|
if (boxp->y1 > boxp->y2)
|
|
{
|
|
f = boxp->y1;
|
|
boxp->y1 = boxp->y2;
|
|
boxp->y2 = f;
|
|
}
|
|
boxp->mat[0] = m1[0] = boxp->x2 - boxp->x1;
|
|
boxp->mat[1] = m1[1] = 0.0F;
|
|
boxp->mat[2] = m1[2] = 0.0F;
|
|
boxp->mat[3] = m1[3] = 0.0F;
|
|
boxp->mat[4] = m1[4] = boxp->y2 - boxp->y1;
|
|
boxp->mat[5] = m1[5] = 0.0F;
|
|
boxp->mat[6] = m1[6] = boxp->x1;
|
|
boxp->mat[7] = m1[7] = boxp->y1;
|
|
boxp->mat[8] = m1[8] = 1.0F;
|
|
switch (orientation)
|
|
{
|
|
case 5:
|
|
boxp->mat[0] = 0.0F;
|
|
boxp->mat[1] = 0.0F - m1[4];
|
|
boxp->mat[3] = 0.0F - m1[0];
|
|
boxp->mat[4] = 0.0F;
|
|
boxp->mat[6] += m1[0];
|
|
boxp->mat[7] += m1[4];
|
|
break;
|
|
case 6:
|
|
boxp->mat[0] = 0.0F;
|
|
boxp->mat[1] = 0.0F - m1[4];
|
|
boxp->mat[3] = m1[0];
|
|
boxp->mat[4] = 0.0F;
|
|
boxp->mat[7] += m1[4];
|
|
break;
|
|
case 7:
|
|
boxp->mat[0] = 0.0F;
|
|
boxp->mat[1] = m1[4];
|
|
boxp->mat[3] = m1[0];
|
|
boxp->mat[4] = 0.0F;
|
|
break;
|
|
case 8:
|
|
boxp->mat[0] = 0.0F;
|
|
boxp->mat[1] = m1[4];
|
|
boxp->mat[3] = 0.0F - m1[0];
|
|
boxp->mat[4] = 0.0F;
|
|
boxp->mat[6] += m1[0];
|
|
break;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/*
|
|
This function writes a PDF Contents stream to output.
|
|
*/
|
|
|
|
tsize_t t2p_write_pdf_page_content_stream(T2P *t2p, TIFF *output)
|
|
{
|
|
|
|
tsize_t written = 0;
|
|
ttile_t i = 0;
|
|
char buffer[512];
|
|
int buflen = 0;
|
|
T2P_BOX box;
|
|
|
|
if (t2p->tiff_tiles[t2p->pdf_page].tiles_tilecount > 0)
|
|
{
|
|
for (i = 0; i < t2p->tiff_tiles[t2p->pdf_page].tiles_tilecount; i++)
|
|
{
|
|
box = t2p->tiff_tiles[t2p->pdf_page].tiles_tiles[i].tile_box;
|
|
buflen = snprintf(
|
|
buffer, sizeof(buffer),
|
|
"q %s %.4f %.4f %.4f %.4f %.4f %.4f cm /Im%" PRIu16 "_%" PRIu32
|
|
" Do Q\n",
|
|
t2p->tiff_transferfunctioncount ? "/GS1 gs " : "", box.mat[0],
|
|
box.mat[1], box.mat[3], box.mat[4], box.mat[6], box.mat[7],
|
|
(uint16_t)(t2p->pdf_page + 1u), i + 1u);
|
|
check_snprintf_ret(t2p, buflen, buffer);
|
|
written += t2p_write_pdf_stream(buffer, buflen, output);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
box = t2p->pdf_imagebox;
|
|
buflen = snprintf(
|
|
buffer, sizeof(buffer),
|
|
"q %s %.4f %.4f %.4f %.4f %.4f %.4f cm /Im%" PRIu16 " Do Q\n",
|
|
t2p->tiff_transferfunctioncount ? "/GS1 gs " : "", box.mat[0],
|
|
box.mat[1], box.mat[3], box.mat[4], box.mat[6], box.mat[7],
|
|
(uint16_t)(t2p->pdf_page + 1u));
|
|
check_snprintf_ret(t2p, buflen, buffer);
|
|
written += t2p_write_pdf_stream(buffer, buflen, output);
|
|
}
|
|
|
|
return (written);
|
|
}
|
|
|
|
/*
|
|
This function writes a PDF Image XObject stream dictionary to output.
|
|
*/
|
|
|
|
tsize_t t2p_write_pdf_xobject_stream_dict(ttile_t tile, T2P *t2p, TIFF *output)
|
|
{
|
|
|
|
tsize_t written = 0;
|
|
char buffer[32];
|
|
int buflen = 0;
|
|
|
|
written += t2p_write_pdf_stream_dict(0, t2p->pdf_xrefcount + 1, output);
|
|
written += t2pWriteFile(
|
|
output, (tdata_t) "/Type /XObject \n/Subtype /Image \n/Name /Im", 42);
|
|
buflen = snprintf(buffer, sizeof(buffer), "%" PRIu16,
|
|
(uint16_t)(t2p->pdf_page + 1u));
|
|
check_snprintf_ret(t2p, buflen, buffer);
|
|
written += t2pWriteFile(output, (tdata_t)buffer, buflen);
|
|
if (tile != 0)
|
|
{
|
|
written += t2pWriteFile(output, (tdata_t) "_", 1);
|
|
buflen = snprintf(buffer, sizeof(buffer), "%" PRIu32, tile);
|
|
check_snprintf_ret(t2p, buflen, buffer);
|
|
written += t2pWriteFile(output, (tdata_t)buffer, buflen);
|
|
}
|
|
written += t2pWriteFile(output, (tdata_t) "\n/Width ", 8);
|
|
if (tile == 0)
|
|
{
|
|
buflen = snprintf(buffer, sizeof(buffer), "%" PRIu32, t2p->tiff_width);
|
|
}
|
|
else
|
|
{
|
|
if (t2p_tile_is_right_edge(t2p->tiff_tiles[t2p->pdf_page], tile - 1) !=
|
|
0)
|
|
{
|
|
buflen =
|
|
snprintf(buffer, sizeof(buffer), "%" PRIu32,
|
|
t2p->tiff_tiles[t2p->pdf_page].tiles_edgetilewidth);
|
|
}
|
|
else
|
|
{
|
|
buflen = snprintf(buffer, sizeof(buffer), "%" PRIu32,
|
|
t2p->tiff_tiles[t2p->pdf_page].tiles_tilewidth);
|
|
}
|
|
}
|
|
check_snprintf_ret(t2p, buflen, buffer);
|
|
written += t2pWriteFile(output, (tdata_t)buffer, buflen);
|
|
written += t2pWriteFile(output, (tdata_t) "\n/Height ", 9);
|
|
if (tile == 0)
|
|
{
|
|
buflen = snprintf(buffer, sizeof(buffer), "%" PRIu32, t2p->tiff_length);
|
|
}
|
|
else
|
|
{
|
|
if (t2p_tile_is_bottom_edge(t2p->tiff_tiles[t2p->pdf_page], tile - 1) !=
|
|
0)
|
|
{
|
|
buflen =
|
|
snprintf(buffer, sizeof(buffer), "%" PRIu32,
|
|
t2p->tiff_tiles[t2p->pdf_page].tiles_edgetilelength);
|
|
}
|
|
else
|
|
{
|
|
buflen = snprintf(buffer, sizeof(buffer), "%" PRIu32,
|
|
t2p->tiff_tiles[t2p->pdf_page].tiles_tilelength);
|
|
}
|
|
}
|
|
check_snprintf_ret(t2p, buflen, buffer);
|
|
written += t2pWriteFile(output, (tdata_t)buffer, buflen);
|
|
written += t2pWriteFile(output, (tdata_t) "\n/BitsPerComponent ", 19);
|
|
buflen =
|
|
snprintf(buffer, sizeof(buffer), "%" PRIu16, t2p->tiff_bitspersample);
|
|
check_snprintf_ret(t2p, buflen, buffer);
|
|
written += t2pWriteFile(output, (tdata_t)buffer, buflen);
|
|
written += t2pWriteFile(output, (tdata_t) "\n/ColorSpace ", 13);
|
|
written += t2p_write_pdf_xobject_cs(t2p, output);
|
|
if (t2p->pdf_image_interpolate)
|
|
written += t2pWriteFile(output, (tdata_t) "\n/Interpolate true", 18);
|
|
if ((t2p->pdf_switchdecode != 0)
|
|
#ifdef CCITT_SUPPORT
|
|
&& !(t2p->pdf_colorspace & T2P_CS_BILEVEL &&
|
|
t2p->pdf_compression == T2P_COMPRESS_G4)
|
|
#endif
|
|
)
|
|
{
|
|
written += t2p_write_pdf_xobject_decode(t2p, output);
|
|
}
|
|
written += t2p_write_pdf_xobject_stream_filter(tile, t2p, output);
|
|
|
|
return (written);
|
|
}
|
|
|
|
/* used to normalize the White Point */
|
|
#define normalizePoint(x, y, z) \
|
|
do \
|
|
{ \
|
|
if (y != 0.0F) \
|
|
{ \
|
|
x /= y; \
|
|
z /= y; \
|
|
y = 1.0F; \
|
|
} \
|
|
} while (0)
|
|
|
|
/*
|
|
* This function writes a PDF Image XObject Colorspace name to output.
|
|
*/
|
|
|
|
tsize_t t2p_write_pdf_xobject_cs(T2P *t2p, TIFF *output)
|
|
{
|
|
|
|
tsize_t written = 0;
|
|
char buffer[128];
|
|
int buflen = 0;
|
|
|
|
float X_W = 1.0;
|
|
float Y_W = 1.0;
|
|
float Z_W = 1.0;
|
|
|
|
if ((t2p->pdf_colorspace & T2P_CS_ICCBASED) != 0)
|
|
{
|
|
written += t2p_write_pdf_xobject_icccs(t2p, output);
|
|
return (written);
|
|
}
|
|
if ((t2p->pdf_colorspace & T2P_CS_PALETTE) != 0)
|
|
{
|
|
written += t2pWriteFile(output, (tdata_t) "[ /Indexed ", 11);
|
|
t2p->pdf_colorspace ^= T2P_CS_PALETTE;
|
|
written += t2p_write_pdf_xobject_cs(t2p, output);
|
|
t2p->pdf_colorspace |= T2P_CS_PALETTE;
|
|
buflen = snprintf(buffer, sizeof(buffer), "%" PRIu32,
|
|
(uint32_t)(0x1u << t2p->tiff_bitspersample) - 1u);
|
|
check_snprintf_ret(t2p, buflen, buffer);
|
|
written += t2pWriteFile(output, (tdata_t)buffer, buflen);
|
|
written += t2pWriteFile(output, (tdata_t) " ", 1);
|
|
buflen =
|
|
snprintf(buffer, sizeof(buffer), "%" PRIu32, t2p->pdf_palettecs);
|
|
check_snprintf_ret(t2p, buflen, buffer);
|
|
written += t2pWriteFile(output, (tdata_t)buffer, buflen);
|
|
written += t2pWriteFile(output, (tdata_t) " 0 R ]\n", 7);
|
|
return (written);
|
|
}
|
|
if (t2p->pdf_colorspace & T2P_CS_BILEVEL)
|
|
{
|
|
written += t2pWriteFile(output, (tdata_t) "/DeviceGray \n", 13);
|
|
}
|
|
if (t2p->pdf_colorspace & T2P_CS_GRAY)
|
|
{
|
|
if (t2p->pdf_colorspace & T2P_CS_CALGRAY)
|
|
{
|
|
written += t2p_write_pdf_xobject_calcs(t2p, output);
|
|
}
|
|
else
|
|
{
|
|
written += t2pWriteFile(output, (tdata_t) "/DeviceGray \n", 13);
|
|
}
|
|
}
|
|
if (t2p->pdf_colorspace & T2P_CS_RGB)
|
|
{
|
|
if (t2p->pdf_colorspace & T2P_CS_CALRGB)
|
|
{
|
|
written += t2p_write_pdf_xobject_calcs(t2p, output);
|
|
}
|
|
else
|
|
{
|
|
written += t2pWriteFile(output, (tdata_t) "/DeviceRGB \n", 12);
|
|
}
|
|
}
|
|
if (t2p->pdf_colorspace & T2P_CS_CMYK)
|
|
{
|
|
written += t2pWriteFile(output, (tdata_t) "/DeviceCMYK \n", 13);
|
|
}
|
|
if (t2p->pdf_colorspace & T2P_CS_LAB)
|
|
{
|
|
written += t2pWriteFile(output, (tdata_t) "[/Lab << \n", 10);
|
|
written += t2pWriteFile(output, (tdata_t) "/WhitePoint ", 12);
|
|
X_W = t2p->tiff_whitechromaticities[0];
|
|
Y_W = t2p->tiff_whitechromaticities[1];
|
|
Z_W = 1.0F - (X_W + Y_W);
|
|
normalizePoint(X_W, Y_W, Z_W);
|
|
buflen = snprintf(buffer, sizeof(buffer), "[%.4f %.4f %.4f] \n", X_W,
|
|
Y_W, Z_W);
|
|
check_snprintf_ret(t2p, buflen, buffer);
|
|
written += t2pWriteFile(output, (tdata_t)buffer, buflen);
|
|
written += t2pWriteFile(output, (tdata_t) "/Range ", 7);
|
|
buflen = snprintf(buffer, sizeof(buffer), "[%d %d %d %d] \n",
|
|
t2p->pdf_labrange[0], t2p->pdf_labrange[1],
|
|
t2p->pdf_labrange[2], t2p->pdf_labrange[3]);
|
|
check_snprintf_ret(t2p, buflen, buffer);
|
|
written += t2pWriteFile(output, (tdata_t)buffer, buflen);
|
|
written += t2pWriteFile(output, (tdata_t) ">>] \n", 5);
|
|
}
|
|
|
|
return (written);
|
|
}
|
|
|
|
tsize_t t2p_write_pdf_transfer(T2P *t2p, TIFF *output)
|
|
{
|
|
|
|
tsize_t written = 0;
|
|
char buffer[32];
|
|
int buflen = 0;
|
|
|
|
written += t2pWriteFile(output, (tdata_t) "<< /Type /ExtGState \n/TR ", 25);
|
|
if (t2p->tiff_transferfunctioncount == 1)
|
|
{
|
|
buflen = snprintf(buffer, sizeof(buffer), "%" PRIu32,
|
|
t2p->pdf_xrefcount + 1u);
|
|
check_snprintf_ret(t2p, buflen, buffer);
|
|
written += t2pWriteFile(output, (tdata_t)buffer, buflen);
|
|
written += t2pWriteFile(output, (tdata_t) " 0 R ", 5);
|
|
}
|
|
else
|
|
{
|
|
written += t2pWriteFile(output, (tdata_t) "[ ", 2);
|
|
buflen = snprintf(buffer, sizeof(buffer), "%" PRIu32,
|
|
t2p->pdf_xrefcount + 1u);
|
|
check_snprintf_ret(t2p, buflen, buffer);
|
|
written += t2pWriteFile(output, (tdata_t)buffer, buflen);
|
|
written += t2pWriteFile(output, (tdata_t) " 0 R ", 5);
|
|
buflen = snprintf(buffer, sizeof(buffer), "%" PRIu32,
|
|
t2p->pdf_xrefcount + 2u);
|
|
check_snprintf_ret(t2p, buflen, buffer);
|
|
written += t2pWriteFile(output, (tdata_t)buffer, buflen);
|
|
written += t2pWriteFile(output, (tdata_t) " 0 R ", 5);
|
|
buflen = snprintf(buffer, sizeof(buffer), "%" PRIu32,
|
|
t2p->pdf_xrefcount + 3u);
|
|
check_snprintf_ret(t2p, buflen, buffer);
|
|
written += t2pWriteFile(output, (tdata_t)buffer, buflen);
|
|
written += t2pWriteFile(output, (tdata_t) " 0 R ", 5);
|
|
written += t2pWriteFile(output, (tdata_t) "/Identity ] ", 12);
|
|
}
|
|
|
|
written += t2pWriteFile(output, (tdata_t) " >> \n", 5);
|
|
|
|
return (written);
|
|
}
|
|
|
|
tsize_t t2p_write_pdf_transfer_dict(T2P *t2p, TIFF *output, uint16_t i)
|
|
{
|
|
|
|
tsize_t written = 0;
|
|
char buffer[32];
|
|
int buflen = 0;
|
|
(void)i; /* XXX */
|
|
|
|
written += t2pWriteFile(output, (tdata_t) "/FunctionType 0 \n", 17);
|
|
written += t2pWriteFile(output, (tdata_t) "/Domain [0.0 1.0] \n", 19);
|
|
written += t2pWriteFile(output, (tdata_t) "/Range [0.0 1.0] \n", 18);
|
|
buflen = snprintf(buffer, sizeof(buffer), "/Size [%" PRIu16 "] \n",
|
|
(uint16_t)(1u << t2p->tiff_bitspersample));
|
|
check_snprintf_ret(t2p, buflen, buffer);
|
|
written += t2pWriteFile(output, (tdata_t)buffer, buflen);
|
|
written += t2pWriteFile(output, (tdata_t) "/BitsPerSample 16 \n", 19);
|
|
written += t2p_write_pdf_stream_dict(
|
|
((tsize_t)1) << (t2p->tiff_bitspersample + 1), 0, output);
|
|
|
|
return (written);
|
|
}
|
|
|
|
tsize_t t2p_write_pdf_transfer_stream(T2P *t2p, TIFF *output, uint16_t i)
|
|
{
|
|
|
|
tsize_t written = 0;
|
|
|
|
written += t2p_write_pdf_stream(
|
|
t2p->tiff_transferfunction[i],
|
|
(((tsize_t)1) << (t2p->tiff_bitspersample + 1)), output);
|
|
|
|
return (written);
|
|
}
|
|
|
|
/*
|
|
This function writes a PDF Image XObject Colorspace array to output.
|
|
*/
|
|
|
|
tsize_t t2p_write_pdf_xobject_calcs(T2P *t2p, TIFF *output)
|
|
{
|
|
|
|
tsize_t written = 0;
|
|
char buffer[256];
|
|
int buflen = 0;
|
|
|
|
float X_W = 0.0;
|
|
float Y_W = 0.0;
|
|
float Z_W = 0.0;
|
|
float X_R = 0.0;
|
|
float Y_R = 0.0;
|
|
float Z_R = 0.0;
|
|
float X_G = 0.0;
|
|
float Y_G = 0.0;
|
|
float Z_G = 0.0;
|
|
float X_B = 0.0;
|
|
float Y_B = 0.0;
|
|
float Z_B = 0.0;
|
|
float x_w = 0.0;
|
|
float y_w = 0.0;
|
|
float z_w = 0.0;
|
|
float x_r = 0.0;
|
|
float y_r = 0.0;
|
|
float x_g = 0.0;
|
|
float y_g = 0.0;
|
|
float x_b = 0.0;
|
|
float y_b = 0.0;
|
|
float R = 1.0;
|
|
float G = 1.0;
|
|
float B = 1.0;
|
|
|
|
written += t2pWriteFile(output, (tdata_t) "[", 1);
|
|
if (t2p->pdf_colorspace & T2P_CS_CALGRAY)
|
|
{
|
|
written += t2pWriteFile(output, (tdata_t) "/CalGray ", 9);
|
|
X_W = t2p->tiff_whitechromaticities[0];
|
|
Y_W = t2p->tiff_whitechromaticities[1];
|
|
Z_W = 1.0F - (X_W + Y_W);
|
|
normalizePoint(X_W, Y_W, Z_W);
|
|
}
|
|
if (t2p->pdf_colorspace & T2P_CS_CALRGB)
|
|
{
|
|
written += t2pWriteFile(output, (tdata_t) "/CalRGB ", 8);
|
|
x_w = t2p->tiff_whitechromaticities[0];
|
|
y_w = t2p->tiff_whitechromaticities[1];
|
|
x_r = t2p->tiff_primarychromaticities[0];
|
|
y_r = t2p->tiff_primarychromaticities[1];
|
|
x_g = t2p->tiff_primarychromaticities[2];
|
|
y_g = t2p->tiff_primarychromaticities[3];
|
|
x_b = t2p->tiff_primarychromaticities[4];
|
|
y_b = t2p->tiff_primarychromaticities[5];
|
|
z_w = y_w * ((x_g - x_b) * y_r - (x_r - x_b) * y_g + (x_r - x_g) * y_b);
|
|
Y_R = (y_r / R) *
|
|
((x_g - x_b) * y_w - (x_w - x_b) * y_g + (x_w - x_g) * y_b) / z_w;
|
|
X_R = Y_R * x_r / y_r;
|
|
Z_R = Y_R * (((1 - x_r) / y_r) - 1);
|
|
Y_G = ((0.0F - (y_g)) / G) *
|
|
((x_r - x_b) * y_w - (x_w - x_b) * y_r + (x_w - x_r) * y_b) / z_w;
|
|
X_G = Y_G * x_g / y_g;
|
|
Z_G = Y_G * (((1 - x_g) / y_g) - 1);
|
|
Y_B = (y_b / B) *
|
|
((x_r - x_g) * y_w - (x_w - x_g) * y_r + (x_w - x_r) * y_g) / z_w;
|
|
X_B = Y_B * x_b / y_b;
|
|
Z_B = Y_B * (((1 - x_b) / y_b) - 1);
|
|
X_W = (X_R * R) + (X_G * G) + (X_B * B);
|
|
Y_W = (Y_R * R) + (Y_G * G) + (Y_B * B);
|
|
Z_W = (Z_R * R) + (Z_G * G) + (Z_B * B);
|
|
normalizePoint(X_W, Y_W, Z_W);
|
|
}
|
|
written += t2pWriteFile(output, (tdata_t) "<< \n", 4);
|
|
if (t2p->pdf_colorspace & T2P_CS_CALGRAY)
|
|
{
|
|
written += t2pWriteFile(output, (tdata_t) "/WhitePoint ", 12);
|
|
buflen = snprintf(buffer, sizeof(buffer), "[%.4f %.4f %.4f] \n", X_W,
|
|
Y_W, Z_W);
|
|
check_snprintf_ret(t2p, buflen, buffer);
|
|
written += t2pWriteFile(output, (tdata_t)buffer, buflen);
|
|
written += t2pWriteFile(output, (tdata_t) "/Gamma 2.2 \n", 12);
|
|
}
|
|
if (t2p->pdf_colorspace & T2P_CS_CALRGB)
|
|
{
|
|
written += t2pWriteFile(output, (tdata_t) "/WhitePoint ", 12);
|
|
buflen = snprintf(buffer, sizeof(buffer), "[%.4f %.4f %.4f] \n", X_W,
|
|
Y_W, Z_W);
|
|
check_snprintf_ret(t2p, buflen, buffer);
|
|
written += t2pWriteFile(output, (tdata_t)buffer, buflen);
|
|
written += t2pWriteFile(output, (tdata_t) "/Matrix ", 8);
|
|
buflen = snprintf(buffer, sizeof(buffer),
|
|
"[%.4f %.4f %.4f %.4f %.4f %.4f %.4f %.4f %.4f] \n",
|
|
X_R, Y_R, Z_R, X_G, Y_G, Z_G, X_B, Y_B, Z_B);
|
|
check_snprintf_ret(t2p, buflen, buffer);
|
|
written += t2pWriteFile(output, (tdata_t)buffer, buflen);
|
|
written +=
|
|
t2pWriteFile(output, (tdata_t) "/Gamma [2.2 2.2 2.2] \n", 22);
|
|
}
|
|
written += t2pWriteFile(output, (tdata_t) ">>] \n", 5);
|
|
|
|
return (written);
|
|
}
|
|
|
|
/*
|
|
This function writes a PDF Image XObject Colorspace array to output.
|
|
*/
|
|
|
|
tsize_t t2p_write_pdf_xobject_icccs(T2P *t2p, TIFF *output)
|
|
{
|
|
|
|
tsize_t written = 0;
|
|
char buffer[32];
|
|
int buflen = 0;
|
|
|
|
written += t2pWriteFile(output, (tdata_t) "[/ICCBased ", 11);
|
|
buflen = snprintf(buffer, sizeof(buffer), "%" PRIu32, t2p->pdf_icccs);
|
|
check_snprintf_ret(t2p, buflen, buffer);
|
|
written += t2pWriteFile(output, (tdata_t)buffer, buflen);
|
|
written += t2pWriteFile(output, (tdata_t) " 0 R] \n", 7);
|
|
|
|
return (written);
|
|
}
|
|
|
|
tsize_t t2p_write_pdf_xobject_icccs_dict(T2P *t2p, TIFF *output)
|
|
{
|
|
|
|
tsize_t written = 0;
|
|
char buffer[32];
|
|
int buflen = 0;
|
|
|
|
written += t2pWriteFile(output, (tdata_t) "/N ", 3);
|
|
buflen = snprintf(buffer, sizeof(buffer), "%" PRIu16 " \n",
|
|
t2p->tiff_samplesperpixel);
|
|
check_snprintf_ret(t2p, buflen, buffer);
|
|
written += t2pWriteFile(output, (tdata_t)buffer, buflen);
|
|
written += t2pWriteFile(output, (tdata_t) "/Alternate ", 11);
|
|
t2p->pdf_colorspace ^= T2P_CS_ICCBASED;
|
|
written += t2p_write_pdf_xobject_cs(t2p, output);
|
|
t2p->pdf_colorspace |= T2P_CS_ICCBASED;
|
|
written += t2p_write_pdf_stream_dict(t2p->tiff_iccprofilelength, 0, output);
|
|
|
|
return (written);
|
|
}
|
|
|
|
tsize_t t2p_write_pdf_xobject_icccs_stream(T2P *t2p, TIFF *output)
|
|
{
|
|
|
|
tsize_t written = 0;
|
|
|
|
written +=
|
|
t2p_write_pdf_stream((tdata_t)t2p->tiff_iccprofile,
|
|
(tsize_t)t2p->tiff_iccprofilelength, output);
|
|
|
|
return (written);
|
|
}
|
|
|
|
/*
|
|
This function writes a palette stream for an indexed color space to
|
|
output.
|
|
*/
|
|
|
|
tsize_t t2p_write_pdf_xobject_palettecs_stream(T2P *t2p, TIFF *output)
|
|
{
|
|
|
|
tsize_t written = 0;
|
|
|
|
written += t2p_write_pdf_stream((tdata_t)t2p->pdf_palette,
|
|
(tsize_t)t2p->pdf_palettesize, output);
|
|
|
|
return (written);
|
|
}
|
|
|
|
/*
|
|
This function writes a PDF Image XObject Decode array to output.
|
|
*/
|
|
|
|
tsize_t t2p_write_pdf_xobject_decode(T2P *t2p, TIFF *output)
|
|
{
|
|
|
|
tsize_t written = 0;
|
|
int i = 0;
|
|
|
|
written += t2pWriteFile(output, (tdata_t) "/Decode [ ", 10);
|
|
for (i = 0; i < t2p->tiff_samplesperpixel; i++)
|
|
{
|
|
written += t2pWriteFile(output, (tdata_t) "1 0 ", 4);
|
|
}
|
|
written += t2pWriteFile(output, (tdata_t) "]\n", 2);
|
|
|
|
return (written);
|
|
}
|
|
|
|
/*
|
|
This function writes a PDF Image XObject stream filter name and
|
|
parameters to output.
|
|
*/
|
|
|
|
tsize_t t2p_write_pdf_xobject_stream_filter(ttile_t tile, T2P *t2p,
|
|
TIFF *output)
|
|
{
|
|
|
|
tsize_t written = 0;
|
|
char buffer[32];
|
|
int buflen = 0;
|
|
|
|
if (t2p->pdf_compression == T2P_COMPRESS_NONE)
|
|
{
|
|
return (written);
|
|
}
|
|
written += t2pWriteFile(output, (tdata_t) "/Filter ", 8);
|
|
switch (t2p->pdf_compression)
|
|
{
|
|
#ifdef CCITT_SUPPORT
|
|
case T2P_COMPRESS_G4:
|
|
written += t2pWriteFile(output, (tdata_t) "/CCITTFaxDecode ", 16);
|
|
written += t2pWriteFile(output, (tdata_t) "/DecodeParms ", 13);
|
|
written += t2pWriteFile(output, (tdata_t) "<< /K -1 ", 9);
|
|
if (tile == 0)
|
|
{
|
|
written += t2pWriteFile(output, (tdata_t) "/Columns ", 9);
|
|
buflen = snprintf(buffer, sizeof(buffer), "%" PRIu32,
|
|
t2p->tiff_width);
|
|
check_snprintf_ret(t2p, buflen, buffer);
|
|
written += t2pWriteFile(output, (tdata_t)buffer, buflen);
|
|
written += t2pWriteFile(output, (tdata_t) " /Rows ", 7);
|
|
buflen = snprintf(buffer, sizeof(buffer), "%" PRIu32,
|
|
t2p->tiff_length);
|
|
check_snprintf_ret(t2p, buflen, buffer);
|
|
written += t2pWriteFile(output, (tdata_t)buffer, buflen);
|
|
}
|
|
else
|
|
{
|
|
if (t2p_tile_is_right_edge(t2p->tiff_tiles[t2p->pdf_page],
|
|
tile - 1) == 0)
|
|
{
|
|
written += t2pWriteFile(output, (tdata_t) "/Columns ", 9);
|
|
buflen = snprintf(
|
|
buffer, sizeof(buffer), "%" PRIu32,
|
|
t2p->tiff_tiles[t2p->pdf_page].tiles_tilewidth);
|
|
check_snprintf_ret(t2p, buflen, buffer);
|
|
written += t2pWriteFile(output, (tdata_t)buffer, buflen);
|
|
}
|
|
else
|
|
{
|
|
written += t2pWriteFile(output, (tdata_t) "/Columns ", 9);
|
|
buflen = snprintf(
|
|
buffer, sizeof(buffer), "%" PRIu32,
|
|
t2p->tiff_tiles[t2p->pdf_page].tiles_edgetilewidth);
|
|
check_snprintf_ret(t2p, buflen, buffer);
|
|
written += t2pWriteFile(output, (tdata_t)buffer, buflen);
|
|
}
|
|
if (t2p_tile_is_bottom_edge(t2p->tiff_tiles[t2p->pdf_page],
|
|
tile - 1) == 0)
|
|
{
|
|
written += t2pWriteFile(output, (tdata_t) " /Rows ", 7);
|
|
buflen = snprintf(
|
|
buffer, sizeof(buffer), "%" PRIu32,
|
|
t2p->tiff_tiles[t2p->pdf_page].tiles_tilelength);
|
|
check_snprintf_ret(t2p, buflen, buffer);
|
|
written += t2pWriteFile(output, (tdata_t)buffer, buflen);
|
|
}
|
|
else
|
|
{
|
|
written += t2pWriteFile(output, (tdata_t) " /Rows ", 7);
|
|
buflen = snprintf(
|
|
buffer, sizeof(buffer), "%" PRIu32,
|
|
t2p->tiff_tiles[t2p->pdf_page].tiles_edgetilelength);
|
|
check_snprintf_ret(t2p, buflen, buffer);
|
|
written += t2pWriteFile(output, (tdata_t)buffer, buflen);
|
|
}
|
|
}
|
|
if (t2p->pdf_switchdecode == 0)
|
|
{
|
|
written +=
|
|
t2pWriteFile(output, (tdata_t) " /BlackIs1 true ", 16);
|
|
}
|
|
written += t2pWriteFile(output, (tdata_t) ">>\n", 3);
|
|
break;
|
|
#endif
|
|
#ifdef JPEG_SUPPORT
|
|
case T2P_COMPRESS_JPEG:
|
|
written += t2pWriteFile(output, (tdata_t) "/DCTDecode ", 11);
|
|
|
|
if (t2p->tiff_photometric != PHOTOMETRIC_YCBCR)
|
|
{
|
|
written += t2pWriteFile(output, (tdata_t) "/DecodeParms ", 13);
|
|
written += t2pWriteFile(
|
|
output, (tdata_t) "<< /ColorTransform 1 >>\n", 24);
|
|
}
|
|
break;
|
|
#endif
|
|
#ifdef ZIP_SUPPORT
|
|
case T2P_COMPRESS_ZIP:
|
|
written += t2pWriteFile(output, (tdata_t) "/FlateDecode ", 13);
|
|
if (t2p->pdf_compressionquality % 100)
|
|
{
|
|
written += t2pWriteFile(output, (tdata_t) "/DecodeParms ", 13);
|
|
written += t2pWriteFile(output, (tdata_t) "<< /Predictor ", 14);
|
|
buflen =
|
|
snprintf(buffer, sizeof(buffer), "%" PRIu16,
|
|
(uint16_t)(t2p->pdf_compressionquality % 100u));
|
|
check_snprintf_ret(t2p, buflen, buffer);
|
|
written += t2pWriteFile(output, (tdata_t)buffer, buflen);
|
|
written += t2pWriteFile(output, (tdata_t) " /Columns ", 10);
|
|
buflen = snprintf(buffer, sizeof(buffer), "%" PRIu32,
|
|
t2p->tiff_width);
|
|
check_snprintf_ret(t2p, buflen, buffer);
|
|
written += t2pWriteFile(output, (tdata_t)buffer, buflen);
|
|
written += t2pWriteFile(output, (tdata_t) " /Colors ", 9);
|
|
buflen = snprintf(buffer, sizeof(buffer), "%" PRIu16,
|
|
t2p->tiff_samplesperpixel);
|
|
check_snprintf_ret(t2p, buflen, buffer);
|
|
written += t2pWriteFile(output, (tdata_t)buffer, buflen);
|
|
written +=
|
|
t2pWriteFile(output, (tdata_t) " /BitsPerComponent ", 19);
|
|
buflen = snprintf(buffer, sizeof(buffer), "%" PRIu16,
|
|
t2p->tiff_bitspersample);
|
|
check_snprintf_ret(t2p, buflen, buffer);
|
|
written += t2pWriteFile(output, (tdata_t)buffer, buflen);
|
|
written += t2pWriteFile(output, (tdata_t) ">>\n", 3);
|
|
}
|
|
break;
|
|
#endif
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return (written);
|
|
}
|
|
|
|
/*
|
|
This function writes a PDF xref table to output.
|
|
*/
|
|
|
|
tsize_t t2p_write_pdf_xreftable(T2P *t2p, TIFF *output)
|
|
{
|
|
|
|
tsize_t written = 0;
|
|
char buffer[64];
|
|
int buflen = 0;
|
|
uint32_t i = 0;
|
|
|
|
written += t2pWriteFile(output, (tdata_t) "xref\n0 ", 7);
|
|
buflen =
|
|
snprintf(buffer, sizeof(buffer), "%" PRIu32, t2p->pdf_xrefcount + 1u);
|
|
check_snprintf_ret(t2p, buflen, buffer);
|
|
written += t2pWriteFile(output, (tdata_t)buffer, buflen);
|
|
written += t2pWriteFile(output, (tdata_t) " \n0000000000 65535 f \n", 22);
|
|
for (i = 0; i < t2p->pdf_xrefcount; i++)
|
|
{
|
|
snprintf(buffer, sizeof(buffer), "%.10lu 00000 n \n",
|
|
(unsigned long)t2p->pdf_xrefoffsets[i]);
|
|
written += t2pWriteFile(output, (tdata_t)buffer, 20);
|
|
}
|
|
|
|
return (written);
|
|
}
|
|
|
|
/*
|
|
* This function writes a PDF trailer to output.
|
|
*/
|
|
|
|
tsize_t t2p_write_pdf_trailer(T2P *t2p, TIFF *output)
|
|
{
|
|
|
|
tsize_t written = 0;
|
|
char buffer[32];
|
|
int buflen = 0;
|
|
size_t i = 0;
|
|
|
|
for (i = 0; i < sizeof(t2p->pdf_fileid) - 8; i += 8)
|
|
snprintf(t2p->pdf_fileid + i, 9, "%.8X", rand());
|
|
|
|
written += t2pWriteFile(output, (tdata_t) "trailer\n<<\n/Size ", 17);
|
|
buflen =
|
|
snprintf(buffer, sizeof(buffer), "%" PRIu32, t2p->pdf_xrefcount + 1u);
|
|
check_snprintf_ret(t2p, buflen, buffer);
|
|
written += t2pWriteFile(output, (tdata_t)buffer, buflen);
|
|
written += t2pWriteFile(output, (tdata_t) "\n/Root ", 7);
|
|
buflen = snprintf(buffer, sizeof(buffer), "%" PRIu32, t2p->pdf_catalog);
|
|
check_snprintf_ret(t2p, buflen, buffer);
|
|
written += t2pWriteFile(output, (tdata_t)buffer, buflen);
|
|
written += t2pWriteFile(output, (tdata_t) " 0 R \n/Info ", 12);
|
|
buflen = snprintf(buffer, sizeof(buffer), "%" PRIu32, t2p->pdf_info);
|
|
check_snprintf_ret(t2p, buflen, buffer);
|
|
written += t2pWriteFile(output, (tdata_t)buffer, buflen);
|
|
written += t2pWriteFile(output, (tdata_t) " 0 R \n/ID[<", 11);
|
|
written += t2pWriteFile(output, (tdata_t)t2p->pdf_fileid,
|
|
sizeof(t2p->pdf_fileid) - 1);
|
|
written += t2pWriteFile(output, (tdata_t) "><", 2);
|
|
written += t2pWriteFile(output, (tdata_t)t2p->pdf_fileid,
|
|
sizeof(t2p->pdf_fileid) - 1);
|
|
written += t2pWriteFile(output, (tdata_t) ">]\n>>\nstartxref\n", 16);
|
|
buflen = snprintf(buffer, sizeof(buffer), "%" PRIu32, t2p->pdf_startxref);
|
|
check_snprintf_ret(t2p, buflen, buffer);
|
|
written += t2pWriteFile(output, (tdata_t)buffer, buflen);
|
|
written += t2pWriteFile(output, (tdata_t) "\n%%EOF\n", 7);
|
|
|
|
return (written);
|
|
}
|
|
|
|
/*
|
|
|
|
This function writes a PDF to a file given a pointer to a TIFF.
|
|
|
|
The idea with using a TIFF* as output for a PDF file is that the file
|
|
can be created with TIFFClientOpen for memory-mapped use within the TIFF
|
|
library, and TIFFWriteEncodedStrip can be used to write compressed data to
|
|
the output. The output is not actually a TIFF file, it is a PDF file.
|
|
|
|
This function uses only t2pWriteFile and TIFFWriteEncodedStrip to write to
|
|
the output TIFF file. When libtiff would otherwise be writing data to the
|
|
output file, the write procedure of the TIFF structure is replaced with an
|
|
empty implementation.
|
|
|
|
The first argument to the function is an initialized and validated T2P
|
|
context struct pointer.
|
|
|
|
The second argument to the function is the TIFF* that is the input that has
|
|
been opened for reading and no other functions have been called upon it.
|
|
|
|
The third argument to the function is the TIFF* that is the output that has
|
|
been opened for writing. It has to be opened so that it hasn't written any
|
|
data to the output. If the output is seekable then it's OK to seek to the
|
|
beginning of the file. The function only writes to the output PDF and does
|
|
not seek. See the example usage in the main() function.
|
|
|
|
TIFF* output = TIFFOpen("output.pdf", "w");
|
|
assert(output != NULL);
|
|
|
|
if(output->tif_seekproc != NULL){
|
|
t2pSeekFile(output, (toff_t) 0, SEEK_SET);
|
|
}
|
|
|
|
This function returns the file size of the output PDF file. On error it
|
|
returns zero and the t2p->t2p_error variable is set to T2P_ERR_ERROR.
|
|
|
|
After this function completes, call t2p_free on t2p, TIFFClose on input,
|
|
and TIFFClose on output.
|
|
*/
|
|
|
|
tsize_t t2p_write_pdf(T2P *t2p, TIFF *input, TIFF *output)
|
|
{
|
|
|
|
tsize_t written = 0;
|
|
ttile_t i2 = 0;
|
|
tsize_t streamlen = 0;
|
|
uint16_t i = 0;
|
|
|
|
t2p_read_tiff_init(t2p, input);
|
|
if (t2p->t2p_error != T2P_ERR_OK)
|
|
{
|
|
return (0);
|
|
}
|
|
t2p->pdf_xrefoffsets = (uint32_t *)_TIFFmalloc(
|
|
TIFFSafeMultiply(tmsize_t, t2p->pdf_xrefcount, sizeof(uint32_t)));
|
|
if (t2p->pdf_xrefoffsets == NULL)
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"Can't allocate %" TIFF_SIZE_FORMAT
|
|
" bytes of memory for t2p_write_pdf",
|
|
sizeof(uint32_t) * t2p->pdf_xrefcount);
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return (written);
|
|
}
|
|
t2p->pdf_xrefcount = 0;
|
|
t2p->pdf_catalog = 1;
|
|
t2p->pdf_info = 2;
|
|
t2p->pdf_pages = 3;
|
|
written += t2p_write_pdf_header(t2p, output);
|
|
t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++] = written;
|
|
t2p->pdf_catalog = t2p->pdf_xrefcount;
|
|
written += t2p_write_pdf_obj_start(t2p->pdf_xrefcount, output);
|
|
written += t2p_write_pdf_catalog(t2p, output);
|
|
written += t2p_write_pdf_obj_end(output);
|
|
t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++] = written;
|
|
t2p->pdf_info = t2p->pdf_xrefcount;
|
|
written += t2p_write_pdf_obj_start(t2p->pdf_xrefcount, output);
|
|
written += t2p_write_pdf_info(t2p, input, output);
|
|
written += t2p_write_pdf_obj_end(output);
|
|
t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++] = written;
|
|
t2p->pdf_pages = t2p->pdf_xrefcount;
|
|
written += t2p_write_pdf_obj_start(t2p->pdf_xrefcount, output);
|
|
written += t2p_write_pdf_pages(t2p, output);
|
|
written += t2p_write_pdf_obj_end(output);
|
|
for (t2p->pdf_page = 0; t2p->pdf_page < t2p->tiff_pagecount;
|
|
t2p->pdf_page++)
|
|
{
|
|
t2p_read_tiff_data(t2p, input);
|
|
if (t2p->t2p_error != T2P_ERR_OK)
|
|
{
|
|
return (0);
|
|
}
|
|
t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++] = written;
|
|
written += t2p_write_pdf_obj_start(t2p->pdf_xrefcount, output);
|
|
written += t2p_write_pdf_page(t2p->pdf_xrefcount, t2p, output);
|
|
written += t2p_write_pdf_obj_end(output);
|
|
t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++] = written;
|
|
written += t2p_write_pdf_obj_start(t2p->pdf_xrefcount, output);
|
|
written += t2p_write_pdf_stream_dict_start(output);
|
|
written += t2p_write_pdf_stream_dict(0, t2p->pdf_xrefcount + 1, output);
|
|
written += t2p_write_pdf_stream_dict_end(output);
|
|
written += t2p_write_pdf_stream_start(output);
|
|
streamlen = written;
|
|
written += t2p_write_pdf_page_content_stream(t2p, output);
|
|
streamlen = written - streamlen;
|
|
written += t2p_write_pdf_stream_end(output);
|
|
written += t2p_write_pdf_obj_end(output);
|
|
t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++] = written;
|
|
written += t2p_write_pdf_obj_start(t2p->pdf_xrefcount, output);
|
|
written += t2p_write_pdf_stream_length(streamlen, output);
|
|
written += t2p_write_pdf_obj_end(output);
|
|
if (t2p->tiff_transferfunctioncount != 0)
|
|
{
|
|
t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++] = written;
|
|
written += t2p_write_pdf_obj_start(t2p->pdf_xrefcount, output);
|
|
written += t2p_write_pdf_transfer(t2p, output);
|
|
written += t2p_write_pdf_obj_end(output);
|
|
for (i = 0; i < t2p->tiff_transferfunctioncount; i++)
|
|
{
|
|
t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++] = written;
|
|
written += t2p_write_pdf_obj_start(t2p->pdf_xrefcount, output);
|
|
written += t2p_write_pdf_stream_dict_start(output);
|
|
written += t2p_write_pdf_transfer_dict(t2p, output, i);
|
|
written += t2p_write_pdf_stream_dict_end(output);
|
|
written += t2p_write_pdf_stream_start(output);
|
|
/* streamlen=written; */ /* value not used */
|
|
written += t2p_write_pdf_transfer_stream(t2p, output, i);
|
|
/* streamlen=written-streamlen; */ /* value not used */
|
|
written += t2p_write_pdf_stream_end(output);
|
|
written += t2p_write_pdf_obj_end(output);
|
|
}
|
|
}
|
|
if ((t2p->pdf_colorspace & T2P_CS_PALETTE) != 0)
|
|
{
|
|
t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++] = written;
|
|
t2p->pdf_palettecs = t2p->pdf_xrefcount;
|
|
written += t2p_write_pdf_obj_start(t2p->pdf_xrefcount, output);
|
|
written += t2p_write_pdf_stream_dict_start(output);
|
|
written +=
|
|
t2p_write_pdf_stream_dict(t2p->pdf_palettesize, 0, output);
|
|
written += t2p_write_pdf_stream_dict_end(output);
|
|
written += t2p_write_pdf_stream_start(output);
|
|
/* streamlen=written; */ /* value not used */
|
|
written += t2p_write_pdf_xobject_palettecs_stream(t2p, output);
|
|
/* streamlen=written-streamlen; */ /* value not used */
|
|
written += t2p_write_pdf_stream_end(output);
|
|
written += t2p_write_pdf_obj_end(output);
|
|
}
|
|
if ((t2p->pdf_colorspace & T2P_CS_ICCBASED) != 0)
|
|
{
|
|
t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++] = written;
|
|
t2p->pdf_icccs = t2p->pdf_xrefcount;
|
|
written += t2p_write_pdf_obj_start(t2p->pdf_xrefcount, output);
|
|
written += t2p_write_pdf_stream_dict_start(output);
|
|
written += t2p_write_pdf_xobject_icccs_dict(t2p, output);
|
|
written += t2p_write_pdf_stream_dict_end(output);
|
|
written += t2p_write_pdf_stream_start(output);
|
|
/* streamlen=written; */ /* value not used */
|
|
written += t2p_write_pdf_xobject_icccs_stream(t2p, output);
|
|
/* streamlen=written-streamlen; */ /* value not used */
|
|
written += t2p_write_pdf_stream_end(output);
|
|
written += t2p_write_pdf_obj_end(output);
|
|
}
|
|
if (t2p->tiff_tiles[t2p->pdf_page].tiles_tilecount != 0)
|
|
{
|
|
for (i2 = 0; i2 < t2p->tiff_tiles[t2p->pdf_page].tiles_tilecount;
|
|
i2++)
|
|
{
|
|
t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++] = written;
|
|
written += t2p_write_pdf_obj_start(t2p->pdf_xrefcount, output);
|
|
written += t2p_write_pdf_stream_dict_start(output);
|
|
written +=
|
|
t2p_write_pdf_xobject_stream_dict(i2 + 1, t2p, output);
|
|
written += t2p_write_pdf_stream_dict_end(output);
|
|
written += t2p_write_pdf_stream_start(output);
|
|
streamlen = written;
|
|
t2p_read_tiff_size_tile(t2p, input, i2);
|
|
if (t2p->tiff_maxdatasize &&
|
|
(t2p->tiff_datasize > t2p->tiff_maxdatasize))
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"Allocation of %" PRIu64
|
|
" bytes is forbidden. Limit is %" PRIu64
|
|
". Use -m option to change limit",
|
|
(uint64_t)t2p->tiff_datasize,
|
|
(uint64_t)t2p->tiff_maxdatasize);
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return (0);
|
|
}
|
|
written += t2p_readwrite_pdf_image_tile(t2p, input, output, i2);
|
|
t2p_write_advance_directory(t2p, output);
|
|
if (t2p->t2p_error != T2P_ERR_OK)
|
|
{
|
|
return (0);
|
|
}
|
|
streamlen = written - streamlen;
|
|
written += t2p_write_pdf_stream_end(output);
|
|
written += t2p_write_pdf_obj_end(output);
|
|
t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++] = written;
|
|
written += t2p_write_pdf_obj_start(t2p->pdf_xrefcount, output);
|
|
written += t2p_write_pdf_stream_length(streamlen, output);
|
|
written += t2p_write_pdf_obj_end(output);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++] = written;
|
|
written += t2p_write_pdf_obj_start(t2p->pdf_xrefcount, output);
|
|
written += t2p_write_pdf_stream_dict_start(output);
|
|
written += t2p_write_pdf_xobject_stream_dict(0, t2p, output);
|
|
written += t2p_write_pdf_stream_dict_end(output);
|
|
written += t2p_write_pdf_stream_start(output);
|
|
streamlen = written;
|
|
t2p_read_tiff_size(t2p, input);
|
|
if (t2p->tiff_maxdatasize &&
|
|
(t2p->tiff_datasize > t2p->tiff_maxdatasize))
|
|
{
|
|
TIFFError(TIFF2PDF_MODULE,
|
|
"Allocation of %" PRIu64
|
|
" bytes is forbidden. Limit is %" PRIu64
|
|
". Use -m option to change limit",
|
|
(uint64_t)t2p->tiff_datasize,
|
|
(uint64_t)t2p->tiff_maxdatasize);
|
|
t2p->t2p_error = T2P_ERR_ERROR;
|
|
return (0);
|
|
}
|
|
written += t2p_readwrite_pdf_image(t2p, input, output);
|
|
t2p_write_advance_directory(t2p, output);
|
|
if (t2p->t2p_error != T2P_ERR_OK)
|
|
{
|
|
return (0);
|
|
}
|
|
streamlen = written - streamlen;
|
|
written += t2p_write_pdf_stream_end(output);
|
|
written += t2p_write_pdf_obj_end(output);
|
|
t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++] = written;
|
|
written += t2p_write_pdf_obj_start(t2p->pdf_xrefcount, output);
|
|
written += t2p_write_pdf_stream_length(streamlen, output);
|
|
written += t2p_write_pdf_obj_end(output);
|
|
}
|
|
}
|
|
t2p->pdf_startxref = written;
|
|
written += t2p_write_pdf_xreftable(t2p, output);
|
|
written += t2p_write_pdf_trailer(t2p, output);
|
|
t2p_disable(output);
|
|
|
|
return (written);
|
|
}
|