Applied big patch from Scott for TIFFTAG_JPEGCOLORMODE support.

Did some surgery on "OJPEGDecode()" to handle Zack the Cat's problems,
and to copy the Wang color-correction hack that Scott previously put only in
"OJPEGDecodeRaw()".  Also corrected a couple of small bugs elsewhere in the
module.
This commit is contained in:
Frank Warmerdam 2001-09-08 16:58:17 +00:00
parent 335d2428c1
commit 0759b2fbf9

View File

@ -2,11 +2,11 @@
#ifdef OJPEG_SUPPORT #ifdef OJPEG_SUPPORT
/* JPEG Compression support, as per the original TIFF 6.0 specification. /* JPEG Compression support, as per the original TIFF 6.0 specification.
WARNING: KLUDGE ALERT! The type of JPEG encapsulation defined by the TIFF WARNING: KLUDGE ALERT! The type of JPEG encapsulation defined by the TIFF
Version 6.0 specification is now totally obsolete and Version 6.0 specification is now totally obsolete and
deprecated for new applications and images. This file is an unsupported hack deprecated for new applications and images. This file is an unsupported hack
that was created solely in order to read (but NOT write!) a few old, that was created solely in order to read (but NOT write!) a few old,
unconverted images still present on some users' computer systems. The code unconverted images still present on some users' computer systems. The code
isn't pretty or robust, and it won't read every "old format" JPEG-in-TIFF isn't pretty or robust, and it won't read every "old format" JPEG-in-TIFF
file (see Samuel Leffler's draft "TIFF Technical Note No. 2" for a long and file (see Samuel Leffler's draft "TIFF Technical Note No. 2" for a long and
@ -15,11 +15,11 @@
file should NEVER be enhanced to write new images using anything other than file should NEVER be enhanced to write new images using anything other than
the latest approved JPEG-in-TIFF encapsulation method, implemented by the the latest approved JPEG-in-TIFF encapsulation method, implemented by the
"tif_jpeg.c" file elsewhere in this library. "tif_jpeg.c" file elsewhere in this library.
This file interfaces with Release 5 (or later) of the "libjpeg" library, This file interfaces with Release 5 (or later) of the "libjpeg" library,
written by the Independent JPEG Group, which you can find on the Internet at: written by the Independent JPEG Group, which you can find on the Internet at:
ftp.uu.net:/graphics/jpeg/. ftp.uu.net:/graphics/jpeg/.
Contributed by Scott Marovich <marovich@hpl.hp.com>. Contributed by Scott Marovich <marovich@hpl.hp.com>.
*/ */
#include <setjmp.h> #include <setjmp.h>
@ -27,8 +27,8 @@
#ifdef FAR #ifdef FAR
#undef FAR /* Undefine FAR to avoid conflict with JPEG definition */ #undef FAR /* Undefine FAR to avoid conflict with JPEG definition */
#endif #endif
#undef INLINE
#define JPEG_INTERNALS /* Include "jpegint.h" for "DSTATE_*" symbols */ #define JPEG_INTERNALS /* Include "jpegint.h" for "DSTATE_*" symbols */
#undef INLINE
#include "jpeglib.h" #include "jpeglib.h"
#undef JPEG_INTERNALS #undef JPEG_INTERNALS
@ -57,6 +57,7 @@ extern void jpeg_reset_huff_decode(j_decompress_ptr,float *);
#define FIELD_JPEGDCTABLES (FIELD_CODEC+8) #define FIELD_JPEGDCTABLES (FIELD_CODEC+8)
#define FIELD_JPEGACTABLES (FIELD_CODEC+9) #define FIELD_JPEGACTABLES (FIELD_CODEC+9)
#define FIELD_WANG_PAGECONTROL (FIELD_CODEC+10) #define FIELD_WANG_PAGECONTROL (FIELD_CODEC+10)
#define FIELD_JPEGCOLORMODE (FIELD_CODEC+11)
typedef struct jpeg_destination_mgr jpeg_destination_mgr; typedef struct jpeg_destination_mgr jpeg_destination_mgr;
typedef struct jpeg_source_mgr jpeg_source_mgr; typedef struct jpeg_source_mgr jpeg_source_mgr;
@ -84,7 +85,7 @@ typedef struct /* This module's private, per-image state variable */
# ifdef never # ifdef never
/* (The following two fields could be a "union", but they're small enough that /* (The following two fields could be a "union", but they're small enough that
it's not worth the effort. it's not worth the effort.)
*/ */
jpeg_destination_mgr dest; /* Destination for compressed data */ jpeg_destination_mgr dest; /* Destination for compressed data */
# endif # endif
@ -106,7 +107,10 @@ typedef struct /* This module's private, per-image state variable */
v_sampling, v_sampling,
photometric; /* Copy of "PhotometricInterpretation" tag value */ photometric; /* Copy of "PhotometricInterpretation" tag value */
u_char is_WANG, /* <=> Microsoft Wang Imaging for Windows output file? */ u_char is_WANG, /* <=> Microsoft Wang Imaging for Windows output file? */
jpegcolormode; /* <=> Automatic RGB <-> YCbCr conversion? */
jpegcolormode; /* Who performs RGB <-> YCbCr conversion? */
/* JPEGCOLORMODE_RAW <=> TIFF Library does conversion */
/* JPEGCOLORMODE_RGB <=> JPEG Library does conversion */
} OJPEGState; } OJPEGState;
#define OJState(tif)((OJPEGState*)(tif)->tif_data) #define OJState(tif)((OJPEGState*)(tif)->tif_data)
@ -171,6 +175,17 @@ static const TIFFFieldInfo ojpegFieldInfo[]= /* JPEG-specific TIFF-record tags *
TIFFTAG_WANG_PAGECONTROL ,1 ,1 , TIFFTAG_WANG_PAGECONTROL ,1 ,1 ,
TIFF_LONG ,FIELD_WANG_PAGECONTROL ,FALSE,FALSE,"WANG PageControl" TIFF_LONG ,FIELD_WANG_PAGECONTROL ,FALSE,FALSE,"WANG PageControl"
}, },
/* This is a pseudo tag intended for internal use only by the TIFF Library and
its clients, which should never appear in an input/output image file. It
specifies whether the TIFF Library will perform YCbCr<->RGB color-space
conversion (JPEGCOLORMODE_RAW <=> 0) or ask the JPEG Library to do it
(JPEGCOLORMODE_RGB <=> 1).
*/
{
TIFFTAG_JPEGCOLORMODE ,0 ,0 ,
TIFF_ANY ,FIELD_PSEUDO ,FALSE,FALSE,"JPEGColorMode"
}
}; };
static const char JPEGLib_name[]={"JPEG Library"}, static const char JPEGLib_name[]={"JPEG Library"},
bad_bps[]={"%u BitsPerSample not allowed for JPEG"}, bad_bps[]={"%u BitsPerSample not allowed for JPEG"},
@ -570,7 +585,7 @@ OJPEGSetupEncode(register TIFF *tif)
{ static const char module[]={"OJPEGSetupEncode"}; { static const char module[]={"OJPEGSetupEncode"};
register OJPEGState *sp = OJState(tif); register OJPEGState *sp = OJState(tif);
# define td (&tif->tif_dir) # define td (&tif->tif_dir)
/* Verify miscellaneous parameters. This will need work if the TIFF Library /* Verify miscellaneous parameters. This will need work if the TIFF Library
ever supports different depths for different components, or if the JPEG ever supports different depths for different components, or if the JPEG
Library ever supports run-time depth selection. Neither seems imminent. Library ever supports run-time depth selection. Neither seems imminent.
@ -580,7 +595,7 @@ OJPEGSetupEncode(register TIFF *tif)
TIFFError(module,bad_bps,td->td_bitspersample); TIFFError(module,bad_bps,td->td_bitspersample);
return 0; return 0;
}; };
/* Initialize all JPEG parameters to default values. Note that the JPEG /* Initialize all JPEG parameters to default values. Note that the JPEG
Library's "jpeg_set_defaults()" method needs legal values for the Library's "jpeg_set_defaults()" method needs legal values for the
"in_color_space" and "input_components" fields. "in_color_space" and "input_components" fields.
@ -872,7 +887,7 @@ OJPEGPostEncode(register TIFF *tif)
if (sp->scancount < DCTSIZE && sp->cinfo.c.num_components > 0) if (sp->scancount < DCTSIZE && sp->cinfo.c.num_components > 0)
{ int ci = 0, n; /* Pad the data vertically */ { int ci = 0, n; /* Pad the data vertically */
register jpeg_component_info *compptr = sp->cinfo.c.comp_info; register jpeg_component_info *compptr = sp->cinfo.c.comp_info;
do do
{ tsize_t row_width = { tsize_t row_width =
compptr->width_in_blocks*DCTSIZE*sizeof(JSAMPLE); compptr->width_in_blocks*DCTSIZE*sizeof(JSAMPLE);
@ -900,7 +915,7 @@ OJPEGSetupDecode(register TIFF *tif)
{ static const char module[]={"OJPEGSetupDecode"}; { static const char module[]={"OJPEGSetupDecode"};
register OJPEGState *sp = OJState(tif); register OJPEGState *sp = OJState(tif);
# define td (&tif->tif_dir) # define td (&tif->tif_dir)
/* Verify miscellaneous parameters. This will need work if the TIFF Library /* Verify miscellaneous parameters. This will need work if the TIFF Library
ever supports different depths for different components, or if the JPEG ever supports different depths for different components, or if the JPEG
Library ever supports run-time depth selection. Neither seems imminent. Library ever supports run-time depth selection. Neither seems imminent.
@ -945,19 +960,50 @@ OJPEGSetupDecode(register TIFF *tif)
OJPEGDecode(register TIFF *tif,tidata_t buf,tsize_t cc,tsample_t s) OJPEGDecode(register TIFF *tif,tidata_t buf,tsize_t cc,tsample_t s)
{ tsize_t nrows; { tsize_t nrows;
register OJPEGState *sp = OJState(tif); register OJPEGState *sp = OJState(tif);
# ifndef COLORIMETRY_SUPPORT
static float zeroes[6];
/* BEWARE OF KLUDGE: If our input file was produced by Microsoft's Wang
Imaging for Windows application, the DC coefficients of
each JPEG image component (Y,Cb,Cr) must be reset at the beginning of each
TIFF "strip", and any JPEG data bits remaining in the decoder's input buffer
must be discarded, up to the next input-Byte storage boundary. To do so, we
create an "ad hoc" interface in the "jdhuff.c" module of IJG JPEG Library
Version 6, and we invoke that interface here before decoding each "strip".
*/
if (sp->is_WANG) jpeg_reset_huff_decode(&sp->cinfo.d,zeroes);
# else /* COLORIMETRY_SUPPORT */
if (sp->is_WANG)
jpeg_reset_huff_decode(&sp->cinfo.d,tif->tif_dir.td_refblackwhite);
# endif
/* Decode a chunk of pixels, where returned data is NOT down-sampled (the /* Decode a chunk of pixels, where returned data is NOT down-sampled (the
standard case). The data is expected to be read in scan-line multiples. standard case). The data is expected to be read in scan-line multiples.
*/ */
if (nrows = sp->cinfo.d.image_height) if (nrows = sp->cinfo.d.image_height)
do { unsigned int bytesperline = isTiled(tif)
{ JSAMPROW bufptr = (JSAMPROW)buf; ? TIFFTileRowSize(tif)
: TIFFScanlineSize(tif);
if (TIFFojpeg_read_scanlines(sp,&bufptr,1) != 1) return 0; /* WARNING: Unlike "OJPEGDecodeRaw()", below, the no. of Bytes in each
++tif->tif_row; decoded row is calculated here as "bytesperline" instead of
buf += sp->bytesperline; using "sp->bytesperline", which might be a little smaller. This can
} occur for an old tiled image whose width isn't a multiple of 8 pixels.
while ((cc -= sp->bytesperline) > 0 && --nrows > 0); That's illegal according to the TIFF Version 6 specification, but some
test files, like "zackthecat.tif", were built that way. In those cases,
we want to embed the image's true width in our caller's buffer (which is
presumably allocated according to the expected tile width) by
effectively "padding" it with unused Bytes at the end of each row.
*/
do
{ JSAMPROW bufptr = (JSAMPROW)buf;
if (TIFFojpeg_read_scanlines(sp,&bufptr,1) != 1) return 0;
buf += bytesperline;
++tif->tif_row;
}
while ((cc -= bytesperline) > 0 && --nrows > 0);
}
return sp->cinfo.d.output_scanline < sp->cinfo.d.output_height return sp->cinfo.d.output_scanline < sp->cinfo.d.output_height
|| TIFFojpeg_finish_decompress(sp); || TIFFojpeg_finish_decompress(sp);
} }
@ -1033,7 +1079,7 @@ OJPEGDecodeRaw(register TIFF *tif,tidata_t buf,tsize_t cc,tsample_t s)
do do
{ register int xpos = 0; { register int xpos = 0;
do outptr[xpos] = *inptr++; do outptr[xpos] = *inptr++;
while (++xpos < compptr->h_samp_factor); while (++xpos < compptr->h_samp_factor);
} }
@ -1048,8 +1094,8 @@ OJPEGDecodeRaw(register TIFF *tif,tidata_t buf,tsize_t cc,tsample_t s)
while (++compptr,++ci < sp->cinfo.d.num_components); while (++compptr,++ci < sp->cinfo.d.num_components);
}; };
++sp->scancount; ++sp->scancount;
++tif->tif_row;
buf += sp->bytesperline; buf += sp->bytesperline;
++tif->tif_row;
} }
while ((cc -= sp->bytesperline) > 0 && --nrows > 0); while ((cc -= sp->bytesperline) > 0 && --nrows > 0);
return sp->cinfo.d.output_scanline < sp->cinfo.d.output_height return sp->cinfo.d.output_scanline < sp->cinfo.d.output_height
@ -1118,7 +1164,7 @@ OJPEGPreDecode(register TIFF *tif,tsample_t s)
case PHOTOMETRIC_SEPARATED : in_color_space = JCS_CMYK; case PHOTOMETRIC_SEPARATED : in_color_space = JCS_CMYK;
break; break;
case PHOTOMETRIC_YCBCR : in_color_space = JCS_YCbCr; case PHOTOMETRIC_YCBCR : in_color_space = JCS_YCbCr;
/* Convert YCbCr to RGB? */ /* JPEG Library converts YCbCr to RGB? */
if ( sp->jpegcolormode if ( sp->jpegcolormode
== JPEGCOLORMODE_RGB == JPEGCOLORMODE_RGB
) downsampled_output = FALSE; ) downsampled_output = FALSE;
@ -1309,6 +1355,7 @@ OJPEGPreDecode(register TIFF *tif,tsample_t s)
p = (unsigned char *)sp->jpegtables + sp->jpegtables_length; p = (unsigned char *)sp->jpegtables + sp->jpegtables_length;
p[-2] = 0xFF; p[-1] = JPEG_EOI; /* Append EOI marker */ p[-2] = 0xFF; p[-1] = JPEG_EOI; /* Append EOI marker */
TIFFSetFieldBit(tif,FIELD_JPEGTABLES); TIFFSetFieldBit(tif,FIELD_JPEGTABLES);
tif->tif_flags |= TIFF_DIRTYDIRECT;
} }
else sp->jpegtables = 0; /* Don't simulate "JPEGTables" */ else sp->jpegtables = 0; /* Don't simulate "JPEGTables" */
if (TIFFojpeg_read_header(sp,TRUE) != JPEG_HEADER_OK) return 0; if (TIFFojpeg_read_header(sp,TRUE) != JPEG_HEADER_OK) return 0;
@ -1335,9 +1382,9 @@ OJPEGPreDecode(register TIFF *tif,tsample_t s)
}; };
if (td->td_planarconfig == PLANARCONFIG_CONTIG) if (td->td_planarconfig == PLANARCONFIG_CONTIG)
{ int ci; { int ci;
/* Component 0 should have expected sampling factors. */ /* Component 0 should have expected sampling factors. */
if ( sp->cinfo.d.comp_info[0].h_samp_factor != sp->h_sampling if ( sp->cinfo.d.comp_info[0].h_samp_factor != sp->h_sampling
|| sp->cinfo.d.comp_info[0].v_samp_factor != sp->v_sampling || sp->cinfo.d.comp_info[0].v_samp_factor != sp->v_sampling
) )
@ -1403,7 +1450,7 @@ OJPEGPreDecode(register TIFF *tif,tsample_t s)
, sp->cinfo.d.num_components * sizeof *sp->cinfo.d.comp_info , sp->cinfo.d.num_components * sizeof *sp->cinfo.d.comp_info
); );
i = 0; i = 0;
do do
{ {
sp->cinfo.d.comp_info[i].component_index = i; sp->cinfo.d.comp_info[i].component_index = i;
sp->cinfo.d.comp_info[i].component_needed = TRUE; sp->cinfo.d.comp_info[i].component_needed = TRUE;
@ -1480,12 +1527,40 @@ OJPEGPreDecode(register TIFF *tif,tsample_t s)
sp->src.bytes_in_buffer = td->td_stripoffset[i] - sp->src.bytes_in_buffer = td->td_stripoffset[i] -
td->td_stripoffset[0] + td->td_stripbytecount[i]; td->td_stripoffset[0] + td->td_stripbytecount[i];
/* Force the TIFF Library to create a default array of reference black /* We need reference black levels for our "jpeg_reset_huff_decode()"
and white levels in case our input file doesn't define them, since hook into the JPEG Library, so create a default array of reference
we need these for our "jpeg_reset_huff_decode()" hook into the JPEG black and white levels in case our input file doesn't define them.
Library.
BOGOSITY ALERT! Microsoft's Wang Imaging application seems to alter
the intensity and hue of JPEG images when it
encapsulates them in TIFF files, and the exact reason/algorithm is
currently unknown to this author (is it a bug?), but we try to
correct them by debiassing, using the DC coefficient of each image
component (the 0th element of each JPEG quantization table)
weighted by the corresponding CCIR 601-1 luminance coefficient
(this is strictly a wild-ass guess at what Microsoft might have
screwed up). Experiments with a few test images indicate that this
does not produce an exact correction, but it is reasonably close.
Can someone else figure out a better algorithm?
*/ */
(void)TIFFGetFieldDefaulted(tif,TIFFTAG_REFERENCEBLACKWHITE,&refbw); if (!TIFFGetFieldDefaulted(tif,TIFFTAG_REFERENCEBLACKWHITE,&refbw))
{
TIFFError(tif->tif_name,"Can't extract reference black and white levels");
return 0;
};
if (refbw[0] == 0.0 && refbw[2] == 0.0 && refbw[4] == 0.0)
{ /* default reference black levels */
refbw[2] =
sp->cinfo.d.quant_tbl_ptrs[sp->cinfo.d.comp_info[1].quant_tbl_no]
->quantval[0] * 1.402;
refbw[4] =
sp->cinfo.d.quant_tbl_ptrs[sp->cinfo.d.comp_info[2].quant_tbl_no]
->quantval[0] * 1.772;
refbw[0] =
refbw[2] + refbw[4] -
sp->cinfo.d.quant_tbl_ptrs[sp->cinfo.d.comp_info[0].quant_tbl_no]
->quantval[0];
};
i = TIFFojpeg_read_header(sp,TRUE); i = TIFFojpeg_read_header(sp,TRUE);
}; };
if (i != JPEG_HEADER_OK) return 0; if (i != JPEG_HEADER_OK) return 0;
@ -1518,6 +1593,7 @@ static int
OJPEGVSetField(register TIFF *tif,ttag_t tag,va_list ap) OJPEGVSetField(register TIFF *tif,ttag_t tag,va_list ap)
{ uint32 v32; { uint32 v32;
register OJPEGState *sp = OJState(tif); register OJPEGState *sp = OJState(tif);
# define td (&tif->tif_dir)
switch (tag) switch (tag)
{ {
@ -1532,7 +1608,8 @@ OJPEGVSetField(register TIFF *tif,ttag_t tag,va_list ap)
case TIFFTAG_JPEGQTABLES : case TIFFTAG_JPEGQTABLES :
case TIFFTAG_JPEGDCTABLES : case TIFFTAG_JPEGDCTABLES :
case TIFFTAG_JPEGACTABLES : case TIFFTAG_JPEGACTABLES :
case TIFFTAG_WANG_PAGECONTROL : ; case TIFFTAG_WANG_PAGECONTROL :
case TIFFTAG_JPEGCOLORMODE : ;
}; };
v32 = va_arg(ap,uint32); /* No. of values in this TIFF record */ v32 = va_arg(ap,uint32); /* No. of values in this TIFF record */
@ -1688,9 +1765,41 @@ OJPEGVSetField(register TIFF *tif,ttag_t tag,va_list ap)
}; };
sp->is_WANG = 1; sp->is_WANG = 1;
tag = TIFFTAG_JPEGPROC+FIELD_WANG_PAGECONTROL-FIELD_JPEGPROC; tag = TIFFTAG_JPEGPROC+FIELD_WANG_PAGECONTROL-FIELD_JPEGPROC;
break;
/* This pseudo tag indicates whether we think that our caller is supposed
to do YCbCr<->RGB color-space conversion (JPEGCOLORMODE_RAW <=> 0) or
whether we must ask the JPEG Library to do it (JPEGCOLORMODE_RGB <=> 1).
*/
case TIFFTAG_JPEGCOLORMODE :
sp->jpegcolormode = v32;
/* Mark the image to indicate whether returned data is up-sampled, so
that "TIFF{Strip,Tile}Size()" reflect the true amount of data present.
*/
v32 = tif->tif_flags; /* Save flags temporarily */
tif->tif_flags &= ~TIFF_UPSAMPLED;
if (td->td_planarconfig == PLANARCONFIG_CONTIG)
if ( td->td_photometric == PHOTOMETRIC_YCBCR
&& sp->jpegcolormode == JPEGCOLORMODE_RGB
) tif->tif_flags |= TIFF_UPSAMPLED;
else
if ( (td->td_ycbcrsubsampling[1]<<16|td->td_ycbcrsubsampling[0])
!= (1 << 16 | 1)
) /* XXX what about up-sampling? */;
/* If the up-sampling state changed, re-calculate tile size. */
if ((tif->tif_flags ^ v32) & TIFF_UPSAMPLED)
{
tif->tif_tilesize = TIFFTileSize(tif);
tif->tif_flags |= TIFF_DIRTYDIRECT;
};
return 1;
}; };
TIFFSetFieldBit(tif,tag-TIFFTAG_JPEGPROC+FIELD_JPEGPROC); TIFFSetFieldBit(tif,tag-TIFFTAG_JPEGPROC+FIELD_JPEGPROC);
return 1; return 1;
# undef td
} }
static int static int
@ -1713,6 +1822,14 @@ OJPEGVGetField(register TIFF *tif,ttag_t tag,va_list ap)
return 1; return 1;
}; };
/* This pseudo tag indicates whether we think that our caller is supposed
to do YCbCr<->RGB color-space conversion (JPEGCOLORMODE_RAW <=> 0) or
whether we must ask the JPEG Library to do it (JPEGCOLORMODE_RGB <=> 1).
*/
case TIFFTAG_JPEGCOLORMODE :
*va_arg(ap,uint32 *) = sp->jpegcolormode;
return 1;
/* The following tags are defined by the TIFF Version 6.0 specification /* The following tags are defined by the TIFF Version 6.0 specification
and are obsolete. If our caller asks for information about them, do not and are obsolete. If our caller asks for information about them, do not
return anything, even if we parsed them in an old-format "source" image. return anything, even if we parsed them in an old-format "source" image.