2010-07-16 20:54:53 +08:00
/* $Id: tif_ojpeg.c,v 1.24.2.6 2010-06-08 23:29:51 bfriesen 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 6 B 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
developement . 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 . Allthough
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
consistenly 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 dissadvantage 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 .
*/
2010-05-12 01:44:00 +08:00
# include "tiffiop.h"
# ifdef OJPEG_SUPPORT
2010-07-16 20:54:53 +08:00
/* 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
* conviniently 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 accomodate 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 64 K since it is indexed
* with uint16 . We recommend 2 K .
* 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)
# define FIELD_OJPEG_COUNT 7
static const TIFFFieldInfo ojpeg_field_info [ ] = {
{ TIFFTAG_JPEGIFOFFSET , 1 , 1 , TIFF_LONG , FIELD_OJPEG_JPEGINTERCHANGEFORMAT , TRUE , FALSE , " JpegInterchangeFormat " } ,
{ TIFFTAG_JPEGIFBYTECOUNT , 1 , 1 , TIFF_LONG , FIELD_OJPEG_JPEGINTERCHANGEFORMATLENGTH , TRUE , FALSE , " JpegInterchangeFormatLength " } ,
{ TIFFTAG_JPEGQTABLES , TIFF_VARIABLE , TIFF_VARIABLE , TIFF_LONG , FIELD_OJPEG_JPEGQTABLES , FALSE , TRUE , " JpegQTables " } ,
{ TIFFTAG_JPEGDCTABLES , TIFF_VARIABLE , TIFF_VARIABLE , TIFF_LONG , FIELD_OJPEG_JPEGDCTABLES , FALSE , TRUE , " JpegDcTables " } ,
{ TIFFTAG_JPEGACTABLES , TIFF_VARIABLE , TIFF_VARIABLE , TIFF_LONG , FIELD_OJPEG_JPEGACTABLES , FALSE , TRUE , " JpegAcTables " } ,
{ TIFFTAG_JPEGPROC , 1 , 1 , TIFF_SHORT , FIELD_OJPEG_JPEGPROC , FALSE , FALSE , " JpegProc " } ,
{ TIFFTAG_JPEGRESTARTINTERVAL , 1 , 1 , TIFF_SHORT , FIELD_OJPEG_JPEGRESTARTINTERVAL , FALSE , FALSE , " JpegRestartInterval " } ,
} ;
# ifndef LIBJPEG_ENCAP_EXTERNAL
2010-05-12 01:44:00 +08:00
# include <setjmp.h>
# endif
2010-07-16 20:54:53 +08:00
2010-05-12 01:44:00 +08:00
# include "jpeglib.h"
2010-07-16 20:54:53 +08:00
# include "jerror.h"
2010-05-12 01:44:00 +08:00
2010-07-16 20:54:53 +08:00
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 ;
2010-05-12 01:44:00 +08:00
2010-07-16 20:54:53 +08:00
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 ;
# ifndef LIBJPEG_ENCAP_EXTERNAL
JMP_BUF exit_jmpbuf ;
# endif
TIFFVGetMethod vgetparent ;
TIFFVSetMethod vsetparent ;
toff_t 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 ;
toff_t jpeg_interchange_format ;
toff_t 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 ;
toff_t qtable_offset [ 3 ] ;
toff_t dctable_offset [ 3 ] ;
toff_t 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 ;
tstrile_t in_buffer_next_strile ;
toff_t in_buffer_file_pos ;
toff_t in_buffer_file_togo ;
} sos_end [ 3 ] ;
uint8 readheader_done ;
uint8 writeheader_done ;
tsample_t write_cursample ;
tstrile_t 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 ;
tstrile_t in_buffer_next_strile ;
tstrile_t in_buffer_strile_count ;
toff_t in_buffer_file_pos ;
uint8 in_buffer_file_pos_log ;
toff_t 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 , ttag_t tag , va_list ap ) ;
static int OJPEGVSetField ( TIFF * tif , ttag_t tag , va_list ap ) ;
static void OJPEGPrintDir ( TIFF * tif , FILE * fd , long flags ) ;
static int OJPEGSetupDecode ( TIFF * tif ) ;
static int OJPEGPreDecode ( TIFF * tif , tsample_t s ) ;
static int OJPEGPreDecodeSkipRaw ( TIFF * tif ) ;
static int OJPEGPreDecodeSkipScanlines ( TIFF * tif ) ;
static int OJPEGDecode ( TIFF * tif , tidata_t buf , tsize_t cc , tsample_t s ) ;
static int OJPEGDecodeRaw ( TIFF * tif , tidata_t buf , tsize_t cc ) ;
static int OJPEGDecodeScanlines ( TIFF * tif , tidata_t buf , tsize_t cc ) ;
static void OJPEGPostDecode ( TIFF * tif , tidata_t buf , tsize_t cc ) ;
static int OJPEGSetupEncode ( TIFF * tif ) ;
static int OJPEGPreEncode ( TIFF * tif , tsample_t s ) ;
static int OJPEGEncode ( TIFF * tif , tidata_t buf , tsize_t cc , tsample_t 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 , tsample_t 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
2010-05-12 01:44:00 +08:00
2010-07-16 20:54:53 +08:00
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 ) ;
2010-05-12 01:44:00 +08:00
2010-07-16 20:54:53 +08:00
int
TIFFInitOJPEG ( TIFF * tif , int scheme )
{
static const char module [ ] = " TIFFInitOJPEG " ;
OJPEGState * sp ;
assert ( scheme = = COMPRESSION_OJPEG ) ;
/*
* Merge codec - specific tag information .
*/
if ( ! _TIFFMergeFieldInfo ( tif , ojpeg_field_info , FIELD_OJPEG_COUNT ) ) {
TIFFErrorExt ( tif - > tif_clientdata , module ,
" Merging Old JPEG codec-specific tags failed " ) ;
return 0 ;
}
2010-05-12 01:44:00 +08:00
2010-07-16 20:54:53 +08:00
/* 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_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 = ( tidata_t ) 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 ;
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 ) ;
}
2010-05-12 01:44:00 +08:00
2010-07-16 20:54:53 +08:00
static int
OJPEGVGetField ( TIFF * tif , ttag_t tag , va_list ap )
{
OJPEGState * sp = ( OJPEGState * ) tif - > tif_data ;
switch ( tag )
{
case TIFFTAG_JPEGIFOFFSET :
* va_arg ( ap , uint32 * ) = ( uint32 ) sp - > jpeg_interchange_format ;
break ;
case TIFFTAG_JPEGIFBYTECOUNT :
* va_arg ( ap , uint32 * ) = ( uint32 ) 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 ) ;
}
2010-05-12 01:44:00 +08:00
2010-07-16 20:54:53 +08:00
static int
OJPEGVSetField ( TIFF * tif , ttag_t tag , va_list ap )
2010-05-12 01:44:00 +08:00
{
2010-07-16 20:54:53 +08:00
static const char module [ ] = " OJPEGVSetField " ;
OJPEGState * sp = ( OJPEGState * ) tif - > tif_data ;
uint32 ma ;
uint32 * mb ;
uint32 n ;
switch ( tag )
{
case TIFFTAG_JPEGIFOFFSET :
sp - > jpeg_interchange_format = ( toff_t ) va_arg ( ap , uint32 ) ;
break ;
case TIFFTAG_JPEGIFBYTECOUNT :
sp - > jpeg_interchange_format_length = ( toff_t ) va_arg ( ap , uint32 ) ;
break ;
case TIFFTAG_YCBCRSUBSAMPLING :
sp - > subsampling_tag = 1 ;
sp - > subsampling_hor = ( uint8 ) va_arg ( ap , int ) ;
sp - > subsampling_ver = ( uint8 ) va_arg ( ap , int ) ;
tif - > tif_dir . td_ycbcrsubsampling [ 0 ] = sp - > subsampling_hor ;
tif - > tif_dir . td_ycbcrsubsampling [ 1 ] = sp - > subsampling_ver ;
break ;
case TIFFTAG_JPEGQTABLES :
ma = 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 = va_arg ( ap , uint32 * ) ;
for ( n = 0 ; n < ma ; n + + )
sp - > qtable_offset [ n ] = ( toff_t ) mb [ n ] ;
}
break ;
case TIFFTAG_JPEGDCTABLES :
ma = 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 = va_arg ( ap , uint32 * ) ;
for ( n = 0 ; n < ma ; n + + )
sp - > dctable_offset [ n ] = ( toff_t ) mb [ n ] ;
}
break ;
case TIFFTAG_JPEGACTABLES :
ma = 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 = va_arg ( ap , uint32 * ) ;
for ( n = 0 ; n < ma ; n + + )
sp - > actable_offset [ n ] = ( toff_t ) mb [ n ] ;
}
break ;
case TIFFTAG_JPEGPROC :
sp - > jpeg_proc = ( uint8 ) va_arg ( ap , uint32 ) ;
break ;
case TIFFTAG_JPEGRESTARTINTERVAL :
sp - > restart_interval = ( uint16 ) va_arg ( ap , uint32 ) ;
break ;
default :
return ( * sp - > vsetparent ) ( tif , tag , ap ) ;
}
TIFFSetFieldBit ( tif , _TIFFFieldWithTag ( tif , tag ) - > field_bit ) ;
tif - > tif_flags | = TIFF_DIRTYDIRECT ;
return ( 1 ) ;
2010-05-12 01:44:00 +08:00
}
static void
2010-07-16 20:54:53 +08:00
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: %lu \n " , ( unsigned long ) sp - > jpeg_interchange_format ) ;
if ( TIFFFieldSet ( tif , FIELD_OJPEG_JPEGINTERCHANGEFORMATLENGTH ) )
fprintf ( fd , " JpegInterchangeFormatLength: %lu \n " , ( unsigned long ) 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 , " %lu " , ( unsigned long ) 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 , " %lu " , ( unsigned long ) 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 , " %lu " , ( unsigned long ) 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 ) ;
}
2010-05-12 01:44:00 +08:00
2010-07-16 20:54:53 +08:00
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 ) ;
}
2010-05-12 01:44:00 +08:00
2010-07-16 20:54:53 +08:00
static int
OJPEGPreDecode ( TIFF * tif , tsample_t s )
{
OJPEGState * sp = ( OJPEGState * ) tif - > tif_data ;
tstrile_t 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 = ( tstrile_t ) tif - > tif_curtile ;
else
m = ( tstrile_t ) 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 = 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 + + ;
}
return ( 1 ) ;
}
2010-05-12 01:44:00 +08:00
static int
2010-07-16 20:54:53 +08:00
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 ) ;
}
2010-05-12 01:44:00 +08:00
2010-07-16 20:54:53 +08:00
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 ) ;
}
2010-05-12 01:44:00 +08:00
2010-07-16 20:54:53 +08:00
static int
OJPEGDecode ( TIFF * tif , tidata_t buf , tsize_t cc , tsample_t s )
{
OJPEGState * sp = ( OJPEGState * ) tif - > tif_data ;
( void ) s ;
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 ) ;
}
2010-05-12 01:44:00 +08:00
2010-07-16 20:54:53 +08:00
static int
OJPEGDecodeRaw ( TIFF * tif , tidata_t buf , tsize_t cc )
{
static const char module [ ] = " OJPEGDecodeRaw " ;
OJPEGState * sp = ( OJPEGState * ) tif - > tif_data ;
uint8 * m ;
uint32 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 ) ;
}
2010-05-12 01:44:00 +08:00
2010-07-16 20:54:53 +08:00
static int
OJPEGDecodeScanlines ( TIFF * tif , tidata_t buf , tsize_t cc )
{
static const char module [ ] = " OJPEGDecodeScanlines " ;
OJPEGState * sp = ( OJPEGState * ) tif - > tif_data ;
uint8 * m ;
uint32 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 ) ;
}
2010-05-12 01:44:00 +08:00
static void
2010-07-16 20:54:53 +08:00
OJPEGPostDecode ( TIFF * tif , tidata_t buf , tsize_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 ;
}
}
2010-05-12 01:44:00 +08:00
2010-07-16 20:54:53 +08:00
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 , tsample_t 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 , tidata_t buf , tsize_t cc , tsample_t 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 ) ;
}
2010-05-12 01:44:00 +08:00
static void
2010-07-16 20:54:53 +08:00
OJPEGCleanup ( TIFF * tif )
{
OJPEGState * sp = ( OJPEGState * ) tif - > tif_data ;
if ( sp ! = 0 )
{
tif - > tif_tagmethods . vgetfield = sp - > vgetparent ;
tif - > tif_tagmethods . vsetfield = sp - > vsetparent ;
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 ;
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 ;
}
2010-05-12 01:44:00 +08:00
static int
2010-07-16 20:54:53 +08:00
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 ;
}
sp - > samples_per_pixel = tif - > tif_dir . td_samplesperpixel ;
if ( 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 ( sp - > samples_per_pixel ! = 3 )
{
TIFFErrorExt ( tif - > tif_clientdata , module , " SamplesPerPixel %d not supported for this compression scheme " , sp - > samples_per_pixel ) ;
return ( 0 ) ;
}
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 = ( ( 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 ) ;
}
2010-05-12 01:44:00 +08:00
2010-07-16 20:54:53 +08:00
static int
OJPEGReadSecondarySos ( TIFF * tif , tsample_t 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 = 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 ;
assert ( sp - > libjpeg_session_active = = 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 ) ;
}
2010-05-12 01:44:00 +08:00
static void
2010-07-16 20:54:53 +08:00
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 ;
}
2010-05-12 01:44:00 +08:00
2010-07-16 20:54:53 +08:00
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 ) ;
}
2010-05-12 01:44:00 +08:00
2010-07-16 20:54:53 +08:00
static int
OJPEGReadHeaderInfoSecStreamDri ( TIFF * tif )
{
/* this could easilly cause trouble in some cases... but no such cases have occured sofar */
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 )
return ( 0 ) ;
o = nb [ sizeof ( uint32 ) + 4 ] & 15 ;
if ( 3 < o )
{
TIFFErrorExt ( tif - > tif_clientdata , module , " Corrupt DQT marker in JPEG data " ) ;
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 )
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 " ) ;
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 " ) ;
return ( 0 ) ;
}
o & = 15 ;
if ( 3 < o )
{
TIFFErrorExt ( tif - > tif_clientdata , module , " Corrupt DHT marker in JPEG data " ) ;
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
{
/* TODO: probably best to also add check on allowed upper bound, especially x, may cause buffer overflow otherwise i think */
/* Y: Number of lines */
if ( OJPEGReadWord ( sp , & p ) = = 0 )
return ( 0 ) ;
if ( ( p < sp - > image_length ) & & ( 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 ( ( p < sp - > image_width ) & & ( p < sp - > strile_width ) )
{
TIFFErrorExt ( tif - > tif_clientdata , module , " JPEG compressed data indicates unexpected 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 = TIFFReadFile ( tif , & ob [ sizeof ( uint32 ) + 5 ] , 64 ) ;
if ( p ! = 64 )
return ( 0 ) ;
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 = 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 ] = ( ( 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 = TIFFReadFile ( tif , & ( rb [ sizeof ( uint32 ) + 21 ] ) , q ) ;
if ( p ! = q )
return ( 0 ) ;
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 = 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 ] = ( ( 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 = TIFFReadFile ( tif , & ( rb [ sizeof ( uint32 ) + 21 ] ) , q ) ;
if ( p ! = q )
return ( 0 ) ;
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 ;
tsize_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 ( m > sp - > in_buffer_file_togo )
m = ( uint16 ) sp - > in_buffer_file_togo ;
n = TIFFReadFile ( sp - > tif , sp - > in_buffer , ( tsize_t ) m ) ;
if ( n = = 0 )
return ( 0 ) ;
assert ( n > 0 ) ;
assert ( n < = OJPEG_BUFFER ) ;
assert ( n < 65536 ) ;
assert ( ( uint16 ) 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 ;
case osibsStrile :
if ( sp - > in_buffer_next_strile = = sp - > in_buffer_strile_count )
sp - > in_buffer_source = osibsEof ;
else
{
if ( sp - > tif - > tif_dir . td_stripoffset = = 0 ) {
TIFFErrorExt ( sp - > tif - > tif_clientdata , sp - > tif - > tif_name , " Strip offsets are missing " ) ;
return ( 0 ) ;
}
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
{
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 ) ;
}
2010-05-12 01:44:00 +08:00
static void
2010-07-16 20:54:53 +08:00
OJPEGReadByteAdvance ( OJPEGState * sp )
{
assert ( sp - > in_buffer_togo > 0 ) ;
sp - > in_buffer_cur + + ;
sp - > in_buffer_togo - - ;
}
2010-05-12 01:44:00 +08:00
static int
2010-07-16 20:54:53 +08:00
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 ) ;
}
2010-05-12 01:44:00 +08:00
static int
2010-07-16 20:54:53 +08:00
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 ( n > sp - > in_buffer_file_togo )
n = 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
*/
}
}
2010-05-12 01:44:00 +08:00
static int
2010-07-16 20:54:53 +08:00
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 ] = ( sp - > sof_y > > 8 ) ;
sp - > out_buffer [ 6 ] = ( sp - > sof_y & 255 ) ;
/* X */
sp - > out_buffer [ 7 ] = ( 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 + + ;
}
2010-05-12 01:44:00 +08:00
static int
2010-07-16 20:54:53 +08:00
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 ;
}
2010-05-12 01:44:00 +08:00
2010-07-16 20:54:53 +08:00
# ifndef LIBJPEG_ENCAP_EXTERNAL
2010-05-12 01:44:00 +08:00
static int
2010-07-16 20:54:53 +08:00
jpeg_create_decompress_encap ( OJPEGState * sp , jpeg_decompress_struct * cinfo )
{
return ( SETJMP ( sp - > exit_jmpbuf ) ? 0 : ( jpeg_create_decompress ( cinfo ) , 1 ) ) ;
}
# endif
2010-05-12 01:44:00 +08:00
2010-07-16 20:54:53 +08:00
# ifndef LIBJPEG_ENCAP_EXTERNAL
static int
jpeg_read_header_encap ( OJPEGState * sp , jpeg_decompress_struct * cinfo , uint8 require_image )
{
return ( SETJMP ( sp - > exit_jmpbuf ) ? 0 : ( jpeg_read_header ( cinfo , require_image ) , 1 ) ) ;
}
# endif
2010-05-12 01:44:00 +08:00
2010-07-16 20:54:53 +08:00
# ifndef LIBJPEG_ENCAP_EXTERNAL
2010-05-12 01:44:00 +08:00
static int
2010-07-16 20:54:53 +08:00
jpeg_start_decompress_encap ( OJPEGState * sp , jpeg_decompress_struct * cinfo )
{
return ( SETJMP ( sp - > exit_jmpbuf ) ? 0 : ( jpeg_start_decompress ( cinfo ) , 1 ) ) ;
}
# endif
2010-05-12 01:44:00 +08:00
2010-07-16 20:54:53 +08:00
# ifndef LIBJPEG_ENCAP_EXTERNAL
2010-05-12 01:44:00 +08:00
static int
2010-07-16 20:54:53 +08:00
jpeg_read_scanlines_encap ( OJPEGState * sp , jpeg_decompress_struct * cinfo , void * scanlines , uint32 max_lines )
2010-05-12 01:44:00 +08:00
{
2010-07-16 20:54:53 +08:00
return ( SETJMP ( sp - > exit_jmpbuf ) ? 0 : ( jpeg_read_scanlines ( cinfo , scanlines , max_lines ) , 1 ) ) ;
}
# endif
2010-05-12 01:44:00 +08:00
2010-07-16 20:54:53 +08:00
# ifndef LIBJPEG_ENCAP_EXTERNAL
2010-05-12 01:44:00 +08:00
static int
2010-07-16 20:54:53 +08:00
jpeg_read_raw_data_encap ( OJPEGState * sp , jpeg_decompress_struct * cinfo , void * data , uint32 max_lines )
{
return ( SETJMP ( sp - > exit_jmpbuf ) ? 0 : ( jpeg_read_raw_data ( cinfo , data , max_lines ) , 1 ) ) ;
}
# endif
2010-05-12 01:44:00 +08:00
2010-07-16 20:54:53 +08:00
# ifndef LIBJPEG_ENCAP_EXTERNAL
2010-05-12 01:44:00 +08:00
static void
2010-07-16 20:54:53 +08:00
jpeg_encap_unwind ( TIFF * tif )
{
OJPEGState * sp = ( OJPEGState * ) tif - > tif_data ;
LONGJMP ( sp - > exit_jmpbuf , 1 ) ;
}
# endif
2010-05-12 01:44:00 +08:00
static void
2010-07-16 20:54:53 +08:00
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 ) ;
}
2010-05-12 01:44:00 +08:00
static void
2010-07-16 20:54:53 +08:00
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 = 0 ;
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 ) ;
}
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 ) ;
}
static void
OJPEGLibjpegJpegSourceMgrTermSource ( jpeg_decompress_struct * cinfo )
{
( void ) cinfo ;
}
# endif
2010-05-12 01:44:00 +08:00
2010-07-16 20:54:53 +08:00
/*
* Local Variables :
* mode : c
* c - basic - offset : 8
* fill - column : 78
* End :
2010-05-12 01:44:00 +08:00
*/