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:
parent
335d2428c1
commit
0759b2fbf9
@ -2,11 +2,11 @@
|
||||
#ifdef OJPEG_SUPPORT
|
||||
|
||||
/* JPEG Compression support, as per the original TIFF 6.0 specification.
|
||||
|
||||
|
||||
WARNING: KLUDGE ALERT! 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 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
|
||||
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
|
||||
@ -15,11 +15,11 @@
|
||||
file should NEVER be enhanced to write new images using anything other than
|
||||
the latest approved JPEG-in-TIFF encapsulation method, implemented by the
|
||||
"tif_jpeg.c" file elsewhere in this 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:
|
||||
ftp.uu.net:/graphics/jpeg/.
|
||||
|
||||
|
||||
Contributed by Scott Marovich <marovich@hpl.hp.com>.
|
||||
*/
|
||||
#include <setjmp.h>
|
||||
@ -27,8 +27,8 @@
|
||||
#ifdef FAR
|
||||
#undef FAR /* Undefine FAR to avoid conflict with JPEG definition */
|
||||
#endif
|
||||
#undef INLINE
|
||||
#define JPEG_INTERNALS /* Include "jpegint.h" for "DSTATE_*" symbols */
|
||||
#undef INLINE
|
||||
#include "jpeglib.h"
|
||||
#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_JPEGACTABLES (FIELD_CODEC+9)
|
||||
#define FIELD_WANG_PAGECONTROL (FIELD_CODEC+10)
|
||||
#define FIELD_JPEGCOLORMODE (FIELD_CODEC+11)
|
||||
|
||||
typedef struct jpeg_destination_mgr jpeg_destination_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
|
||||
|
||||
/* (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 */
|
||||
# endif
|
||||
@ -106,7 +107,10 @@ typedef struct /* This module's private, per-image state variable */
|
||||
v_sampling,
|
||||
photometric; /* Copy of "PhotometricInterpretation" tag value */
|
||||
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;
|
||||
#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 ,
|
||||
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"},
|
||||
bad_bps[]={"%u BitsPerSample not allowed for JPEG"},
|
||||
@ -570,7 +585,7 @@ OJPEGSetupEncode(register TIFF *tif)
|
||||
{ static const char module[]={"OJPEGSetupEncode"};
|
||||
register OJPEGState *sp = OJState(tif);
|
||||
# define td (&tif->tif_dir)
|
||||
|
||||
|
||||
/* Verify miscellaneous parameters. This will need work if the TIFF Library
|
||||
ever supports different depths for different components, or if the JPEG
|
||||
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);
|
||||
return 0;
|
||||
};
|
||||
|
||||
|
||||
/* Initialize all JPEG parameters to default values. Note that the JPEG
|
||||
Library's "jpeg_set_defaults()" method needs legal values for the
|
||||
"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)
|
||||
{ int ci = 0, n; /* Pad the data vertically */
|
||||
register jpeg_component_info *compptr = sp->cinfo.c.comp_info;
|
||||
|
||||
|
||||
do
|
||||
{ tsize_t row_width =
|
||||
compptr->width_in_blocks*DCTSIZE*sizeof(JSAMPLE);
|
||||
@ -900,7 +915,7 @@ OJPEGSetupDecode(register TIFF *tif)
|
||||
{ static const char module[]={"OJPEGSetupDecode"};
|
||||
register OJPEGState *sp = OJState(tif);
|
||||
# define td (&tif->tif_dir)
|
||||
|
||||
|
||||
/* Verify miscellaneous parameters. This will need work if the TIFF Library
|
||||
ever supports different depths for different components, or if the JPEG
|
||||
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)
|
||||
{ tsize_t nrows;
|
||||
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
|
||||
standard case). The data is expected to be read in scan-line multiples.
|
||||
*/
|
||||
if (nrows = sp->cinfo.d.image_height)
|
||||
do
|
||||
{ JSAMPROW bufptr = (JSAMPROW)buf;
|
||||
{ unsigned int bytesperline = isTiled(tif)
|
||||
? TIFFTileRowSize(tif)
|
||||
: TIFFScanlineSize(tif);
|
||||
|
||||
if (TIFFojpeg_read_scanlines(sp,&bufptr,1) != 1) return 0;
|
||||
++tif->tif_row;
|
||||
buf += sp->bytesperline;
|
||||
}
|
||||
while ((cc -= sp->bytesperline) > 0 && --nrows > 0);
|
||||
/* WARNING: Unlike "OJPEGDecodeRaw()", below, the no. of Bytes in each
|
||||
decoded row is calculated here as "bytesperline" instead of
|
||||
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.
|
||||
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
|
||||
|| TIFFojpeg_finish_decompress(sp);
|
||||
}
|
||||
@ -1033,7 +1079,7 @@ OJPEGDecodeRaw(register TIFF *tif,tidata_t buf,tsize_t cc,tsample_t s)
|
||||
|
||||
do
|
||||
{ register int xpos = 0;
|
||||
|
||||
|
||||
do outptr[xpos] = *inptr++;
|
||||
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);
|
||||
};
|
||||
++sp->scancount;
|
||||
++tif->tif_row;
|
||||
buf += sp->bytesperline;
|
||||
++tif->tif_row;
|
||||
}
|
||||
while ((cc -= sp->bytesperline) > 0 && --nrows > 0);
|
||||
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;
|
||||
break;
|
||||
case PHOTOMETRIC_YCBCR : in_color_space = JCS_YCbCr;
|
||||
/* Convert YCbCr to RGB? */
|
||||
/* JPEG Library converts YCbCr to RGB? */
|
||||
if ( sp->jpegcolormode
|
||||
== JPEGCOLORMODE_RGB
|
||||
) downsampled_output = FALSE;
|
||||
@ -1309,6 +1355,7 @@ OJPEGPreDecode(register TIFF *tif,tsample_t s)
|
||||
p = (unsigned char *)sp->jpegtables + sp->jpegtables_length;
|
||||
p[-2] = 0xFF; p[-1] = JPEG_EOI; /* Append EOI marker */
|
||||
TIFFSetFieldBit(tif,FIELD_JPEGTABLES);
|
||||
tif->tif_flags |= TIFF_DIRTYDIRECT;
|
||||
}
|
||||
else sp->jpegtables = 0; /* Don't simulate "JPEGTables" */
|
||||
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)
|
||||
{ int ci;
|
||||
|
||||
|
||||
/* Component 0 should have expected sampling factors. */
|
||||
|
||||
|
||||
if ( sp->cinfo.d.comp_info[0].h_samp_factor != sp->h_sampling
|
||||
|| sp->cinfo.d.comp_info[0].v_samp_factor != sp->v_sampling
|
||||
)
|
||||
@ -1403,7 +1450,7 @@ OJPEGPreDecode(register TIFF *tif,tsample_t s)
|
||||
, sp->cinfo.d.num_components * sizeof *sp->cinfo.d.comp_info
|
||||
);
|
||||
i = 0;
|
||||
do
|
||||
do
|
||||
{
|
||||
sp->cinfo.d.comp_info[i].component_index = i;
|
||||
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] -
|
||||
td->td_stripoffset[0] + td->td_stripbytecount[i];
|
||||
|
||||
/* Force the TIFF Library to create a default array of reference black
|
||||
and white levels in case our input file doesn't define them, since
|
||||
we need these for our "jpeg_reset_huff_decode()" hook into the JPEG
|
||||
Library.
|
||||
/* We need reference black levels for our "jpeg_reset_huff_decode()"
|
||||
hook into the JPEG Library, so create a default array of reference
|
||||
black and white levels in case our input file doesn't define them.
|
||||
|
||||
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);
|
||||
};
|
||||
if (i != JPEG_HEADER_OK) return 0;
|
||||
@ -1518,6 +1593,7 @@ static int
|
||||
OJPEGVSetField(register TIFF *tif,ttag_t tag,va_list ap)
|
||||
{ uint32 v32;
|
||||
register OJPEGState *sp = OJState(tif);
|
||||
# define td (&tif->tif_dir)
|
||||
|
||||
switch (tag)
|
||||
{
|
||||
@ -1532,7 +1608,8 @@ OJPEGVSetField(register TIFF *tif,ttag_t tag,va_list ap)
|
||||
case TIFFTAG_JPEGQTABLES :
|
||||
case TIFFTAG_JPEGDCTABLES :
|
||||
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 */
|
||||
|
||||
@ -1688,9 +1765,41 @@ OJPEGVSetField(register TIFF *tif,ttag_t tag,va_list ap)
|
||||
};
|
||||
sp->is_WANG = 1;
|
||||
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);
|
||||
return 1;
|
||||
# undef td
|
||||
}
|
||||
|
||||
static int
|
||||
@ -1713,6 +1822,14 @@ OJPEGVGetField(register TIFF *tif,ttag_t tag,va_list ap)
|
||||
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
|
||||
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.
|
||||
|
Loading…
Reference in New Issue
Block a user