diff options
Diffstat (limited to 'libtiff/tif_jpeg.c')
-rw-r--r-- | libtiff/tif_jpeg.c | 1480 |
1 files changed, 1480 insertions, 0 deletions
diff --git a/libtiff/tif_jpeg.c b/libtiff/tif_jpeg.c new file mode 100644 index 00000000..f88a13a3 --- /dev/null +++ b/libtiff/tif_jpeg.c @@ -0,0 +1,1480 @@ +/* $Header: /usr/people/sam/tiff/libtiff/RCS/tif_jpeg.c,v 1.23 1995/06/30 15:29:02 sam Exp $ */ + +/* + * Copyright (c) 1994-1995 Sam Leffler + * Copyright (c) 1994-1995 Silicon Graphics, Inc. + * + * 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 names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * 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 SAM LEFFLER OR SILICON GRAPHICS 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 "tiffiop.h" +#ifdef JPEG_SUPPORT +/* + * TIFF Library + * + * JPEG Compression support per TIFF Technical Note #2 + * (*not* per the original TIFF 6.0 spec). + * + * This file is simply an interface to the libjpeg library written by + * the Independent JPEG Group. You need release 5 or later of the IJG + * code, which you can find on the Internet at ftp.uu.net:/graphics/jpeg/. + * + * Contributed by Tom Lane <tgl@sss.pgh.pa.us>. + */ +#include <assert.h> +#include <stdio.h> +#include <setjmp.h> +#include "jpeglib.h" +#include "jerror.h" + +/* + * On some machines it may be worthwhile to use _setjmp or sigsetjmp + * in place of plain setjmp. These macros will make it easier. + */ +#define SETJMP(jbuf) setjmp(jbuf) +#define LONGJMP(jbuf,code) longjmp(jbuf,code) +#define JMP_BUF jmp_buf + +typedef struct jpeg_destination_mgr jpeg_destination_mgr; +typedef struct jpeg_source_mgr jpeg_source_mgr; +typedef struct jpeg_error_mgr jpeg_error_mgr; + +/* + * State block for each open TIFF file using + * libjpeg to do JPEG compression/decompression. + * + * libjpeg's visible state is either a jpeg_compress_struct + * or jpeg_decompress_struct depending on which way we + * are going. comm can be used to refer to the fields + * which are common to both. + * + * NB: cinfo is required to be the first member of JPEGState, + * so we can safely cast JPEGState* -> jpeg_xxx_struct* + * and vice versa! + */ +typedef struct { + union { + struct jpeg_compress_struct c; + struct jpeg_decompress_struct d; + struct jpeg_common_struct comm; + } cinfo; /* NB: must be first */ + jpeg_error_mgr err; /* libjpeg error manager */ + JMP_BUF exit_jmpbuf; /* for catching libjpeg failures */ + /* + * The following two members could be a union, but + * they're small enough that it's not worth the effort. + */ + jpeg_destination_mgr dest; /* data dest for compression */ + jpeg_source_mgr src; /* data source for decompression */ + /* private state */ + TIFF* tif; /* back link needed by some code */ + uint16 photometric; /* copy of PhotometricInterpretation */ + uint16 h_sampling; /* luminance sampling factors */ + uint16 v_sampling; + tsize_t bytesperline; /* decompressed bytes per scanline */ + /* pointers to intermediate buffers when processing downsampled data */ + JSAMPARRAY ds_buffer[MAX_COMPONENTS]; + int scancount; /* number of "scanlines" accumulated */ + int samplesperclump; + + TIFFVGetMethod vgetparent; /* super-class method */ + TIFFVSetMethod vsetparent; /* super-class method */ + TIFFStripMethod defsparent; /* super-class method */ + TIFFTileMethod deftparent; /* super-class method */ + /* pseudo-tag fields */ + void* jpegtables; /* JPEGTables tag value, or NULL */ + uint32 jpegtables_length; /* number of bytes in same */ + int jpegquality; /* Compression quality level */ + int jpegcolormode; /* Auto RGB<=>YCbCr convert? */ + int jpegtablesmode; /* What to put in JPEGTables */ +} JPEGState; + +#define JState(tif) ((JPEGState*)(tif)->tif_data) + +static int JPEGDecode(TIFF*, tidata_t, tsize_t, tsample_t); +static int JPEGDecodeRaw(TIFF*, tidata_t, tsize_t, tsample_t); +static int JPEGEncode(TIFF*, tidata_t, tsize_t, tsample_t); +static int JPEGEncodeRaw(TIFF*, tidata_t, tsize_t, tsample_t); + +#define FIELD_JPEGTABLES (FIELD_CODEC+0) +#define FIELD_JPEGQUALITY (FIELD_CODEC+1) +#define FIELD_JPEGCOLORMODE (FIELD_CODEC+2) +#define FIELD_JPEGTABLESMODE (FIELD_CODEC+3) + +static const TIFFFieldInfo jpegFieldInfo[] = { + { TIFFTAG_JPEGTABLES, -1,-1, TIFF_UNDEFINED, FIELD_JPEGTABLES, + FALSE, TRUE, "JPEGTables" }, + { TIFFTAG_JPEGQUALITY, 0, 0, TIFF_ANY, FIELD_JPEGQUALITY, + TRUE, FALSE, "" }, + { TIFFTAG_JPEGCOLORMODE, 0, 0, TIFF_ANY, FIELD_JPEGCOLORMODE, + FALSE, FALSE, "" }, + { TIFFTAG_JPEGTABLESMODE, 0, 0, TIFF_ANY, FIELD_JPEGTABLESMODE, + FALSE, FALSE, "" }, +}; +#define N(a) (sizeof (a) / sizeof (a[0])) + +/* + * libjpeg interface layer. + * + * We use setjmp/longjmp to return control to libtiff + * when a fatal error is encountered within the JPEG + * library. We also direct libjpeg error and warning + * messages through the appropriate libtiff handlers. + */ + +/* + * Error handling routines (these replace corresponding + * IJG routines from jerror.c). These are used for both + * compression and decompression. + */ +static void +TIFFjpeg_error_exit(j_common_ptr cinfo) +{ + JPEGState *sp = (JPEGState *) cinfo; /* NB: cinfo assumed first */ + char buffer[JMSG_LENGTH_MAX]; + + (*cinfo->err->format_message) (cinfo, buffer); + TIFFError("JPEGLib", buffer); /* display the error message */ + jpeg_abort(cinfo); /* clean up libjpeg state */ + LONGJMP(sp->exit_jmpbuf, 1); /* return to libtiff caller */ +} + +/* + * This routine is invoked only for warning messages, + * since error_exit does its own thing and trace_level + * is never set > 0. + */ +static void +TIFFjpeg_output_message(j_common_ptr cinfo) +{ + char buffer[JMSG_LENGTH_MAX]; + + (*cinfo->err->format_message) (cinfo, buffer); + TIFFWarning("JPEGLib", buffer); +} + +/* + * Interface routines. This layer of routines exists + * primarily to limit side-effects from using setjmp. + * Also, normal/error returns are converted into return + * values per libtiff practice. + */ +#define CALLJPEG(sp, fail, op) (SETJMP((sp)->exit_jmpbuf) ? (fail) : (op)) +#define CALLVJPEG(sp, op) CALLJPEG(sp, 0, ((op),1)) + +static int +TIFFjpeg_create_compress(JPEGState* sp) +{ + /* initialize JPEG error handling */ + sp->cinfo.c.err = jpeg_std_error(&sp->err); + sp->err.error_exit = TIFFjpeg_error_exit; + sp->err.output_message = TIFFjpeg_output_message; + + return CALLVJPEG(sp, jpeg_create_compress(&sp->cinfo.c)); +} + +static int +TIFFjpeg_create_decompress(JPEGState* sp) +{ + /* initialize JPEG error handling */ + sp->cinfo.d.err = jpeg_std_error(&sp->err); + sp->err.error_exit = TIFFjpeg_error_exit; + sp->err.output_message = TIFFjpeg_output_message; + + return CALLVJPEG(sp, jpeg_create_decompress(&sp->cinfo.d)); +} + +static int +TIFFjpeg_set_defaults(JPEGState* sp) +{ + return CALLVJPEG(sp, jpeg_set_defaults(&sp->cinfo.c)); +} + +static int +TIFFjpeg_set_colorspace(JPEGState* sp, J_COLOR_SPACE colorspace) +{ + return CALLVJPEG(sp, jpeg_set_colorspace(&sp->cinfo.c, colorspace)); +} + +static int +TIFFjpeg_set_quality(JPEGState* sp, int quality, boolean force_baseline) +{ + return CALLVJPEG(sp, + jpeg_set_quality(&sp->cinfo.c, quality, force_baseline)); +} + +static int +TIFFjpeg_suppress_tables(JPEGState* sp, boolean suppress) +{ + return CALLVJPEG(sp, jpeg_suppress_tables(&sp->cinfo.c, suppress)); +} + +static int +TIFFjpeg_start_compress(JPEGState* sp, boolean write_all_tables) +{ + return CALLVJPEG(sp, + jpeg_start_compress(&sp->cinfo.c, write_all_tables)); +} + +static int +TIFFjpeg_write_scanlines(JPEGState* sp, JSAMPARRAY scanlines, int num_lines) +{ + return CALLJPEG(sp, -1, (int) jpeg_write_scanlines(&sp->cinfo.c, + scanlines, (JDIMENSION) num_lines)); +} + +static int +TIFFjpeg_write_raw_data(JPEGState* sp, JSAMPIMAGE data, int num_lines) +{ + return CALLJPEG(sp, -1, (int) jpeg_write_raw_data(&sp->cinfo.c, + data, (JDIMENSION) num_lines)); +} + +static int +TIFFjpeg_finish_compress(JPEGState* sp) +{ + return CALLVJPEG(sp, jpeg_finish_compress(&sp->cinfo.c)); +} + +static int +TIFFjpeg_write_tables(JPEGState* sp) +{ + return CALLVJPEG(sp, jpeg_write_tables(&sp->cinfo.c)); +} + +static int +TIFFjpeg_read_header(JPEGState* sp, boolean require_image) +{ + return CALLJPEG(sp, -1, jpeg_read_header(&sp->cinfo.d, require_image)); +} + +static int +TIFFjpeg_start_decompress(JPEGState* sp) +{ + return CALLVJPEG(sp, jpeg_start_decompress(&sp->cinfo.d)); +} + +static int +TIFFjpeg_read_scanlines(JPEGState* sp, JSAMPARRAY scanlines, int max_lines) +{ + return CALLJPEG(sp, -1, (int) jpeg_read_scanlines(&sp->cinfo.d, + scanlines, (JDIMENSION) max_lines)); +} + +static int +TIFFjpeg_read_raw_data(JPEGState* sp, JSAMPIMAGE data, int max_lines) +{ + return CALLJPEG(sp, -1, (int) jpeg_read_raw_data(&sp->cinfo.d, + data, (JDIMENSION) max_lines)); +} + +static int +TIFFjpeg_finish_decompress(JPEGState* sp) +{ + return CALLJPEG(sp, -1, (int) jpeg_finish_decompress(&sp->cinfo.d)); +} + +static int +TIFFjpeg_abort(JPEGState* sp) +{ + return CALLVJPEG(sp, jpeg_abort(&sp->cinfo.comm)); +} + +static int +TIFFjpeg_destroy(JPEGState* sp) +{ + return CALLVJPEG(sp, jpeg_destroy(&sp->cinfo.comm)); +} + +static JSAMPARRAY +TIFFjpeg_alloc_sarray(JPEGState* sp, int pool_id, + JDIMENSION samplesperrow, JDIMENSION numrows) +{ + return CALLJPEG(sp, (JSAMPARRAY) NULL, + (*sp->cinfo.comm.mem->alloc_sarray) + (&sp->cinfo.comm, pool_id, samplesperrow, numrows)); +} + +/* + * JPEG library destination data manager. + * These routines direct compressed data from libjpeg into the + * libtiff output buffer. + */ + +static void +std_init_destination(j_compress_ptr cinfo) +{ + JPEGState* sp = (JPEGState*) cinfo; + TIFF* tif = sp->tif; + + sp->dest.next_output_byte = (JOCTET*) tif->tif_rawdata; + sp->dest.free_in_buffer = (size_t) tif->tif_rawdatasize; +} + +static boolean +std_empty_output_buffer(j_compress_ptr cinfo) +{ + JPEGState* sp = (JPEGState*) cinfo; + TIFF* tif = sp->tif; + + /* the entire buffer has been filled */ + tif->tif_rawcc = tif->tif_rawdatasize; + TIFFFlushData1(tif); + sp->dest.next_output_byte = (JOCTET*) tif->tif_rawdata; + sp->dest.free_in_buffer = (size_t) tif->tif_rawdatasize; + + return (TRUE); +} + +static void +std_term_destination(j_compress_ptr cinfo) +{ + JPEGState* sp = (JPEGState*) cinfo; + TIFF* tif = sp->tif; + + tif->tif_rawcp = (tidata_t) sp->dest.next_output_byte; + tif->tif_rawcc = + tif->tif_rawdatasize - (tsize_t) sp->dest.free_in_buffer; + /* NB: libtiff does the final buffer flush */ +} + +static void +TIFFjpeg_data_dest(JPEGState* sp, TIFF* tif) +{ + (void) tif; + sp->cinfo.c.dest = &sp->dest; + sp->dest.init_destination = std_init_destination; + sp->dest.empty_output_buffer = std_empty_output_buffer; + sp->dest.term_destination = std_term_destination; +} + +/* + * Alternate destination manager for outputting to JPEGTables field. + */ + +static void +tables_init_destination(j_compress_ptr cinfo) +{ + JPEGState* sp = (JPEGState*) cinfo; + + /* while building, jpegtables_length is allocated buffer size */ + sp->dest.next_output_byte = (JOCTET*) sp->jpegtables; + sp->dest.free_in_buffer = (size_t) sp->jpegtables_length; +} + +static boolean +tables_empty_output_buffer(j_compress_ptr cinfo) +{ + JPEGState* sp = (JPEGState*) cinfo; + void* newbuf; + + /* the entire buffer has been filled; enlarge it by 1000 bytes */ + newbuf = _TIFFrealloc((tdata_t) sp->jpegtables, + (tsize_t) (sp->jpegtables_length + 1000)); + if (newbuf == NULL) + ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 100); + sp->dest.next_output_byte = (JOCTET*) newbuf + sp->jpegtables_length; + sp->dest.free_in_buffer = (size_t) 1000; + sp->jpegtables = newbuf; + sp->jpegtables_length += 1000; + return (TRUE); +} + +static void +tables_term_destination(j_compress_ptr cinfo) +{ + JPEGState* sp = (JPEGState*) cinfo; + + /* set tables length to number of bytes actually emitted */ + sp->jpegtables_length -= sp->dest.free_in_buffer; +} + +static int +TIFFjpeg_tables_dest(JPEGState* sp, TIFF* tif) +{ + (void) tif; + /* + * Allocate a working buffer for building tables. + * Initial size is 1000 bytes, which is usually adequate. + */ + if (sp->jpegtables) + _TIFFfree(sp->jpegtables); + sp->jpegtables_length = 1000; + sp->jpegtables = (void*) _TIFFmalloc((tsize_t) sp->jpegtables_length); + if (sp->jpegtables == NULL) { + sp->jpegtables_length = 0; + TIFFError("TIFFjpeg_tables_dest", "No space for JPEGTables"); + return (0); + } + sp->cinfo.c.dest = &sp->dest; + sp->dest.init_destination = tables_init_destination; + sp->dest.empty_output_buffer = tables_empty_output_buffer; + sp->dest.term_destination = tables_term_destination; + return (1); +} + +/* + * JPEG library source data manager. + * These routines supply compressed data to libjpeg. + */ + +static void +std_init_source(j_decompress_ptr cinfo) +{ + JPEGState* sp = (JPEGState*) cinfo; + TIFF* tif = sp->tif; + + sp->src.next_input_byte = (const JOCTET*) tif->tif_rawdata; + sp->src.bytes_in_buffer = (size_t) tif->tif_rawcc; +} + +static boolean +std_fill_input_buffer(j_decompress_ptr cinfo) +{ + JPEGState* sp = (JPEGState* ) cinfo; + static const JOCTET dummy_EOI[2] = { 0xFF, JPEG_EOI }; + + /* + * Should never get here since entire strip/tile is + * read into memory before the decompressor is called, + * and thus was supplied by init_source. + */ + WARNMS(cinfo, JWRN_JPEG_EOF); + /* insert a fake EOI marker */ + sp->src.next_input_byte = dummy_EOI; + sp->src.bytes_in_buffer = 2; + return (TRUE); +} + +static void +std_skip_input_data(j_decompress_ptr cinfo, long num_bytes) +{ + JPEGState* sp = (JPEGState*) cinfo; + + if (num_bytes > 0) { + if (num_bytes > (long) sp->src.bytes_in_buffer) { + /* oops, buffer overrun */ + (void) std_fill_input_buffer(cinfo); + } else { + sp->src.next_input_byte += (size_t) num_bytes; + sp->src.bytes_in_buffer -= (size_t) num_bytes; + } + } +} + +static void +std_term_source(j_decompress_ptr cinfo) +{ + /* No work necessary here */ + /* Or must we update tif->tif_rawcp, tif->tif_rawcc ??? */ + /* (if so, need empty tables_term_source!) */ + (void) cinfo; +} + +static void +TIFFjpeg_data_src(JPEGState* sp, TIFF* tif) +{ + (void) tif; + sp->cinfo.d.src = &sp->src; + sp->src.init_source = std_init_source; + sp->src.fill_input_buffer = std_fill_input_buffer; + sp->src.skip_input_data = std_skip_input_data; + sp->src.resync_to_restart = jpeg_resync_to_restart; + sp->src.term_source = std_term_source; + sp->src.bytes_in_buffer = 0; /* for safety */ + sp->src.next_input_byte = NULL; +} + +/* + * Alternate source manager for reading from JPEGTables. + * We can share all the code except for the init routine. + */ + +static void +tables_init_source(j_decompress_ptr cinfo) +{ + JPEGState* sp = (JPEGState*) cinfo; + + sp->src.next_input_byte = (const JOCTET*) sp->jpegtables; + sp->src.bytes_in_buffer = (size_t) sp->jpegtables_length; +} + +static void +TIFFjpeg_tables_src(JPEGState* sp, TIFF* tif) +{ + TIFFjpeg_data_src(sp, tif); + sp->src.init_source = tables_init_source; +} + +/* + * Allocate downsampled-data buffers needed for downsampled I/O. + * We use values computed in jpeg_start_compress or jpeg_start_decompress. + * We use libjpeg's allocator so that buffers will be released automatically + * when done with strip/tile. + * This is also a handy place to compute samplesperclump, bytesperline. + */ +static int +alloc_downsampled_buffers(TIFF* tif, jpeg_component_info* comp_info, + int num_components) +{ + JPEGState* sp = JState(tif); + int ci; + jpeg_component_info* compptr; + JSAMPARRAY buf; + int samples_per_clump = 0; + + for (ci = 0, compptr = comp_info; ci < num_components; + ci++, compptr++) { + samples_per_clump += compptr->h_samp_factor * + compptr->v_samp_factor; + buf = TIFFjpeg_alloc_sarray(sp, JPOOL_IMAGE, + compptr->width_in_blocks * DCTSIZE, + (JDIMENSION) (compptr->v_samp_factor*DCTSIZE)); + if (buf == NULL) + return (0); + sp->ds_buffer[ci] = buf; + } + sp->samplesperclump = samples_per_clump; + /* Cb,Cr both have sampling factors 1 */ + /* so downsampled width of Cb is # of clumps per line */ + sp->bytesperline = sizeof(JSAMPLE) * samples_per_clump * + comp_info[1].downsampled_width; + return (1); +} + + +/* + * JPEG Decoding. + */ + +static int +JPEGSetupDecode(TIFF* tif) +{ + JPEGState* sp = JState(tif); + TIFFDirectory *td = &tif->tif_dir; + + assert(sp != NULL); + assert(sp->cinfo.comm.is_decompressor); + + /* Read JPEGTables if it is present */ + if (TIFFFieldSet(tif,FIELD_JPEGTABLES)) { + TIFFjpeg_tables_src(sp, tif); + if(TIFFjpeg_read_header(sp,FALSE) != JPEG_HEADER_TABLES_ONLY) { + TIFFError("JPEGSetupDecode", "Bogus JPEGTables field"); + return (0); + } + } + + /* Grab parameters that are same for all strips/tiles */ + sp->photometric = td->td_photometric; + switch (sp->photometric) { + case PHOTOMETRIC_YCBCR: + sp->h_sampling = td->td_ycbcrsubsampling[0]; + sp->v_sampling = td->td_ycbcrsubsampling[1]; + break; + default: + /* TIFF 6.0 forbids subsampling of all other color spaces */ + sp->h_sampling = 1; + sp->v_sampling = 1; + break; + } + + /* Set up for reading normal data */ + TIFFjpeg_data_src(sp, tif); + tif->tif_postdecode = _TIFFNoPostDecode; /* override byte swapping */ + return (1); +} + +/* + * Set up for decoding a strip or tile. + */ +static int +JPEGPreDecode(TIFF* tif, tsample_t s) +{ + JPEGState *sp = JState(tif); + TIFFDirectory *td = &tif->tif_dir; + static char module[] = "JPEGPreDecode"; + uint32 segment_width, segment_height; + int downsampled_output; + int ci; + + assert(sp != NULL); + assert(sp->cinfo.comm.is_decompressor); + /* + * Reset decoder state from any previous strip/tile, + * in case application didn't read the whole strip. + */ + if (!TIFFjpeg_abort(sp)) + return (0); + /* + * Read the header for this strip/tile. + */ + if (TIFFjpeg_read_header(sp, TRUE) != JPEG_HEADER_OK) + return (0); + /* + * Check image parameters and set decompression parameters. + */ + if (isTiled(tif)) { + segment_width = td->td_tilewidth; + segment_height = td->td_tilelength; + sp->bytesperline = TIFFTileRowSize(tif); + } else { + segment_width = td->td_imagewidth; + segment_height = td->td_imagelength - tif->tif_row; + if (segment_height > td->td_rowsperstrip) + segment_height = td->td_rowsperstrip; + sp->bytesperline = TIFFScanlineSize(tif); + } + if (td->td_planarconfig == PLANARCONFIG_SEPARATE && s > 0) { + /* + * For PC 2, scale down the expected strip/tile size + * to match a downsampled component + */ + segment_width = TIFFhowmany(segment_width, sp->h_sampling); + segment_height = TIFFhowmany(segment_height, sp->v_sampling); + } + if (sp->cinfo.d.image_width != segment_width || + sp->cinfo.d.image_height != segment_height) { + TIFFError(module, "Improper JPEG strip/tile size"); + return (0); + } + if (sp->cinfo.d.num_components != + (td->td_planarconfig == PLANARCONFIG_CONTIG ? + td->td_samplesperpixel : 1)) { + TIFFError(module, "Improper JPEG component count"); + return (0); + } + if (sp->cinfo.d.data_precision != td->td_bitspersample) { + TIFFError(module, "Improper JPEG data precision"); + return (0); + } + if (td->td_planarconfig == PLANARCONFIG_CONTIG) { + /* Component 0 should have expected sampling factors */ + if (sp->cinfo.d.comp_info[0].h_samp_factor != sp->h_sampling || + sp->cinfo.d.comp_info[0].v_samp_factor != sp->v_sampling) { + TIFFError(module, "Improper JPEG sampling factors"); + return (0); + } + /* Rest should have sampling factors 1,1 */ + for (ci = 1; ci < sp->cinfo.d.num_components; ci++) { + if (sp->cinfo.d.comp_info[ci].h_samp_factor != 1 || + sp->cinfo.d.comp_info[ci].v_samp_factor != 1) { + TIFFError(module, "Improper JPEG sampling factors"); + return (0); + } + } + } else { + /* PC 2's single component should have sampling factors 1,1 */ + if (sp->cinfo.d.comp_info[0].h_samp_factor != 1 || + sp->cinfo.d.comp_info[0].v_samp_factor != 1) { + TIFFError(module, "Improper JPEG sampling factors"); + return (0); + } + } + downsampled_output = FALSE; + if (td->td_planarconfig == PLANARCONFIG_CONTIG && + sp->photometric == PHOTOMETRIC_YCBCR && + sp->jpegcolormode == JPEGCOLORMODE_RGB) { + /* Convert YCbCr to RGB */ + sp->cinfo.d.jpeg_color_space = JCS_YCbCr; + sp->cinfo.d.out_color_space = JCS_RGB; + } else { + /* Suppress colorspace handling */ + sp->cinfo.d.jpeg_color_space = JCS_UNKNOWN; + sp->cinfo.d.out_color_space = JCS_UNKNOWN; + if (td->td_planarconfig == PLANARCONFIG_CONTIG && + (sp->h_sampling != 1 || sp->v_sampling != 1)) + downsampled_output = TRUE; + /* XXX what about up-sampling? */ + } + if (downsampled_output) { + /* Need to use raw-data interface to libjpeg */ + sp->cinfo.d.raw_data_out = TRUE; + tif->tif_decoderow = JPEGDecodeRaw; + tif->tif_decodestrip = JPEGDecodeRaw; + tif->tif_decodetile = JPEGDecodeRaw; + } else { + /* Use normal interface to libjpeg */ + sp->cinfo.d.raw_data_out = FALSE; + tif->tif_decoderow = JPEGDecode; + tif->tif_decodestrip = JPEGDecode; + tif->tif_decodetile = JPEGDecode; + } + /* Start JPEG decompressor */ + if (!TIFFjpeg_start_decompress(sp)) + return (0); + /* Allocate downsampled-data buffers if needed */ + if (downsampled_output) { + if (!alloc_downsampled_buffers(tif, sp->cinfo.d.comp_info, + sp->cinfo.d.num_components)) + return (0); + sp->scancount = DCTSIZE; /* mark buffer empty */ + } + return (1); +} + +/* + * Decode a chunk of pixels. + * "Standard" case: returned data is not downsampled. + */ +static int +JPEGDecode(TIFF* tif, tidata_t buf, tsize_t cc, tsample_t s) +{ + JPEGState *sp = JState(tif); + tsize_t nrows; + JSAMPROW bufptr[1]; + + (void) s; + assert(sp != NULL); + /* data is expected to be read in multiples of a scanline */ + nrows = cc / sp->bytesperline; + if (cc % sp->bytesperline) + TIFFWarning(tif->tif_name, "fractional scanline not read"); + + while (nrows-- > 0) { + bufptr[0] = (JSAMPROW) buf; + if (TIFFjpeg_read_scanlines(sp, bufptr, 1) != 1) + return (0); + if (nrows > 0) + tif->tif_row++; + buf += sp->bytesperline; + } + /* Close down the decompressor if we've finished the strip or tile. */ + if (sp->cinfo.d.output_scanline == sp->cinfo.d.output_height) { + if (TIFFjpeg_finish_decompress(sp) != TRUE) + return (0); + } + return (1); +} + +/* + * Decode a chunk of pixels. + * Returned data is downsampled per sampling factors. + */ +static int +JPEGDecodeRaw(TIFF* tif, tidata_t buf, tsize_t cc, tsample_t s) +{ + JPEGState *sp = JState(tif); + JSAMPLE* inptr; + JSAMPLE* outptr; + tsize_t nrows; + JDIMENSION clumps_per_line, nclump; + int clumpoffset, ci, xpos, ypos; + jpeg_component_info* compptr; + int samples_per_clump = sp->samplesperclump; + + (void) s; + assert(sp != NULL); + /* data is expected to be read in multiples of a scanline */ + nrows = cc / sp->bytesperline; + if (cc % sp->bytesperline) + TIFFWarning(tif->tif_name, "fractional scanline not read"); + + /* Cb,Cr both have sampling factors 1, so this is correct */ + clumps_per_line = sp->cinfo.d.comp_info[1].downsampled_width; + + while (nrows-- > 0) { + /* Reload downsampled-data buffer if needed */ + if (sp->scancount >= DCTSIZE) { + int n = sp->cinfo.d.max_v_samp_factor * DCTSIZE; + if (TIFFjpeg_read_raw_data(sp, sp->ds_buffer, n) != n) + return (0); + sp->scancount = 0; + /* Close down the decompressor if done. */ + if (sp->cinfo.d.output_scanline >= + sp->cinfo.d.output_height) { + if (TIFFjpeg_finish_decompress(sp) != TRUE) + return (0); + } + } + /* + * Fastest way to unseparate the data is to make one pass + * over the scanline for each row of each component. + */ + clumpoffset = 0; /* first sample in clump */ + for (ci = 0, compptr = sp->cinfo.d.comp_info; + ci < sp->cinfo.d.num_components; + ci++, compptr++) { + int hsamp = compptr->h_samp_factor; + int vsamp = compptr->v_samp_factor; + for (ypos = 0; ypos < vsamp; ypos++) { + inptr = sp->ds_buffer[ci][sp->scancount*vsamp + ypos]; + outptr = ((JSAMPLE*) buf) + clumpoffset; + if (hsamp == 1) { + /* fast path for at least Cb and Cr */ + for (nclump = clumps_per_line; nclump-- > 0; ) { + outptr[0] = *inptr++; + outptr += samples_per_clump; + } + } else { + /* general case */ + for (nclump = clumps_per_line; nclump-- > 0; ) { + for (xpos = 0; xpos < hsamp; xpos++) + outptr[xpos] = *inptr++; + outptr += samples_per_clump; + } + } + clumpoffset += hsamp; + } + } + sp->scancount++; + if (nrows > 0) + tif->tif_row++; + buf += sp->bytesperline; + } + return (1); +} + + +/* + * JPEG Encoding. + */ + +static void +unsuppress_quant_table (JPEGState* sp, int tblno) +{ + JQUANT_TBL* qtbl; + + if ((qtbl = sp->cinfo.c.quant_tbl_ptrs[tblno]) != NULL) + qtbl->sent_table = FALSE; +} + +static void +unsuppress_huff_table (JPEGState* sp, int tblno) +{ + JHUFF_TBL* htbl; + + if ((htbl = sp->cinfo.c.dc_huff_tbl_ptrs[tblno]) != NULL) + htbl->sent_table = FALSE; + if ((htbl = sp->cinfo.c.ac_huff_tbl_ptrs[tblno]) != NULL) + htbl->sent_table = FALSE; +} + +static int +prepare_JPEGTables(TIFF* tif) +{ + JPEGState* sp = JState(tif); + + /* Initialize quant tables for current quality setting */ + if (!TIFFjpeg_set_quality(sp, sp->jpegquality, FALSE)) + return (0); + /* Mark only the tables we want for output */ + /* NB: chrominance tables are currently used only with YCbCr */ + if (!TIFFjpeg_suppress_tables(sp, TRUE)) + return (0); + if (sp->jpegtablesmode & JPEGTABLESMODE_QUANT) { + unsuppress_quant_table(sp, 0); + if (sp->photometric == PHOTOMETRIC_YCBCR) + unsuppress_quant_table(sp, 1); + } + if (sp->jpegtablesmode & JPEGTABLESMODE_HUFF) { + unsuppress_huff_table(sp, 0); + if (sp->photometric == PHOTOMETRIC_YCBCR) + unsuppress_huff_table(sp, 1); + } + /* Direct libjpeg output into jpegtables */ + if (!TIFFjpeg_tables_dest(sp, tif)) + return (0); + /* Emit tables-only datastream */ + if (!TIFFjpeg_write_tables(sp)) + return (0); + + return (1); +} + +static int +JPEGSetupEncode(TIFF* tif) +{ + JPEGState* sp = JState(tif); + TIFFDirectory *td = &tif->tif_dir; + static char module[] = "JPEGSetupEncode"; + + assert(sp != NULL); + assert(!sp->cinfo.comm.is_decompressor); + + /* + * Initialize all JPEG parameters to default values. + * Note that jpeg_set_defaults needs legal values for + * in_color_space and input_components. + */ + sp->cinfo.c.in_color_space = JCS_UNKNOWN; + sp->cinfo.c.input_components = 1; + if (!TIFFjpeg_set_defaults(sp)) + return (0); + /* Set per-file parameters */ + sp->photometric = td->td_photometric; + switch (sp->photometric) { + case PHOTOMETRIC_YCBCR: + sp->h_sampling = td->td_ycbcrsubsampling[0]; + sp->v_sampling = td->td_ycbcrsubsampling[1]; + /* + * A ReferenceBlackWhite field *must* be present since the + * default value is inappropriate for YCbCr. Fill in the + * proper value if application didn't set it. + */ +#ifdef COLORIMETRY_SUPPORT + if (!TIFFFieldSet(tif, FIELD_REFBLACKWHITE)) { + float refbw[6]; + long top = 1L << td->td_bitspersample; + refbw[0] = 0; + refbw[1] = (float)(top-1L); + refbw[2] = (float)(top>>1); + refbw[3] = refbw[1]; + refbw[4] = refbw[2]; + refbw[5] = refbw[1]; + TIFFSetField(tif, TIFFTAG_REFERENCEBLACKWHITE, refbw); + } +#endif + break; + case PHOTOMETRIC_PALETTE: /* disallowed by Tech Note */ + case PHOTOMETRIC_MASK: + TIFFError(module, + "PhotometricInterpretation %d not allowed for JPEG", + (int) sp->photometric); + return (0); + default: + /* TIFF 6.0 forbids subsampling of all other color spaces */ + sp->h_sampling = 1; + sp->v_sampling = 1; + break; + } + + /* Verify miscellaneous parameters */ + + /* + * This would need work if libtiff ever supports different + * depths for different components, or if libjpeg ever supports + * run-time selection of depth. Neither is imminent. + */ + if (td->td_bitspersample != BITS_IN_JSAMPLE) { + TIFFError(module, "BitsPerSample %d not allowed for JPEG", + (int) td->td_bitspersample); + return (0); + } + sp->cinfo.c.data_precision = td->td_bitspersample; + if (isTiled(tif)) { + if ((td->td_tilelength % (sp->v_sampling * DCTSIZE)) != 0) { + TIFFError(module, + "JPEG tile height must be multiple of %d", + sp->v_sampling * DCTSIZE); + return (0); + } + if ((td->td_tilewidth % (sp->h_sampling * DCTSIZE)) != 0) { + TIFFError(module, + "JPEG tile width must be multiple of %d", + sp->h_sampling * DCTSIZE); + return (0); + } + } else { + if (td->td_rowsperstrip < td->td_imagelength && + (td->td_rowsperstrip % (sp->v_sampling * DCTSIZE)) != 0) { + TIFFError(module, + "RowsPerStrip must be multiple of %d for JPEG", + sp->v_sampling * DCTSIZE); + return (0); + } + } + + /* Create a JPEGTables field if appropriate */ + if (sp->jpegtablesmode & (JPEGTABLESMODE_QUANT|JPEGTABLESMODE_HUFF)) { + if (!prepare_JPEGTables(tif)) + return (0); + /* Mark the field present */ + /* Can't use TIFFSetField since BEENWRITING is already set! */ + TIFFSetFieldBit(tif, FIELD_JPEGTABLES); + tif->tif_flags |= TIFF_DIRTYDIRECT; + } else { + /* We do not support application-supplied JPEGTables, */ + /* so mark the field not present */ + TIFFClrFieldBit(tif, FIELD_JPEGTABLES); + } + + /* Direct libjpeg output to libtiff's output buffer */ + TIFFjpeg_data_dest(sp, tif); + + return (1); +} + +/* + * Set encoding state at the start of a strip or tile. + */ +static int +JPEGPreEncode(TIFF* tif, tsample_t s) +{ + JPEGState *sp = JState(tif); + TIFFDirectory *td = &tif->tif_dir; + static char module[] = "JPEGPreEncode"; + uint32 segment_width, segment_height; + int downsampled_input; + + assert(sp != NULL); + assert(!sp->cinfo.comm.is_decompressor); + /* + * Set encoding parameters for this strip/tile. + */ + if (isTiled(tif)) { + segment_width = td->td_tilewidth; + segment_height = td->td_tilelength; + sp->bytesperline = TIFFTileRowSize(tif); + } else { + segment_width = td->td_imagewidth; + segment_height = td->td_imagelength - tif->tif_row; + if (segment_height > td->td_rowsperstrip) + segment_height = td->td_rowsperstrip; + sp->bytesperline = TIFFScanlineSize(tif); + } + if (td->td_planarconfig == PLANARCONFIG_SEPARATE && s > 0) { + /* for PC 2, scale down the strip/tile size + * to match a downsampled component + */ + segment_width = TIFFhowmany(segment_width, sp->h_sampling); + segment_height = TIFFhowmany(segment_height, sp->v_sampling); + } + if (segment_width > 65535 || segment_height > 65535) { + TIFFError(module, "Strip/tile too large for JPEG"); + return (0); + } + sp->cinfo.c.image_width = segment_width; + sp->cinfo.c.image_height = segment_height; + downsampled_input = FALSE; + if (td->td_planarconfig == PLANARCONFIG_CONTIG) { + sp->cinfo.c.input_components = td->td_samplesperpixel; + if (sp->photometric == PHOTOMETRIC_YCBCR) { + if (sp->jpegcolormode == JPEGCOLORMODE_RGB) { + sp->cinfo.c.in_color_space = JCS_RGB; + } else { + sp->cinfo.c.in_color_space = JCS_YCbCr; + if (sp->h_sampling != 1 || sp->v_sampling != 1) + downsampled_input = TRUE; + } + if (!TIFFjpeg_set_colorspace(sp, JCS_YCbCr)) + return (0); + /* + * Set Y sampling factors; + * we assume jpeg_set_colorspace() set the rest to 1 + */ + sp->cinfo.c.comp_info[0].h_samp_factor = sp->h_sampling; + sp->cinfo.c.comp_info[0].v_samp_factor = sp->v_sampling; + } else { + sp->cinfo.c.in_color_space = JCS_UNKNOWN; + if (!TIFFjpeg_set_colorspace(sp, JCS_UNKNOWN)) + return (0); + /* jpeg_set_colorspace set all sampling factors to 1 */ + } + } else { + sp->cinfo.c.input_components = 1; + sp->cinfo.c.in_color_space = JCS_UNKNOWN; + if (!TIFFjpeg_set_colorspace(sp, JCS_UNKNOWN)) + return (0); + sp->cinfo.c.comp_info[0].component_id = s; + /* jpeg_set_colorspace() set sampling factors to 1 */ + if (sp->photometric == PHOTOMETRIC_YCBCR && s > 0) { + sp->cinfo.c.comp_info[0].quant_tbl_no = 1; + sp->cinfo.c.comp_info[0].dc_tbl_no = 1; + sp->cinfo.c.comp_info[0].ac_tbl_no = 1; + } + } + /* ensure libjpeg won't write any extraneous markers */ + sp->cinfo.c.write_JFIF_header = FALSE; + sp->cinfo.c.write_Adobe_marker = FALSE; + /* set up table handling correctly */ + if (! (sp->jpegtablesmode & JPEGTABLESMODE_QUANT)) { + if (!TIFFjpeg_set_quality(sp, sp->jpegquality, FALSE)) + return (0); + unsuppress_quant_table(sp, 0); + unsuppress_quant_table(sp, 1); + } + if (sp->jpegtablesmode & JPEGTABLESMODE_HUFF) + sp->cinfo.c.optimize_coding = FALSE; + else + sp->cinfo.c.optimize_coding = TRUE; + if (downsampled_input) { + /* Need to use raw-data interface to libjpeg */ + sp->cinfo.c.raw_data_in = TRUE; + tif->tif_encoderow = JPEGEncodeRaw; + tif->tif_encodestrip = JPEGEncodeRaw; + tif->tif_encodetile = JPEGEncodeRaw; + } else { + /* Use normal interface to libjpeg */ + sp->cinfo.c.raw_data_in = FALSE; + tif->tif_encoderow = JPEGEncode; + tif->tif_encodestrip = JPEGEncode; + tif->tif_encodetile = JPEGEncode; + } + /* Start JPEG compressor */ + if (!TIFFjpeg_start_compress(sp, FALSE)) + return (0); + /* Allocate downsampled-data buffers if needed */ + if (downsampled_input) { + if (!alloc_downsampled_buffers(tif, sp->cinfo.c.comp_info, + sp->cinfo.c.num_components)) + return (0); + } + sp->scancount = 0; + + return (1); +} + +/* + * Encode a chunk of pixels. + * "Standard" case: incoming data is not downsampled. + */ +static int +JPEGEncode(TIFF* tif, tidata_t buf, tsize_t cc, tsample_t s) +{ + JPEGState *sp = JState(tif); + tsize_t nrows; + JSAMPROW bufptr[1]; + + (void) s; + assert(sp != NULL); + /* data is expected to be supplied in multiples of a scanline */ + nrows = cc / sp->bytesperline; + if (cc % sp->bytesperline) + TIFFWarning(tif->tif_name, "fractional scanline discarded"); + + while (nrows-- > 0) { + bufptr[0] = (JSAMPROW) buf; + if (TIFFjpeg_write_scanlines(sp, bufptr, 1) != 1) + return (0); + if (nrows > 0) + tif->tif_row++; + buf += sp->bytesperline; + } + return (1); +} + +/* + * Encode a chunk of pixels. + * Incoming data is expected to be downsampled per sampling factors. + */ +static int +JPEGEncodeRaw(TIFF* tif, tidata_t buf, tsize_t cc, tsample_t s) +{ + JPEGState *sp = JState(tif); + JSAMPLE* inptr; + JSAMPLE* outptr; + tsize_t nrows; + JDIMENSION clumps_per_line, nclump; + int clumpoffset, ci, xpos, ypos; + jpeg_component_info* compptr; + int samples_per_clump = sp->samplesperclump; + + (void) s; + assert(sp != NULL); + /* data is expected to be supplied in multiples of a scanline */ + nrows = cc / sp->bytesperline; + if (cc % sp->bytesperline) + TIFFWarning(tif->tif_name, "fractional scanline discarded"); + + /* Cb,Cr both have sampling factors 1, so this is correct */ + clumps_per_line = sp->cinfo.c.comp_info[1].downsampled_width; + + while (nrows-- > 0) { + /* + * Fastest way to separate the data is to make one pass + * over the scanline for each row of each component. + */ + clumpoffset = 0; /* first sample in clump */ + for (ci = 0, compptr = sp->cinfo.c.comp_info; + ci < sp->cinfo.c.num_components; + ci++, compptr++) { + int hsamp = compptr->h_samp_factor; + int vsamp = compptr->v_samp_factor; + int padding = (int) (compptr->width_in_blocks * DCTSIZE - + clumps_per_line * hsamp); + for (ypos = 0; ypos < vsamp; ypos++) { + inptr = ((JSAMPLE*) buf) + clumpoffset; + outptr = sp->ds_buffer[ci][sp->scancount*vsamp + ypos]; + if (hsamp == 1) { + /* fast path for at least Cb and Cr */ + for (nclump = clumps_per_line; nclump-- > 0; ) { + *outptr++ = inptr[0]; + inptr += samples_per_clump; + } + } else { + /* general case */ + for (nclump = clumps_per_line; nclump-- > 0; ) { + for (xpos = 0; xpos < hsamp; xpos++) + *outptr++ = inptr[xpos]; + inptr += samples_per_clump; + } + } + /* pad each scanline as needed */ + for (xpos = 0; xpos < padding; xpos++) { + *outptr = outptr[-1]; + outptr++; + } + clumpoffset += hsamp; + } + } + sp->scancount++; + if (sp->scancount >= DCTSIZE) { + int n = sp->cinfo.c.max_v_samp_factor * DCTSIZE; + if (TIFFjpeg_write_raw_data(sp, sp->ds_buffer, n) != n) + return (0); + sp->scancount = 0; + } + if (nrows > 0) + tif->tif_row++; + buf += sp->bytesperline; + } + return (1); +} + +/* + * Finish up at the end of a strip or tile. + */ +static int +JPEGPostEncode(TIFF* tif) +{ + JPEGState *sp = JState(tif); + + if (sp->scancount > 0) { + /* + * Need to emit a partial bufferload of downsampled data. + * Pad the data vertically. + */ + int ci, ypos, n; + jpeg_component_info* compptr; + + for (ci = 0, compptr = sp->cinfo.c.comp_info; + ci < sp->cinfo.c.num_components; + ci++, compptr++) { + int vsamp = compptr->v_samp_factor; + tsize_t row_width = compptr->width_in_blocks * DCTSIZE + * sizeof(JSAMPLE); + for (ypos = sp->scancount * vsamp; + ypos < DCTSIZE * vsamp; ypos++) { + _TIFFmemcpy((tdata_t)sp->ds_buffer[ci][ypos], + (tdata_t)sp->ds_buffer[ci][ypos-1], + row_width); + + } + } + n = sp->cinfo.c.max_v_samp_factor * DCTSIZE; + if (TIFFjpeg_write_raw_data(sp, sp->ds_buffer, n) != n) + return (0); + } + + return (TIFFjpeg_finish_compress(JState(tif))); +} + +static void +JPEGCleanup(TIFF* tif) +{ + if (tif->tif_data) { + JPEGState *sp = JState(tif); + TIFFjpeg_destroy(sp); /* release libjpeg resources */ + if (sp->jpegtables) /* tag value */ + _TIFFfree(sp->jpegtables); + _TIFFfree(tif->tif_data); /* release local state */ + tif->tif_data = NULL; + } +} + +static int +JPEGVSetField(TIFF* tif, ttag_t tag, va_list ap) +{ + JPEGState* sp = JState(tif); + TIFFDirectory* td = &tif->tif_dir; + uint32 v32; + + switch (tag) { + case TIFFTAG_JPEGTABLES: + v32 = va_arg(ap, uint32); + if (v32 == 0) { + /* XXX */ + return (0); + } + _TIFFsetByteArray(&sp->jpegtables, va_arg(ap, void*), + (long) v32); + sp->jpegtables_length = v32; + TIFFSetFieldBit(tif, FIELD_JPEGTABLES); + break; + case TIFFTAG_JPEGQUALITY: + sp->jpegquality = va_arg(ap, int); + return (1); /* pseudo tag */ + case TIFFTAG_JPEGCOLORMODE: + sp->jpegcolormode = va_arg(ap, int); + /* + * Mark whether returned data is up-sampled or not + * so TIFFStripSize and TIFFTileSize return values + * that reflect the true amount of data. + */ + tif->tif_flags &= ~TIFF_UPSAMPLED; + if (td->td_planarconfig == PLANARCONFIG_CONTIG) { + if (td->td_photometric == PHOTOMETRIC_YCBCR && + sp->jpegcolormode == JPEGCOLORMODE_RGB) { + tif->tif_flags |= TIFF_UPSAMPLED; + } else { + if (td->td_ycbcrsubsampling[0] != 1 || + td->td_ycbcrsubsampling[1] != 1) + ; /* XXX what about up-sampling? */ + } + } + /* + * Must recalculate cached tile size + * in case sampling state changed. + */ + tif->tif_tilesize = TIFFTileSize(tif); + return (1); /* pseudo tag */ + case TIFFTAG_JPEGTABLESMODE: + sp->jpegtablesmode = va_arg(ap, int); + return (1); /* pseudo tag */ + default: + return (*sp->vsetparent)(tif, tag, ap); + } + tif->tif_flags |= TIFF_DIRTYDIRECT; + return (1); +} + +static int +JPEGVGetField(TIFF* tif, ttag_t tag, va_list ap) +{ + JPEGState* sp = JState(tif); + + switch (tag) { + case TIFFTAG_JPEGTABLES: + /* u_short is bogus --- should be uint32 ??? */ + /* TIFFWriteNormalTag needs fixed XXX */ + *va_arg(ap, u_short*) = (u_short) sp->jpegtables_length; + *va_arg(ap, void**) = sp->jpegtables; + break; + case TIFFTAG_JPEGQUALITY: + *va_arg(ap, int*) = sp->jpegquality; + break; + case TIFFTAG_JPEGCOLORMODE: + *va_arg(ap, int*) = sp->jpegcolormode; + break; + case TIFFTAG_JPEGTABLESMODE: + *va_arg(ap, int*) = sp->jpegtablesmode; + break; + default: + return (*sp->vgetparent)(tif, tag, ap); + } + return (1); +} + +static void +JPEGPrintDir(TIFF* tif, FILE* fd, long flags) +{ + JPEGState* sp = JState(tif); + + (void) flags; + if (TIFFFieldSet(tif,FIELD_JPEGTABLES)) + fprintf(fd, " JPEG Tables: (%lu bytes)\n", + (u_long) sp->jpegtables_length); +} + +static uint32 +JPEGDefaultStripSize(TIFF* tif, uint32 s) +{ + JPEGState* sp = JState(tif); + TIFFDirectory *td = &tif->tif_dir; + + s = (*sp->defsparent)(tif, s); + if (s < td->td_imagelength) + s = TIFFroundup(s, td->td_ycbcrsubsampling[1] * DCTSIZE); + return (s); +} + +static void +JPEGDefaultTileSize(TIFF* tif, uint32* tw, uint32* th) +{ + JPEGState* sp = JState(tif); + TIFFDirectory *td = &tif->tif_dir; + + (*sp->deftparent)(tif, tw, th); + *tw = TIFFroundup(*tw, td->td_ycbcrsubsampling[0] * DCTSIZE); + *th = TIFFroundup(*th, td->td_ycbcrsubsampling[1] * DCTSIZE); +} + +int +TIFFInitJPEG(TIFF* tif, int scheme) +{ + JPEGState* sp; + + assert(scheme == COMPRESSION_JPEG); + + /* + * Allocate state block so tag methods have storage to record values. + */ + tif->tif_data = (tidata_t) _TIFFmalloc(sizeof (JPEGState)); + if (tif->tif_data == NULL) { + TIFFError("TIFFInitJPEG", "No space for JPEG state block"); + return (0); + } + sp = JState(tif); + sp->tif = tif; /* back link */ + + /* + * Merge codec-specific tag information and + * override parent get/set field methods. + */ + _TIFFMergeFieldInfo(tif, jpegFieldInfo, N(jpegFieldInfo)); + sp->vgetparent = tif->tif_vgetfield; + tif->tif_vgetfield = JPEGVGetField; /* hook for codec tags */ + sp->vsetparent = tif->tif_vsetfield; + tif->tif_vsetfield = JPEGVSetField; /* hook for codec tags */ + tif->tif_printdir = JPEGPrintDir; /* hook for codec tags */ + + /* Default values for codec-specific fields */ + sp->jpegtables = NULL; + sp->jpegtables_length = 0; + sp->jpegquality = 75; /* Default IJG quality */ + sp->jpegcolormode = JPEGCOLORMODE_RAW; + sp->jpegtablesmode = JPEGTABLESMODE_QUANT | JPEGTABLESMODE_HUFF; + + /* + * Install codec methods. + */ + tif->tif_setupdecode = JPEGSetupDecode; + tif->tif_predecode = JPEGPreDecode; + tif->tif_decoderow = JPEGDecode; + tif->tif_decodestrip = JPEGDecode; + tif->tif_decodetile = JPEGDecode; + tif->tif_setupencode = JPEGSetupEncode; + tif->tif_preencode = JPEGPreEncode; + tif->tif_postencode = JPEGPostEncode; + tif->tif_encoderow = JPEGEncode; + tif->tif_encodestrip = JPEGEncode; + tif->tif_encodetile = JPEGEncode; + tif->tif_cleanup = JPEGCleanup; + sp->defsparent = tif->tif_defstripsize; + tif->tif_defstripsize = JPEGDefaultStripSize; + sp->deftparent = tif->tif_deftilesize; + tif->tif_deftilesize = JPEGDefaultTileSize; + tif->tif_flags |= TIFF_NOBITREV; /* no bit reversal, please */ + + /* + * Initialize libjpeg. + */ + if (tif->tif_mode == O_RDONLY) { + if (!TIFFjpeg_create_decompress(sp)) + return (0); + } else { + if (!TIFFjpeg_create_compress(sp)) + return (0); + } + + return (1); +} +#endif /* JPEG_SUPPORT */ |