| /* $Id: tif_ojpeg.c,v 1.69 2017-04-27 17:29:26 erouault Exp $ */ |
| |
| /* WARNING: The type of JPEG encapsulation defined by the TIFF Version 6.0 |
| specification is now totally obsolete and deprecated for new applications and |
| images. This file was was created solely in order to read unconverted images |
| still present on some users' computer systems. It will never be extended |
| to write such files. Writing new-style JPEG compressed TIFFs is implemented |
| in tif_jpeg.c. |
| |
| The code is carefully crafted to robustly read all gathered JPEG-in-TIFF |
| testfiles, and anticipate as much as possible all other... But still, it may |
| fail on some. If you encounter problems, please report them on the TIFF |
| mailing list and/or to Joris Van Damme <info@awaresystems.be>. |
| |
| Please read the file called "TIFF Technical Note #2" if you need to be |
| convinced this compression scheme is bad and breaks TIFF. That document |
| is linked to from the LibTiff site <http://www.remotesensing.org/libtiff/> |
| and from AWare Systems' TIFF section |
| <http://www.awaresystems.be/imaging/tiff.html>. It is also absorbed |
| in Adobe's specification supplements, marked "draft" up to this day, but |
| supported by the TIFF community. |
| |
| This file interfaces with Release 6B of the JPEG Library written by the |
| Independent JPEG Group. Previous versions of this file required a hack inside |
| the LibJpeg library. This version no longer requires that. Remember to |
| remove the hack if you update from the old version. |
| |
| Copyright (c) Joris Van Damme <info@awaresystems.be> |
| Copyright (c) AWare Systems <http://www.awaresystems.be/> |
| |
| The licence agreement for this file is the same as the rest of the LibTiff |
| library. |
| |
| IN NO EVENT SHALL JORIS VAN DAMME OR AWARE SYSTEMS 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. |
| |
| Joris Van Damme and/or AWare Systems may be available for custom |
| development. If you like what you see, and need anything similar or related, |
| contact <info@awaresystems.be>. |
| */ |
| |
| /* What is what, and what is not? |
| |
| This decoder starts with an input stream, that is essentially the JpegInterchangeFormat |
| stream, if any, followed by the strile data, if any. This stream is read in |
| OJPEGReadByte and related functions. |
| |
| It analyzes the start of this stream, until it encounters non-marker data, i.e. |
| compressed image data. Some of the header markers it sees have no actual content, |
| like the SOI marker, and APP/COM markers that really shouldn't even be there. Some |
| other markers do have content, and the valuable bits and pieces of information |
| in these markers are saved, checking all to verify that the stream is more or |
| less within expected bounds. This happens inside the OJPEGReadHeaderInfoSecStreamXxx |
| functions. |
| |
| Some OJPEG imagery contains no valid JPEG header markers. This situation is picked |
| up on if we've seen no SOF marker when we're at the start of the compressed image |
| data. In this case, the tables are read from JpegXxxTables tags, and the other |
| bits and pieces of information is initialized to its most basic value. This is |
| implemented in the OJPEGReadHeaderInfoSecTablesXxx functions. |
| |
| When this is complete, a good and valid JPEG header can be assembled, and this is |
| passed through to LibJpeg. When that's done, the remainder of the input stream, i.e. |
| the compressed image data, can be passed through unchanged. This is done in |
| OJPEGWriteStream functions. |
| |
| LibTiff rightly expects to know the subsampling values before decompression. Just like |
| in new-style JPEG-in-TIFF, though, or even more so, actually, the YCbCrsubsampling |
| tag is notoriously unreliable. To correct these tag values with the ones inside |
| the JPEG stream, the first part of the input stream is pre-scanned in |
| OJPEGSubsamplingCorrect, making no note of any other data, reporting no warnings |
| or errors, up to the point where either these values are read, or it's clear they |
| aren't there. This means that some of the data is read twice, but we feel speed |
| in correcting these values is important enough to warrant this sacrifice. Although |
| there is currently no define or other configuration mechanism to disable this behaviour, |
| the actual header scanning is build to robustly respond with error report if it |
| should encounter an uncorrected mismatch of subsampling values. See |
| OJPEGReadHeaderInfoSecStreamSof. |
| |
| The restart interval and restart markers are the most tricky part... The restart |
| interval can be specified in a tag. It can also be set inside the input JPEG stream. |
| It can be used inside the input JPEG stream. If reading from strile data, we've |
| consistently discovered the need to insert restart markers in between the different |
| striles, as is also probably the most likely interpretation of the original TIFF 6.0 |
| specification. With all this setting of interval, and actual use of markers that is not |
| predictable at the time of valid JPEG header assembly, the restart thing may turn |
| out the Achilles heel of this implementation. Fortunately, most OJPEG writer vendors |
| succeed in reading back what they write, which may be the reason why we've been able |
| to discover ways that seem to work. |
| |
| Some special provision is made for planarconfig separate OJPEG files. These seem |
| to consistently contain header info, a SOS marker, a plane, SOS marker, plane, SOS, |
| and plane. This may or may not be a valid JPEG configuration, we don't know and don't |
| care. We want LibTiff to be able to access the planes individually, without huge |
| buffering inside LibJpeg, anyway. So we compose headers to feed to LibJpeg, in this |
| case, that allow us to pass a single plane such that LibJpeg sees a valid |
| single-channel JPEG stream. Locating subsequent SOS markers, and thus subsequent |
| planes, is done inside OJPEGReadSecondarySos. |
| |
| The benefit of the scheme is... that it works, basically. We know of no other that |
| does. It works without checking software tag, or otherwise going about things in an |
| OJPEG flavor specific manner. Instead, it is a single scheme, that covers the cases |
| with and without JpegInterchangeFormat, with and without striles, with part of |
| the header in JpegInterchangeFormat and remainder in first strile, etc. It is forgiving |
| and robust, may likely work with OJPEG flavors we've not seen yet, and makes most out |
| of the data. |
| |
| Another nice side-effect is that a complete JPEG single valid stream is build if |
| planarconfig is not separate (vast majority). We may one day use that to build |
| converters to JPEG, and/or to new-style JPEG compression inside TIFF. |
| |
| A disadvantage is the lack of random access to the individual striles. This is the |
| reason for much of the complicated restart-and-position stuff inside OJPEGPreDecode. |
| Applications would do well accessing all striles in order, as this will result in |
| a single sequential scan of the input stream, and no restarting of LibJpeg decoding |
| session. |
| */ |
| |
| #define WIN32_LEAN_AND_MEAN |
| #define VC_EXTRALEAN |
| |
| #include "tiffiop.h" |
| #ifdef OJPEG_SUPPORT |
| |
| /* Configuration defines here are: |
| * JPEG_ENCAP_EXTERNAL: The normal way to call libjpeg, uses longjump. In some environments, |
| * like eg LibTiffDelphi, this is not possible. For this reason, the actual calls to |
| * libjpeg, with longjump stuff, are encapsulated in dedicated functions. When |
| * JPEG_ENCAP_EXTERNAL is defined, these encapsulating functions are declared external |
| * to this unit, and can be defined elsewhere to use stuff other then longjump. |
| * The default mode, without JPEG_ENCAP_EXTERNAL, implements the call encapsulators |
| * here, internally, with normal longjump. |
| * SETJMP, LONGJMP, JMP_BUF: On some machines/environments a longjump equivalent is |
| * conveniently available, but still it may be worthwhile to use _setjmp or sigsetjmp |
| * in place of plain setjmp. These macros will make it easier. It is useless |
| * to fiddle with these if you define JPEG_ENCAP_EXTERNAL. |
| * OJPEG_BUFFER: Define the size of the desired buffer here. Should be small enough so as to guarantee |
| * instant processing, optimal streaming and optimal use of processor cache, but also big |
| * enough so as to not result in significant call overhead. It should be at least a few |
| * bytes to accommodate some structures (this is verified in asserts), but it would not be |
| * sensible to make it this small anyway, and it should be at most 64K since it is indexed |
| * with uint16. We recommend 2K. |
| * EGYPTIANWALK: You could also define EGYPTIANWALK here, but it is not used anywhere and has |
| * absolutely no effect. That is why most people insist the EGYPTIANWALK is a bit silly. |
| */ |
| |
| /* define LIBJPEG_ENCAP_EXTERNAL */ |
| #define SETJMP(jbuf) setjmp(jbuf) |
| #define LONGJMP(jbuf,code) longjmp(jbuf,code) |
| #define JMP_BUF jmp_buf |
| #define OJPEG_BUFFER 2048 |
| /* define EGYPTIANWALK */ |
| |
| #define JPEG_MARKER_SOF0 0xC0 |
| #define JPEG_MARKER_SOF1 0xC1 |
| #define JPEG_MARKER_SOF3 0xC3 |
| #define JPEG_MARKER_DHT 0xC4 |
| #define JPEG_MARKER_RST0 0XD0 |
| #define JPEG_MARKER_SOI 0xD8 |
| #define JPEG_MARKER_EOI 0xD9 |
| #define JPEG_MARKER_SOS 0xDA |
| #define JPEG_MARKER_DQT 0xDB |
| #define JPEG_MARKER_DRI 0xDD |
| #define JPEG_MARKER_APP0 0xE0 |
| #define JPEG_MARKER_COM 0xFE |
| |
| #define FIELD_OJPEG_JPEGINTERCHANGEFORMAT (FIELD_CODEC+0) |
| #define FIELD_OJPEG_JPEGINTERCHANGEFORMATLENGTH (FIELD_CODEC+1) |
| #define FIELD_OJPEG_JPEGQTABLES (FIELD_CODEC+2) |
| #define FIELD_OJPEG_JPEGDCTABLES (FIELD_CODEC+3) |
| #define FIELD_OJPEG_JPEGACTABLES (FIELD_CODEC+4) |
| #define FIELD_OJPEG_JPEGPROC (FIELD_CODEC+5) |
| #define FIELD_OJPEG_JPEGRESTARTINTERVAL (FIELD_CODEC+6) |
| |
| static const TIFFField ojpegFields[] = { |
| {TIFFTAG_JPEGIFOFFSET,1,1,TIFF_LONG8,0,TIFF_SETGET_UINT64,TIFF_SETGET_UNDEFINED,FIELD_OJPEG_JPEGINTERCHANGEFORMAT,TRUE,FALSE,"JpegInterchangeFormat",NULL}, |
| {TIFFTAG_JPEGIFBYTECOUNT,1,1,TIFF_LONG8,0,TIFF_SETGET_UINT64,TIFF_SETGET_UNDEFINED,FIELD_OJPEG_JPEGINTERCHANGEFORMATLENGTH,TRUE,FALSE,"JpegInterchangeFormatLength",NULL}, |
| {TIFFTAG_JPEGQTABLES,TIFF_VARIABLE2,TIFF_VARIABLE2,TIFF_LONG8,0,TIFF_SETGET_C32_UINT64,TIFF_SETGET_UNDEFINED,FIELD_OJPEG_JPEGQTABLES,FALSE,TRUE,"JpegQTables",NULL}, |
| {TIFFTAG_JPEGDCTABLES,TIFF_VARIABLE2,TIFF_VARIABLE2,TIFF_LONG8,0,TIFF_SETGET_C32_UINT64,TIFF_SETGET_UNDEFINED,FIELD_OJPEG_JPEGDCTABLES,FALSE,TRUE,"JpegDcTables",NULL}, |
| {TIFFTAG_JPEGACTABLES,TIFF_VARIABLE2,TIFF_VARIABLE2,TIFF_LONG8,0,TIFF_SETGET_C32_UINT64,TIFF_SETGET_UNDEFINED,FIELD_OJPEG_JPEGACTABLES,FALSE,TRUE,"JpegAcTables",NULL}, |
| {TIFFTAG_JPEGPROC,1,1,TIFF_SHORT,0,TIFF_SETGET_UINT16,TIFF_SETGET_UNDEFINED,FIELD_OJPEG_JPEGPROC,FALSE,FALSE,"JpegProc",NULL}, |
| {TIFFTAG_JPEGRESTARTINTERVAL,1,1,TIFF_SHORT,0,TIFF_SETGET_UINT16,TIFF_SETGET_UNDEFINED,FIELD_OJPEG_JPEGRESTARTINTERVAL,FALSE,FALSE,"JpegRestartInterval",NULL}, |
| }; |
| |
| #ifndef LIBJPEG_ENCAP_EXTERNAL |
| #include <setjmp.h> |
| #endif |
| |
| /* We undefine FAR to avoid conflict with JPEG definition */ |
| |
| #ifdef FAR |
| #undef FAR |
| #endif |
| |
| /* |
| Libjpeg's jmorecfg.h defines INT16 and INT32, but only if XMD_H is |
| not defined. Unfortunately, the MinGW and Borland compilers include |
| a typedef for INT32, which causes a conflict. MSVC does not include |
| a conflicting typedef given the headers which are included. |
| */ |
| #if defined(__BORLANDC__) || defined(__MINGW32__) |
| # define XMD_H 1 |
| #endif |
| |
| /* Define "boolean" as unsigned char, not int, per Windows custom. */ |
| #if defined(__WIN32__) && !defined(__MINGW32__) |
| # ifndef __RPCNDR_H__ /* don't conflict if rpcndr.h already read */ |
| typedef unsigned char boolean; |
| # endif |
| # define HAVE_BOOLEAN /* prevent jmorecfg.h from redefining it */ |
| #endif |
| |
| #if defined(USE_SYSTEM_LIBJPEG) |
| #include <jerror.h> |
| #include <jpeglib.h> |
| #elif defined(USE_LIBJPEG_TURBO) |
| #include "third_party/libjpeg_turbo/jerror.h" |
| #include "third_party/libjpeg_turbo/jpeglib.h" |
| #else |
| #include "third_party/libjpeg/jerror.h" |
| #include "third_party/libjpeg/jpeglib.h" |
| #endif |
| |
| |
| typedef struct jpeg_error_mgr jpeg_error_mgr; |
| typedef struct jpeg_common_struct jpeg_common_struct; |
| typedef struct jpeg_decompress_struct jpeg_decompress_struct; |
| typedef struct jpeg_source_mgr jpeg_source_mgr; |
| |
| typedef enum { |
| osibsNotSetYet, |
| osibsJpegInterchangeFormat, |
| osibsStrile, |
| osibsEof |
| } OJPEGStateInBufferSource; |
| |
| typedef enum { |
| ososSoi, |
| ososQTable0,ososQTable1,ososQTable2,ososQTable3, |
| ososDcTable0,ososDcTable1,ososDcTable2,ososDcTable3, |
| ososAcTable0,ososAcTable1,ososAcTable2,ososAcTable3, |
| ososDri, |
| ososSof, |
| ososSos, |
| ososCompressed, |
| ososRst, |
| ososEoi |
| } OJPEGStateOutState; |
| |
| typedef struct { |
| TIFF* tif; |
| int decoder_ok; |
| #ifndef LIBJPEG_ENCAP_EXTERNAL |
| JMP_BUF exit_jmpbuf; |
| #endif |
| TIFFVGetMethod vgetparent; |
| TIFFVSetMethod vsetparent; |
| TIFFPrintMethod printdir; |
| uint64 file_size; |
| uint32 image_width; |
| uint32 image_length; |
| uint32 strile_width; |
| uint32 strile_length; |
| uint32 strile_length_total; |
| uint8 samples_per_pixel; |
| uint8 plane_sample_offset; |
| uint8 samples_per_pixel_per_plane; |
| uint64 jpeg_interchange_format; |
| uint64 jpeg_interchange_format_length; |
| uint8 jpeg_proc; |
| uint8 subsamplingcorrect; |
| uint8 subsamplingcorrect_done; |
| uint8 subsampling_tag; |
| uint8 subsampling_hor; |
| uint8 subsampling_ver; |
| uint8 subsampling_force_desubsampling_inside_decompression; |
| uint8 qtable_offset_count; |
| uint8 dctable_offset_count; |
| uint8 actable_offset_count; |
| uint64 qtable_offset[3]; |
| uint64 dctable_offset[3]; |
| uint64 actable_offset[3]; |
| uint8* qtable[4]; |
| uint8* dctable[4]; |
| uint8* actable[4]; |
| uint16 restart_interval; |
| uint8 restart_index; |
| uint8 sof_log; |
| uint8 sof_marker_id; |
| uint32 sof_x; |
| uint32 sof_y; |
| uint8 sof_c[3]; |
| uint8 sof_hv[3]; |
| uint8 sof_tq[3]; |
| uint8 sos_cs[3]; |
| uint8 sos_tda[3]; |
| struct { |
| uint8 log; |
| OJPEGStateInBufferSource in_buffer_source; |
| uint32 in_buffer_next_strile; |
| uint64 in_buffer_file_pos; |
| uint64 in_buffer_file_togo; |
| } sos_end[3]; |
| uint8 readheader_done; |
| uint8 writeheader_done; |
| uint16 write_cursample; |
| uint32 write_curstrile; |
| uint8 libjpeg_session_active; |
| uint8 libjpeg_jpeg_query_style; |
| jpeg_error_mgr libjpeg_jpeg_error_mgr; |
| jpeg_decompress_struct libjpeg_jpeg_decompress_struct; |
| jpeg_source_mgr libjpeg_jpeg_source_mgr; |
| uint8 subsampling_convert_log; |
| uint32 subsampling_convert_ylinelen; |
| uint32 subsampling_convert_ylines; |
| uint32 subsampling_convert_clinelen; |
| uint32 subsampling_convert_clines; |
| uint32 subsampling_convert_ybuflen; |
| uint32 subsampling_convert_cbuflen; |
| uint32 subsampling_convert_ycbcrbuflen; |
| uint8* subsampling_convert_ycbcrbuf; |
| uint8* subsampling_convert_ybuf; |
| uint8* subsampling_convert_cbbuf; |
| uint8* subsampling_convert_crbuf; |
| uint32 subsampling_convert_ycbcrimagelen; |
| uint8** subsampling_convert_ycbcrimage; |
| uint32 subsampling_convert_clinelenout; |
| uint32 subsampling_convert_state; |
| uint32 bytes_per_line; /* if the codec outputs subsampled data, a 'line' in bytes_per_line */ |
| uint32 lines_per_strile; /* and lines_per_strile means subsampling_ver desubsampled rows */ |
| OJPEGStateInBufferSource in_buffer_source; |
| uint32 in_buffer_next_strile; |
| uint32 in_buffer_strile_count; |
| uint64 in_buffer_file_pos; |
| uint8 in_buffer_file_pos_log; |
| uint64 in_buffer_file_togo; |
| uint16 in_buffer_togo; |
| uint8* in_buffer_cur; |
| uint8 in_buffer[OJPEG_BUFFER]; |
| OJPEGStateOutState out_state; |
| uint8 out_buffer[OJPEG_BUFFER]; |
| uint8* skip_buffer; |
| } OJPEGState; |
| |
| static int OJPEGVGetField(TIFF* tif, uint32 tag, va_list ap); |
| static int OJPEGVSetField(TIFF* tif, uint32 tag, va_list ap); |
| static void OJPEGPrintDir(TIFF* tif, FILE* fd, long flags); |
| |
| static int OJPEGFixupTags(TIFF* tif); |
| static int OJPEGSetupDecode(TIFF* tif); |
| static int OJPEGPreDecode(TIFF* tif, uint16 s); |
| static int OJPEGPreDecodeSkipRaw(TIFF* tif); |
| static int OJPEGPreDecodeSkipScanlines(TIFF* tif); |
| static int OJPEGDecode(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s); |
| static int OJPEGDecodeRaw(TIFF* tif, uint8* buf, tmsize_t cc); |
| static int OJPEGDecodeScanlines(TIFF* tif, uint8* buf, tmsize_t cc); |
| static void OJPEGPostDecode(TIFF* tif, uint8* buf, tmsize_t cc); |
| static int OJPEGSetupEncode(TIFF* tif); |
| static int OJPEGPreEncode(TIFF* tif, uint16 s); |
| static int OJPEGEncode(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s); |
| static int OJPEGPostEncode(TIFF* tif); |
| static void OJPEGCleanup(TIFF* tif); |
| |
| static void OJPEGSubsamplingCorrect(TIFF* tif); |
| static int OJPEGReadHeaderInfo(TIFF* tif); |
| static int OJPEGReadSecondarySos(TIFF* tif, uint16 s); |
| static int OJPEGWriteHeaderInfo(TIFF* tif); |
| static void OJPEGLibjpegSessionAbort(TIFF* tif); |
| |
| static int OJPEGReadHeaderInfoSec(TIFF* tif); |
| static int OJPEGReadHeaderInfoSecStreamDri(TIFF* tif); |
| static int OJPEGReadHeaderInfoSecStreamDqt(TIFF* tif); |
| static int OJPEGReadHeaderInfoSecStreamDht(TIFF* tif); |
| static int OJPEGReadHeaderInfoSecStreamSof(TIFF* tif, uint8 marker_id); |
| static int OJPEGReadHeaderInfoSecStreamSos(TIFF* tif); |
| static int OJPEGReadHeaderInfoSecTablesQTable(TIFF* tif); |
| static int OJPEGReadHeaderInfoSecTablesDcTable(TIFF* tif); |
| static int OJPEGReadHeaderInfoSecTablesAcTable(TIFF* tif); |
| |
| static int OJPEGReadBufferFill(OJPEGState* sp); |
| static int OJPEGReadByte(OJPEGState* sp, uint8* byte); |
| static int OJPEGReadBytePeek(OJPEGState* sp, uint8* byte); |
| static void OJPEGReadByteAdvance(OJPEGState* sp); |
| static int OJPEGReadWord(OJPEGState* sp, uint16* word); |
| static int OJPEGReadBlock(OJPEGState* sp, uint16 len, void* mem); |
| static void OJPEGReadSkip(OJPEGState* sp, uint16 len); |
| |
| static int OJPEGWriteStream(TIFF* tif, void** mem, uint32* len); |
| static void OJPEGWriteStreamSoi(TIFF* tif, void** mem, uint32* len); |
| static void OJPEGWriteStreamQTable(TIFF* tif, uint8 table_index, void** mem, uint32* len); |
| static void OJPEGWriteStreamDcTable(TIFF* tif, uint8 table_index, void** mem, uint32* len); |
| static void OJPEGWriteStreamAcTable(TIFF* tif, uint8 table_index, void** mem, uint32* len); |
| static void OJPEGWriteStreamDri(TIFF* tif, void** mem, uint32* len); |
| static void OJPEGWriteStreamSof(TIFF* tif, void** mem, uint32* len); |
| static void OJPEGWriteStreamSos(TIFF* tif, void** mem, uint32* len); |
| static int OJPEGWriteStreamCompressed(TIFF* tif, void** mem, uint32* len); |
| static void OJPEGWriteStreamRst(TIFF* tif, void** mem, uint32* len); |
| static void OJPEGWriteStreamEoi(TIFF* tif, void** mem, uint32* len); |
| |
| #ifdef LIBJPEG_ENCAP_EXTERNAL |
| extern int jpeg_create_decompress_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo); |
| extern int jpeg_read_header_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo, uint8 require_image); |
| extern int jpeg_start_decompress_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo); |
| extern int jpeg_read_scanlines_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo, void* scanlines, uint32 max_lines); |
| extern int jpeg_read_raw_data_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo, void* data, uint32 max_lines); |
| extern void jpeg_encap_unwind(TIFF* tif); |
| #else |
| static int jpeg_create_decompress_encap(OJPEGState* sp, jpeg_decompress_struct* j); |
| static int jpeg_read_header_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo, uint8 require_image); |
| static int jpeg_start_decompress_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo); |
| static int jpeg_read_scanlines_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo, void* scanlines, uint32 max_lines); |
| static int jpeg_read_raw_data_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo, void* data, uint32 max_lines); |
| static void jpeg_encap_unwind(TIFF* tif); |
| #endif |
| |
| static void OJPEGLibjpegJpegErrorMgrOutputMessage(jpeg_common_struct* cinfo); |
| static void OJPEGLibjpegJpegErrorMgrErrorExit(jpeg_common_struct* cinfo); |
| static void OJPEGLibjpegJpegSourceMgrInitSource(jpeg_decompress_struct* cinfo); |
| static boolean OJPEGLibjpegJpegSourceMgrFillInputBuffer(jpeg_decompress_struct* cinfo); |
| static void OJPEGLibjpegJpegSourceMgrSkipInputData(jpeg_decompress_struct* cinfo, long num_bytes); |
| static boolean OJPEGLibjpegJpegSourceMgrResyncToRestart(jpeg_decompress_struct* cinfo, int desired); |
| static void OJPEGLibjpegJpegSourceMgrTermSource(jpeg_decompress_struct* cinfo); |
| |
| int |
| TIFFInitOJPEG(TIFF* tif, int scheme) |
| { |
| static const char module[]="TIFFInitOJPEG"; |
| OJPEGState* sp; |
| |
| assert(scheme==COMPRESSION_OJPEG); |
| |
| /* |
| * Merge codec-specific tag information. |
| */ |
| if (!_TIFFMergeFields(tif, ojpegFields, TIFFArrayCount(ojpegFields))) { |
| TIFFErrorExt(tif->tif_clientdata, module, |
| "Merging Old JPEG codec-specific tags failed"); |
| return 0; |
| } |
| |
| /* state block */ |
| sp=_TIFFmalloc(sizeof(OJPEGState)); |
| if (sp==NULL) |
| { |
| TIFFErrorExt(tif->tif_clientdata,module,"No space for OJPEG state block"); |
| return(0); |
| } |
| _TIFFmemset(sp,0,sizeof(OJPEGState)); |
| sp->tif=tif; |
| sp->jpeg_proc=1; |
| sp->subsampling_hor=2; |
| sp->subsampling_ver=2; |
| TIFFSetField(tif,TIFFTAG_YCBCRSUBSAMPLING,2,2); |
| /* tif codec methods */ |
| tif->tif_fixuptags=OJPEGFixupTags; |
| tif->tif_setupdecode=OJPEGSetupDecode; |
| tif->tif_predecode=OJPEGPreDecode; |
| tif->tif_postdecode=OJPEGPostDecode; |
| tif->tif_decoderow=OJPEGDecode; |
| tif->tif_decodestrip=OJPEGDecode; |
| tif->tif_decodetile=OJPEGDecode; |
| tif->tif_setupencode=OJPEGSetupEncode; |
| tif->tif_preencode=OJPEGPreEncode; |
| tif->tif_postencode=OJPEGPostEncode; |
| tif->tif_encoderow=OJPEGEncode; |
| tif->tif_encodestrip=OJPEGEncode; |
| tif->tif_encodetile=OJPEGEncode; |
| tif->tif_cleanup=OJPEGCleanup; |
| tif->tif_data=(uint8*)sp; |
| /* tif tag methods */ |
| sp->vgetparent=tif->tif_tagmethods.vgetfield; |
| tif->tif_tagmethods.vgetfield=OJPEGVGetField; |
| sp->vsetparent=tif->tif_tagmethods.vsetfield; |
| tif->tif_tagmethods.vsetfield=OJPEGVSetField; |
| sp->printdir=tif->tif_tagmethods.printdir; |
| tif->tif_tagmethods.printdir=OJPEGPrintDir; |
| /* Some OJPEG files don't have strip or tile offsets or bytecounts tags. |
| Some others do, but have totally meaningless or corrupt values |
| in these tags. In these cases, the JpegInterchangeFormat stream is |
| reliable. In any case, this decoder reads the compressed data itself, |
| from the most reliable locations, and we need to notify encapsulating |
| LibTiff not to read raw strips or tiles for us. */ |
| tif->tif_flags|=TIFF_NOREADRAW; |
| return(1); |
| } |
| |
| static int |
| OJPEGVGetField(TIFF* tif, uint32 tag, va_list ap) |
| { |
| OJPEGState* sp=(OJPEGState*)tif->tif_data; |
| switch(tag) |
| { |
| case TIFFTAG_JPEGIFOFFSET: |
| *va_arg(ap,uint64*)=(uint64)sp->jpeg_interchange_format; |
| break; |
| case TIFFTAG_JPEGIFBYTECOUNT: |
| *va_arg(ap,uint64*)=(uint64)sp->jpeg_interchange_format_length; |
| break; |
| case TIFFTAG_YCBCRSUBSAMPLING: |
| if (sp->subsamplingcorrect_done==0) |
| OJPEGSubsamplingCorrect(tif); |
| *va_arg(ap,uint16*)=(uint16)sp->subsampling_hor; |
| *va_arg(ap,uint16*)=(uint16)sp->subsampling_ver; |
| break; |
| case TIFFTAG_JPEGQTABLES: |
| *va_arg(ap,uint32*)=(uint32)sp->qtable_offset_count; |
| *va_arg(ap,void**)=(void*)sp->qtable_offset; |
| break; |
| case TIFFTAG_JPEGDCTABLES: |
| *va_arg(ap,uint32*)=(uint32)sp->dctable_offset_count; |
| *va_arg(ap,void**)=(void*)sp->dctable_offset; |
| break; |
| case TIFFTAG_JPEGACTABLES: |
| *va_arg(ap,uint32*)=(uint32)sp->actable_offset_count; |
| *va_arg(ap,void**)=(void*)sp->actable_offset; |
| break; |
| case TIFFTAG_JPEGPROC: |
| *va_arg(ap,uint16*)=(uint16)sp->jpeg_proc; |
| break; |
| case TIFFTAG_JPEGRESTARTINTERVAL: |
| *va_arg(ap,uint16*)=sp->restart_interval; |
| break; |
| default: |
| return (*sp->vgetparent)(tif,tag,ap); |
| } |
| return (1); |
| } |
| |
| static int |
| OJPEGVSetField(TIFF* tif, uint32 tag, va_list ap) |
| { |
| static const char module[]="OJPEGVSetField"; |
| OJPEGState* sp=(OJPEGState*)tif->tif_data; |
| uint32 ma; |
| uint64* mb; |
| uint32 n; |
| const TIFFField* fip; |
| |
| switch(tag) |
| { |
| case TIFFTAG_JPEGIFOFFSET: |
| sp->jpeg_interchange_format=(uint64)va_arg(ap,uint64); |
| break; |
| case TIFFTAG_JPEGIFBYTECOUNT: |
| sp->jpeg_interchange_format_length=(uint64)va_arg(ap,uint64); |
| break; |
| case TIFFTAG_YCBCRSUBSAMPLING: |
| sp->subsampling_tag=1; |
| sp->subsampling_hor=(uint8)va_arg(ap,uint16_vap); |
| sp->subsampling_ver=(uint8)va_arg(ap,uint16_vap); |
| tif->tif_dir.td_ycbcrsubsampling[0]=sp->subsampling_hor; |
| tif->tif_dir.td_ycbcrsubsampling[1]=sp->subsampling_ver; |
| break; |
| case TIFFTAG_JPEGQTABLES: |
| ma=(uint32)va_arg(ap,uint32); |
| if (ma!=0) |
| { |
| if (ma>3) |
| { |
| TIFFErrorExt(tif->tif_clientdata,module,"JpegQTables tag has incorrect count"); |
| return(0); |
| } |
| sp->qtable_offset_count=(uint8)ma; |
| mb=(uint64*)va_arg(ap,uint64*); |
| for (n=0; n<ma; n++) |
| sp->qtable_offset[n]=mb[n]; |
| } |
| break; |
| case TIFFTAG_JPEGDCTABLES: |
| ma=(uint32)va_arg(ap,uint32); |
| if (ma!=0) |
| { |
| if (ma>3) |
| { |
| TIFFErrorExt(tif->tif_clientdata,module,"JpegDcTables tag has incorrect count"); |
| return(0); |
| } |
| sp->dctable_offset_count=(uint8)ma; |
| mb=(uint64*)va_arg(ap,uint64*); |
| for (n=0; n<ma; n++) |
| sp->dctable_offset[n]=mb[n]; |
| } |
| break; |
| case TIFFTAG_JPEGACTABLES: |
| ma=(uint32)va_arg(ap,uint32); |
| if (ma!=0) |
| { |
| if (ma>3) |
| { |
| TIFFErrorExt(tif->tif_clientdata,module,"JpegAcTables tag has incorrect count"); |
| return(0); |
| } |
| sp->actable_offset_count=(uint8)ma; |
| mb=(uint64*)va_arg(ap,uint64*); |
| for (n=0; n<ma; n++) |
| sp->actable_offset[n]=mb[n]; |
| } |
| break; |
| case TIFFTAG_JPEGPROC: |
| sp->jpeg_proc=(uint8)va_arg(ap,uint16_vap); |
| break; |
| case TIFFTAG_JPEGRESTARTINTERVAL: |
| sp->restart_interval=(uint16)va_arg(ap,uint16_vap); |
| break; |
| default: |
| return (*sp->vsetparent)(tif,tag,ap); |
| } |
| fip = TIFFFieldWithTag(tif,tag); |
| if( fip == NULL ) /* shouldn't happen */ |
| return(0); |
| TIFFSetFieldBit(tif,fip->field_bit); |
| tif->tif_flags|=TIFF_DIRTYDIRECT; |
| return(1); |
| } |
| |
| static void |
| OJPEGPrintDir(TIFF* tif, FILE* fd, long flags) |
| { |
| OJPEGState* sp=(OJPEGState*)tif->tif_data; |
| uint8 m; |
| (void)flags; |
| assert(sp!=NULL); |
| if (TIFFFieldSet(tif,FIELD_OJPEG_JPEGINTERCHANGEFORMAT)) |
| fprintf(fd," JpegInterchangeFormat: " TIFF_UINT64_FORMAT "\n",(TIFF_UINT64_T)sp->jpeg_interchange_format); |
| if (TIFFFieldSet(tif,FIELD_OJPEG_JPEGINTERCHANGEFORMATLENGTH)) |
| fprintf(fd," JpegInterchangeFormatLength: " TIFF_UINT64_FORMAT "\n",(TIFF_UINT64_T)sp->jpeg_interchange_format_length); |
| if (TIFFFieldSet(tif,FIELD_OJPEG_JPEGQTABLES)) |
| { |
| fprintf(fd," JpegQTables:"); |
| for (m=0; m<sp->qtable_offset_count; m++) |
| fprintf(fd," " TIFF_UINT64_FORMAT,(TIFF_UINT64_T)sp->qtable_offset[m]); |
| fprintf(fd,"\n"); |
| } |
| if (TIFFFieldSet(tif,FIELD_OJPEG_JPEGDCTABLES)) |
| { |
| fprintf(fd," JpegDcTables:"); |
| for (m=0; m<sp->dctable_offset_count; m++) |
| fprintf(fd," " TIFF_UINT64_FORMAT,(TIFF_UINT64_T)sp->dctable_offset[m]); |
| fprintf(fd,"\n"); |
| } |
| if (TIFFFieldSet(tif,FIELD_OJPEG_JPEGACTABLES)) |
| { |
| fprintf(fd," JpegAcTables:"); |
| for (m=0; m<sp->actable_offset_count; m++) |
| fprintf(fd," " TIFF_UINT64_FORMAT,(TIFF_UINT64_T)sp->actable_offset[m]); |
| fprintf(fd,"\n"); |
| } |
| if (TIFFFieldSet(tif,FIELD_OJPEG_JPEGPROC)) |
| fprintf(fd," JpegProc: %u\n",(unsigned int)sp->jpeg_proc); |
| if (TIFFFieldSet(tif,FIELD_OJPEG_JPEGRESTARTINTERVAL)) |
| fprintf(fd," JpegRestartInterval: %u\n",(unsigned int)sp->restart_interval); |
| if (sp->printdir) |
| (*sp->printdir)(tif, fd, flags); |
| } |
| |
| static int |
| OJPEGFixupTags(TIFF* tif) |
| { |
| (void) tif; |
| return(1); |
| } |
| |
| static int |
| OJPEGSetupDecode(TIFF* tif) |
| { |
| static const char module[]="OJPEGSetupDecode"; |
| TIFFWarningExt(tif->tif_clientdata,module,"Depreciated and troublesome old-style JPEG compression mode, please convert to new-style JPEG compression and notify vendor of writing software"); |
| return(1); |
| } |
| |
| static int |
| OJPEGPreDecode(TIFF* tif, uint16 s) |
| { |
| OJPEGState* sp=(OJPEGState*)tif->tif_data; |
| uint32 m; |
| if (sp->subsamplingcorrect_done==0) |
| OJPEGSubsamplingCorrect(tif); |
| if (sp->readheader_done==0) |
| { |
| if (OJPEGReadHeaderInfo(tif)==0) |
| return(0); |
| } |
| if (sp->sos_end[s].log==0) |
| { |
| if (OJPEGReadSecondarySos(tif,s)==0) |
| return(0); |
| } |
| if isTiled(tif) |
| m=tif->tif_curtile; |
| else |
| m=tif->tif_curstrip; |
| if ((sp->writeheader_done!=0) && ((sp->write_cursample!=s) || (sp->write_curstrile>m))) |
| { |
| if (sp->libjpeg_session_active!=0) |
| OJPEGLibjpegSessionAbort(tif); |
| sp->writeheader_done=0; |
| } |
| if (sp->writeheader_done==0) |
| { |
| sp->plane_sample_offset=(uint8)s; |
| sp->write_cursample=s; |
| sp->write_curstrile=s*tif->tif_dir.td_stripsperimage; |
| if ((sp->in_buffer_file_pos_log==0) || |
| (sp->in_buffer_file_pos-sp->in_buffer_togo!=sp->sos_end[s].in_buffer_file_pos)) |
| { |
| sp->in_buffer_source=sp->sos_end[s].in_buffer_source; |
| sp->in_buffer_next_strile=sp->sos_end[s].in_buffer_next_strile; |
| sp->in_buffer_file_pos=sp->sos_end[s].in_buffer_file_pos; |
| sp->in_buffer_file_pos_log=0; |
| sp->in_buffer_file_togo=sp->sos_end[s].in_buffer_file_togo; |
| sp->in_buffer_togo=0; |
| sp->in_buffer_cur=0; |
| } |
| if (OJPEGWriteHeaderInfo(tif)==0) |
| return(0); |
| } |
| while (sp->write_curstrile<m) |
| { |
| if (sp->libjpeg_jpeg_query_style==0) |
| { |
| if (OJPEGPreDecodeSkipRaw(tif)==0) |
| return(0); |
| } |
| else |
| { |
| if (OJPEGPreDecodeSkipScanlines(tif)==0) |
| return(0); |
| } |
| sp->write_curstrile++; |
| } |
| sp->decoder_ok = 1; |
| return(1); |
| } |
| |
| static int |
| OJPEGPreDecodeSkipRaw(TIFF* tif) |
| { |
| OJPEGState* sp=(OJPEGState*)tif->tif_data; |
| uint32 m; |
| m=sp->lines_per_strile; |
| if (sp->subsampling_convert_state!=0) |
| { |
| if (sp->subsampling_convert_clines-sp->subsampling_convert_state>=m) |
| { |
| sp->subsampling_convert_state+=m; |
| if (sp->subsampling_convert_state==sp->subsampling_convert_clines) |
| sp->subsampling_convert_state=0; |
| return(1); |
| } |
| m-=sp->subsampling_convert_clines-sp->subsampling_convert_state; |
| sp->subsampling_convert_state=0; |
| } |
| while (m>=sp->subsampling_convert_clines) |
| { |
| if (jpeg_read_raw_data_encap(sp,&(sp->libjpeg_jpeg_decompress_struct),sp->subsampling_convert_ycbcrimage,sp->subsampling_ver*8)==0) |
| return(0); |
| m-=sp->subsampling_convert_clines; |
| } |
| if (m>0) |
| { |
| if (jpeg_read_raw_data_encap(sp,&(sp->libjpeg_jpeg_decompress_struct),sp->subsampling_convert_ycbcrimage,sp->subsampling_ver*8)==0) |
| return(0); |
| sp->subsampling_convert_state=m; |
| } |
| return(1); |
| } |
| |
| static int |
| OJPEGPreDecodeSkipScanlines(TIFF* tif) |
| { |
| static const char module[]="OJPEGPreDecodeSkipScanlines"; |
| OJPEGState* sp=(OJPEGState*)tif->tif_data; |
| uint32 m; |
| if (sp->skip_buffer==NULL) |
| { |
| sp->skip_buffer=_TIFFmalloc(sp->bytes_per_line); |
| if (sp->skip_buffer==NULL) |
| { |
| TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); |
| return(0); |
| } |
| } |
| for (m=0; m<sp->lines_per_strile; m++) |
| { |
| if (jpeg_read_scanlines_encap(sp,&(sp->libjpeg_jpeg_decompress_struct),&sp->skip_buffer,1)==0) |
| return(0); |
| } |
| return(1); |
| } |
| |
| static int |
| OJPEGDecode(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s) |
| { |
| static const char module[]="OJPEGDecode"; |
| OJPEGState* sp=(OJPEGState*)tif->tif_data; |
| (void)s; |
| if( !sp->decoder_ok ) |
| { |
| TIFFErrorExt(tif->tif_clientdata,module,"Cannot decode: decoder not correctly initialized"); |
| return 0; |
| } |
| if (sp->libjpeg_jpeg_query_style==0) |
| { |
| if (OJPEGDecodeRaw(tif,buf,cc)==0) |
| return(0); |
| } |
| else |
| { |
| if (OJPEGDecodeScanlines(tif,buf,cc)==0) |
| return(0); |
| } |
| return(1); |
| } |
| |
| static int |
| OJPEGDecodeRaw(TIFF* tif, uint8* buf, tmsize_t cc) |
| { |
| static const char module[]="OJPEGDecodeRaw"; |
| OJPEGState* sp=(OJPEGState*)tif->tif_data; |
| uint8* m; |
| tmsize_t n; |
| uint8* oy; |
| uint8* ocb; |
| uint8* ocr; |
| uint8* p; |
| uint32 q; |
| uint8* r; |
| uint8 sx,sy; |
| if (cc%sp->bytes_per_line!=0) |
| { |
| TIFFErrorExt(tif->tif_clientdata,module,"Fractional scanline not read"); |
| return(0); |
| } |
| assert(cc>0); |
| m=buf; |
| n=cc; |
| do |
| { |
| if (sp->subsampling_convert_state==0) |
| { |
| if (jpeg_read_raw_data_encap(sp,&(sp->libjpeg_jpeg_decompress_struct),sp->subsampling_convert_ycbcrimage,sp->subsampling_ver*8)==0) |
| return(0); |
| } |
| oy=sp->subsampling_convert_ybuf+sp->subsampling_convert_state*sp->subsampling_ver*sp->subsampling_convert_ylinelen; |
| ocb=sp->subsampling_convert_cbbuf+sp->subsampling_convert_state*sp->subsampling_convert_clinelen; |
| ocr=sp->subsampling_convert_crbuf+sp->subsampling_convert_state*sp->subsampling_convert_clinelen; |
| p=m; |
| for (q=0; q<sp->subsampling_convert_clinelenout; q++) |
| { |
| r=oy; |
| for (sy=0; sy<sp->subsampling_ver; sy++) |
| { |
| for (sx=0; sx<sp->subsampling_hor; sx++) |
| *p++=*r++; |
| r+=sp->subsampling_convert_ylinelen-sp->subsampling_hor; |
| } |
| oy+=sp->subsampling_hor; |
| *p++=*ocb++; |
| *p++=*ocr++; |
| } |
| sp->subsampling_convert_state++; |
| if (sp->subsampling_convert_state==sp->subsampling_convert_clines) |
| sp->subsampling_convert_state=0; |
| m+=sp->bytes_per_line; |
| n-=sp->bytes_per_line; |
| } while(n>0); |
| return(1); |
| } |
| |
| static int |
| OJPEGDecodeScanlines(TIFF* tif, uint8* buf, tmsize_t cc) |
| { |
| static const char module[]="OJPEGDecodeScanlines"; |
| OJPEGState* sp=(OJPEGState*)tif->tif_data; |
| uint8* m; |
| tmsize_t n; |
| if (cc%sp->bytes_per_line!=0) |
| { |
| TIFFErrorExt(tif->tif_clientdata,module,"Fractional scanline not read"); |
| return(0); |
| } |
| assert(cc>0); |
| m=buf; |
| n=cc; |
| do |
| { |
| if (jpeg_read_scanlines_encap(sp,&(sp->libjpeg_jpeg_decompress_struct),&m,1)==0) |
| return(0); |
| m+=sp->bytes_per_line; |
| n-=sp->bytes_per_line; |
| } while(n>0); |
| return(1); |
| } |
| |
| static void |
| OJPEGPostDecode(TIFF* tif, uint8* buf, tmsize_t cc) |
| { |
| OJPEGState* sp=(OJPEGState*)tif->tif_data; |
| (void)buf; |
| (void)cc; |
| sp->write_curstrile++; |
| if (sp->write_curstrile%tif->tif_dir.td_stripsperimage==0) |
| { |
| assert(sp->libjpeg_session_active!=0); |
| OJPEGLibjpegSessionAbort(tif); |
| sp->writeheader_done=0; |
| } |
| } |
| |
| static int |
| OJPEGSetupEncode(TIFF* tif) |
| { |
| static const char module[]="OJPEGSetupEncode"; |
| TIFFErrorExt(tif->tif_clientdata,module,"OJPEG encoding not supported; use new-style JPEG compression instead"); |
| return(0); |
| } |
| |
| static int |
| OJPEGPreEncode(TIFF* tif, uint16 s) |
| { |
| static const char module[]="OJPEGPreEncode"; |
| (void)s; |
| TIFFErrorExt(tif->tif_clientdata,module,"OJPEG encoding not supported; use new-style JPEG compression instead"); |
| return(0); |
| } |
| |
| static int |
| OJPEGEncode(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s) |
| { |
| static const char module[]="OJPEGEncode"; |
| (void)buf; |
| (void)cc; |
| (void)s; |
| TIFFErrorExt(tif->tif_clientdata,module,"OJPEG encoding not supported; use new-style JPEG compression instead"); |
| return(0); |
| } |
| |
| static int |
| OJPEGPostEncode(TIFF* tif) |
| { |
| static const char module[]="OJPEGPostEncode"; |
| TIFFErrorExt(tif->tif_clientdata,module,"OJPEG encoding not supported; use new-style JPEG compression instead"); |
| return(0); |
| } |
| |
| static void |
| OJPEGCleanup(TIFF* tif) |
| { |
| OJPEGState* sp=(OJPEGState*)tif->tif_data; |
| if (sp!=0) |
| { |
| tif->tif_tagmethods.vgetfield=sp->vgetparent; |
| tif->tif_tagmethods.vsetfield=sp->vsetparent; |
| tif->tif_tagmethods.printdir=sp->printdir; |
| if (sp->qtable[0]!=0) |
| _TIFFfree(sp->qtable[0]); |
| if (sp->qtable[1]!=0) |
| _TIFFfree(sp->qtable[1]); |
| if (sp->qtable[2]!=0) |
| _TIFFfree(sp->qtable[2]); |
| if (sp->qtable[3]!=0) |
| _TIFFfree(sp->qtable[3]); |
| if (sp->dctable[0]!=0) |
| _TIFFfree(sp->dctable[0]); |
| if (sp->dctable[1]!=0) |
| _TIFFfree(sp->dctable[1]); |
| if (sp->dctable[2]!=0) |
| _TIFFfree(sp->dctable[2]); |
| if (sp->dctable[3]!=0) |
| _TIFFfree(sp->dctable[3]); |
| if (sp->actable[0]!=0) |
| _TIFFfree(sp->actable[0]); |
| if (sp->actable[1]!=0) |
| _TIFFfree(sp->actable[1]); |
| if (sp->actable[2]!=0) |
| _TIFFfree(sp->actable[2]); |
| if (sp->actable[3]!=0) |
| _TIFFfree(sp->actable[3]); |
| if (sp->libjpeg_session_active!=0) |
| OJPEGLibjpegSessionAbort(tif); |
| if (sp->subsampling_convert_ycbcrbuf!=0) |
| _TIFFfree(sp->subsampling_convert_ycbcrbuf); |
| if (sp->subsampling_convert_ycbcrimage!=0) |
| _TIFFfree(sp->subsampling_convert_ycbcrimage); |
| if (sp->skip_buffer!=0) |
| _TIFFfree(sp->skip_buffer); |
| _TIFFfree(sp); |
| tif->tif_data=NULL; |
| _TIFFSetDefaultCompressionState(tif); |
| } |
| } |
| |
| static void |
| OJPEGSubsamplingCorrect(TIFF* tif) |
| { |
| static const char module[]="OJPEGSubsamplingCorrect"; |
| OJPEGState* sp=(OJPEGState*)tif->tif_data; |
| uint8 mh; |
| uint8 mv; |
| _TIFFFillStriles( tif ); |
| |
| assert(sp->subsamplingcorrect_done==0); |
| if ((tif->tif_dir.td_samplesperpixel!=3) || ((tif->tif_dir.td_photometric!=PHOTOMETRIC_YCBCR) && |
| (tif->tif_dir.td_photometric!=PHOTOMETRIC_ITULAB))) |
| { |
| if (sp->subsampling_tag!=0) |
| TIFFWarningExt(tif->tif_clientdata,module,"Subsampling tag not appropriate for this Photometric and/or SamplesPerPixel"); |
| sp->subsampling_hor=1; |
| sp->subsampling_ver=1; |
| sp->subsampling_force_desubsampling_inside_decompression=0; |
| } |
| else |
| { |
| sp->subsamplingcorrect_done=1; |
| mh=sp->subsampling_hor; |
| mv=sp->subsampling_ver; |
| sp->subsamplingcorrect=1; |
| OJPEGReadHeaderInfoSec(tif); |
| if (sp->subsampling_force_desubsampling_inside_decompression!=0) |
| { |
| sp->subsampling_hor=1; |
| sp->subsampling_ver=1; |
| } |
| sp->subsamplingcorrect=0; |
| if (((sp->subsampling_hor!=mh) || (sp->subsampling_ver!=mv)) && (sp->subsampling_force_desubsampling_inside_decompression==0)) |
| { |
| if (sp->subsampling_tag==0) |
| TIFFWarningExt(tif->tif_clientdata,module,"Subsampling tag is not set, yet subsampling inside JPEG data [%d,%d] does not match default values [2,2]; assuming subsampling inside JPEG data is correct",sp->subsampling_hor,sp->subsampling_ver); |
| else |
| TIFFWarningExt(tif->tif_clientdata,module,"Subsampling inside JPEG data [%d,%d] does not match subsampling tag values [%d,%d]; assuming subsampling inside JPEG data is correct",sp->subsampling_hor,sp->subsampling_ver,mh,mv); |
| } |
| if (sp->subsampling_force_desubsampling_inside_decompression!=0) |
| { |
| if (sp->subsampling_tag==0) |
| TIFFWarningExt(tif->tif_clientdata,module,"Subsampling tag is not set, yet subsampling inside JPEG data does not match default values [2,2] (nor any other values allowed in TIFF); assuming subsampling inside JPEG data is correct and desubsampling inside JPEG decompression"); |
| else |
| TIFFWarningExt(tif->tif_clientdata,module,"Subsampling inside JPEG data does not match subsampling tag values [%d,%d] (nor any other values allowed in TIFF); assuming subsampling inside JPEG data is correct and desubsampling inside JPEG decompression",mh,mv); |
| } |
| if (sp->subsampling_force_desubsampling_inside_decompression==0) |
| { |
| if (sp->subsampling_hor<sp->subsampling_ver) |
| TIFFWarningExt(tif->tif_clientdata,module,"Subsampling values [%d,%d] are not allowed in TIFF",sp->subsampling_hor,sp->subsampling_ver); |
| } |
| } |
| sp->subsamplingcorrect_done=1; |
| } |
| |
| static int |
| OJPEGReadHeaderInfo(TIFF* tif) |
| { |
| static const char module[]="OJPEGReadHeaderInfo"; |
| OJPEGState* sp=(OJPEGState*)tif->tif_data; |
| assert(sp->readheader_done==0); |
| sp->image_width=tif->tif_dir.td_imagewidth; |
| sp->image_length=tif->tif_dir.td_imagelength; |
| if isTiled(tif) |
| { |
| sp->strile_width=tif->tif_dir.td_tilewidth; |
| sp->strile_length=tif->tif_dir.td_tilelength; |
| sp->strile_length_total=((sp->image_length+sp->strile_length-1)/sp->strile_length)*sp->strile_length; |
| } |
| else |
| { |
| sp->strile_width=sp->image_width; |
| sp->strile_length=tif->tif_dir.td_rowsperstrip; |
| sp->strile_length_total=sp->image_length; |
| } |
| if (tif->tif_dir.td_samplesperpixel==1) |
| { |
| sp->samples_per_pixel=1; |
| sp->plane_sample_offset=0; |
| sp->samples_per_pixel_per_plane=sp->samples_per_pixel; |
| sp->subsampling_hor=1; |
| sp->subsampling_ver=1; |
| } |
| else |
| { |
| if (tif->tif_dir.td_samplesperpixel!=3) |
| { |
| TIFFErrorExt(tif->tif_clientdata,module,"SamplesPerPixel %d not supported for this compression scheme",sp->samples_per_pixel); |
| return(0); |
| } |
| sp->samples_per_pixel=3; |
| sp->plane_sample_offset=0; |
| if (tif->tif_dir.td_planarconfig==PLANARCONFIG_CONTIG) |
| sp->samples_per_pixel_per_plane=3; |
| else |
| sp->samples_per_pixel_per_plane=1; |
| } |
| if (sp->strile_length<sp->image_length) |
| { |
| if (sp->strile_length%(sp->subsampling_ver*8)!=0) |
| { |
| TIFFErrorExt(tif->tif_clientdata,module,"Incompatible vertical subsampling and image strip/tile length"); |
| return(0); |
| } |
| sp->restart_interval=(uint16)(((sp->strile_width+sp->subsampling_hor*8-1)/(sp->subsampling_hor*8))*(sp->strile_length/(sp->subsampling_ver*8))); |
| } |
| if (OJPEGReadHeaderInfoSec(tif)==0) |
| return(0); |
| sp->sos_end[0].log=1; |
| sp->sos_end[0].in_buffer_source=sp->in_buffer_source; |
| sp->sos_end[0].in_buffer_next_strile=sp->in_buffer_next_strile; |
| sp->sos_end[0].in_buffer_file_pos=sp->in_buffer_file_pos-sp->in_buffer_togo; |
| sp->sos_end[0].in_buffer_file_togo=sp->in_buffer_file_togo+sp->in_buffer_togo; |
| sp->readheader_done=1; |
| return(1); |
| } |
| |
| static int |
| OJPEGReadSecondarySos(TIFF* tif, uint16 s) |
| { |
| OJPEGState* sp=(OJPEGState*)tif->tif_data; |
| uint8 m; |
| assert(s>0); |
| assert(s<3); |
| assert(sp->sos_end[0].log!=0); |
| assert(sp->sos_end[s].log==0); |
| sp->plane_sample_offset=(uint8)(s-1); |
| while(sp->sos_end[sp->plane_sample_offset].log==0) |
| sp->plane_sample_offset--; |
| sp->in_buffer_source=sp->sos_end[sp->plane_sample_offset].in_buffer_source; |
| sp->in_buffer_next_strile=sp->sos_end[sp->plane_sample_offset].in_buffer_next_strile; |
| sp->in_buffer_file_pos=sp->sos_end[sp->plane_sample_offset].in_buffer_file_pos; |
| sp->in_buffer_file_pos_log=0; |
| sp->in_buffer_file_togo=sp->sos_end[sp->plane_sample_offset].in_buffer_file_togo; |
| sp->in_buffer_togo=0; |
| sp->in_buffer_cur=0; |
| while(sp->plane_sample_offset<s) |
| { |
| do |
| { |
| if (OJPEGReadByte(sp,&m)==0) |
| return(0); |
| if (m==255) |
| { |
| do |
| { |
| if (OJPEGReadByte(sp,&m)==0) |
| return(0); |
| if (m!=255) |
| break; |
| } while(1); |
| if (m==JPEG_MARKER_SOS) |
| break; |
| } |
| } while(1); |
| sp->plane_sample_offset++; |
| if (OJPEGReadHeaderInfoSecStreamSos(tif)==0) |
| return(0); |
| sp->sos_end[sp->plane_sample_offset].log=1; |
| sp->sos_end[sp->plane_sample_offset].in_buffer_source=sp->in_buffer_source; |
| sp->sos_end[sp->plane_sample_offset].in_buffer_next_strile=sp->in_buffer_next_strile; |
| sp->sos_end[sp->plane_sample_offset].in_buffer_file_pos=sp->in_buffer_file_pos-sp->in_buffer_togo; |
| sp->sos_end[sp->plane_sample_offset].in_buffer_file_togo=sp->in_buffer_file_togo+sp->in_buffer_togo; |
| } |
| return(1); |
| } |
| |
| static int |
| OJPEGWriteHeaderInfo(TIFF* tif) |
| { |
| static const char module[]="OJPEGWriteHeaderInfo"; |
| OJPEGState* sp=(OJPEGState*)tif->tif_data; |
| uint8** m; |
| uint32 n; |
| /* if a previous attempt failed, don't try again */ |
| if (sp->libjpeg_session_active != 0) |
| return 0; |
| sp->out_state=ososSoi; |
| sp->restart_index=0; |
| jpeg_std_error(&(sp->libjpeg_jpeg_error_mgr)); |
| sp->libjpeg_jpeg_error_mgr.output_message=OJPEGLibjpegJpegErrorMgrOutputMessage; |
| sp->libjpeg_jpeg_error_mgr.error_exit=OJPEGLibjpegJpegErrorMgrErrorExit; |
| sp->libjpeg_jpeg_decompress_struct.err=&(sp->libjpeg_jpeg_error_mgr); |
| sp->libjpeg_jpeg_decompress_struct.client_data=(void*)tif; |
| if (jpeg_create_decompress_encap(sp,&(sp->libjpeg_jpeg_decompress_struct))==0) |
| return(0); |
| sp->libjpeg_session_active=1; |
| sp->libjpeg_jpeg_source_mgr.bytes_in_buffer=0; |
| sp->libjpeg_jpeg_source_mgr.init_source=OJPEGLibjpegJpegSourceMgrInitSource; |
| sp->libjpeg_jpeg_source_mgr.fill_input_buffer=OJPEGLibjpegJpegSourceMgrFillInputBuffer; |
| sp->libjpeg_jpeg_source_mgr.skip_input_data=OJPEGLibjpegJpegSourceMgrSkipInputData; |
| sp->libjpeg_jpeg_source_mgr.resync_to_restart=OJPEGLibjpegJpegSourceMgrResyncToRestart; |
| sp->libjpeg_jpeg_source_mgr.term_source=OJPEGLibjpegJpegSourceMgrTermSource; |
| sp->libjpeg_jpeg_decompress_struct.src=&(sp->libjpeg_jpeg_source_mgr); |
| if (jpeg_read_header_encap(sp,&(sp->libjpeg_jpeg_decompress_struct),1)==0) |
| return(0); |
| if ((sp->subsampling_force_desubsampling_inside_decompression==0) && (sp->samples_per_pixel_per_plane>1)) |
| { |
| sp->libjpeg_jpeg_decompress_struct.raw_data_out=1; |
| #if JPEG_LIB_VERSION >= 70 |
| sp->libjpeg_jpeg_decompress_struct.do_fancy_upsampling=FALSE; |
| #endif |
| sp->libjpeg_jpeg_query_style=0; |
| if (sp->subsampling_convert_log==0) |
| { |
| assert(sp->subsampling_convert_ycbcrbuf==0); |
| assert(sp->subsampling_convert_ycbcrimage==0); |
| sp->subsampling_convert_ylinelen=((sp->strile_width+sp->subsampling_hor*8-1)/(sp->subsampling_hor*8)*sp->subsampling_hor*8); |
| sp->subsampling_convert_ylines=sp->subsampling_ver*8; |
| sp->subsampling_convert_clinelen=sp->subsampling_convert_ylinelen/sp->subsampling_hor; |
| sp->subsampling_convert_clines=8; |
| sp->subsampling_convert_ybuflen=sp->subsampling_convert_ylinelen*sp->subsampling_convert_ylines; |
| sp->subsampling_convert_cbuflen=sp->subsampling_convert_clinelen*sp->subsampling_convert_clines; |
| sp->subsampling_convert_ycbcrbuflen=sp->subsampling_convert_ybuflen+2*sp->subsampling_convert_cbuflen; |
| sp->subsampling_convert_ycbcrbuf=_TIFFmalloc(sp->subsampling_convert_ycbcrbuflen); |
| if (sp->subsampling_convert_ycbcrbuf==0) |
| { |
| TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); |
| return(0); |
| } |
| sp->subsampling_convert_ybuf=sp->subsampling_convert_ycbcrbuf; |
| sp->subsampling_convert_cbbuf=sp->subsampling_convert_ybuf+sp->subsampling_convert_ybuflen; |
| sp->subsampling_convert_crbuf=sp->subsampling_convert_cbbuf+sp->subsampling_convert_cbuflen; |
| sp->subsampling_convert_ycbcrimagelen=3+sp->subsampling_convert_ylines+2*sp->subsampling_convert_clines; |
| sp->subsampling_convert_ycbcrimage=_TIFFmalloc(sp->subsampling_convert_ycbcrimagelen*sizeof(uint8*)); |
| if (sp->subsampling_convert_ycbcrimage==0) |
| { |
| TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); |
| return(0); |
| } |
| m=sp->subsampling_convert_ycbcrimage; |
| *m++=(uint8*)(sp->subsampling_convert_ycbcrimage+3); |
| *m++=(uint8*)(sp->subsampling_convert_ycbcrimage+3+sp->subsampling_convert_ylines); |
| *m++=(uint8*)(sp->subsampling_convert_ycbcrimage+3+sp->subsampling_convert_ylines+sp->subsampling_convert_clines); |
| for (n=0; n<sp->subsampling_convert_ylines; n++) |
| *m++=sp->subsampling_convert_ybuf+n*sp->subsampling_convert_ylinelen; |
| for (n=0; n<sp->subsampling_convert_clines; n++) |
| *m++=sp->subsampling_convert_cbbuf+n*sp->subsampling_convert_clinelen; |
| for (n=0; n<sp->subsampling_convert_clines; n++) |
| *m++=sp->subsampling_convert_crbuf+n*sp->subsampling_convert_clinelen; |
| sp->subsampling_convert_clinelenout=((sp->strile_width+sp->subsampling_hor-1)/sp->subsampling_hor); |
| sp->subsampling_convert_state=0; |
| sp->bytes_per_line=sp->subsampling_convert_clinelenout*(sp->subsampling_ver*sp->subsampling_hor+2); |
| sp->lines_per_strile=((sp->strile_length+sp->subsampling_ver-1)/sp->subsampling_ver); |
| sp->subsampling_convert_log=1; |
| } |
| } |
| else |
| { |
| sp->libjpeg_jpeg_decompress_struct.jpeg_color_space=JCS_UNKNOWN; |
| sp->libjpeg_jpeg_decompress_struct.out_color_space=JCS_UNKNOWN; |
| sp->libjpeg_jpeg_query_style=1; |
| sp->bytes_per_line=sp->samples_per_pixel_per_plane*sp->strile_width; |
| sp->lines_per_strile=sp->strile_length; |
| } |
| if (jpeg_start_decompress_encap(sp,&(sp->libjpeg_jpeg_decompress_struct))==0) |
| return(0); |
| sp->writeheader_done=1; |
| return(1); |
| } |
| |
| static void |
| OJPEGLibjpegSessionAbort(TIFF* tif) |
| { |
| OJPEGState* sp=(OJPEGState*)tif->tif_data; |
| assert(sp->libjpeg_session_active!=0); |
| jpeg_destroy((jpeg_common_struct*)(&(sp->libjpeg_jpeg_decompress_struct))); |
| sp->libjpeg_session_active=0; |
| } |
| |
| static int |
| OJPEGReadHeaderInfoSec(TIFF* tif) |
| { |
| static const char module[]="OJPEGReadHeaderInfoSec"; |
| OJPEGState* sp=(OJPEGState*)tif->tif_data; |
| uint8 m; |
| uint16 n; |
| uint8 o; |
| if (sp->file_size==0) |
| sp->file_size=TIFFGetFileSize(tif); |
| if (sp->jpeg_interchange_format!=0) |
| { |
| if (sp->jpeg_interchange_format>=sp->file_size) |
| { |
| sp->jpeg_interchange_format=0; |
| sp->jpeg_interchange_format_length=0; |
| } |
| else |
| { |
| if ((sp->jpeg_interchange_format_length==0) || (sp->jpeg_interchange_format+sp->jpeg_interchange_format_length>sp->file_size)) |
| sp->jpeg_interchange_format_length=sp->file_size-sp->jpeg_interchange_format; |
| } |
| } |
| sp->in_buffer_source=osibsNotSetYet; |
| sp->in_buffer_next_strile=0; |
| sp->in_buffer_strile_count=tif->tif_dir.td_nstrips; |
| sp->in_buffer_file_togo=0; |
| sp->in_buffer_togo=0; |
| do |
| { |
| if (OJPEGReadBytePeek(sp,&m)==0) |
| return(0); |
| if (m!=255) |
| break; |
| OJPEGReadByteAdvance(sp); |
| do |
| { |
| if (OJPEGReadByte(sp,&m)==0) |
| return(0); |
| } while(m==255); |
| switch(m) |
| { |
| case JPEG_MARKER_SOI: |
| /* this type of marker has no data, and should be skipped */ |
| break; |
| case JPEG_MARKER_COM: |
| case JPEG_MARKER_APP0: |
| case JPEG_MARKER_APP0+1: |
| case JPEG_MARKER_APP0+2: |
| case JPEG_MARKER_APP0+3: |
| case JPEG_MARKER_APP0+4: |
| case JPEG_MARKER_APP0+5: |
| case JPEG_MARKER_APP0+6: |
| case JPEG_MARKER_APP0+7: |
| case JPEG_MARKER_APP0+8: |
| case JPEG_MARKER_APP0+9: |
| case JPEG_MARKER_APP0+10: |
| case JPEG_MARKER_APP0+11: |
| case JPEG_MARKER_APP0+12: |
| case JPEG_MARKER_APP0+13: |
| case JPEG_MARKER_APP0+14: |
| case JPEG_MARKER_APP0+15: |
| /* this type of marker has data, but it has no use to us (and no place here) and should be skipped */ |
| if (OJPEGReadWord(sp,&n)==0) |
| return(0); |
| if (n<2) |
| { |
| if (sp->subsamplingcorrect==0) |
| TIFFErrorExt(tif->tif_clientdata,module,"Corrupt JPEG data"); |
| return(0); |
| } |
| if (n>2) |
| OJPEGReadSkip(sp,n-2); |
| break; |
| case JPEG_MARKER_DRI: |
| if (OJPEGReadHeaderInfoSecStreamDri(tif)==0) |
| return(0); |
| break; |
| case JPEG_MARKER_DQT: |
| if (OJPEGReadHeaderInfoSecStreamDqt(tif)==0) |
| return(0); |
| break; |
| case JPEG_MARKER_DHT: |
| if (OJPEGReadHeaderInfoSecStreamDht(tif)==0) |
| return(0); |
| break; |
| case JPEG_MARKER_SOF0: |
| case JPEG_MARKER_SOF1: |
| case JPEG_MARKER_SOF3: |
| if (OJPEGReadHeaderInfoSecStreamSof(tif,m)==0) |
| return(0); |
| if (sp->subsamplingcorrect!=0) |
| return(1); |
| break; |
| case JPEG_MARKER_SOS: |
| if (sp->subsamplingcorrect!=0) |
| return(1); |
| assert(sp->plane_sample_offset==0); |
| if (OJPEGReadHeaderInfoSecStreamSos(tif)==0) |
| return(0); |
| break; |
| default: |
| TIFFErrorExt(tif->tif_clientdata,module,"Unknown marker type %d in JPEG data",m); |
| return(0); |
| } |
| } while(m!=JPEG_MARKER_SOS); |
| if (sp->subsamplingcorrect) |
| return(1); |
| if (sp->sof_log==0) |
| { |
| if (OJPEGReadHeaderInfoSecTablesQTable(tif)==0) |
| return(0); |
| sp->sof_marker_id=JPEG_MARKER_SOF0; |
| for (o=0; o<sp->samples_per_pixel; o++) |
| sp->sof_c[o]=o; |
| sp->sof_hv[0]=((sp->subsampling_hor<<4)|sp->subsampling_ver); |
| for (o=1; o<sp->samples_per_pixel; o++) |
| sp->sof_hv[o]=17; |
| sp->sof_x=sp->strile_width; |
| sp->sof_y=sp->strile_length_total; |
| sp->sof_log=1; |
| if (OJPEGReadHeaderInfoSecTablesDcTable(tif)==0) |
| return(0); |
| if (OJPEGReadHeaderInfoSecTablesAcTable(tif)==0) |
| return(0); |
| for (o=1; o<sp->samples_per_pixel; o++) |
| sp->sos_cs[o]=o; |
| } |
| return(1); |
| } |
| |
| static int |
| OJPEGReadHeaderInfoSecStreamDri(TIFF* tif) |
| { |
| /* This could easily cause trouble in some cases... but no such cases have |
| occurred so far */ |
| static const char module[]="OJPEGReadHeaderInfoSecStreamDri"; |
| OJPEGState* sp=(OJPEGState*)tif->tif_data; |
| uint16 m; |
| if (OJPEGReadWord(sp,&m)==0) |
| return(0); |
| if (m!=4) |
| { |
| TIFFErrorExt(tif->tif_clientdata,module,"Corrupt DRI marker in JPEG data"); |
| return(0); |
| } |
| if (OJPEGReadWord(sp,&m)==0) |
| return(0); |
| sp->restart_interval=m; |
| return(1); |
| } |
| |
| static int |
| OJPEGReadHeaderInfoSecStreamDqt(TIFF* tif) |
| { |
| /* this is a table marker, and it is to be saved as a whole for exact pushing on the jpeg stream later on */ |
| static const char module[]="OJPEGReadHeaderInfoSecStreamDqt"; |
| OJPEGState* sp=(OJPEGState*)tif->tif_data; |
| uint16 m; |
| uint32 na; |
| uint8* nb; |
| uint8 o; |
| if (OJPEGReadWord(sp,&m)==0) |
| return(0); |
| if (m<=2) |
| { |
| if (sp->subsamplingcorrect==0) |
| TIFFErrorExt(tif->tif_clientdata,module,"Corrupt DQT marker in JPEG data"); |
| return(0); |
| } |
| if (sp->subsamplingcorrect!=0) |
| OJPEGReadSkip(sp,m-2); |
| else |
| { |
| m-=2; |
| do |
| { |
| if (m<65) |
| { |
| TIFFErrorExt(tif->tif_clientdata,module,"Corrupt DQT marker in JPEG data"); |
| return(0); |
| } |
| na=sizeof(uint32)+69; |
| nb=_TIFFmalloc(na); |
| if (nb==0) |
| { |
| TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); |
| return(0); |
| } |
| *(uint32*)nb=na; |
| nb[sizeof(uint32)]=255; |
| nb[sizeof(uint32)+1]=JPEG_MARKER_DQT; |
| nb[sizeof(uint32)+2]=0; |
| nb[sizeof(uint32)+3]=67; |
| if (OJPEGReadBlock(sp,65,&nb[sizeof(uint32)+4])==0) { |
| _TIFFfree(nb); |
| return(0); |
| } |
| o=nb[sizeof(uint32)+4]&15; |
| if (3<o) |
| { |
| TIFFErrorExt(tif->tif_clientdata,module,"Corrupt DQT marker in JPEG data"); |
| _TIFFfree(nb); |
| return(0); |
| } |
| if (sp->qtable[o]!=0) |
| _TIFFfree(sp->qtable[o]); |
| sp->qtable[o]=nb; |
| m-=65; |
| } while(m>0); |
| } |
| return(1); |
| } |
| |
| static int |
| OJPEGReadHeaderInfoSecStreamDht(TIFF* tif) |
| { |
| /* this is a table marker, and it is to be saved as a whole for exact pushing on the jpeg stream later on */ |
| /* TODO: the following assumes there is only one table in this marker... but i'm not quite sure that assumption is guaranteed correct */ |
| static const char module[]="OJPEGReadHeaderInfoSecStreamDht"; |
| OJPEGState* sp=(OJPEGState*)tif->tif_data; |
| uint16 m; |
| uint32 na; |
| uint8* nb; |
| uint8 o; |
| if (OJPEGReadWord(sp,&m)==0) |
| return(0); |
| if (m<=2) |
| { |
| if (sp->subsamplingcorrect==0) |
| TIFFErrorExt(tif->tif_clientdata,module,"Corrupt DHT marker in JPEG data"); |
| return(0); |
| } |
| if (sp->subsamplingcorrect!=0) |
| { |
| OJPEGReadSkip(sp,m-2); |
| } |
| else |
| { |
| na=sizeof(uint32)+2+m; |
| nb=_TIFFmalloc(na); |
| if (nb==0) |
| { |
| TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); |
| return(0); |
| } |
| *(uint32*)nb=na; |
| nb[sizeof(uint32)]=255; |
| nb[sizeof(uint32)+1]=JPEG_MARKER_DHT; |
| nb[sizeof(uint32)+2]=(m>>8); |
| nb[sizeof(uint32)+3]=(m&255); |
| if (OJPEGReadBlock(sp,m-2,&nb[sizeof(uint32)+4])==0) { |
| _TIFFfree(nb); |
| return(0); |
| } |
| o=nb[sizeof(uint32)+4]; |
| if ((o&240)==0) |
| { |
| if (3<o) |
| { |
| TIFFErrorExt(tif->tif_clientdata,module,"Corrupt DHT marker in JPEG data"); |
| _TIFFfree(nb); |
| return(0); |
| } |
| if (sp->dctable[o]!=0) |
| _TIFFfree(sp->dctable[o]); |
| sp->dctable[o]=nb; |
| } |
| else |
| { |
| if ((o&240)!=16) |
| { |
| TIFFErrorExt(tif->tif_clientdata,module,"Corrupt DHT marker in JPEG data"); |
| _TIFFfree(nb); |
| return(0); |
| } |
| o&=15; |
| if (3<o) |
| { |
| TIFFErrorExt(tif->tif_clientdata,module,"Corrupt DHT marker in JPEG data"); |
| _TIFFfree(nb); |
| return(0); |
| } |
| if (sp->actable[o]!=0) |
| _TIFFfree(sp->actable[o]); |
| sp->actable[o]=nb; |
| } |
| } |
| return(1); |
| } |
| |
| static int |
| OJPEGReadHeaderInfoSecStreamSof(TIFF* tif, uint8 marker_id) |
| { |
| /* this marker needs to be checked, and part of its data needs to be saved for regeneration later on */ |
| static const char module[]="OJPEGReadHeaderInfoSecStreamSof"; |
| OJPEGState* sp=(OJPEGState*)tif->tif_data; |
| uint16 m; |
| uint16 n; |
| uint8 o; |
| uint16 p; |
| uint16 q; |
| if (sp->sof_log!=0) |
| { |
| TIFFErrorExt(tif->tif_clientdata,module,"Corrupt JPEG data"); |
| return(0); |
| } |
| if (sp->subsamplingcorrect==0) |
| sp->sof_marker_id=marker_id; |
| /* Lf: data length */ |
| if (OJPEGReadWord(sp,&m)==0) |
| return(0); |
| if (m<11) |
| { |
| if (sp->subsamplingcorrect==0) |
| TIFFErrorExt(tif->tif_clientdata,module,"Corrupt SOF marker in JPEG data"); |
| return(0); |
| } |
| m-=8; |
| if (m%3!=0) |
| { |
| if (sp->subsamplingcorrect==0) |
| TIFFErrorExt(tif->tif_clientdata,module,"Corrupt SOF marker in JPEG data"); |
| return(0); |
| } |
| n=m/3; |
| if (sp->subsamplingcorrect==0) |
| { |
| if (n!=sp->samples_per_pixel) |
| { |
| TIFFErrorExt(tif->tif_clientdata,module,"JPEG compressed data indicates unexpected number of samples"); |
| return(0); |
| } |
| } |
| /* P: Sample precision */ |
| if (OJPEGReadByte(sp,&o)==0) |
| return(0); |
| if (o!=8) |
| { |
| if (sp->subsamplingcorrect==0) |
| TIFFErrorExt(tif->tif_clientdata,module,"JPEG compressed data indicates unexpected number of bits per sample"); |
| return(0); |
| } |
| /* Y: Number of lines, X: Number of samples per line */ |
| if (sp->subsamplingcorrect) |
| OJPEGReadSkip(sp,4); |
| else |
| { |
| /* Y: Number of lines */ |
| if (OJPEGReadWord(sp,&p)==0) |
| return(0); |
| if (((uint32)p<sp->image_length) && ((uint32)p<sp->strile_length_total)) |
| { |
| TIFFErrorExt(tif->tif_clientdata,module,"JPEG compressed data indicates unexpected height"); |
| return(0); |
| } |
| sp->sof_y=p; |
| /* X: Number of samples per line */ |
| if (OJPEGReadWord(sp,&p)==0) |
| return(0); |
| if (((uint32)p<sp->image_width) && ((uint32)p<sp->strile_width)) |
| { |
| TIFFErrorExt(tif->tif_clientdata,module,"JPEG compressed data indicates unexpected width"); |
| return(0); |
| } |
| if ((uint32)p>sp->strile_width) |
| { |
| TIFFErrorExt(tif->tif_clientdata,module,"JPEG compressed data image width exceeds expected image width"); |
| return(0); |
| } |
| sp->sof_x=p; |
| } |
| /* Nf: Number of image components in frame */ |
| if (OJPEGReadByte(sp,&o)==0) |
| return(0); |
| if (o!=n) |
| { |
| if (sp->subsamplingcorrect==0) |
| TIFFErrorExt(tif->tif_clientdata,module,"Corrupt SOF marker in JPEG data"); |
| return(0); |
| } |
| /* per component stuff */ |
| /* TODO: double-check that flow implies that n cannot be as big as to make us overflow sof_c, sof_hv and sof_tq arrays */ |
| for (q=0; q<n; q++) |
| { |
| /* C: Component identifier */ |
| if (OJPEGReadByte(sp,&o)==0) |
| return(0); |
| if (sp->subsamplingcorrect==0) |
| sp->sof_c[q]=o; |
| /* H: Horizontal sampling factor, and V: Vertical sampling factor */ |
| if (OJPEGReadByte(sp,&o)==0) |
| return(0); |
| if (sp->subsamplingcorrect!=0) |
| { |
| if (q==0) |
| { |
| sp->subsampling_hor=(o>>4); |
| sp->subsampling_ver=(o&15); |
| if (((sp->subsampling_hor!=1) && (sp->subsampling_hor!=2) && (sp->subsampling_hor!=4)) || |
| ((sp->subsampling_ver!=1) && (sp->subsampling_ver!=2) && (sp->subsampling_ver!=4))) |
| sp->subsampling_force_desubsampling_inside_decompression=1; |
| } |
| else |
| { |
| if (o!=17) |
| sp->subsampling_force_desubsampling_inside_decompression=1; |
| } |
| } |
| else |
| { |
| sp->sof_hv[q]=o; |
| if (sp->subsampling_force_desubsampling_inside_decompression==0) |
| { |
| if (q==0) |
| { |
| if (o!=((sp->subsampling_hor<<4)|sp->subsampling_ver)) |
| { |
| TIFFErrorExt(tif->tif_clientdata,module,"JPEG compressed data indicates unexpected subsampling values"); |
| return(0); |
| } |
| } |
| else |
| { |
| if (o!=17) |
| { |
| TIFFErrorExt(tif->tif_clientdata,module,"JPEG compressed data indicates unexpected subsampling values"); |
| return(0); |
| } |
| } |
| } |
| } |
| /* Tq: Quantization table destination selector */ |
| if (OJPEGReadByte(sp,&o)==0) |
| return(0); |
| if (sp->subsamplingcorrect==0) |
| sp->sof_tq[q]=o; |
| } |
| if (sp->subsamplingcorrect==0) |
| sp->sof_log=1; |
| return(1); |
| } |
| |
| static int |
| OJPEGReadHeaderInfoSecStreamSos(TIFF* tif) |
| { |
| /* this marker needs to be checked, and part of its data needs to be saved for regeneration later on */ |
| static const char module[]="OJPEGReadHeaderInfoSecStreamSos"; |
| OJPEGState* sp=(OJPEGState*)tif->tif_data; |
| uint16 m; |
| uint8 n; |
| uint8 o; |
| assert(sp->subsamplingcorrect==0); |
| if (sp->sof_log==0) |
| { |
| TIFFErrorExt(tif->tif_clientdata,module,"Corrupt SOS marker in JPEG data"); |
| return(0); |
| } |
| /* Ls */ |
| if (OJPEGReadWord(sp,&m)==0) |
| return(0); |
| if (m!=6+sp->samples_per_pixel_per_plane*2) |
| { |
| TIFFErrorExt(tif->tif_clientdata,module,"Corrupt SOS marker in JPEG data"); |
| return(0); |
| } |
| /* Ns */ |
| if (OJPEGReadByte(sp,&n)==0) |
| return(0); |
| if (n!=sp->samples_per_pixel_per_plane) |
| { |
| TIFFErrorExt(tif->tif_clientdata,module,"Corrupt SOS marker in JPEG data"); |
| return(0); |
| } |
| /* Cs, Td, and Ta */ |
| for (o=0; o<sp->samples_per_pixel_per_plane; o++) |
| { |
| /* Cs */ |
| if (OJPEGReadByte(sp,&n)==0) |
| return(0); |
| sp->sos_cs[sp->plane_sample_offset+o]=n; |
| /* Td and Ta */ |
| if (OJPEGReadByte(sp,&n)==0) |
| return(0); |
| sp->sos_tda[sp->plane_sample_offset+o]=n; |
| } |
| /* skip Ss, Se, Ah, en Al -> no check, as per Tom Lane recommendation, as per LibJpeg source */ |
| OJPEGReadSkip(sp,3); |
| return(1); |
| } |
| |
| static int |
| OJPEGReadHeaderInfoSecTablesQTable(TIFF* tif) |
| { |
| static const char module[]="OJPEGReadHeaderInfoSecTablesQTable"; |
| OJPEGState* sp=(OJPEGState*)tif->tif_data; |
| uint8 m; |
| uint8 n; |
| uint32 oa; |
| uint8* ob; |
| uint32 p; |
| if (sp->qtable_offset[0]==0) |
| { |
| TIFFErrorExt(tif->tif_clientdata,module,"Missing JPEG tables"); |
| return(0); |
| } |
| sp->in_buffer_file_pos_log=0; |
| for (m=0; m<sp->samples_per_pixel; m++) |
| { |
| if ((sp->qtable_offset[m]!=0) && ((m==0) || (sp->qtable_offset[m]!=sp->qtable_offset[m-1]))) |
| { |
| for (n=0; n<m-1; n++) |
| { |
| if (sp->qtable_offset[m]==sp->qtable_offset[n]) |
| { |
| TIFFErrorExt(tif->tif_clientdata,module,"Corrupt JpegQTables tag value"); |
| return(0); |
| } |
| } |
| oa=sizeof(uint32)+69; |
| ob=_TIFFmalloc(oa); |
| if (ob==0) |
| { |
| TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); |
| return(0); |
| } |
| *(uint32*)ob=oa; |
| ob[sizeof(uint32)]=255; |
| ob[sizeof(uint32)+1]=JPEG_MARKER_DQT; |
| ob[sizeof(uint32)+2]=0; |
| ob[sizeof(uint32)+3]=67; |
| ob[sizeof(uint32)+4]=m; |
| TIFFSeekFile(tif,sp->qtable_offset[m],SEEK_SET); |
| p=(uint32)TIFFReadFile(tif,&ob[sizeof(uint32)+5],64); |
| if (p!=64) |
| { |
| _TIFFfree(ob); |
| return(0); |
| } |
| if (sp->qtable[m]!=0) |
| _TIFFfree(sp->qtable[m]); |
| sp->qtable[m]=ob; |
| sp->sof_tq[m]=m; |
| } |
| else |
| sp->sof_tq[m]=sp->sof_tq[m-1]; |
| } |
| return(1); |
| } |
| |
| static int |
| OJPEGReadHeaderInfoSecTablesDcTable(TIFF* tif) |
| { |
| static const char module[]="OJPEGReadHeaderInfoSecTablesDcTable"; |
| OJPEGState* sp=(OJPEGState*)tif->tif_data; |
| uint8 m; |
| uint8 n; |
| uint8 o[16]; |
| uint32 p; |
| uint32 q; |
| uint32 ra; |
| uint8* rb; |
| if (sp->dctable_offset[0]==0) |
| { |
| TIFFErrorExt(tif->tif_clientdata,module,"Missing JPEG tables"); |
| return(0); |
| } |
| sp->in_buffer_file_pos_log=0; |
| for (m=0; m<sp->samples_per_pixel; m++) |
| { |
| if ((sp->dctable_offset[m]!=0) && ((m==0) || (sp->dctable_offset[m]!=sp->dctable_offset[m-1]))) |
| { |
| for (n=0; n<m-1; n++) |
| { |
| if (sp->dctable_offset[m]==sp->dctable_offset[n]) |
| { |
| TIFFErrorExt(tif->tif_clientdata,module,"Corrupt JpegDcTables tag value"); |
| return(0); |
| } |
| } |
| TIFFSeekFile(tif,sp->dctable_offset[m],SEEK_SET); |
| p=(uint32)TIFFReadFile(tif,o,16); |
| if (p!=16) |
| return(0); |
| q=0; |
| for (n=0; n<16; n++) |
| q+=o[n]; |
| ra=sizeof(uint32)+21+q; |
| rb=_TIFFmalloc(ra); |
| if (rb==0) |
| { |
| TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); |
| return(0); |
| } |
| *(uint32*)rb=ra; |
| rb[sizeof(uint32)]=255; |
| rb[sizeof(uint32)+1]=JPEG_MARKER_DHT; |
| rb[sizeof(uint32)+2]=(uint8)((19+q)>>8); |
| rb[sizeof(uint32)+3]=((19+q)&255); |
| rb[sizeof(uint32)+4]=m; |
| for (n=0; n<16; n++) |
| rb[sizeof(uint32)+5+n]=o[n]; |
| p=(uint32)TIFFReadFile(tif,&(rb[sizeof(uint32)+21]),q); |
| if (p!=q) |
| { |
| _TIFFfree(rb); |
| return(0); |
| } |
| if (sp->dctable[m]!=0) |
| _TIFFfree(sp->dctable[m]); |
| sp->dctable[m]=rb; |
| sp->sos_tda[m]=(m<<4); |
| } |
| else |
| sp->sos_tda[m]=sp->sos_tda[m-1]; |
| } |
| return(1); |
| } |
| |
| static int |
| OJPEGReadHeaderInfoSecTablesAcTable(TIFF* tif) |
| { |
| static const char module[]="OJPEGReadHeaderInfoSecTablesAcTable"; |
| OJPEGState* sp=(OJPEGState*)tif->tif_data; |
| uint8 m; |
| uint8 n; |
| uint8 o[16]; |
| uint32 p; |
| uint32 q; |
| uint32 ra; |
| uint8* rb; |
| if (sp->actable_offset[0]==0) |
| { |
| TIFFErrorExt(tif->tif_clientdata,module,"Missing JPEG tables"); |
| return(0); |
| } |
| sp->in_buffer_file_pos_log=0; |
| for (m=0; m<sp->samples_per_pixel; m++) |
| { |
| if ((sp->actable_offset[m]!=0) && ((m==0) || (sp->actable_offset[m]!=sp->actable_offset[m-1]))) |
| { |
| for (n=0; n<m-1; n++) |
| { |
| if (sp->actable_offset[m]==sp->actable_offset[n]) |
| { |
| TIFFErrorExt(tif->tif_clientdata,module,"Corrupt JpegAcTables tag value"); |
| return(0); |
| } |
| } |
| TIFFSeekFile(tif,sp->actable_offset[m],SEEK_SET); |
| p=(uint32)TIFFReadFile(tif,o,16); |
| if (p!=16) |
| return(0); |
| q=0; |
| for (n=0; n<16; n++) |
| q+=o[n]; |
| ra=sizeof(uint32)+21+q; |
| rb=_TIFFmalloc(ra); |
| if (rb==0) |
| { |
| TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); |
| return(0); |
| } |
| *(uint32*)rb=ra; |
| rb[sizeof(uint32)]=255; |
| rb[sizeof(uint32)+1]=JPEG_MARKER_DHT; |
| rb[sizeof(uint32)+2]=(uint8)((19+q)>>8); |
| rb[sizeof(uint32)+3]=((19+q)&255); |
| rb[sizeof(uint32)+4]=(16|m); |
| for (n=0; n<16; n++) |
| rb[sizeof(uint32)+5+n]=o[n]; |
| p=(uint32)TIFFReadFile(tif,&(rb[sizeof(uint32)+21]),q); |
| if (p!=q) |
| { |
| _TIFFfree(rb); |
| return(0); |
| } |
| if (sp->actable[m]!=0) |
| _TIFFfree(sp->actable[m]); |
| sp->actable[m]=rb; |
| sp->sos_tda[m]=(sp->sos_tda[m]|m); |
| } |
| else |
| sp->sos_tda[m]=(sp->sos_tda[m]|(sp->sos_tda[m-1]&15)); |
| } |
| return(1); |
| } |
| |
| static int |
| OJPEGReadBufferFill(OJPEGState* sp) |
| { |
| uint16 m; |
| tmsize_t n; |
| /* TODO: double-check: when subsamplingcorrect is set, no call to TIFFErrorExt or TIFFWarningExt should be made |
| * in any other case, seek or read errors should be passed through */ |
| do |
| { |
| if (sp->in_buffer_file_togo!=0) |
| { |
| if (sp->in_buffer_file_pos_log==0) |
| { |
| TIFFSeekFile(sp->tif,sp->in_buffer_file_pos,SEEK_SET); |
| sp->in_buffer_file_pos_log=1; |
| } |
| m=OJPEG_BUFFER; |
| if ((uint64)m>sp->in_buffer_file_togo) |
| m=(uint16)sp->in_buffer_file_togo; |
| n=TIFFReadFile(sp->tif,sp->in_buffer,(tmsize_t)m); |
| if (n==0) |
| return(0); |
| assert(n>0); |
| assert(n<=OJPEG_BUFFER); |
| assert(n<65536); |
| assert((uint64)n<=sp->in_buffer_file_togo); |
| m=(uint16)n; |
| sp->in_buffer_togo=m; |
| sp->in_buffer_cur=sp->in_buffer; |
| sp->in_buffer_file_togo-=m; |
| sp->in_buffer_file_pos+=m; |
| break; |
| } |
| sp->in_buffer_file_pos_log=0; |
| switch(sp->in_buffer_source) |
| { |
| case osibsNotSetYet: |
| if (sp->jpeg_interchange_format!=0) |
| { |
| sp->in_buffer_file_pos=sp->jpeg_interchange_format; |
| sp->in_buffer_file_togo=sp->jpeg_interchange_format_length; |
| } |
| sp->in_buffer_source=osibsJpegInterchangeFormat; |
| break; |
| case osibsJpegInterchangeFormat: |
| sp->in_buffer_source=osibsStrile; |
| break; |
| case osibsStrile: |
| if (!_TIFFFillStriles( sp->tif ) |
| || sp->tif->tif_dir.td_stripoffset == NULL |
| || sp->tif->tif_dir.td_stripbytecount == NULL) |
| return 0; |
| |
| if (sp->in_buffer_next_strile==sp->in_buffer_strile_count) |
| sp->in_buffer_source=osibsEof; |
| else |
| { |
| sp->in_buffer_file_pos=sp->tif->tif_dir.td_stripoffset[sp->in_buffer_next_strile]; |
| if (sp->in_buffer_file_pos!=0) |
| { |
| if (sp->in_buffer_file_pos>=sp->file_size) |
| sp->in_buffer_file_pos=0; |
| else if (sp->tif->tif_dir.td_stripbytecount==NULL) |
| sp->in_buffer_file_togo=sp->file_size-sp->in_buffer_file_pos; |
| else |
| { |
| if (sp->tif->tif_dir.td_stripbytecount == 0) { |
| TIFFErrorExt(sp->tif->tif_clientdata,sp->tif->tif_name,"Strip byte counts are missing"); |
| return(0); |
| } |
| sp->in_buffer_file_togo=sp->tif->tif_dir.td_stripbytecount[sp->in_buffer_next_strile]; |
| if (sp->in_buffer_file_togo==0) |
| sp->in_buffer_file_pos=0; |
| else if (sp->in_buffer_file_pos+sp->in_buffer_file_togo>sp->file_size) |
| sp->in_buffer_file_togo=sp->file_size-sp->in_buffer_file_pos; |
| } |
| } |
| sp->in_buffer_next_strile++; |
| } |
| break; |
| default: |
| return(0); |
| } |
| } while (1); |
| return(1); |
| } |
| |
| static int |
| OJPEGReadByte(OJPEGState* sp, uint8* byte) |
| { |
| if (sp->in_buffer_togo==0) |
| { |
| if (OJPEGReadBufferFill(sp)==0) |
| return(0); |
| assert(sp->in_buffer_togo>0); |
| } |
| *byte=*(sp->in_buffer_cur); |
| sp->in_buffer_cur++; |
| sp->in_buffer_togo--; |
| return(1); |
| } |
| |
| static int |
| OJPEGReadBytePeek(OJPEGState* sp, uint8* byte) |
| { |
| if (sp->in_buffer_togo==0) |
| { |
| if (OJPEGReadBufferFill(sp)==0) |
| return(0); |
| assert(sp->in_buffer_togo>0); |
| } |
| *byte=*(sp->in_buffer_cur); |
| return(1); |
| } |
| |
| static void |
| OJPEGReadByteAdvance(OJPEGState* sp) |
| { |
| assert(sp->in_buffer_togo>0); |
| sp->in_buffer_cur++; |
| sp->in_buffer_togo--; |
| } |
| |
| static int |
| OJPEGReadWord(OJPEGState* sp, uint16* word) |
| { |
| uint8 m; |
| if (OJPEGReadByte(sp,&m)==0) |
| return(0); |
| *word=(m<<8); |
| if (OJPEGReadByte(sp,&m)==0) |
| return(0); |
| *word|=m; |
| return(1); |
| } |
| |
| static int |
| OJPEGReadBlock(OJPEGState* sp, uint16 len, void* mem) |
| { |
| uint16 mlen; |
| uint8* mmem; |
| uint16 n; |
| assert(len>0); |
| mlen=len; |
| mmem=mem; |
| do |
| { |
| if (sp->in_buffer_togo==0) |
| { |
| if (OJPEGReadBufferFill(sp)==0) |
| return(0); |
| assert(sp->in_buffer_togo>0); |
| } |
| n=mlen; |
| if (n>sp->in_buffer_togo) |
| n=sp->in_buffer_togo; |
| _TIFFmemcpy(mmem,sp->in_buffer_cur,n); |
| sp->in_buffer_cur+=n; |
| sp->in_buffer_togo-=n; |
| mlen-=n; |
| mmem+=n; |
| } while(mlen>0); |
| return(1); |
| } |
| |
| static void |
| OJPEGReadSkip(OJPEGState* sp, uint16 len) |
| { |
| uint16 m; |
| uint16 n; |
| m=len; |
| n=m; |
| if (n>sp->in_buffer_togo) |
| n=sp->in_buffer_togo; |
| sp->in_buffer_cur+=n; |
| sp->in_buffer_togo-=n; |
| m-=n; |
| if (m>0) |
| { |
| assert(sp->in_buffer_togo==0); |
| n=m; |
| if ((uint64)n>sp->in_buffer_file_togo) |
| n=(uint16)sp->in_buffer_file_togo; |
| sp->in_buffer_file_pos+=n; |
| sp->in_buffer_file_togo-=n; |
| sp->in_buffer_file_pos_log=0; |
| /* we don't skip past jpeginterchangeformat/strile block... |
| * if that is asked from us, we're dealing with totally bazurk |
| * data anyway, and we've not seen this happening on any |
| * testfile, so we might as well likely cause some other |
| * meaningless error to be passed at some later time |
| */ |
| } |
| } |
| |
| static int |
| OJPEGWriteStream(TIFF* tif, void** mem, uint32* len) |
| { |
| OJPEGState* sp=(OJPEGState*)tif->tif_data; |
| *len=0; |
| do |
| { |
| assert(sp->out_state<=ososEoi); |
| switch(sp->out_state) |
| { |
| case ososSoi: |
| OJPEGWriteStreamSoi(tif,mem,len); |
| break; |
| case ososQTable0: |
| OJPEGWriteStreamQTable(tif,0,mem,len); |
| break; |
| case ososQTable1: |
| OJPEGWriteStreamQTable(tif,1,mem,len); |
| break; |
| case ososQTable2: |
| OJPEGWriteStreamQTable(tif,2,mem,len); |
| break; |
| case ososQTable3: |
| OJPEGWriteStreamQTable(tif,3,mem,len); |
| break; |
| case ososDcTable0: |
| OJPEGWriteStreamDcTable(tif,0,mem,len); |
| break; |
| case ososDcTable1: |
| OJPEGWriteStreamDcTable(tif,1,mem,len); |
| break; |
| case ososDcTable2: |
| OJPEGWriteStreamDcTable(tif,2,mem,len); |
| break; |
| case ososDcTable3: |
| OJPEGWriteStreamDcTable(tif,3,mem,len); |
| break; |
| case ososAcTable0: |
| OJPEGWriteStreamAcTable(tif,0,mem,len); |
| break; |
| case ososAcTable1: |
| OJPEGWriteStreamAcTable(tif,1,mem,len); |
| break; |
| case ososAcTable2: |
| OJPEGWriteStreamAcTable(tif,2,mem,len); |
| break; |
| case ososAcTable3: |
| OJPEGWriteStreamAcTable(tif,3,mem,len); |
| break; |
| case ososDri: |
| OJPEGWriteStreamDri(tif,mem,len); |
| break; |
| case ososSof: |
| OJPEGWriteStreamSof(tif,mem,len); |
| break; |
| case ososSos: |
| OJPEGWriteStreamSos(tif,mem,len); |
| break; |
| case ososCompressed: |
| if (OJPEGWriteStreamCompressed(tif,mem,len)==0) |
| return(0); |
| break; |
| case ososRst: |
| OJPEGWriteStreamRst(tif,mem,len); |
| break; |
| case ososEoi: |
| OJPEGWriteStreamEoi(tif,mem,len); |
| break; |
| } |
| } while (*len==0); |
| return(1); |
| } |
| |
| static void |
| OJPEGWriteStreamSoi(TIFF* tif, void** mem, uint32* len) |
| { |
| OJPEGState* sp=(OJPEGState*)tif->tif_data; |
| assert(OJPEG_BUFFER>=2); |
| sp->out_buffer[0]=255; |
| sp->out_buffer[1]=JPEG_MARKER_SOI; |
| *len=2; |
| *mem=(void*)sp->out_buffer; |
| sp->out_state++; |
| } |
| |
| static void |
| OJPEGWriteStreamQTable(TIFF* tif, uint8 table_index, void** mem, uint32* len) |
| { |
| OJPEGState* sp=(OJPEGState*)tif->tif_data; |
| if (sp->qtable[table_index]!=0) |
| { |
| *mem=(void*)(sp->qtable[table_index]+sizeof(uint32)); |
| *len=*((uint32*)sp->qtable[table_index])-sizeof(uint32); |
| } |
| sp->out_state++; |
| } |
| |
| static void |
| OJPEGWriteStreamDcTable(TIFF* tif, uint8 table_index, void** mem, uint32* len) |
| { |
| OJPEGState* sp=(OJPEGState*)tif->tif_data; |
| if (sp->dctable[table_index]!=0) |
| { |
| *mem=(void*)(sp->dctable[table_index]+sizeof(uint32)); |
| *len=*((uint32*)sp->dctable[table_index])-sizeof(uint32); |
| } |
| sp->out_state++; |
| } |
| |
| static void |
| OJPEGWriteStreamAcTable(TIFF* tif, uint8 table_index, void** mem, uint32* len) |
| { |
| OJPEGState* sp=(OJPEGState*)tif->tif_data; |
| if (sp->actable[table_index]!=0) |
| { |
| *mem=(void*)(sp->actable[table_index]+sizeof(uint32)); |
| *len=*((uint32*)sp->actable[table_index])-sizeof(uint32); |
| } |
| sp->out_state++; |
| } |
| |
| static void |
| OJPEGWriteStreamDri(TIFF* tif, void** mem, uint32* len) |
| { |
| OJPEGState* sp=(OJPEGState*)tif->tif_data; |
| assert(OJPEG_BUFFER>=6); |
| if (sp->restart_interval!=0) |
| { |
| sp->out_buffer[0]=255; |
| sp->out_buffer[1]=JPEG_MARKER_DRI; |
| sp->out_buffer[2]=0; |
| sp->out_buffer[3]=4; |
| sp->out_buffer[4]=(sp->restart_interval>>8); |
| sp->out_buffer[5]=(sp->restart_interval&255); |
| *len=6; |
| *mem=(void*)sp->out_buffer; |
| } |
| sp->out_state++; |
| } |
| |
| static void |
| OJPEGWriteStreamSof(TIFF* tif, void** mem, uint32* len) |
| { |
| OJPEGState* sp=(OJPEGState*)tif->tif_data; |
| uint8 m; |
| assert(OJPEG_BUFFER>=2+8+sp->samples_per_pixel_per_plane*3); |
| assert(255>=8+sp->samples_per_pixel_per_plane*3); |
| sp->out_buffer[0]=255; |
| sp->out_buffer[1]=sp->sof_marker_id; |
| /* Lf */ |
| sp->out_buffer[2]=0; |
| sp->out_buffer[3]=8+sp->samples_per_pixel_per_plane*3; |
| /* P */ |
| sp->out_buffer[4]=8; |
| /* Y */ |
| sp->out_buffer[5]=(uint8)(sp->sof_y>>8); |
| sp->out_buffer[6]=(sp->sof_y&255); |
| /* X */ |
| sp->out_buffer[7]=(uint8)(sp->sof_x>>8); |
| sp->out_buffer[8]=(sp->sof_x&255); |
| /* Nf */ |
| sp->out_buffer[9]=sp->samples_per_pixel_per_plane; |
| for (m=0; m<sp->samples_per_pixel_per_plane; m++) |
| { |
| /* C */ |
| sp->out_buffer[10+m*3]=sp->sof_c[sp->plane_sample_offset+m]; |
| /* H and V */ |
| sp->out_buffer[10+m*3+1]=sp->sof_hv[sp->plane_sample_offset+m]; |
| /* Tq */ |
| sp->out_buffer[10+m*3+2]=sp->sof_tq[sp->plane_sample_offset+m]; |
| } |
| *len=10+sp->samples_per_pixel_per_plane*3; |
| *mem=(void*)sp->out_buffer; |
| sp->out_state++; |
| } |
| |
| static void |
| OJPEGWriteStreamSos(TIFF* tif, void** mem, uint32* len) |
| { |
| OJPEGState* sp=(OJPEGState*)tif->tif_data; |
| uint8 m; |
| assert(OJPEG_BUFFER>=2+6+sp->samples_per_pixel_per_plane*2); |
| assert(255>=6+sp->samples_per_pixel_per_plane*2); |
| sp->out_buffer[0]=255; |
| sp->out_buffer[1]=JPEG_MARKER_SOS; |
| /* Ls */ |
| sp->out_buffer[2]=0; |
| sp->out_buffer[3]=6+sp->samples_per_pixel_per_plane*2; |
| /* Ns */ |
| sp->out_buffer[4]=sp->samples_per_pixel_per_plane; |
| for (m=0; m<sp->samples_per_pixel_per_plane; m++) |
| { |
| /* Cs */ |
| sp->out_buffer[5+m*2]=sp->sos_cs[sp->plane_sample_offset+m]; |
| /* Td and Ta */ |
| sp->out_buffer[5+m*2+1]=sp->sos_tda[sp->plane_sample_offset+m]; |
| } |
| /* Ss */ |
| sp->out_buffer[5+sp->samples_per_pixel_per_plane*2]=0; |
| /* Se */ |
| sp->out_buffer[5+sp->samples_per_pixel_per_plane*2+1]=63; |
| /* Ah and Al */ |
| sp->out_buffer[5+sp->samples_per_pixel_per_plane*2+2]=0; |
| *len=8+sp->samples_per_pixel_per_plane*2; |
| *mem=(void*)sp->out_buffer; |
| sp->out_state++; |
| } |
| |
| static int |
| OJPEGWriteStreamCompressed(TIFF* tif, void** mem, uint32* len) |
| { |
| OJPEGState* sp=(OJPEGState*)tif->tif_data; |
| if (sp->in_buffer_togo==0) |
| { |
| if (OJPEGReadBufferFill(sp)==0) |
| return(0); |
| assert(sp->in_buffer_togo>0); |
| } |
| *len=sp->in_buffer_togo; |
| *mem=(void*)sp->in_buffer_cur; |
| sp->in_buffer_togo=0; |
| if (sp->in_buffer_file_togo==0) |
| { |
| switch(sp->in_buffer_source) |
| { |
| case osibsStrile: |
| if (sp->in_buffer_next_strile<sp->in_buffer_strile_count) |
| sp->out_state=ososRst; |
| else |
| sp->out_state=ososEoi; |
| break; |
| case osibsEof: |
| sp->out_state=ososEoi; |
| break; |
| default: |
| break; |
| } |
| } |
| return(1); |
| } |
| |
| static void |
| OJPEGWriteStreamRst(TIFF* tif, void** mem, uint32* len) |
| { |
| OJPEGState* sp=(OJPEGState*)tif->tif_data; |
| assert(OJPEG_BUFFER>=2); |
| sp->out_buffer[0]=255; |
| sp->out_buffer[1]=JPEG_MARKER_RST0+sp->restart_index; |
| sp->restart_index++; |
| if (sp->restart_index==8) |
| sp->restart_index=0; |
| *len=2; |
| *mem=(void*)sp->out_buffer; |
| sp->out_state=ososCompressed; |
| } |
| |
| static void |
| OJPEGWriteStreamEoi(TIFF* tif, void** mem, uint32* len) |
| { |
| OJPEGState* sp=(OJPEGState*)tif->tif_data; |
| assert(OJPEG_BUFFER>=2); |
| sp->out_buffer[0]=255; |
| sp->out_buffer[1]=JPEG_MARKER_EOI; |
| *len=2; |
| *mem=(void*)sp->out_buffer; |
| } |
| |
| #ifndef LIBJPEG_ENCAP_EXTERNAL |
| static int |
| jpeg_create_decompress_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo) |
| { |
| if( SETJMP(sp->exit_jmpbuf) ) |
| return 0; |
| else { |
| jpeg_create_decompress(cinfo); |
| return 1; |
| } |
| } |
| #endif |
| |
| #ifndef LIBJPEG_ENCAP_EXTERNAL |
| static int |
| jpeg_read_header_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo, uint8 require_image) |
| { |
| if( SETJMP(sp->exit_jmpbuf) ) |
| return 0; |
| else { |
| jpeg_read_header(cinfo,require_image); |
| return 1; |
| } |
| } |
| #endif |
| |
| #ifndef LIBJPEG_ENCAP_EXTERNAL |
| static int |
| jpeg_start_decompress_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo) |
| { |
| if( SETJMP(sp->exit_jmpbuf) ) |
| return 0; |
| else { |
| jpeg_start_decompress(cinfo); |
| return 1; |
| } |
| } |
| #endif |
| |
| #ifndef LIBJPEG_ENCAP_EXTERNAL |
| static int |
| jpeg_read_scanlines_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo, void* scanlines, uint32 max_lines) |
| { |
| if( SETJMP(sp->exit_jmpbuf) ) |
| return 0; |
| else { |
| jpeg_read_scanlines(cinfo,scanlines,max_lines); |
| return 1; |
| } |
| } |
| #endif |
| |
| #ifndef LIBJPEG_ENCAP_EXTERNAL |
| static int |
| jpeg_read_raw_data_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo, void* data, uint32 max_lines) |
| { |
| if( SETJMP(sp->exit_jmpbuf) ) |
| return 0; |
| else { |
| jpeg_read_raw_data(cinfo,data,max_lines); |
| return 1; |
| } |
| } |
| #endif |
| |
| #ifndef LIBJPEG_ENCAP_EXTERNAL |
| static void |
| jpeg_encap_unwind(TIFF* tif) |
| { |
| OJPEGState* sp=(OJPEGState*)tif->tif_data; |
| LONGJMP(sp->exit_jmpbuf,1); |
| } |
| #endif |
| |
| static void |
| OJPEGLibjpegJpegErrorMgrOutputMessage(jpeg_common_struct* cinfo) |
| { |
| char buffer[JMSG_LENGTH_MAX]; |
| (*cinfo->err->format_message)(cinfo,buffer); |
| TIFFWarningExt(((TIFF*)(cinfo->client_data))->tif_clientdata,"LibJpeg","%s",buffer); |
| } |
| |
| static void |
| OJPEGLibjpegJpegErrorMgrErrorExit(jpeg_common_struct* cinfo) |
| { |
| char buffer[JMSG_LENGTH_MAX]; |
| (*cinfo->err->format_message)(cinfo,buffer); |
| TIFFErrorExt(((TIFF*)(cinfo->client_data))->tif_clientdata,"LibJpeg","%s",buffer); |
| jpeg_encap_unwind((TIFF*)(cinfo->client_data)); |
| } |
| |
| static void |
| OJPEGLibjpegJpegSourceMgrInitSource(jpeg_decompress_struct* cinfo) |
| { |
| (void)cinfo; |
| } |
| |
| static boolean |
| OJPEGLibjpegJpegSourceMgrFillInputBuffer(jpeg_decompress_struct* cinfo) |
| { |
| TIFF* tif=(TIFF*)cinfo->client_data; |
| OJPEGState* sp=(OJPEGState*)tif->tif_data; |
| void* mem=0; |
| uint32 len=0U; |
| if (OJPEGWriteStream(tif,&mem,&len)==0) |
| { |
| TIFFErrorExt(tif->tif_clientdata,"LibJpeg","Premature end of JPEG data"); |
| jpeg_encap_unwind(tif); |
| } |
| sp->libjpeg_jpeg_source_mgr.bytes_in_buffer=len; |
| sp->libjpeg_jpeg_source_mgr.next_input_byte=mem; |
| return(1); |
| } |
| |
| static void |
| OJPEGLibjpegJpegSourceMgrSkipInputData(jpeg_decompress_struct* cinfo, long num_bytes) |
| { |
| TIFF* tif=(TIFF*)cinfo->client_data; |
| (void)num_bytes; |
| TIFFErrorExt(tif->tif_clientdata,"LibJpeg","Unexpected error"); |
| jpeg_encap_unwind(tif); |
| } |
| |
| #ifdef _MSC_VER |
| #pragma warning( push ) |
| #pragma warning( disable : 4702 ) /* unreachable code */ |
| #endif |
| static boolean |
| OJPEGLibjpegJpegSourceMgrResyncToRestart(jpeg_decompress_struct* cinfo, int desired) |
| { |
| TIFF* tif=(TIFF*)cinfo->client_data; |
| (void)desired; |
| TIFFErrorExt(tif->tif_clientdata,"LibJpeg","Unexpected error"); |
| jpeg_encap_unwind(tif); |
| return(0); |
| } |
| #ifdef _MSC_VER |
| #pragma warning( pop ) |
| #endif |
| |
| static void |
| OJPEGLibjpegJpegSourceMgrTermSource(jpeg_decompress_struct* cinfo) |
| { |
| (void)cinfo; |
| } |
| |
| #endif |
| |
| |
| /* |
| * Local Variables: |
| * mode: c |
| * c-basic-offset: 8 |
| * fill-column: 78 |
| * End: |
| */ |