Merge branch 'ijg' into dev
- Restore GIF read/compressed GIF write support from jpeg-6a and jpeg-9d. - Integrate jpegtran -wipe and -drop options from jpeg-9a and jpeg-9d. - Integrate jpegtran -crop extension (for expanding the image size) from jpeg-9a and jpeg-9d. - Integrate other minor code tweaks from jpeg-9*
This commit is contained in:
@@ -101,6 +101,14 @@ TurboJPEG API libraries. This facilitates using libjpeg-turbo with CMake's
|
|||||||
target_link_libraries(turbojpeg_program_static PUBLIC
|
target_link_libraries(turbojpeg_program_static PUBLIC
|
||||||
libjpeg-turbo::turbojpeg-static)
|
libjpeg-turbo::turbojpeg-static)
|
||||||
|
|
||||||
|
11. Since the Unisys LZW patent has long expired, cjpeg and djpeg can now
|
||||||
|
read/write both LZW-compressed and uncompressed GIF files (feature ported from
|
||||||
|
jpeg-6a and jpeg-9d.)
|
||||||
|
|
||||||
|
12. jpegtran now includes the `-wipe` and `-drop` options from jpeg-9a and
|
||||||
|
jpeg-9d, as well as the ability to expand the image size using the `-crop`
|
||||||
|
option. Refer to jpegtran.1 or usage.txt for more details.
|
||||||
|
|
||||||
|
|
||||||
2.0.6
|
2.0.6
|
||||||
=====
|
=====
|
||||||
|
|||||||
15
README.ijg
15
README.ijg
@@ -128,7 +128,7 @@ with respect to this software, its quality, accuracy, merchantability, or
|
|||||||
fitness for a particular purpose. This software is provided "AS IS", and you,
|
fitness for a particular purpose. This software is provided "AS IS", and you,
|
||||||
its user, assume the entire risk as to its quality and accuracy.
|
its user, assume the entire risk as to its quality and accuracy.
|
||||||
|
|
||||||
This software is copyright (C) 1991-2016, Thomas G. Lane, Guido Vollbeding.
|
This software is copyright (C) 1991-2020, Thomas G. Lane, Guido Vollbeding.
|
||||||
All Rights Reserved except as specified below.
|
All Rights Reserved except as specified below.
|
||||||
|
|
||||||
Permission is hereby granted to use, copy, modify, and distribute this
|
Permission is hereby granted to use, copy, modify, and distribute this
|
||||||
@@ -159,19 +159,6 @@ commercial products, provided that all warranty or liability claims are
|
|||||||
assumed by the product vendor.
|
assumed by the product vendor.
|
||||||
|
|
||||||
|
|
||||||
The IJG distribution formerly included code to read and write GIF files.
|
|
||||||
To avoid entanglement with the Unisys LZW patent (now expired), GIF reading
|
|
||||||
support has been removed altogether, and the GIF writer has been simplified
|
|
||||||
to produce "uncompressed GIFs". This technique does not use the LZW
|
|
||||||
algorithm; the resulting GIF files are larger than usual, but are readable
|
|
||||||
by all standard GIF decoders.
|
|
||||||
|
|
||||||
We are required to state that
|
|
||||||
"The Graphics Interchange Format(c) is the Copyright property of
|
|
||||||
CompuServe Incorporated. GIF(sm) is a Service Mark property of
|
|
||||||
CompuServe Incorporated."
|
|
||||||
|
|
||||||
|
|
||||||
REFERENCES
|
REFERENCES
|
||||||
==========
|
==========
|
||||||
|
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ JMESSAGE(JMSG_FIRSTADDONCODE = 1000, NULL) /* Must be first entry! */
|
|||||||
|
|
||||||
#ifdef BMP_SUPPORTED
|
#ifdef BMP_SUPPORTED
|
||||||
JMESSAGE(JERR_BMP_BADCMAP, "Unsupported BMP colormap format")
|
JMESSAGE(JERR_BMP_BADCMAP, "Unsupported BMP colormap format")
|
||||||
JMESSAGE(JERR_BMP_BADDEPTH, "Only 8- and 24-bit BMP files are supported")
|
JMESSAGE(JERR_BMP_BADDEPTH, "Only 8-, 24-, and 32-bit BMP files are supported")
|
||||||
JMESSAGE(JERR_BMP_BADHEADER, "Invalid BMP file: bad header length")
|
JMESSAGE(JERR_BMP_BADHEADER, "Invalid BMP file: bad header length")
|
||||||
JMESSAGE(JERR_BMP_BADPLANES, "Invalid BMP file: biPlanes not equal to 1")
|
JMESSAGE(JERR_BMP_BADPLANES, "Invalid BMP file: biPlanes not equal to 1")
|
||||||
JMESSAGE(JERR_BMP_COLORSPACE, "BMP output must be grayscale or RGB")
|
JMESSAGE(JERR_BMP_COLORSPACE, "BMP output must be grayscale or RGB")
|
||||||
@@ -50,9 +50,9 @@ JMESSAGE(JERR_BMP_COMPRESSED, "Sorry, compressed BMPs not yet supported")
|
|||||||
JMESSAGE(JERR_BMP_EMPTY, "Empty BMP image")
|
JMESSAGE(JERR_BMP_EMPTY, "Empty BMP image")
|
||||||
JMESSAGE(JERR_BMP_NOT, "Not a BMP file - does not start with BM")
|
JMESSAGE(JERR_BMP_NOT, "Not a BMP file - does not start with BM")
|
||||||
JMESSAGE(JERR_BMP_OUTOFRANGE, "Numeric value out of range in BMP file")
|
JMESSAGE(JERR_BMP_OUTOFRANGE, "Numeric value out of range in BMP file")
|
||||||
JMESSAGE(JTRC_BMP, "%ux%u 24-bit BMP image")
|
JMESSAGE(JTRC_BMP, "%ux%u %d-bit BMP image")
|
||||||
JMESSAGE(JTRC_BMP_MAPPED, "%ux%u 8-bit colormapped BMP image")
|
JMESSAGE(JTRC_BMP_MAPPED, "%ux%u 8-bit colormapped BMP image")
|
||||||
JMESSAGE(JTRC_BMP_OS2, "%ux%u 24-bit OS2 BMP image")
|
JMESSAGE(JTRC_BMP_OS2, "%ux%u %d-bit OS2 BMP image")
|
||||||
JMESSAGE(JTRC_BMP_OS2_MAPPED, "%ux%u 8-bit colormapped OS2 BMP image")
|
JMESSAGE(JTRC_BMP_OS2_MAPPED, "%ux%u 8-bit colormapped OS2 BMP image")
|
||||||
#endif /* BMP_SUPPORTED */
|
#endif /* BMP_SUPPORTED */
|
||||||
|
|
||||||
|
|||||||
3
cdjpeg.h
3
cdjpeg.h
@@ -3,6 +3,7 @@
|
|||||||
*
|
*
|
||||||
* This file was part of the Independent JPEG Group's software:
|
* This file was part of the Independent JPEG Group's software:
|
||||||
* Copyright (C) 1994-1997, Thomas G. Lane.
|
* Copyright (C) 1994-1997, Thomas G. Lane.
|
||||||
|
* Modified 2019 by Guido Vollbeding.
|
||||||
* libjpeg-turbo Modifications:
|
* libjpeg-turbo Modifications:
|
||||||
* Copyright (C) 2017, 2019, D. R. Commander.
|
* Copyright (C) 2017, 2019, D. R. Commander.
|
||||||
* For conditions of distribution and use, see the accompanying README.ijg
|
* For conditions of distribution and use, see the accompanying README.ijg
|
||||||
@@ -104,7 +105,7 @@ EXTERN(cjpeg_source_ptr) jinit_read_bmp(j_compress_ptr cinfo,
|
|||||||
EXTERN(djpeg_dest_ptr) jinit_write_bmp(j_decompress_ptr cinfo, boolean is_os2,
|
EXTERN(djpeg_dest_ptr) jinit_write_bmp(j_decompress_ptr cinfo, boolean is_os2,
|
||||||
boolean use_inversion_array);
|
boolean use_inversion_array);
|
||||||
EXTERN(cjpeg_source_ptr) jinit_read_gif(j_compress_ptr cinfo);
|
EXTERN(cjpeg_source_ptr) jinit_read_gif(j_compress_ptr cinfo);
|
||||||
EXTERN(djpeg_dest_ptr) jinit_write_gif(j_decompress_ptr cinfo);
|
EXTERN(djpeg_dest_ptr) jinit_write_gif(j_decompress_ptr cinfo, boolean is_lzw);
|
||||||
EXTERN(cjpeg_source_ptr) jinit_read_ppm(j_compress_ptr cinfo);
|
EXTERN(cjpeg_source_ptr) jinit_read_ppm(j_compress_ptr cinfo);
|
||||||
EXTERN(djpeg_dest_ptr) jinit_write_ppm(j_decompress_ptr cinfo);
|
EXTERN(djpeg_dest_ptr) jinit_write_ppm(j_decompress_ptr cinfo);
|
||||||
EXTERN(cjpeg_source_ptr) jinit_read_targa(j_compress_ptr cinfo);
|
EXTERN(cjpeg_source_ptr) jinit_read_targa(j_compress_ptr cinfo);
|
||||||
|
|||||||
31
change.log
31
change.log
@@ -6,6 +6,25 @@ reference. Please see ChangeLog.md for information specific to libjpeg-turbo.
|
|||||||
CHANGE LOG for Independent JPEG Group's JPEG software
|
CHANGE LOG for Independent JPEG Group's JPEG software
|
||||||
|
|
||||||
|
|
||||||
|
Version 9d 12-Jan-2020
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
Restore GIF read and write support from libjpeg version 6a.
|
||||||
|
Thank to Wolfgang Werner (W.W.) Heinz for suggestion.
|
||||||
|
|
||||||
|
Add jpegtran -drop option; add options to the crop extension and wipe
|
||||||
|
to fill the extra area with content from the source image region,
|
||||||
|
instead of gray out.
|
||||||
|
|
||||||
|
|
||||||
|
Version 9c 14-Jan-2018
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
jpegtran: add an option to the -wipe switch to fill the region
|
||||||
|
with the average of adjacent blocks, instead of gray out.
|
||||||
|
Thank to Caitlyn Feddock and Maddie Ziegler for inspiration.
|
||||||
|
|
||||||
|
|
||||||
Version 9b 17-Jan-2016
|
Version 9b 17-Jan-2016
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
@@ -13,6 +32,13 @@ Document 'f' specifier for jpegtran -crop specification.
|
|||||||
Thank to Michele Martone for suggestion.
|
Thank to Michele Martone for suggestion.
|
||||||
|
|
||||||
|
|
||||||
|
Version 9a 19-Jan-2014
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
Add jpegtran -wipe option and extension for -crop.
|
||||||
|
Thank to Andrew Senior, David Clunie, and Josef Schmid for suggestion.
|
||||||
|
|
||||||
|
|
||||||
Version 9 13-Jan-2013
|
Version 9 13-Jan-2013
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
@@ -138,11 +164,6 @@ Huffman tables being used.
|
|||||||
|
|
||||||
Huffman tables are checked for validity much more carefully than before.
|
Huffman tables are checked for validity much more carefully than before.
|
||||||
|
|
||||||
To avoid the Unisys LZW patent, djpeg's GIF output capability has been
|
|
||||||
changed to produce "uncompressed GIFs", and cjpeg's GIF input capability
|
|
||||||
has been removed altogether. We're not happy about it either, but there
|
|
||||||
seems to be no good alternative.
|
|
||||||
|
|
||||||
The configure script now supports building libjpeg as a shared library
|
The configure script now supports building libjpeg as a shared library
|
||||||
on many flavors of Unix (all the ones that GNU libtool knows how to
|
on many flavors of Unix (all the ones that GNU libtool knows how to
|
||||||
build shared libraries for). Use "./configure --enable-shared" to
|
build shared libraries for). Use "./configure --enable-shared" to
|
||||||
|
|||||||
13
cjpeg.1
13
cjpeg.1
@@ -16,7 +16,7 @@ cjpeg \- compress an image file to a JPEG file
|
|||||||
compresses the named image file, or the standard input if no file is
|
compresses the named image file, or the standard input if no file is
|
||||||
named, and produces a JPEG/JFIF file on the standard output.
|
named, and produces a JPEG/JFIF file on the standard output.
|
||||||
The currently supported input file formats are: PPM (PBMPLUS color
|
The currently supported input file formats are: PPM (PBMPLUS color
|
||||||
format), PGM (PBMPLUS grayscale format), BMP, and Targa.
|
format), PGM (PBMPLUS grayscale format), BMP, GIF, and Targa.
|
||||||
.SH OPTIONS
|
.SH OPTIONS
|
||||||
All switch names may be abbreviated; for example,
|
All switch names may be abbreviated; for example,
|
||||||
.B \-grayscale
|
.B \-grayscale
|
||||||
@@ -41,10 +41,10 @@ Scale quantization tables to adjust image quality. Quality is 0 (worst) to
|
|||||||
.TP
|
.TP
|
||||||
.B \-grayscale
|
.B \-grayscale
|
||||||
Create monochrome JPEG file from color input. Be sure to use this switch when
|
Create monochrome JPEG file from color input. Be sure to use this switch when
|
||||||
compressing a grayscale BMP file, because
|
compressing a grayscale BMP or GIF file, because
|
||||||
.B cjpeg
|
.B cjpeg
|
||||||
isn't bright enough to notice whether a BMP file uses only shades of gray.
|
isn't bright enough to notice whether a BMP or GIF file uses only shades of
|
||||||
By saying
|
gray. By saying
|
||||||
.BR \-grayscale,
|
.BR \-grayscale,
|
||||||
you'll get a smaller JPEG file that takes less time to process.
|
you'll get a smaller JPEG file that takes less time to process.
|
||||||
.TP
|
.TP
|
||||||
@@ -343,11 +343,6 @@ This file was modified by The libjpeg-turbo Project to include only information
|
|||||||
relevant to libjpeg-turbo, to wordsmith certain sections, and to describe
|
relevant to libjpeg-turbo, to wordsmith certain sections, and to describe
|
||||||
features not present in libjpeg.
|
features not present in libjpeg.
|
||||||
.SH ISSUES
|
.SH ISSUES
|
||||||
Support for GIF input files was removed in cjpeg v6b due to concerns over
|
|
||||||
the Unisys LZW patent. Although this patent expired in 2006, cjpeg still
|
|
||||||
lacks GIF support, for these historical reasons. (Conversion of GIF files to
|
|
||||||
JPEG is usually a bad idea anyway, since GIF is a 256-color format.)
|
|
||||||
.PP
|
|
||||||
Not all variants of BMP and Targa file formats are supported.
|
Not all variants of BMP and Targa file formats are supported.
|
||||||
.PP
|
.PP
|
||||||
The
|
The
|
||||||
|
|||||||
22
djpeg.1
22
djpeg.1
@@ -80,9 +80,20 @@ is specified, or if the JPEG file is grayscale; otherwise, 24-bit full-color
|
|||||||
format is emitted.
|
format is emitted.
|
||||||
.TP
|
.TP
|
||||||
.B \-gif
|
.B \-gif
|
||||||
Select GIF output format. Since GIF does not support more than 256 colors,
|
Select GIF output format (LZW-compressed). Since GIF does not support more
|
||||||
|
than 256 colors,
|
||||||
.B \-colors 256
|
.B \-colors 256
|
||||||
is assumed (unless you specify a smaller number of colors).
|
is assumed (unless you specify a smaller number of colors). If you specify
|
||||||
|
.BR \-fast,
|
||||||
|
the default number of colors is 216.
|
||||||
|
.TP
|
||||||
|
.B \-gif0
|
||||||
|
Select GIF output format (uncompressed). Since GIF does not support more than
|
||||||
|
256 colors,
|
||||||
|
.B \-colors 256
|
||||||
|
is assumed (unless you specify a smaller number of colors). If you specify
|
||||||
|
.BR \-fast,
|
||||||
|
the default number of colors is 216.
|
||||||
.TP
|
.TP
|
||||||
.B \-os2
|
.B \-os2
|
||||||
Select BMP output format (OS/2 1.x flavor). 8-bit colormapped format is
|
Select BMP output format (OS/2 1.x flavor). 8-bit colormapped format is
|
||||||
@@ -305,10 +316,3 @@ Independent JPEG Group
|
|||||||
This file was modified by The libjpeg-turbo Project to include only information
|
This file was modified by The libjpeg-turbo Project to include only information
|
||||||
relevant to libjpeg-turbo, to wordsmith certain sections, and to describe
|
relevant to libjpeg-turbo, to wordsmith certain sections, and to describe
|
||||||
features not present in libjpeg.
|
features not present in libjpeg.
|
||||||
.SH ISSUES
|
|
||||||
Support for compressed GIF output files was removed in djpeg v6b due to
|
|
||||||
concerns over the Unisys LZW patent. Although this patent expired in 2006,
|
|
||||||
djpeg still lacks compressed GIF support, for these historical reasons.
|
|
||||||
(Conversion of JPEG files to GIF is usually a bad idea anyway, since GIF is a
|
|
||||||
256-color format.) The uncompressed GIF files that djpeg generates are larger
|
|
||||||
than they should be, but they are readable by standard GIF decoders.
|
|
||||||
|
|||||||
22
djpeg.c
22
djpeg.c
@@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* This file was part of the Independent JPEG Group's software:
|
* This file was part of the Independent JPEG Group's software:
|
||||||
* Copyright (C) 1991-1997, Thomas G. Lane.
|
* Copyright (C) 1991-1997, Thomas G. Lane.
|
||||||
* Modified 2013 by Guido Vollbeding.
|
* Modified 2013-2019 by Guido Vollbeding.
|
||||||
* libjpeg-turbo Modifications:
|
* libjpeg-turbo Modifications:
|
||||||
* Copyright (C) 2010-2011, 2013-2017, 2019-2020, D. R. Commander.
|
* Copyright (C) 2010-2011, 2013-2017, 2019-2020, D. R. Commander.
|
||||||
* Copyright (C) 2015, Google, Inc.
|
* Copyright (C) 2015, Google, Inc.
|
||||||
@@ -68,7 +68,8 @@ static const char * const cdjpeg_message_table[] = {
|
|||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
FMT_BMP, /* BMP format (Windows flavor) */
|
FMT_BMP, /* BMP format (Windows flavor) */
|
||||||
FMT_GIF, /* GIF format */
|
FMT_GIF, /* GIF format (LZW-compressed) */
|
||||||
|
FMT_GIF0, /* GIF format (uncompressed) */
|
||||||
FMT_OS2, /* BMP format (OS/2 flavor) */
|
FMT_OS2, /* BMP format (OS/2 flavor) */
|
||||||
FMT_PPM, /* PPM/PGM (PBMPLUS formats) */
|
FMT_PPM, /* PPM/PGM (PBMPLUS formats) */
|
||||||
FMT_TARGA, /* Targa format */
|
FMT_TARGA, /* Targa format */
|
||||||
@@ -129,8 +130,10 @@ usage(void)
|
|||||||
(DEFAULT_FMT == FMT_BMP ? " (default)" : ""));
|
(DEFAULT_FMT == FMT_BMP ? " (default)" : ""));
|
||||||
#endif
|
#endif
|
||||||
#ifdef GIF_SUPPORTED
|
#ifdef GIF_SUPPORTED
|
||||||
fprintf(stderr, " -gif Select GIF output format%s\n",
|
fprintf(stderr, " -gif Select GIF output format (LZW-compressed)%s\n",
|
||||||
(DEFAULT_FMT == FMT_GIF ? " (default)" : ""));
|
(DEFAULT_FMT == FMT_GIF ? " (default)" : ""));
|
||||||
|
fprintf(stderr, " -gif0 Select GIF output format (uncompressed)%s\n",
|
||||||
|
(DEFAULT_FMT == FMT_GIF0 ? " (default)" : ""));
|
||||||
#endif
|
#endif
|
||||||
#ifdef BMP_SUPPORTED
|
#ifdef BMP_SUPPORTED
|
||||||
fprintf(stderr, " -os2 Select BMP output format (OS/2 style)%s\n",
|
fprintf(stderr, " -os2 Select BMP output format (OS/2 style)%s\n",
|
||||||
@@ -227,7 +230,7 @@ parse_switches(j_decompress_ptr cinfo, int argc, char **argv,
|
|||||||
arg++; /* advance past switch marker character */
|
arg++; /* advance past switch marker character */
|
||||||
|
|
||||||
if (keymatch(arg, "bmp", 1)) {
|
if (keymatch(arg, "bmp", 1)) {
|
||||||
/* BMP output format. */
|
/* BMP output format (Windows flavor). */
|
||||||
requested_fmt = FMT_BMP;
|
requested_fmt = FMT_BMP;
|
||||||
|
|
||||||
} else if (keymatch(arg, "colors", 1) || keymatch(arg, "colours", 1) ||
|
} else if (keymatch(arg, "colors", 1) || keymatch(arg, "colours", 1) ||
|
||||||
@@ -298,9 +301,13 @@ parse_switches(j_decompress_ptr cinfo, int argc, char **argv,
|
|||||||
cinfo->do_fancy_upsampling = FALSE;
|
cinfo->do_fancy_upsampling = FALSE;
|
||||||
|
|
||||||
} else if (keymatch(arg, "gif", 1)) {
|
} else if (keymatch(arg, "gif", 1)) {
|
||||||
/* GIF output format. */
|
/* GIF output format (LZW-compressed). */
|
||||||
requested_fmt = FMT_GIF;
|
requested_fmt = FMT_GIF;
|
||||||
|
|
||||||
|
} else if (keymatch(arg, "gif0", 4)) {
|
||||||
|
/* GIF output format (uncompressed). */
|
||||||
|
requested_fmt = FMT_GIF0;
|
||||||
|
|
||||||
} else if (keymatch(arg, "grayscale", 2) ||
|
} else if (keymatch(arg, "grayscale", 2) ||
|
||||||
keymatch(arg, "greyscale", 2)) {
|
keymatch(arg, "greyscale", 2)) {
|
||||||
/* Force monochrome output. */
|
/* Force monochrome output. */
|
||||||
@@ -680,7 +687,10 @@ main(int argc, char **argv)
|
|||||||
#endif
|
#endif
|
||||||
#ifdef GIF_SUPPORTED
|
#ifdef GIF_SUPPORTED
|
||||||
case FMT_GIF:
|
case FMT_GIF:
|
||||||
dest_mgr = jinit_write_gif(&cinfo);
|
dest_mgr = jinit_write_gif(&cinfo, TRUE);
|
||||||
|
break;
|
||||||
|
case FMT_GIF0:
|
||||||
|
dest_mgr = jinit_write_gif(&cinfo, FALSE);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#ifdef PPM_SUPPORTED
|
#ifdef PPM_SUPPORTED
|
||||||
|
|||||||
13
jerror.h
13
jerror.h
@@ -207,6 +207,10 @@ JMESSAGE(JWRN_ARITH_BAD_CODE, "Corrupt JPEG data: bad arithmetic code")
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
JMESSAGE(JWRN_BOGUS_ICC, "Corrupt JPEG data: bad ICC marker")
|
JMESSAGE(JWRN_BOGUS_ICC, "Corrupt JPEG data: bad ICC marker")
|
||||||
|
#if JPEG_LIB_VERSION < 70
|
||||||
|
JMESSAGE(JERR_BAD_DROP_SAMPLING,
|
||||||
|
"Component index %d: mismatching sampling ratio %d:%d, %d:%d, %c")
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef JMAKE_ENUM_LIST
|
#ifdef JMAKE_ENUM_LIST
|
||||||
|
|
||||||
@@ -252,6 +256,15 @@ JMESSAGE(JWRN_BOGUS_ICC, "Corrupt JPEG data: bad ICC marker")
|
|||||||
(cinfo)->err->msg_parm.i[2] = (p3), \
|
(cinfo)->err->msg_parm.i[2] = (p3), \
|
||||||
(cinfo)->err->msg_parm.i[3] = (p4), \
|
(cinfo)->err->msg_parm.i[3] = (p4), \
|
||||||
(*(cinfo)->err->error_exit) ((j_common_ptr)(cinfo)))
|
(*(cinfo)->err->error_exit) ((j_common_ptr)(cinfo)))
|
||||||
|
#define ERREXIT6(cinfo, code, p1, p2, p3, p4, p5, p6) \
|
||||||
|
((cinfo)->err->msg_code = (code), \
|
||||||
|
(cinfo)->err->msg_parm.i[0] = (p1), \
|
||||||
|
(cinfo)->err->msg_parm.i[1] = (p2), \
|
||||||
|
(cinfo)->err->msg_parm.i[2] = (p3), \
|
||||||
|
(cinfo)->err->msg_parm.i[3] = (p4), \
|
||||||
|
(cinfo)->err->msg_parm.i[4] = (p5), \
|
||||||
|
(cinfo)->err->msg_parm.i[5] = (p6), \
|
||||||
|
(*(cinfo)->err->error_exit) ((j_common_ptr)(cinfo)))
|
||||||
#define ERREXITS(cinfo, code, str) \
|
#define ERREXITS(cinfo, code, str) \
|
||||||
((cinfo)->err->msg_code = (code), \
|
((cinfo)->err->msg_code = (code), \
|
||||||
strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \
|
strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* This file was part of the Independent JPEG Group's software:
|
* This file was part of the Independent JPEG Group's software:
|
||||||
* Copyright (C) 1991-1998, Thomas G. Lane.
|
* Copyright (C) 1991-1998, Thomas G. Lane.
|
||||||
* Modification developed 2002-2009 by Guido Vollbeding.
|
* Modification developed 2002-2018 by Guido Vollbeding.
|
||||||
* libjpeg-turbo Modifications:
|
* libjpeg-turbo Modifications:
|
||||||
* Copyright (C) 2015, D. R. Commander.
|
* Copyright (C) 2015, D. R. Commander.
|
||||||
* For conditions of distribution and use, see the accompanying README.ijg
|
* For conditions of distribution and use, see the accompanying README.ijg
|
||||||
@@ -417,7 +417,7 @@ jpeg_idct_islow(j_decompress_ptr cinfo, jpeg_component_info *compptr,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Perform dequantization and inverse DCT on one block of coefficients,
|
* Perform dequantization and inverse DCT on one block of coefficients,
|
||||||
* producing a 7x7 output block.
|
* producing a reduced-size 7x7 output block.
|
||||||
*
|
*
|
||||||
* Optimized algorithm with 12 multiplications in the 1-D kernel.
|
* Optimized algorithm with 12 multiplications in the 1-D kernel.
|
||||||
* cK represents sqrt(2) * cos(K*pi/14).
|
* cK represents sqrt(2) * cos(K*pi/14).
|
||||||
@@ -1258,7 +1258,7 @@ jpeg_idct_10x10(j_decompress_ptr cinfo, jpeg_component_info *compptr,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Perform dequantization and inverse DCT on one block of coefficients,
|
* Perform dequantization and inverse DCT on one block of coefficients,
|
||||||
* producing a 11x11 output block.
|
* producing an 11x11 output block.
|
||||||
*
|
*
|
||||||
* Optimized algorithm with 24 multiplications in the 1-D kernel.
|
* Optimized algorithm with 24 multiplications in the 1-D kernel.
|
||||||
* cK represents sqrt(2) * cos(K*pi/22).
|
* cK represents sqrt(2) * cos(K*pi/22).
|
||||||
@@ -2398,7 +2398,7 @@ jpeg_idct_16x16(j_decompress_ptr cinfo, jpeg_component_info *compptr,
|
|||||||
tmp0 = DEQUANTIZE(inptr[DCTSIZE * 0], quantptr[DCTSIZE * 0]);
|
tmp0 = DEQUANTIZE(inptr[DCTSIZE * 0], quantptr[DCTSIZE * 0]);
|
||||||
tmp0 = LEFT_SHIFT(tmp0, CONST_BITS);
|
tmp0 = LEFT_SHIFT(tmp0, CONST_BITS);
|
||||||
/* Add fudge factor here for final descale. */
|
/* Add fudge factor here for final descale. */
|
||||||
tmp0 += 1 << (CONST_BITS - PASS1_BITS - 1);
|
tmp0 += ONE << (CONST_BITS - PASS1_BITS - 1);
|
||||||
|
|
||||||
z1 = DEQUANTIZE(inptr[DCTSIZE * 4], quantptr[DCTSIZE * 4]);
|
z1 = DEQUANTIZE(inptr[DCTSIZE * 4], quantptr[DCTSIZE * 4]);
|
||||||
tmp1 = MULTIPLY(z1, FIX(1.306562965)); /* c4[16] = c2[8] */
|
tmp1 = MULTIPLY(z1, FIX(1.306562965)); /* c4[16] = c2[8] */
|
||||||
|
|||||||
55
jpegtran.1
55
jpegtran.1
@@ -1,4 +1,4 @@
|
|||||||
.TH JPEGTRAN 1 "18 December 2019"
|
.TH JPEGTRAN 1 "26 October 2020"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
jpegtran \- lossless transformation of JPEG files
|
jpegtran \- lossless transformation of JPEG files
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
@@ -161,13 +161,13 @@ to do a perfect rotation, if available, or an approximated one if not.
|
|||||||
.PP
|
.PP
|
||||||
This version of \fBjpegtran\fR also offers a lossless crop option, which
|
This version of \fBjpegtran\fR also offers a lossless crop option, which
|
||||||
discards data outside of a given image region but losslessly preserves what is
|
discards data outside of a given image region but losslessly preserves what is
|
||||||
inside. Like the rotate and flip transforms, lossless crop is restricted by the
|
inside. Like the rotate and flip transforms, lossless crop is restricted by
|
||||||
current JPEG format; the upper left corner of the selected region must fall on
|
the current JPEG format; the upper left corner of the selected region must fall
|
||||||
an iMCU boundary. If it doesn't, then it is silently moved up and/or left to
|
on an iMCU boundary. If it doesn't, then it is silently moved up and/or left
|
||||||
the nearest iMCU boundary (the lower right corner is unchanged.) Thus, the
|
to the nearest iMCU boundary (the lower right corner is unchanged.) Thus, the
|
||||||
output image covers at least the requested region, but it may cover more. The
|
output image covers at least the requested region, but it may cover more. The
|
||||||
adjustment of the region dimensions may be optionally disabled by attaching
|
adjustment of the region dimensions may be optionally disabled by attaching an
|
||||||
an 'f' character ("force") to the width or height number.
|
'f' character ("force") to the width or height number.
|
||||||
|
|
||||||
The image can be losslessly cropped by giving the switch:
|
The image can be losslessly cropped by giving the switch:
|
||||||
.TP
|
.TP
|
||||||
@@ -180,6 +180,47 @@ left corner of the selected region must fall on an iMCU boundary. If it
|
|||||||
doesn't, then it is silently moved up and/or left to the nearest iMCU boundary
|
doesn't, then it is silently moved up and/or left to the nearest iMCU boundary
|
||||||
(the lower right corner is unchanged.)
|
(the lower right corner is unchanged.)
|
||||||
.PP
|
.PP
|
||||||
|
If W or H is larger than the width/height of the input image, then the output
|
||||||
|
image is expanded in size, and the expanded region is filled in with zeros
|
||||||
|
(neutral gray). Attaching an 'f' character ("flatten") to the width number
|
||||||
|
will cause each block in the expanded region to be filled in with the DC
|
||||||
|
coefficient of the nearest block in the input image rather than grayed out.
|
||||||
|
Attaching an 'r' character ("reflect") to the width number will cause the
|
||||||
|
expanded region to be filled in with repeated reflections of the input image
|
||||||
|
rather than grayed out.
|
||||||
|
.PP
|
||||||
|
A complementary lossless wipe option is provided to discard (gray out) data
|
||||||
|
inside a given image region while losslessly preserving what is outside:
|
||||||
|
.TP
|
||||||
|
.B \-wipe WxH+X+Y
|
||||||
|
Wipe (gray out) a rectangular region of width W and height H from the input
|
||||||
|
image, starting at point X,Y.
|
||||||
|
.PP
|
||||||
|
Attaching an 'f' character ("flatten") to the width number will cause the
|
||||||
|
region to be filled with the average of adjacent blocks rather than grayed out.
|
||||||
|
If the wipe region and the region outside the wipe region, when adjusted to the
|
||||||
|
nearest iMCU boundary, form two horizontally adjacent rectangles, then
|
||||||
|
attaching an 'r' character ("reflect") to the width number will cause the wipe
|
||||||
|
region to be filled with repeated reflections of the outside region rather than
|
||||||
|
grayed out.
|
||||||
|
.PP
|
||||||
|
A lossless drop option is also provided, which allows another JPEG image to be
|
||||||
|
inserted ("dropped") into the input image data at a given position, replacing
|
||||||
|
the existing image data at that position:
|
||||||
|
.TP
|
||||||
|
.B \-drop +X+Y filename
|
||||||
|
Drop (insert) another image at point X,Y
|
||||||
|
.PP
|
||||||
|
Both the input image and the drop image must have the same subsampling level.
|
||||||
|
It is best if they also have the same quantization (quality.) Otherwise, the
|
||||||
|
quantization of the output image will be adapted to accommodate the higher of
|
||||||
|
the input image quality and the drop image quality. The trim option can be
|
||||||
|
used with the drop option to requantize the drop image to match the input
|
||||||
|
image. Note that a grayscale image can be dropped into a full-color image or
|
||||||
|
vice versa, as long as the full-color image has no vertical subsampling. If
|
||||||
|
the input image is grayscale and the drop image is full-color, then the
|
||||||
|
chrominance channels from the drop image will be discarded.
|
||||||
|
.PP
|
||||||
Other not-strictly-lossless transformation switches are:
|
Other not-strictly-lossless transformation switches are:
|
||||||
.TP
|
.TP
|
||||||
.B \-grayscale
|
.B \-grayscale
|
||||||
|
|||||||
102
jpegtran.c
102
jpegtran.c
@@ -2,7 +2,7 @@
|
|||||||
* jpegtran.c
|
* jpegtran.c
|
||||||
*
|
*
|
||||||
* This file was part of the Independent JPEG Group's software:
|
* This file was part of the Independent JPEG Group's software:
|
||||||
* Copyright (C) 1995-2010, Thomas G. Lane, Guido Vollbeding.
|
* Copyright (C) 1995-2019, Thomas G. Lane, Guido Vollbeding.
|
||||||
* libjpeg-turbo Modifications:
|
* libjpeg-turbo Modifications:
|
||||||
* Copyright (C) 2010, 2014, 2017, 2019, D. R. Commander.
|
* Copyright (C) 2010, 2014, 2017, 2019, D. R. Commander.
|
||||||
* For conditions of distribution and use, see the accompanying README.ijg
|
* For conditions of distribution and use, see the accompanying README.ijg
|
||||||
@@ -43,6 +43,7 @@ static const char *progname; /* program name for error messages */
|
|||||||
static char *icc_filename; /* for -icc switch */
|
static char *icc_filename; /* for -icc switch */
|
||||||
JDIMENSION max_scans; /* for -maxscans switch */
|
JDIMENSION max_scans; /* for -maxscans switch */
|
||||||
static char *outfilename; /* for -outfile switch */
|
static char *outfilename; /* for -outfile switch */
|
||||||
|
static char *dropfilename; /* for -drop switch */
|
||||||
boolean report; /* for -report switch */
|
boolean report; /* for -report switch */
|
||||||
boolean strict; /* for -strict switch */
|
boolean strict; /* for -strict switch */
|
||||||
static JCOPY_OPTION copyoption; /* -copy switch */
|
static JCOPY_OPTION copyoption; /* -copy switch */
|
||||||
@@ -72,9 +73,10 @@ usage(void)
|
|||||||
#endif
|
#endif
|
||||||
fprintf(stderr, "Switches for modifying the image:\n");
|
fprintf(stderr, "Switches for modifying the image:\n");
|
||||||
#if TRANSFORMS_SUPPORTED
|
#if TRANSFORMS_SUPPORTED
|
||||||
fprintf(stderr, " -crop WxH+X+Y Crop to a rectangular subarea\n");
|
fprintf(stderr, " -crop WxH+X+Y Crop to a rectangular region\n");
|
||||||
fprintf(stderr, " -grayscale Reduce to grayscale (omit color data)\n");
|
fprintf(stderr, " -drop +X+Y filename Drop (insert) another image\n");
|
||||||
fprintf(stderr, " -flip [horizontal|vertical] Mirror image (left-right or top-bottom)\n");
|
fprintf(stderr, " -flip [horizontal|vertical] Mirror image (left-right or top-bottom)\n");
|
||||||
|
fprintf(stderr, " -grayscale Reduce to grayscale (omit color data)\n");
|
||||||
fprintf(stderr, " -perfect Fail if there is non-transformable edge blocks\n");
|
fprintf(stderr, " -perfect Fail if there is non-transformable edge blocks\n");
|
||||||
fprintf(stderr, " -rotate [90|180|270] Rotate image (degrees clockwise)\n");
|
fprintf(stderr, " -rotate [90|180|270] Rotate image (degrees clockwise)\n");
|
||||||
#endif
|
#endif
|
||||||
@@ -82,6 +84,8 @@ usage(void)
|
|||||||
fprintf(stderr, " -transpose Transpose image\n");
|
fprintf(stderr, " -transpose Transpose image\n");
|
||||||
fprintf(stderr, " -transverse Transverse transpose image\n");
|
fprintf(stderr, " -transverse Transverse transpose image\n");
|
||||||
fprintf(stderr, " -trim Drop non-transformable edge blocks\n");
|
fprintf(stderr, " -trim Drop non-transformable edge blocks\n");
|
||||||
|
fprintf(stderr, " with -drop: Requantize drop file to match source file\n");
|
||||||
|
fprintf(stderr, " -wipe WxH+X+Y Wipe (gray out) a rectangular region\n");
|
||||||
#endif
|
#endif
|
||||||
fprintf(stderr, "Switches for advanced users:\n");
|
fprintf(stderr, "Switches for advanced users:\n");
|
||||||
#ifdef C_ARITH_CODING_SUPPORTED
|
#ifdef C_ARITH_CODING_SUPPORTED
|
||||||
@@ -202,7 +206,8 @@ parse_switches(j_compress_ptr cinfo, int argc, char **argv,
|
|||||||
#if TRANSFORMS_SUPPORTED
|
#if TRANSFORMS_SUPPORTED
|
||||||
if (++argn >= argc) /* advance to next argument */
|
if (++argn >= argc) /* advance to next argument */
|
||||||
usage();
|
usage();
|
||||||
if (!jtransform_parse_crop_spec(&transformoption, argv[argn])) {
|
if (transformoption.crop /* reject multiple crop/drop/wipe requests */ ||
|
||||||
|
!jtransform_parse_crop_spec(&transformoption, argv[argn])) {
|
||||||
fprintf(stderr, "%s: bogus -crop argument '%s'\n",
|
fprintf(stderr, "%s: bogus -crop argument '%s'\n",
|
||||||
progname, argv[argn]);
|
progname, argv[argn]);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
@@ -211,6 +216,26 @@ parse_switches(j_compress_ptr cinfo, int argc, char **argv,
|
|||||||
select_transform(JXFORM_NONE); /* force an error */
|
select_transform(JXFORM_NONE); /* force an error */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
} else if (keymatch(arg, "drop", 2)) {
|
||||||
|
#if TRANSFORMS_SUPPORTED
|
||||||
|
if (++argn >= argc) /* advance to next argument */
|
||||||
|
usage();
|
||||||
|
if (transformoption.crop /* reject multiple crop/drop/wipe requests */ ||
|
||||||
|
!jtransform_parse_crop_spec(&transformoption, argv[argn]) ||
|
||||||
|
transformoption.crop_width_set != JCROP_UNSET ||
|
||||||
|
transformoption.crop_height_set != JCROP_UNSET) {
|
||||||
|
fprintf(stderr, "%s: bogus -drop argument '%s'\n",
|
||||||
|
progname, argv[argn]);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
if (++argn >= argc) /* advance to next argument */
|
||||||
|
usage();
|
||||||
|
dropfilename = argv[argn];
|
||||||
|
select_transform(JXFORM_DROP);
|
||||||
|
#else
|
||||||
|
select_transform(JXFORM_NONE); /* force an error */
|
||||||
|
#endif
|
||||||
|
|
||||||
} else if (keymatch(arg, "debug", 1) || keymatch(arg, "verbose", 1)) {
|
} else if (keymatch(arg, "debug", 1) || keymatch(arg, "verbose", 1)) {
|
||||||
/* Enable debug printouts. */
|
/* Enable debug printouts. */
|
||||||
/* On first -d, print version identification */
|
/* On first -d, print version identification */
|
||||||
@@ -371,6 +396,21 @@ parse_switches(j_compress_ptr cinfo, int argc, char **argv,
|
|||||||
/* Trim off any partial edge MCUs that the transform can't handle. */
|
/* Trim off any partial edge MCUs that the transform can't handle. */
|
||||||
transformoption.trim = TRUE;
|
transformoption.trim = TRUE;
|
||||||
|
|
||||||
|
} else if (keymatch(arg, "wipe", 1)) {
|
||||||
|
#if TRANSFORMS_SUPPORTED
|
||||||
|
if (++argn >= argc) /* advance to next argument */
|
||||||
|
usage();
|
||||||
|
if (transformoption.crop /* reject multiple crop/drop/wipe requests */ ||
|
||||||
|
!jtransform_parse_crop_spec(&transformoption, argv[argn])) {
|
||||||
|
fprintf(stderr, "%s: bogus -wipe argument '%s'\n",
|
||||||
|
progname, argv[argn]);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
select_transform(JXFORM_WIPE);
|
||||||
|
#else
|
||||||
|
select_transform(JXFORM_NONE); /* force an error */
|
||||||
|
#endif
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
usage(); /* bogus switch */
|
usage(); /* bogus switch */
|
||||||
}
|
}
|
||||||
@@ -417,6 +457,11 @@ int
|
|||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
struct jpeg_decompress_struct srcinfo;
|
struct jpeg_decompress_struct srcinfo;
|
||||||
|
#if TRANSFORMS_SUPPORTED
|
||||||
|
struct jpeg_decompress_struct dropinfo;
|
||||||
|
struct jpeg_error_mgr jdroperr;
|
||||||
|
FILE *drop_file;
|
||||||
|
#endif
|
||||||
struct jpeg_compress_struct dstinfo;
|
struct jpeg_compress_struct dstinfo;
|
||||||
struct jpeg_error_mgr jsrcerr, jdsterr;
|
struct jpeg_error_mgr jsrcerr, jdsterr;
|
||||||
struct cdjpeg_progress_mgr src_progress, dst_progress;
|
struct cdjpeg_progress_mgr src_progress, dst_progress;
|
||||||
@@ -452,7 +497,7 @@ main(int argc, char **argv)
|
|||||||
* values read here are mostly ignored; we will rescan the switches after
|
* values read here are mostly ignored; we will rescan the switches after
|
||||||
* opening the input file. Also note that most of the switches affect the
|
* opening the input file. Also note that most of the switches affect the
|
||||||
* destination JPEG object, so we parse into that and then copy over what
|
* destination JPEG object, so we parse into that and then copy over what
|
||||||
* needs to affects the source too.
|
* needs to affect the source too.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
file_index = parse_switches(&dstinfo, argc, argv, 0, FALSE);
|
file_index = parse_switches(&dstinfo, argc, argv, 0, FALSE);
|
||||||
@@ -536,6 +581,21 @@ main(int argc, char **argv)
|
|||||||
src_progress.report = report;
|
src_progress.report = report;
|
||||||
src_progress.max_scans = max_scans;
|
src_progress.max_scans = max_scans;
|
||||||
}
|
}
|
||||||
|
#if TRANSFORMS_SUPPORTED
|
||||||
|
/* Open the drop file. */
|
||||||
|
if (dropfilename != NULL) {
|
||||||
|
if ((drop_file = fopen(dropfilename, READ_BINARY)) == NULL) {
|
||||||
|
fprintf(stderr, "%s: can't open %s for reading\n", progname,
|
||||||
|
dropfilename);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
dropinfo.err = jpeg_std_error(&jdroperr);
|
||||||
|
jpeg_create_decompress(&dropinfo);
|
||||||
|
jpeg_stdio_src(&dropinfo, drop_file);
|
||||||
|
} else {
|
||||||
|
drop_file = NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Specify data source for decompression */
|
/* Specify data source for decompression */
|
||||||
jpeg_stdio_src(&srcinfo, fp);
|
jpeg_stdio_src(&srcinfo, fp);
|
||||||
@@ -546,6 +606,17 @@ main(int argc, char **argv)
|
|||||||
/* Read file header */
|
/* Read file header */
|
||||||
(void)jpeg_read_header(&srcinfo, TRUE);
|
(void)jpeg_read_header(&srcinfo, TRUE);
|
||||||
|
|
||||||
|
#if TRANSFORMS_SUPPORTED
|
||||||
|
if (dropfilename != NULL) {
|
||||||
|
(void)jpeg_read_header(&dropinfo, TRUE);
|
||||||
|
transformoption.crop_width = dropinfo.image_width;
|
||||||
|
transformoption.crop_width_set = JCROP_POS;
|
||||||
|
transformoption.crop_height = dropinfo.image_height;
|
||||||
|
transformoption.crop_height_set = JCROP_POS;
|
||||||
|
transformoption.drop_ptr = &dropinfo;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Any space needed by a transform option must be requested before
|
/* Any space needed by a transform option must be requested before
|
||||||
* jpeg_read_coefficients so that memory allocation will be done right.
|
* jpeg_read_coefficients so that memory allocation will be done right.
|
||||||
*/
|
*/
|
||||||
@@ -561,6 +632,12 @@ main(int argc, char **argv)
|
|||||||
/* Read source file as DCT coefficients */
|
/* Read source file as DCT coefficients */
|
||||||
src_coef_arrays = jpeg_read_coefficients(&srcinfo);
|
src_coef_arrays = jpeg_read_coefficients(&srcinfo);
|
||||||
|
|
||||||
|
#if TRANSFORMS_SUPPORTED
|
||||||
|
if (dropfilename != NULL) {
|
||||||
|
transformoption.drop_coef_arrays = jpeg_read_coefficients(&dropinfo);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Initialize destination compression parameters from source values */
|
/* Initialize destination compression parameters from source values */
|
||||||
jpeg_copy_critical_parameters(&srcinfo, &dstinfo);
|
jpeg_copy_critical_parameters(&srcinfo, &dstinfo);
|
||||||
|
|
||||||
@@ -621,12 +698,22 @@ main(int argc, char **argv)
|
|||||||
/* Finish compression and release memory */
|
/* Finish compression and release memory */
|
||||||
jpeg_finish_compress(&dstinfo);
|
jpeg_finish_compress(&dstinfo);
|
||||||
jpeg_destroy_compress(&dstinfo);
|
jpeg_destroy_compress(&dstinfo);
|
||||||
|
#if TRANSFORMS_SUPPORTED
|
||||||
|
if (dropfilename != NULL) {
|
||||||
|
(void)jpeg_finish_decompress(&dropinfo);
|
||||||
|
jpeg_destroy_decompress(&dropinfo);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
(void)jpeg_finish_decompress(&srcinfo);
|
(void)jpeg_finish_decompress(&srcinfo);
|
||||||
jpeg_destroy_decompress(&srcinfo);
|
jpeg_destroy_decompress(&srcinfo);
|
||||||
|
|
||||||
/* Close output file, if we opened it */
|
/* Close output file, if we opened it */
|
||||||
if (fp != stdout)
|
if (fp != stdout)
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
#if TRANSFORMS_SUPPORTED
|
||||||
|
if (drop_file != NULL)
|
||||||
|
fclose(drop_file);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (report)
|
if (report)
|
||||||
end_progress_monitor((j_common_ptr)&dstinfo);
|
end_progress_monitor((j_common_ptr)&dstinfo);
|
||||||
@@ -636,6 +723,11 @@ main(int argc, char **argv)
|
|||||||
free(icc_profile);
|
free(icc_profile);
|
||||||
|
|
||||||
/* All done. */
|
/* All done. */
|
||||||
|
#if TRANSFORMS_SUPPORTED
|
||||||
|
if (dropfilename != NULL)
|
||||||
|
exit(jsrcerr.num_warnings + jdroperr.num_warnings +
|
||||||
|
jdsterr.num_warnings ? EXIT_WARNING : EXIT_SUCCESS);
|
||||||
|
#endif
|
||||||
exit(jsrcerr.num_warnings + jdsterr.num_warnings ?
|
exit(jsrcerr.num_warnings + jdsterr.num_warnings ?
|
||||||
EXIT_WARNING : EXIT_SUCCESS);
|
EXIT_WARNING : EXIT_SUCCESS);
|
||||||
return 0; /* suppress no-return-value warnings */
|
return 0; /* suppress no-return-value warnings */
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
* jversion.h
|
* jversion.h
|
||||||
*
|
*
|
||||||
* This file was part of the Independent JPEG Group's software:
|
* This file was part of the Independent JPEG Group's software:
|
||||||
* Copyright (C) 1991-2012, Thomas G. Lane, Guido Vollbeding.
|
* Copyright (C) 1991-2020, Thomas G. Lane, Guido Vollbeding.
|
||||||
* libjpeg-turbo Modifications:
|
* libjpeg-turbo Modifications:
|
||||||
* Copyright (C) 2010, 2012-2020, D. R. Commander.
|
* Copyright (C) 2010, 2012-2020, D. R. Commander.
|
||||||
* For conditions of distribution and use, see the accompanying README.ijg
|
* For conditions of distribution and use, see the accompanying README.ijg
|
||||||
@@ -48,7 +48,7 @@
|
|||||||
"Copyright (C) 2009, 2012 Pierre Ossman for Cendio AB\n" \
|
"Copyright (C) 2009, 2012 Pierre Ossman for Cendio AB\n" \
|
||||||
"Copyright (C) 2009-2011 Nokia Corporation and/or its subsidiary(-ies)\n" \
|
"Copyright (C) 2009-2011 Nokia Corporation and/or its subsidiary(-ies)\n" \
|
||||||
"Copyright (C) 1999-2006 MIYASAKA Masaru\n" \
|
"Copyright (C) 1999-2006 MIYASAKA Masaru\n" \
|
||||||
"Copyright (C) 1991-2017 Thomas G. Lane, Guido Vollbeding"
|
"Copyright (C) 1991-2020 Thomas G. Lane, Guido Vollbeding"
|
||||||
|
|
||||||
#define JCOPYRIGHT_SHORT \
|
#define JCOPYRIGHT_SHORT \
|
||||||
"Copyright (C) 1991-2020 The libjpeg-turbo Project and many others"
|
"Copyright (C) 1991-2020 The libjpeg-turbo Project and many others"
|
||||||
|
|||||||
12
rdbmp.c
12
rdbmp.c
@@ -12,7 +12,7 @@
|
|||||||
*
|
*
|
||||||
* This file contains routines to read input images in Microsoft "BMP"
|
* This file contains routines to read input images in Microsoft "BMP"
|
||||||
* format (MS Windows 3.x, OS/2 1.x, and OS/2 2.x flavors).
|
* format (MS Windows 3.x, OS/2 1.x, and OS/2 2.x flavors).
|
||||||
* Currently, only 8-bit and 24-bit images are supported, not 1-bit or
|
* Currently, only 8-, 24-, and 32-bit images are supported, not 1-bit or
|
||||||
* 4-bit (feeding such low-depth images into JPEG would be silly anyway).
|
* 4-bit (feeding such low-depth images into JPEG would be silly anyway).
|
||||||
* Also, we don't support RLE-compressed files.
|
* Also, we don't support RLE-compressed files.
|
||||||
*
|
*
|
||||||
@@ -61,7 +61,7 @@ typedef struct _bmp_source_struct {
|
|||||||
JDIMENSION source_row; /* Current source row number */
|
JDIMENSION source_row; /* Current source row number */
|
||||||
JDIMENSION row_width; /* Physical width of scanlines in file */
|
JDIMENSION row_width; /* Physical width of scanlines in file */
|
||||||
|
|
||||||
int bits_per_pixel; /* remembers 8- or 24-bit format */
|
int bits_per_pixel; /* remembers 8-, 24-, or 32-bit format */
|
||||||
int cmap_length; /* colormap length */
|
int cmap_length; /* colormap length */
|
||||||
|
|
||||||
boolean use_inversion_array; /* TRUE = preload the whole image, which is
|
boolean use_inversion_array; /* TRUE = preload the whole image, which is
|
||||||
@@ -469,7 +469,9 @@ start_input_bmp(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
|
|||||||
TRACEMS2(cinfo, 1, JTRC_BMP_OS2_MAPPED, biWidth, biHeight);
|
TRACEMS2(cinfo, 1, JTRC_BMP_OS2_MAPPED, biWidth, biHeight);
|
||||||
break;
|
break;
|
||||||
case 24: /* RGB image */
|
case 24: /* RGB image */
|
||||||
TRACEMS2(cinfo, 1, JTRC_BMP_OS2, biWidth, biHeight);
|
case 32: /* RGB image + Alpha channel */
|
||||||
|
TRACEMS3(cinfo, 1, JTRC_BMP_OS2, biWidth, biHeight,
|
||||||
|
source->bits_per_pixel);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ERREXIT(cinfo, JERR_BMP_BADDEPTH);
|
ERREXIT(cinfo, JERR_BMP_BADDEPTH);
|
||||||
@@ -496,10 +498,8 @@ start_input_bmp(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
|
|||||||
TRACEMS2(cinfo, 1, JTRC_BMP_MAPPED, biWidth, biHeight);
|
TRACEMS2(cinfo, 1, JTRC_BMP_MAPPED, biWidth, biHeight);
|
||||||
break;
|
break;
|
||||||
case 24: /* RGB image */
|
case 24: /* RGB image */
|
||||||
TRACEMS2(cinfo, 1, JTRC_BMP, biWidth, biHeight);
|
|
||||||
break;
|
|
||||||
case 32: /* RGB image + Alpha channel */
|
case 32: /* RGB image + Alpha channel */
|
||||||
TRACEMS2(cinfo, 1, JTRC_BMP, biWidth, biHeight);
|
TRACEMS3(cinfo, 1, JTRC_BMP, biWidth, biHeight, source->bits_per_pixel);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ERREXIT(cinfo, JERR_BMP_BADDEPTH);
|
ERREXIT(cinfo, JERR_BMP_BADDEPTH);
|
||||||
|
|||||||
663
rdgif.c
663
rdgif.c
@@ -2,28 +2,656 @@
|
|||||||
* rdgif.c
|
* rdgif.c
|
||||||
*
|
*
|
||||||
* Copyright (C) 1991-1997, Thomas G. Lane.
|
* Copyright (C) 1991-1997, Thomas G. Lane.
|
||||||
|
* Modified 2019 by Guido Vollbeding.
|
||||||
* This file is part of the Independent JPEG Group's software.
|
* This file is part of the Independent JPEG Group's software.
|
||||||
* For conditions of distribution and use, see the accompanying README.ijg
|
* For conditions of distribution and use, see the accompanying README.ijg
|
||||||
* file.
|
* file.
|
||||||
*
|
*
|
||||||
* This file contains routines to read input images in GIF format.
|
* This file contains routines to read input images in GIF format.
|
||||||
*
|
*
|
||||||
*****************************************************************************
|
* These routines may need modification for non-Unix environments or
|
||||||
* NOTE: to avoid entanglements with Unisys' patent on LZW compression, *
|
* specialized applications. As they stand, they assume input from
|
||||||
* the ability to read GIF files has been removed from the IJG distribution. *
|
* an ordinary stdio stream. They further assume that reading begins
|
||||||
* Sorry about that. *
|
* at the start of the file; start_input may need work if the
|
||||||
*****************************************************************************
|
* user interface has already read some data (e.g., to determine that
|
||||||
*
|
* the file is indeed GIF format).
|
||||||
* We are required to state that
|
*/
|
||||||
* "The Graphics Interchange Format(c) is the Copyright property of
|
|
||||||
* CompuServe Incorporated. GIF(sm) is a Service Mark property of
|
/*
|
||||||
* CompuServe Incorporated."
|
* This code is loosely based on giftoppm from the PBMPLUS distribution
|
||||||
|
* of Feb. 1991. That file contains the following copyright notice:
|
||||||
|
* +-------------------------------------------------------------------+
|
||||||
|
* | Copyright 1990, David Koblas. |
|
||||||
|
* | Permission to use, copy, modify, and distribute this software |
|
||||||
|
* | and its documentation for any purpose and without fee is hereby |
|
||||||
|
* | granted, provided that the above copyright notice appear in all |
|
||||||
|
* | copies and that both that copyright notice and this permission |
|
||||||
|
* | notice appear in supporting documentation. This software is |
|
||||||
|
* | provided "as is" without express or implied warranty. |
|
||||||
|
* +-------------------------------------------------------------------+
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
|
#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
|
||||||
|
|
||||||
#ifdef GIF_SUPPORTED
|
#ifdef GIF_SUPPORTED
|
||||||
|
|
||||||
|
|
||||||
|
/* Macros to deal with unsigned chars as efficiently as compiler allows */
|
||||||
|
|
||||||
|
typedef unsigned char U_CHAR;
|
||||||
|
#define UCH(x) ((int)(x))
|
||||||
|
|
||||||
|
|
||||||
|
#define ReadOK(file, buffer, len) \
|
||||||
|
(JFREAD(file, buffer, len) == ((size_t)(len)))
|
||||||
|
|
||||||
|
|
||||||
|
#define MAXCOLORMAPSIZE 256 /* max # of colors in a GIF colormap */
|
||||||
|
#define NUMCOLORS 3 /* # of colors */
|
||||||
|
#define CM_RED 0 /* color component numbers */
|
||||||
|
#define CM_GREEN 1
|
||||||
|
#define CM_BLUE 2
|
||||||
|
|
||||||
|
#define MAX_LZW_BITS 12 /* maximum LZW code size */
|
||||||
|
#define LZW_TABLE_SIZE (1 << MAX_LZW_BITS) /* # of possible LZW symbols */
|
||||||
|
|
||||||
|
/* Macros for extracting header data --- note we assume chars may be signed */
|
||||||
|
|
||||||
|
#define LM_to_uint(array, offset) \
|
||||||
|
((unsigned int)UCH(array[offset]) + \
|
||||||
|
(((unsigned int)UCH(array[offset + 1])) << 8))
|
||||||
|
|
||||||
|
#define BitSet(byte, bit) ((byte) & (bit))
|
||||||
|
#define INTERLACE 0x40 /* mask for bit signifying interlaced image */
|
||||||
|
#define COLORMAPFLAG 0x80 /* mask for bit signifying colormap presence */
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* LZW decompression tables look like this:
|
||||||
|
* symbol_head[K] = prefix symbol of any LZW symbol K (0..LZW_TABLE_SIZE-1)
|
||||||
|
* symbol_tail[K] = suffix byte of any LZW symbol K (0..LZW_TABLE_SIZE-1)
|
||||||
|
* Note that entries 0..end_code of the above tables are not used,
|
||||||
|
* since those symbols represent raw bytes or special codes.
|
||||||
|
*
|
||||||
|
* The stack represents the not-yet-used expansion of the last LZW symbol.
|
||||||
|
* In the worst case, a symbol could expand to as many bytes as there are
|
||||||
|
* LZW symbols, so we allocate LZW_TABLE_SIZE bytes for the stack.
|
||||||
|
* (This is conservative since that number includes the raw-byte symbols.)
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* Private version of data source object */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
struct cjpeg_source_struct pub; /* public fields */
|
||||||
|
|
||||||
|
j_compress_ptr cinfo; /* back link saves passing separate parm */
|
||||||
|
|
||||||
|
JSAMPARRAY colormap; /* GIF colormap (converted to my format) */
|
||||||
|
|
||||||
|
/* State for GetCode and LZWReadByte */
|
||||||
|
U_CHAR code_buf[256 + 4]; /* current input data block */
|
||||||
|
int last_byte; /* # of bytes in code_buf */
|
||||||
|
int last_bit; /* # of bits in code_buf */
|
||||||
|
int cur_bit; /* next bit index to read */
|
||||||
|
boolean first_time; /* flags first call to GetCode */
|
||||||
|
boolean out_of_blocks; /* TRUE if hit terminator data block */
|
||||||
|
|
||||||
|
int input_code_size; /* codesize given in GIF file */
|
||||||
|
int clear_code, end_code; /* values for Clear and End codes */
|
||||||
|
|
||||||
|
int code_size; /* current actual code size */
|
||||||
|
int limit_code; /* 2^code_size */
|
||||||
|
int max_code; /* first unused code value */
|
||||||
|
|
||||||
|
/* Private state for LZWReadByte */
|
||||||
|
int oldcode; /* previous LZW symbol */
|
||||||
|
int firstcode; /* first byte of oldcode's expansion */
|
||||||
|
|
||||||
|
/* LZW symbol table and expansion stack */
|
||||||
|
UINT16 *symbol_head; /* => table of prefix symbols */
|
||||||
|
UINT8 *symbol_tail; /* => table of suffix bytes */
|
||||||
|
UINT8 *symbol_stack; /* => stack for symbol expansions */
|
||||||
|
UINT8 *sp; /* stack pointer */
|
||||||
|
|
||||||
|
/* State for interlaced image processing */
|
||||||
|
boolean is_interlaced; /* TRUE if have interlaced image */
|
||||||
|
jvirt_sarray_ptr interlaced_image; /* full image in interlaced order */
|
||||||
|
JDIMENSION cur_row_number; /* need to know actual row number */
|
||||||
|
JDIMENSION pass2_offset; /* # of pixel rows in pass 1 */
|
||||||
|
JDIMENSION pass3_offset; /* # of pixel rows in passes 1&2 */
|
||||||
|
JDIMENSION pass4_offset; /* # of pixel rows in passes 1,2,3 */
|
||||||
|
} gif_source_struct;
|
||||||
|
|
||||||
|
typedef gif_source_struct *gif_source_ptr;
|
||||||
|
|
||||||
|
|
||||||
|
/* Forward declarations */
|
||||||
|
METHODDEF(JDIMENSION) get_pixel_rows(j_compress_ptr cinfo,
|
||||||
|
cjpeg_source_ptr sinfo);
|
||||||
|
METHODDEF(JDIMENSION) load_interlaced_image(j_compress_ptr cinfo,
|
||||||
|
cjpeg_source_ptr sinfo);
|
||||||
|
METHODDEF(JDIMENSION) get_interlaced_row(j_compress_ptr cinfo,
|
||||||
|
cjpeg_source_ptr sinfo);
|
||||||
|
|
||||||
|
|
||||||
|
LOCAL(int)
|
||||||
|
ReadByte(gif_source_ptr sinfo)
|
||||||
|
/* Read next byte from GIF file */
|
||||||
|
{
|
||||||
|
register FILE *infile = sinfo->pub.input_file;
|
||||||
|
register int c;
|
||||||
|
|
||||||
|
if ((c = getc(infile)) == EOF)
|
||||||
|
ERREXIT(sinfo->cinfo, JERR_INPUT_EOF);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LOCAL(int)
|
||||||
|
GetDataBlock(gif_source_ptr sinfo, U_CHAR *buf)
|
||||||
|
/* Read a GIF data block, which has a leading count byte */
|
||||||
|
/* A zero-length block marks the end of a data block sequence */
|
||||||
|
{
|
||||||
|
int count;
|
||||||
|
|
||||||
|
count = ReadByte(sinfo);
|
||||||
|
if (count > 0) {
|
||||||
|
if (!ReadOK(sinfo->pub.input_file, buf, count))
|
||||||
|
ERREXIT(sinfo->cinfo, JERR_INPUT_EOF);
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LOCAL(void)
|
||||||
|
SkipDataBlocks(gif_source_ptr sinfo)
|
||||||
|
/* Skip a series of data blocks, until a block terminator is found */
|
||||||
|
{
|
||||||
|
U_CHAR buf[256];
|
||||||
|
|
||||||
|
while (GetDataBlock(sinfo, buf) > 0)
|
||||||
|
/* skip */;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LOCAL(void)
|
||||||
|
ReInitLZW(gif_source_ptr sinfo)
|
||||||
|
/* (Re)initialize LZW state; shared code for startup and Clear processing */
|
||||||
|
{
|
||||||
|
sinfo->code_size = sinfo->input_code_size + 1;
|
||||||
|
sinfo->limit_code = sinfo->clear_code << 1; /* 2^code_size */
|
||||||
|
sinfo->max_code = sinfo->clear_code + 2; /* first unused code value */
|
||||||
|
sinfo->sp = sinfo->symbol_stack; /* init stack to empty */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LOCAL(void)
|
||||||
|
InitLZWCode(gif_source_ptr sinfo)
|
||||||
|
/* Initialize for a series of LZWReadByte (and hence GetCode) calls */
|
||||||
|
{
|
||||||
|
/* GetCode initialization */
|
||||||
|
sinfo->last_byte = 2; /* make safe to "recopy last two bytes" */
|
||||||
|
sinfo->code_buf[0] = 0;
|
||||||
|
sinfo->code_buf[1] = 0;
|
||||||
|
sinfo->last_bit = 0; /* nothing in the buffer */
|
||||||
|
sinfo->cur_bit = 0; /* force buffer load on first call */
|
||||||
|
sinfo->first_time = TRUE;
|
||||||
|
sinfo->out_of_blocks = FALSE;
|
||||||
|
|
||||||
|
/* LZWReadByte initialization: */
|
||||||
|
/* compute special code values (note that these do not change later) */
|
||||||
|
sinfo->clear_code = 1 << sinfo->input_code_size;
|
||||||
|
sinfo->end_code = sinfo->clear_code + 1;
|
||||||
|
ReInitLZW(sinfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LOCAL(int)
|
||||||
|
GetCode(gif_source_ptr sinfo)
|
||||||
|
/* Fetch the next code_size bits from the GIF data */
|
||||||
|
/* We assume code_size is less than 16 */
|
||||||
|
{
|
||||||
|
register int accum;
|
||||||
|
int offs, count;
|
||||||
|
|
||||||
|
while (sinfo->cur_bit + sinfo->code_size > sinfo->last_bit) {
|
||||||
|
/* Time to reload the buffer */
|
||||||
|
/* First time, share code with Clear case */
|
||||||
|
if (sinfo->first_time) {
|
||||||
|
sinfo->first_time = FALSE;
|
||||||
|
return sinfo->clear_code;
|
||||||
|
}
|
||||||
|
if (sinfo->out_of_blocks) {
|
||||||
|
WARNMS(sinfo->cinfo, JWRN_GIF_NOMOREDATA);
|
||||||
|
return sinfo->end_code; /* fake something useful */
|
||||||
|
}
|
||||||
|
/* preserve last two bytes of what we have -- assume code_size <= 16 */
|
||||||
|
sinfo->code_buf[0] = sinfo->code_buf[sinfo->last_byte-2];
|
||||||
|
sinfo->code_buf[1] = sinfo->code_buf[sinfo->last_byte-1];
|
||||||
|
/* Load more bytes; set flag if we reach the terminator block */
|
||||||
|
if ((count = GetDataBlock(sinfo, &sinfo->code_buf[2])) == 0) {
|
||||||
|
sinfo->out_of_blocks = TRUE;
|
||||||
|
WARNMS(sinfo->cinfo, JWRN_GIF_NOMOREDATA);
|
||||||
|
return sinfo->end_code; /* fake something useful */
|
||||||
|
}
|
||||||
|
/* Reset counters */
|
||||||
|
sinfo->cur_bit = (sinfo->cur_bit - sinfo->last_bit) + 16;
|
||||||
|
sinfo->last_byte = 2 + count;
|
||||||
|
sinfo->last_bit = sinfo->last_byte * 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Form up next 24 bits in accum */
|
||||||
|
offs = sinfo->cur_bit >> 3; /* byte containing cur_bit */
|
||||||
|
accum = UCH(sinfo->code_buf[offs + 2]);
|
||||||
|
accum <<= 8;
|
||||||
|
accum |= UCH(sinfo->code_buf[offs + 1]);
|
||||||
|
accum <<= 8;
|
||||||
|
accum |= UCH(sinfo->code_buf[offs]);
|
||||||
|
|
||||||
|
/* Right-align cur_bit in accum, then mask off desired number of bits */
|
||||||
|
accum >>= (sinfo->cur_bit & 7);
|
||||||
|
sinfo->cur_bit += sinfo->code_size;
|
||||||
|
return accum & ((1 << sinfo->code_size) - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LOCAL(int)
|
||||||
|
LZWReadByte(gif_source_ptr sinfo)
|
||||||
|
/* Read an LZW-compressed byte */
|
||||||
|
{
|
||||||
|
register int code; /* current working code */
|
||||||
|
int incode; /* saves actual input code */
|
||||||
|
|
||||||
|
/* If any codes are stacked from a previously read symbol, return them */
|
||||||
|
if (sinfo->sp > sinfo->symbol_stack)
|
||||||
|
return (int)(*(--sinfo->sp));
|
||||||
|
|
||||||
|
/* Time to read a new symbol */
|
||||||
|
code = GetCode(sinfo);
|
||||||
|
|
||||||
|
if (code == sinfo->clear_code) {
|
||||||
|
/* Reinit state, swallow any extra Clear codes, and */
|
||||||
|
/* return next code, which is expected to be a raw byte. */
|
||||||
|
ReInitLZW(sinfo);
|
||||||
|
do {
|
||||||
|
code = GetCode(sinfo);
|
||||||
|
} while (code == sinfo->clear_code);
|
||||||
|
if (code > sinfo->clear_code) { /* make sure it is a raw byte */
|
||||||
|
WARNMS(sinfo->cinfo, JWRN_GIF_BADDATA);
|
||||||
|
code = 0; /* use something valid */
|
||||||
|
}
|
||||||
|
/* make firstcode, oldcode valid! */
|
||||||
|
sinfo->firstcode = sinfo->oldcode = code;
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (code == sinfo->end_code) {
|
||||||
|
/* Skip the rest of the image, unless GetCode already read terminator */
|
||||||
|
if (!sinfo->out_of_blocks) {
|
||||||
|
SkipDataBlocks(sinfo);
|
||||||
|
sinfo->out_of_blocks = TRUE;
|
||||||
|
}
|
||||||
|
/* Complain that there's not enough data */
|
||||||
|
WARNMS(sinfo->cinfo, JWRN_GIF_ENDCODE);
|
||||||
|
/* Pad data with 0's */
|
||||||
|
return 0; /* fake something usable */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Got normal raw byte or LZW symbol */
|
||||||
|
incode = code; /* save for a moment */
|
||||||
|
|
||||||
|
if (code >= sinfo->max_code) { /* special case for not-yet-defined symbol */
|
||||||
|
/* code == max_code is OK; anything bigger is bad data */
|
||||||
|
if (code > sinfo->max_code) {
|
||||||
|
WARNMS(sinfo->cinfo, JWRN_GIF_BADDATA);
|
||||||
|
incode = 0; /* prevent creation of loops in symbol table */
|
||||||
|
}
|
||||||
|
/* this symbol will be defined as oldcode/firstcode */
|
||||||
|
*(sinfo->sp++) = (UINT8)sinfo->firstcode;
|
||||||
|
code = sinfo->oldcode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If it's a symbol, expand it into the stack */
|
||||||
|
while (code >= sinfo->clear_code) {
|
||||||
|
*(sinfo->sp++) = sinfo->symbol_tail[code]; /* tail is a byte value */
|
||||||
|
code = sinfo->symbol_head[code]; /* head is another LZW symbol */
|
||||||
|
}
|
||||||
|
/* At this point code just represents a raw byte */
|
||||||
|
sinfo->firstcode = code; /* save for possible future use */
|
||||||
|
|
||||||
|
/* If there's room in table... */
|
||||||
|
if ((code = sinfo->max_code) < LZW_TABLE_SIZE) {
|
||||||
|
/* Define a new symbol = prev sym + head of this sym's expansion */
|
||||||
|
sinfo->symbol_head[code] = (UINT16)sinfo->oldcode;
|
||||||
|
sinfo->symbol_tail[code] = (UINT8)sinfo->firstcode;
|
||||||
|
sinfo->max_code++;
|
||||||
|
/* Is it time to increase code_size? */
|
||||||
|
if (sinfo->max_code >= sinfo->limit_code &&
|
||||||
|
sinfo->code_size < MAX_LZW_BITS) {
|
||||||
|
sinfo->code_size++;
|
||||||
|
sinfo->limit_code <<= 1; /* keep equal to 2^code_size */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sinfo->oldcode = incode; /* save last input symbol for future use */
|
||||||
|
return sinfo->firstcode; /* return first byte of symbol's expansion */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LOCAL(void)
|
||||||
|
ReadColorMap(gif_source_ptr sinfo, int cmaplen, JSAMPARRAY cmap)
|
||||||
|
/* Read a GIF colormap */
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < cmaplen; i++) {
|
||||||
|
#if BITS_IN_JSAMPLE == 8
|
||||||
|
#define UPSCALE(x) (x)
|
||||||
|
#else
|
||||||
|
#define UPSCALE(x) ((x) << (BITS_IN_JSAMPLE - 8))
|
||||||
|
#endif
|
||||||
|
cmap[CM_RED][i] = (JSAMPLE)UPSCALE(ReadByte(sinfo));
|
||||||
|
cmap[CM_GREEN][i] = (JSAMPLE)UPSCALE(ReadByte(sinfo));
|
||||||
|
cmap[CM_BLUE][i] = (JSAMPLE)UPSCALE(ReadByte(sinfo));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LOCAL(void)
|
||||||
|
DoExtension(gif_source_ptr sinfo)
|
||||||
|
/* Process an extension block */
|
||||||
|
/* Currently we ignore 'em all */
|
||||||
|
{
|
||||||
|
int extlabel;
|
||||||
|
|
||||||
|
/* Read extension label byte */
|
||||||
|
extlabel = ReadByte(sinfo);
|
||||||
|
TRACEMS1(sinfo->cinfo, 1, JTRC_GIF_EXTENSION, extlabel);
|
||||||
|
/* Skip the data block(s) associated with the extension */
|
||||||
|
SkipDataBlocks(sinfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read the file header; return image size and component count.
|
||||||
|
*/
|
||||||
|
|
||||||
|
METHODDEF(void)
|
||||||
|
start_input_gif(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
|
||||||
|
{
|
||||||
|
gif_source_ptr source = (gif_source_ptr)sinfo;
|
||||||
|
U_CHAR hdrbuf[10]; /* workspace for reading control blocks */
|
||||||
|
unsigned int width, height; /* image dimensions */
|
||||||
|
int colormaplen, aspectRatio;
|
||||||
|
int c;
|
||||||
|
|
||||||
|
/* Read and verify GIF Header */
|
||||||
|
if (!ReadOK(source->pub.input_file, hdrbuf, 6))
|
||||||
|
ERREXIT(cinfo, JERR_GIF_NOT);
|
||||||
|
if (hdrbuf[0] != 'G' || hdrbuf[1] != 'I' || hdrbuf[2] != 'F')
|
||||||
|
ERREXIT(cinfo, JERR_GIF_NOT);
|
||||||
|
/* Check for expected version numbers.
|
||||||
|
* If unknown version, give warning and try to process anyway;
|
||||||
|
* this is per recommendation in GIF89a standard.
|
||||||
|
*/
|
||||||
|
if ((hdrbuf[3] != '8' || hdrbuf[4] != '7' || hdrbuf[5] != 'a') &&
|
||||||
|
(hdrbuf[3] != '8' || hdrbuf[4] != '9' || hdrbuf[5] != 'a'))
|
||||||
|
TRACEMS3(cinfo, 1, JTRC_GIF_BADVERSION, hdrbuf[3], hdrbuf[4], hdrbuf[5]);
|
||||||
|
|
||||||
|
/* Read and decipher Logical Screen Descriptor */
|
||||||
|
if (!ReadOK(source->pub.input_file, hdrbuf, 7))
|
||||||
|
ERREXIT(cinfo, JERR_INPUT_EOF);
|
||||||
|
width = LM_to_uint(hdrbuf, 0);
|
||||||
|
height = LM_to_uint(hdrbuf, 2);
|
||||||
|
/* we ignore the color resolution, sort flag, and background color index */
|
||||||
|
aspectRatio = UCH(hdrbuf[6]);
|
||||||
|
if (aspectRatio != 0 && aspectRatio != 49)
|
||||||
|
TRACEMS(cinfo, 1, JTRC_GIF_NONSQUARE);
|
||||||
|
|
||||||
|
/* Allocate space to store the colormap */
|
||||||
|
source->colormap = (*cinfo->mem->alloc_sarray)
|
||||||
|
((j_common_ptr)cinfo, JPOOL_IMAGE, (JDIMENSION)MAXCOLORMAPSIZE,
|
||||||
|
(JDIMENSION)NUMCOLORS);
|
||||||
|
colormaplen = 0; /* indicate initialization */
|
||||||
|
|
||||||
|
/* Read global colormap if header indicates it is present */
|
||||||
|
if (BitSet(hdrbuf[4], COLORMAPFLAG)) {
|
||||||
|
colormaplen = 2 << (hdrbuf[4] & 0x07);
|
||||||
|
ReadColorMap(source, colormaplen, source->colormap);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Scan until we reach start of desired image.
|
||||||
|
* We don't currently support skipping images, but could add it easily.
|
||||||
|
*/
|
||||||
|
for (;;) {
|
||||||
|
c = ReadByte(source);
|
||||||
|
|
||||||
|
if (c == ';') /* GIF terminator?? */
|
||||||
|
ERREXIT(cinfo, JERR_GIF_IMAGENOTFOUND);
|
||||||
|
|
||||||
|
if (c == '!') { /* Extension */
|
||||||
|
DoExtension(source);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c != ',') { /* Not an image separator? */
|
||||||
|
WARNMS1(cinfo, JWRN_GIF_CHAR, c);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read and decipher Local Image Descriptor */
|
||||||
|
if (!ReadOK(source->pub.input_file, hdrbuf, 9))
|
||||||
|
ERREXIT(cinfo, JERR_INPUT_EOF);
|
||||||
|
/* we ignore top/left position info, also sort flag */
|
||||||
|
width = LM_to_uint(hdrbuf, 4);
|
||||||
|
height = LM_to_uint(hdrbuf, 6);
|
||||||
|
source->is_interlaced = (BitSet(hdrbuf[8], INTERLACE) != 0);
|
||||||
|
|
||||||
|
/* Read local colormap if header indicates it is present */
|
||||||
|
/* Note: if we wanted to support skipping images, */
|
||||||
|
/* we'd need to skip rather than read colormap for ignored images */
|
||||||
|
if (BitSet(hdrbuf[8], COLORMAPFLAG)) {
|
||||||
|
colormaplen = 2 << (hdrbuf[8] & 0x07);
|
||||||
|
ReadColorMap(source, colormaplen, source->colormap);
|
||||||
|
}
|
||||||
|
|
||||||
|
source->input_code_size = ReadByte(source); /* get min-code-size byte */
|
||||||
|
if (source->input_code_size < 2 || source->input_code_size > 8)
|
||||||
|
ERREXIT1(cinfo, JERR_GIF_CODESIZE, source->input_code_size);
|
||||||
|
|
||||||
|
/* Reached desired image, so break out of loop */
|
||||||
|
/* If we wanted to skip this image, */
|
||||||
|
/* we'd call SkipDataBlocks and then continue the loop */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Prepare to read selected image: first initialize LZW decompressor */
|
||||||
|
source->symbol_head = (UINT16 *)
|
||||||
|
(*cinfo->mem->alloc_large) ((j_common_ptr)cinfo, JPOOL_IMAGE,
|
||||||
|
LZW_TABLE_SIZE * sizeof(UINT16));
|
||||||
|
source->symbol_tail = (UINT8 *)
|
||||||
|
(*cinfo->mem->alloc_large) ((j_common_ptr)cinfo, JPOOL_IMAGE,
|
||||||
|
LZW_TABLE_SIZE * sizeof(UINT8));
|
||||||
|
source->symbol_stack = (UINT8 *)
|
||||||
|
(*cinfo->mem->alloc_large) ((j_common_ptr)cinfo, JPOOL_IMAGE,
|
||||||
|
LZW_TABLE_SIZE * sizeof(UINT8));
|
||||||
|
InitLZWCode(source);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If image is interlaced, we read it into a full-size sample array,
|
||||||
|
* decompressing as we go; then get_interlaced_row selects rows from the
|
||||||
|
* sample array in the proper order.
|
||||||
|
*/
|
||||||
|
if (source->is_interlaced) {
|
||||||
|
/* We request the virtual array now, but can't access it until virtual
|
||||||
|
* arrays have been allocated. Hence, the actual work of reading the
|
||||||
|
* image is postponed until the first call to get_pixel_rows.
|
||||||
|
*/
|
||||||
|
source->interlaced_image = (*cinfo->mem->request_virt_sarray)
|
||||||
|
((j_common_ptr)cinfo, JPOOL_IMAGE, FALSE,
|
||||||
|
(JDIMENSION)width, (JDIMENSION)height, (JDIMENSION)1);
|
||||||
|
if (cinfo->progress != NULL) {
|
||||||
|
cd_progress_ptr progress = (cd_progress_ptr)cinfo->progress;
|
||||||
|
progress->total_extra_passes++; /* count file input as separate pass */
|
||||||
|
}
|
||||||
|
source->pub.get_pixel_rows = load_interlaced_image;
|
||||||
|
} else {
|
||||||
|
source->pub.get_pixel_rows = get_pixel_rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create compressor input buffer. */
|
||||||
|
source->pub.buffer = (*cinfo->mem->alloc_sarray)
|
||||||
|
((j_common_ptr)cinfo, JPOOL_IMAGE, (JDIMENSION)width * NUMCOLORS,
|
||||||
|
(JDIMENSION)1);
|
||||||
|
source->pub.buffer_height = 1;
|
||||||
|
|
||||||
|
/* Pad colormap for safety. */
|
||||||
|
for (c = colormaplen; c < source->clear_code; c++) {
|
||||||
|
source->colormap[CM_RED][c] =
|
||||||
|
source->colormap[CM_GREEN][c] =
|
||||||
|
source->colormap[CM_BLUE][c] = CENTERJSAMPLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return info about the image. */
|
||||||
|
cinfo->in_color_space = JCS_RGB;
|
||||||
|
cinfo->input_components = NUMCOLORS;
|
||||||
|
cinfo->data_precision = BITS_IN_JSAMPLE; /* we always rescale data to this */
|
||||||
|
cinfo->image_width = width;
|
||||||
|
cinfo->image_height = height;
|
||||||
|
|
||||||
|
TRACEMS3(cinfo, 1, JTRC_GIF, width, height, colormaplen);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read one row of pixels.
|
||||||
|
* This version is used for noninterlaced GIF images:
|
||||||
|
* we read directly from the GIF file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
METHODDEF(JDIMENSION)
|
||||||
|
get_pixel_rows(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
|
||||||
|
{
|
||||||
|
gif_source_ptr source = (gif_source_ptr)sinfo;
|
||||||
|
register int c;
|
||||||
|
register JSAMPROW ptr;
|
||||||
|
register JDIMENSION col;
|
||||||
|
register JSAMPARRAY colormap = source->colormap;
|
||||||
|
|
||||||
|
ptr = source->pub.buffer[0];
|
||||||
|
for (col = cinfo->image_width; col > 0; col--) {
|
||||||
|
c = LZWReadByte(source);
|
||||||
|
*ptr++ = colormap[CM_RED][c];
|
||||||
|
*ptr++ = colormap[CM_GREEN][c];
|
||||||
|
*ptr++ = colormap[CM_BLUE][c];
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read one row of pixels.
|
||||||
|
* This version is used for the first call on get_pixel_rows when
|
||||||
|
* reading an interlaced GIF file: we read the whole image into memory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
METHODDEF(JDIMENSION)
|
||||||
|
load_interlaced_image(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
|
||||||
|
{
|
||||||
|
gif_source_ptr source = (gif_source_ptr)sinfo;
|
||||||
|
register JSAMPROW sptr;
|
||||||
|
register JDIMENSION col;
|
||||||
|
JDIMENSION row;
|
||||||
|
cd_progress_ptr progress = (cd_progress_ptr)cinfo->progress;
|
||||||
|
|
||||||
|
/* Read the interlaced image into the virtual array we've created. */
|
||||||
|
for (row = 0; row < cinfo->image_height; row++) {
|
||||||
|
if (progress != NULL) {
|
||||||
|
progress->pub.pass_counter = (long)row;
|
||||||
|
progress->pub.pass_limit = (long)cinfo->image_height;
|
||||||
|
(*progress->pub.progress_monitor) ((j_common_ptr)cinfo);
|
||||||
|
}
|
||||||
|
sptr = *(*cinfo->mem->access_virt_sarray)
|
||||||
|
((j_common_ptr)cinfo, source->interlaced_image, row, (JDIMENSION)1,
|
||||||
|
TRUE);
|
||||||
|
for (col = cinfo->image_width; col > 0; col--) {
|
||||||
|
*sptr++ = (JSAMPLE)LZWReadByte(source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (progress != NULL)
|
||||||
|
progress->completed_extra_passes++;
|
||||||
|
|
||||||
|
/* Replace method pointer so subsequent calls don't come here. */
|
||||||
|
source->pub.get_pixel_rows = get_interlaced_row;
|
||||||
|
/* Initialize for get_interlaced_row, and perform first call on it. */
|
||||||
|
source->cur_row_number = 0;
|
||||||
|
source->pass2_offset = (cinfo->image_height + 7) / 8;
|
||||||
|
source->pass3_offset = source->pass2_offset + (cinfo->image_height + 3) / 8;
|
||||||
|
source->pass4_offset = source->pass3_offset + (cinfo->image_height + 1) / 4;
|
||||||
|
|
||||||
|
return get_interlaced_row(cinfo, sinfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read one row of pixels.
|
||||||
|
* This version is used for interlaced GIF images:
|
||||||
|
* we read from the virtual array.
|
||||||
|
*/
|
||||||
|
|
||||||
|
METHODDEF(JDIMENSION)
|
||||||
|
get_interlaced_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
|
||||||
|
{
|
||||||
|
gif_source_ptr source = (gif_source_ptr)sinfo;
|
||||||
|
register int c;
|
||||||
|
register JSAMPROW sptr, ptr;
|
||||||
|
register JDIMENSION col;
|
||||||
|
register JSAMPARRAY colormap = source->colormap;
|
||||||
|
JDIMENSION irow;
|
||||||
|
|
||||||
|
/* Figure out which row of interlaced image is needed, and access it. */
|
||||||
|
switch ((int)(source->cur_row_number & 7)) {
|
||||||
|
case 0: /* first-pass row */
|
||||||
|
irow = source->cur_row_number >> 3;
|
||||||
|
break;
|
||||||
|
case 4: /* second-pass row */
|
||||||
|
irow = (source->cur_row_number >> 3) + source->pass2_offset;
|
||||||
|
break;
|
||||||
|
case 2: /* third-pass row */
|
||||||
|
case 6:
|
||||||
|
irow = (source->cur_row_number >> 2) + source->pass3_offset;
|
||||||
|
break;
|
||||||
|
default: /* fourth-pass row */
|
||||||
|
irow = (source->cur_row_number >> 1) + source->pass4_offset;
|
||||||
|
}
|
||||||
|
sptr = *(*cinfo->mem->access_virt_sarray)
|
||||||
|
((j_common_ptr)cinfo, source->interlaced_image, irow, (JDIMENSION)1,
|
||||||
|
FALSE);
|
||||||
|
/* Scan the row, expand colormap, and output */
|
||||||
|
ptr = source->pub.buffer[0];
|
||||||
|
for (col = cinfo->image_width; col > 0; col--) {
|
||||||
|
c = *sptr++;
|
||||||
|
*ptr++ = colormap[CM_RED][c];
|
||||||
|
*ptr++ = colormap[CM_GREEN][c];
|
||||||
|
*ptr++ = colormap[CM_BLUE][c];
|
||||||
|
}
|
||||||
|
source->cur_row_number++; /* for next time */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Finish up at the end of the file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
METHODDEF(void)
|
||||||
|
finish_input_gif(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
|
||||||
|
{
|
||||||
|
/* no work */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The module selection routine for GIF format input.
|
* The module selection routine for GIF format input.
|
||||||
*/
|
*/
|
||||||
@@ -31,9 +659,18 @@
|
|||||||
GLOBAL(cjpeg_source_ptr)
|
GLOBAL(cjpeg_source_ptr)
|
||||||
jinit_read_gif(j_compress_ptr cinfo)
|
jinit_read_gif(j_compress_ptr cinfo)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "GIF input is unsupported for legal reasons. Sorry.\n");
|
gif_source_ptr source;
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
return NULL; /* keep compiler happy */
|
/* Create module interface object */
|
||||||
|
source = (gif_source_ptr)
|
||||||
|
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
|
||||||
|
sizeof(gif_source_struct));
|
||||||
|
source->cinfo = cinfo; /* make back link for subroutines */
|
||||||
|
/* Fill in method ptrs, except get_pixel_rows which start_input sets */
|
||||||
|
source->pub.start_input = start_input_gif;
|
||||||
|
source->pub.finish_input = finish_input_gif;
|
||||||
|
|
||||||
|
return (cjpeg_source_ptr)source;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* GIF_SUPPORTED */
|
#endif /* GIF_SUPPORTED */
|
||||||
|
|||||||
826
transupp.c
826
transupp.c
@@ -2,7 +2,7 @@
|
|||||||
* transupp.c
|
* transupp.c
|
||||||
*
|
*
|
||||||
* This file was part of the Independent JPEG Group's software:
|
* This file was part of the Independent JPEG Group's software:
|
||||||
* Copyright (C) 1997-2011, Thomas G. Lane, Guido Vollbeding.
|
* Copyright (C) 1997-2019, Thomas G. Lane, Guido Vollbeding.
|
||||||
* libjpeg-turbo Modifications:
|
* libjpeg-turbo Modifications:
|
||||||
* Copyright (C) 2010, 2017, D. R. Commander.
|
* Copyright (C) 2010, 2017, D. R. Commander.
|
||||||
* For conditions of distribution and use, see the accompanying README.ijg
|
* For conditions of distribution and use, see the accompanying README.ijg
|
||||||
@@ -88,6 +88,189 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
LOCAL(void)
|
||||||
|
dequant_comp(j_decompress_ptr cinfo, jpeg_component_info *compptr,
|
||||||
|
jvirt_barray_ptr coef_array, JQUANT_TBL *qtblptr1)
|
||||||
|
{
|
||||||
|
JDIMENSION blk_x, blk_y;
|
||||||
|
int offset_y, k;
|
||||||
|
JQUANT_TBL *qtblptr;
|
||||||
|
JBLOCKARRAY buffer;
|
||||||
|
JBLOCKROW block;
|
||||||
|
JCOEFPTR ptr;
|
||||||
|
|
||||||
|
qtblptr = compptr->quant_table;
|
||||||
|
for (blk_y = 0; blk_y < compptr->height_in_blocks;
|
||||||
|
blk_y += compptr->v_samp_factor) {
|
||||||
|
buffer = (*cinfo->mem->access_virt_barray)
|
||||||
|
((j_common_ptr)cinfo, coef_array, blk_y,
|
||||||
|
(JDIMENSION)compptr->v_samp_factor, TRUE);
|
||||||
|
for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
|
||||||
|
block = buffer[offset_y];
|
||||||
|
for (blk_x = 0; blk_x < compptr->width_in_blocks; blk_x++) {
|
||||||
|
ptr = block[blk_x];
|
||||||
|
for (k = 0; k < DCTSIZE2; k++)
|
||||||
|
if (qtblptr->quantval[k] != qtblptr1->quantval[k])
|
||||||
|
ptr[k] *= qtblptr->quantval[k] / qtblptr1->quantval[k];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LOCAL(void)
|
||||||
|
requant_comp(j_decompress_ptr cinfo, jpeg_component_info *compptr,
|
||||||
|
jvirt_barray_ptr coef_array, JQUANT_TBL *qtblptr1)
|
||||||
|
{
|
||||||
|
JDIMENSION blk_x, blk_y;
|
||||||
|
int offset_y, k;
|
||||||
|
JQUANT_TBL *qtblptr;
|
||||||
|
JBLOCKARRAY buffer;
|
||||||
|
JBLOCKROW block;
|
||||||
|
JCOEFPTR ptr;
|
||||||
|
JCOEF temp, qval;
|
||||||
|
|
||||||
|
qtblptr = compptr->quant_table;
|
||||||
|
for (blk_y = 0; blk_y < compptr->height_in_blocks;
|
||||||
|
blk_y += compptr->v_samp_factor) {
|
||||||
|
buffer = (*cinfo->mem->access_virt_barray)
|
||||||
|
((j_common_ptr)cinfo, coef_array, blk_y,
|
||||||
|
(JDIMENSION)compptr->v_samp_factor, TRUE);
|
||||||
|
for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
|
||||||
|
block = buffer[offset_y];
|
||||||
|
for (blk_x = 0; blk_x < compptr->width_in_blocks; blk_x++) {
|
||||||
|
ptr = block[blk_x];
|
||||||
|
for (k = 0; k < DCTSIZE2; k++) {
|
||||||
|
temp = qtblptr->quantval[k];
|
||||||
|
qval = qtblptr1->quantval[k];
|
||||||
|
if (temp != qval) {
|
||||||
|
temp *= ptr[k];
|
||||||
|
/* The following quantization code is copied from jcdctmgr.c */
|
||||||
|
#ifdef FAST_DIVIDE
|
||||||
|
#define DIVIDE_BY(a, b) a /= b
|
||||||
|
#else
|
||||||
|
#define DIVIDE_BY(a, b) if (a >= b) a /= b; else a = 0
|
||||||
|
#endif
|
||||||
|
if (temp < 0) {
|
||||||
|
temp = -temp;
|
||||||
|
temp += qval >> 1; /* for rounding */
|
||||||
|
DIVIDE_BY(temp, qval);
|
||||||
|
temp = -temp;
|
||||||
|
} else {
|
||||||
|
temp += qval >> 1; /* for rounding */
|
||||||
|
DIVIDE_BY(temp, qval);
|
||||||
|
}
|
||||||
|
ptr[k] = temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calculate largest common denominator using Euclid's algorithm.
|
||||||
|
*/
|
||||||
|
LOCAL(JCOEF)
|
||||||
|
largest_common_denominator(JCOEF a, JCOEF b)
|
||||||
|
{
|
||||||
|
JCOEF c;
|
||||||
|
|
||||||
|
do {
|
||||||
|
c = a % b;
|
||||||
|
a = b;
|
||||||
|
b = c;
|
||||||
|
} while (c);
|
||||||
|
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LOCAL(void)
|
||||||
|
adjust_quant(j_decompress_ptr srcinfo, jvirt_barray_ptr *src_coef_arrays,
|
||||||
|
j_decompress_ptr dropinfo, jvirt_barray_ptr *drop_coef_arrays,
|
||||||
|
boolean trim, j_compress_ptr dstinfo)
|
||||||
|
{
|
||||||
|
jpeg_component_info *compptr1, *compptr2;
|
||||||
|
JQUANT_TBL *qtblptr1, *qtblptr2, *qtblptr3;
|
||||||
|
int ci, k;
|
||||||
|
|
||||||
|
for (ci = 0; ci < dstinfo->num_components && ci < dropinfo->num_components;
|
||||||
|
ci++) {
|
||||||
|
compptr1 = srcinfo->comp_info + ci;
|
||||||
|
compptr2 = dropinfo->comp_info + ci;
|
||||||
|
qtblptr1 = compptr1->quant_table;
|
||||||
|
qtblptr2 = compptr2->quant_table;
|
||||||
|
for (k = 0; k < DCTSIZE2; k++) {
|
||||||
|
if (qtblptr1->quantval[k] != qtblptr2->quantval[k]) {
|
||||||
|
if (trim)
|
||||||
|
requant_comp(dropinfo, compptr2, drop_coef_arrays[ci], qtblptr1);
|
||||||
|
else {
|
||||||
|
qtblptr3 = dstinfo->quant_tbl_ptrs[compptr1->quant_tbl_no];
|
||||||
|
for (k = 0; k < DCTSIZE2; k++)
|
||||||
|
if (qtblptr1->quantval[k] != qtblptr2->quantval[k])
|
||||||
|
qtblptr3->quantval[k] =
|
||||||
|
largest_common_denominator(qtblptr1->quantval[k],
|
||||||
|
qtblptr2->quantval[k]);
|
||||||
|
dequant_comp(srcinfo, compptr1, src_coef_arrays[ci], qtblptr3);
|
||||||
|
dequant_comp(dropinfo, compptr2, drop_coef_arrays[ci], qtblptr3);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LOCAL(void)
|
||||||
|
do_drop(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
|
||||||
|
JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
|
||||||
|
jvirt_barray_ptr *src_coef_arrays,
|
||||||
|
j_decompress_ptr dropinfo, jvirt_barray_ptr *drop_coef_arrays,
|
||||||
|
JDIMENSION drop_width, JDIMENSION drop_height)
|
||||||
|
/* Drop (insert) the contents of another image into the source image. If the
|
||||||
|
* number of components in the drop image is smaller than the number of
|
||||||
|
* components in the destination image, then we fill in the remaining
|
||||||
|
* components with zero. This allows for dropping the contents of grayscale
|
||||||
|
* images into (arbitrarily sampled) color images.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
JDIMENSION comp_width, comp_height;
|
||||||
|
JDIMENSION blk_y, x_drop_blocks, y_drop_blocks;
|
||||||
|
int ci, offset_y;
|
||||||
|
JBLOCKARRAY src_buffer, dst_buffer;
|
||||||
|
jpeg_component_info *compptr;
|
||||||
|
|
||||||
|
for (ci = 0; ci < dstinfo->num_components; ci++) {
|
||||||
|
compptr = dstinfo->comp_info + ci;
|
||||||
|
comp_width = drop_width * compptr->h_samp_factor;
|
||||||
|
comp_height = drop_height * compptr->v_samp_factor;
|
||||||
|
x_drop_blocks = x_crop_offset * compptr->h_samp_factor;
|
||||||
|
y_drop_blocks = y_crop_offset * compptr->v_samp_factor;
|
||||||
|
for (blk_y = 0; blk_y < comp_height; blk_y += compptr->v_samp_factor) {
|
||||||
|
dst_buffer = (*srcinfo->mem->access_virt_barray)
|
||||||
|
((j_common_ptr)srcinfo, src_coef_arrays[ci], blk_y + y_drop_blocks,
|
||||||
|
(JDIMENSION)compptr->v_samp_factor, TRUE);
|
||||||
|
if (ci < dropinfo->num_components) {
|
||||||
|
src_buffer = (*dropinfo->mem->access_virt_barray)
|
||||||
|
((j_common_ptr)dropinfo, drop_coef_arrays[ci], blk_y,
|
||||||
|
(JDIMENSION)compptr->v_samp_factor, FALSE);
|
||||||
|
for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
|
||||||
|
jcopy_block_row(src_buffer[offset_y],
|
||||||
|
dst_buffer[offset_y] + x_drop_blocks, comp_width);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
|
||||||
|
MEMZERO(dst_buffer[offset_y] + x_drop_blocks,
|
||||||
|
comp_width * sizeof(JBLOCK));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
LOCAL(void)
|
LOCAL(void)
|
||||||
do_crop(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
|
do_crop(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
|
||||||
JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
|
JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
|
||||||
@@ -113,13 +296,422 @@ do_crop(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
|
|||||||
((j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y,
|
((j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y,
|
||||||
(JDIMENSION)compptr->v_samp_factor, TRUE);
|
(JDIMENSION)compptr->v_samp_factor, TRUE);
|
||||||
src_buffer = (*srcinfo->mem->access_virt_barray)
|
src_buffer = (*srcinfo->mem->access_virt_barray)
|
||||||
((j_common_ptr)srcinfo, src_coef_arrays[ci],
|
((j_common_ptr)srcinfo, src_coef_arrays[ci], dst_blk_y + y_crop_blocks,
|
||||||
dst_blk_y + y_crop_blocks,
|
|
||||||
(JDIMENSION)compptr->v_samp_factor, FALSE);
|
(JDIMENSION)compptr->v_samp_factor, FALSE);
|
||||||
for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
|
for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
|
||||||
jcopy_block_row(src_buffer[offset_y] + x_crop_blocks,
|
jcopy_block_row(src_buffer[offset_y] + x_crop_blocks,
|
||||||
dst_buffer[offset_y],
|
dst_buffer[offset_y], compptr->width_in_blocks);
|
||||||
compptr->width_in_blocks);
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LOCAL(void)
|
||||||
|
do_crop_ext_zero(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
|
||||||
|
JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
|
||||||
|
jvirt_barray_ptr *src_coef_arrays,
|
||||||
|
jvirt_barray_ptr *dst_coef_arrays)
|
||||||
|
/* Crop. This is only used when no rotate/flip is requested with the crop.
|
||||||
|
* Extension: If the destination size is larger than the source, we fill in the
|
||||||
|
* expanded region with zero (neutral gray). Note that we also have to zero
|
||||||
|
* partial iMCUs at the right and bottom edge of the source image area in this
|
||||||
|
* case.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height;
|
||||||
|
JDIMENSION dst_blk_y, x_crop_blocks, y_crop_blocks;
|
||||||
|
int ci, offset_y;
|
||||||
|
JBLOCKARRAY src_buffer, dst_buffer;
|
||||||
|
jpeg_component_info *compptr;
|
||||||
|
|
||||||
|
MCU_cols = srcinfo->output_width /
|
||||||
|
(dstinfo->max_h_samp_factor * dstinfo_min_DCT_h_scaled_size);
|
||||||
|
MCU_rows = srcinfo->output_height /
|
||||||
|
(dstinfo->max_v_samp_factor * dstinfo_min_DCT_v_scaled_size);
|
||||||
|
|
||||||
|
for (ci = 0; ci < dstinfo->num_components; ci++) {
|
||||||
|
compptr = dstinfo->comp_info + ci;
|
||||||
|
comp_width = MCU_cols * compptr->h_samp_factor;
|
||||||
|
comp_height = MCU_rows * compptr->v_samp_factor;
|
||||||
|
x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
|
||||||
|
y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
|
||||||
|
for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
|
||||||
|
dst_blk_y += compptr->v_samp_factor) {
|
||||||
|
dst_buffer = (*srcinfo->mem->access_virt_barray)
|
||||||
|
((j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y,
|
||||||
|
(JDIMENSION)compptr->v_samp_factor, TRUE);
|
||||||
|
if (dstinfo->_jpeg_height > srcinfo->output_height) {
|
||||||
|
if (dst_blk_y < y_crop_blocks ||
|
||||||
|
dst_blk_y >= y_crop_blocks + comp_height) {
|
||||||
|
for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
|
||||||
|
MEMZERO(dst_buffer[offset_y],
|
||||||
|
compptr->width_in_blocks * sizeof(JBLOCK));
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
src_buffer = (*srcinfo->mem->access_virt_barray)
|
||||||
|
((j_common_ptr)srcinfo, src_coef_arrays[ci],
|
||||||
|
dst_blk_y - y_crop_blocks, (JDIMENSION)compptr->v_samp_factor,
|
||||||
|
FALSE);
|
||||||
|
} else {
|
||||||
|
src_buffer = (*srcinfo->mem->access_virt_barray)
|
||||||
|
((j_common_ptr)srcinfo, src_coef_arrays[ci],
|
||||||
|
dst_blk_y + y_crop_blocks, (JDIMENSION)compptr->v_samp_factor,
|
||||||
|
FALSE);
|
||||||
|
}
|
||||||
|
for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
|
||||||
|
if (dstinfo->_jpeg_width > srcinfo->output_width) {
|
||||||
|
if (x_crop_blocks > 0) {
|
||||||
|
MEMZERO(dst_buffer[offset_y], x_crop_blocks * sizeof(JBLOCK));
|
||||||
|
}
|
||||||
|
jcopy_block_row(src_buffer[offset_y],
|
||||||
|
dst_buffer[offset_y] + x_crop_blocks, comp_width);
|
||||||
|
if (compptr->width_in_blocks > x_crop_blocks + comp_width) {
|
||||||
|
MEMZERO(dst_buffer[offset_y] + x_crop_blocks + comp_width,
|
||||||
|
(compptr->width_in_blocks - x_crop_blocks - comp_width) *
|
||||||
|
sizeof(JBLOCK));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
jcopy_block_row(src_buffer[offset_y] + x_crop_blocks,
|
||||||
|
dst_buffer[offset_y], compptr->width_in_blocks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LOCAL(void)
|
||||||
|
do_crop_ext_flat(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
|
||||||
|
JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
|
||||||
|
jvirt_barray_ptr *src_coef_arrays,
|
||||||
|
jvirt_barray_ptr *dst_coef_arrays)
|
||||||
|
/* Crop. This is only used when no rotate/flip is requested with the crop.
|
||||||
|
* Extension: The destination width is larger than the source, and we fill in
|
||||||
|
* the expanded region with the DC coefficient of the adjacent block. Note
|
||||||
|
* that we also have to fill partial iMCUs at the right and bottom edge of the
|
||||||
|
* source image area in this case.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height;
|
||||||
|
JDIMENSION dst_blk_x, dst_blk_y, x_crop_blocks, y_crop_blocks;
|
||||||
|
int ci, offset_y;
|
||||||
|
JCOEF dc;
|
||||||
|
JBLOCKARRAY src_buffer, dst_buffer;
|
||||||
|
jpeg_component_info *compptr;
|
||||||
|
|
||||||
|
MCU_cols = srcinfo->output_width /
|
||||||
|
(dstinfo->max_h_samp_factor * dstinfo_min_DCT_h_scaled_size);
|
||||||
|
MCU_rows = srcinfo->output_height /
|
||||||
|
(dstinfo->max_v_samp_factor * dstinfo_min_DCT_v_scaled_size);
|
||||||
|
|
||||||
|
for (ci = 0; ci < dstinfo->num_components; ci++) {
|
||||||
|
compptr = dstinfo->comp_info + ci;
|
||||||
|
comp_width = MCU_cols * compptr->h_samp_factor;
|
||||||
|
comp_height = MCU_rows * compptr->v_samp_factor;
|
||||||
|
x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
|
||||||
|
y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
|
||||||
|
for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
|
||||||
|
dst_blk_y += compptr->v_samp_factor) {
|
||||||
|
dst_buffer = (*srcinfo->mem->access_virt_barray)
|
||||||
|
((j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y,
|
||||||
|
(JDIMENSION)compptr->v_samp_factor, TRUE);
|
||||||
|
if (dstinfo->_jpeg_height > srcinfo->output_height) {
|
||||||
|
if (dst_blk_y < y_crop_blocks ||
|
||||||
|
dst_blk_y >= y_crop_blocks + comp_height) {
|
||||||
|
for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
|
||||||
|
MEMZERO(dst_buffer[offset_y],
|
||||||
|
compptr->width_in_blocks * sizeof(JBLOCK));
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
src_buffer = (*srcinfo->mem->access_virt_barray)
|
||||||
|
((j_common_ptr)srcinfo, src_coef_arrays[ci],
|
||||||
|
dst_blk_y - y_crop_blocks, (JDIMENSION)compptr->v_samp_factor,
|
||||||
|
FALSE);
|
||||||
|
} else {
|
||||||
|
src_buffer = (*srcinfo->mem->access_virt_barray)
|
||||||
|
((j_common_ptr)srcinfo, src_coef_arrays[ci],
|
||||||
|
dst_blk_y + y_crop_blocks, (JDIMENSION)compptr->v_samp_factor,
|
||||||
|
FALSE);
|
||||||
|
}
|
||||||
|
for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
|
||||||
|
if (x_crop_blocks > 0) {
|
||||||
|
MEMZERO(dst_buffer[offset_y], x_crop_blocks * sizeof(JBLOCK));
|
||||||
|
dc = src_buffer[offset_y][0][0];
|
||||||
|
for (dst_blk_x = 0; dst_blk_x < x_crop_blocks; dst_blk_x++) {
|
||||||
|
dst_buffer[offset_y][dst_blk_x][0] = dc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
jcopy_block_row(src_buffer[offset_y],
|
||||||
|
dst_buffer[offset_y] + x_crop_blocks, comp_width);
|
||||||
|
if (compptr->width_in_blocks > x_crop_blocks + comp_width) {
|
||||||
|
MEMZERO(dst_buffer[offset_y] + x_crop_blocks + comp_width,
|
||||||
|
(compptr->width_in_blocks - x_crop_blocks - comp_width) *
|
||||||
|
sizeof(JBLOCK));
|
||||||
|
dc = src_buffer[offset_y][comp_width - 1][0];
|
||||||
|
for (dst_blk_x = x_crop_blocks + comp_width;
|
||||||
|
dst_blk_x < compptr->width_in_blocks; dst_blk_x++) {
|
||||||
|
dst_buffer[offset_y][dst_blk_x][0] = dc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LOCAL(void)
|
||||||
|
do_crop_ext_reflect(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
|
||||||
|
JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
|
||||||
|
jvirt_barray_ptr *src_coef_arrays,
|
||||||
|
jvirt_barray_ptr *dst_coef_arrays)
|
||||||
|
/* Crop. This is only used when no rotate/flip is requested with the crop.
|
||||||
|
* Extension: The destination width is larger than the source, and we fill in
|
||||||
|
* the expanded region with repeated reflections of the source image. Note
|
||||||
|
* that we also have to fill partial iMCUs at the right and bottom edge of the
|
||||||
|
* source image area in this case.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, src_blk_x;
|
||||||
|
JDIMENSION dst_blk_x, dst_blk_y, x_crop_blocks, y_crop_blocks;
|
||||||
|
int ci, k, offset_y;
|
||||||
|
JBLOCKARRAY src_buffer, dst_buffer;
|
||||||
|
JBLOCKROW src_row_ptr, dst_row_ptr;
|
||||||
|
JCOEFPTR src_ptr, dst_ptr;
|
||||||
|
jpeg_component_info *compptr;
|
||||||
|
|
||||||
|
MCU_cols = srcinfo->output_width /
|
||||||
|
(dstinfo->max_h_samp_factor * dstinfo_min_DCT_h_scaled_size);
|
||||||
|
MCU_rows = srcinfo->output_height /
|
||||||
|
(dstinfo->max_v_samp_factor * dstinfo_min_DCT_v_scaled_size);
|
||||||
|
|
||||||
|
for (ci = 0; ci < dstinfo->num_components; ci++) {
|
||||||
|
compptr = dstinfo->comp_info + ci;
|
||||||
|
comp_width = MCU_cols * compptr->h_samp_factor;
|
||||||
|
comp_height = MCU_rows * compptr->v_samp_factor;
|
||||||
|
x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
|
||||||
|
y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
|
||||||
|
for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
|
||||||
|
dst_blk_y += compptr->v_samp_factor) {
|
||||||
|
dst_buffer = (*srcinfo->mem->access_virt_barray)
|
||||||
|
((j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y,
|
||||||
|
(JDIMENSION)compptr->v_samp_factor, TRUE);
|
||||||
|
if (dstinfo->_jpeg_height > srcinfo->output_height) {
|
||||||
|
if (dst_blk_y < y_crop_blocks ||
|
||||||
|
dst_blk_y >= y_crop_blocks + comp_height) {
|
||||||
|
for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
|
||||||
|
MEMZERO(dst_buffer[offset_y],
|
||||||
|
compptr->width_in_blocks * sizeof(JBLOCK));
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
src_buffer = (*srcinfo->mem->access_virt_barray)
|
||||||
|
((j_common_ptr)srcinfo, src_coef_arrays[ci],
|
||||||
|
dst_blk_y - y_crop_blocks, (JDIMENSION)compptr->v_samp_factor,
|
||||||
|
FALSE);
|
||||||
|
} else {
|
||||||
|
src_buffer = (*srcinfo->mem->access_virt_barray)
|
||||||
|
((j_common_ptr)srcinfo, src_coef_arrays[ci],
|
||||||
|
dst_blk_y + y_crop_blocks, (JDIMENSION)compptr->v_samp_factor,
|
||||||
|
FALSE);
|
||||||
|
}
|
||||||
|
for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
|
||||||
|
/* Copy source region */
|
||||||
|
jcopy_block_row(src_buffer[offset_y],
|
||||||
|
dst_buffer[offset_y] + x_crop_blocks, comp_width);
|
||||||
|
if (x_crop_blocks > 0) {
|
||||||
|
/* Reflect to left */
|
||||||
|
dst_row_ptr = dst_buffer[offset_y] + x_crop_blocks;
|
||||||
|
for (dst_blk_x = x_crop_blocks; dst_blk_x > 0;) {
|
||||||
|
src_row_ptr = dst_row_ptr; /* (re)set axis of reflection */
|
||||||
|
for (src_blk_x = comp_width; src_blk_x > 0 && dst_blk_x > 0;
|
||||||
|
src_blk_x--, dst_blk_x--) {
|
||||||
|
dst_ptr = *(--dst_row_ptr); /* destination goes left */
|
||||||
|
src_ptr = *src_row_ptr++; /* source goes right */
|
||||||
|
/* This unrolled loop doesn't need to know which row it's on. */
|
||||||
|
for (k = 0; k < DCTSIZE2; k += 2) {
|
||||||
|
*dst_ptr++ = *src_ptr++; /* copy even column */
|
||||||
|
*dst_ptr++ = -(*src_ptr++); /* copy odd column with sign
|
||||||
|
change */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (compptr->width_in_blocks > x_crop_blocks + comp_width) {
|
||||||
|
/* Reflect to right */
|
||||||
|
dst_row_ptr = dst_buffer[offset_y] + x_crop_blocks + comp_width;
|
||||||
|
for (dst_blk_x = compptr->width_in_blocks - x_crop_blocks - comp_width;
|
||||||
|
dst_blk_x > 0;) {
|
||||||
|
src_row_ptr = dst_row_ptr; /* (re)set axis of reflection */
|
||||||
|
for (src_blk_x = comp_width; src_blk_x > 0 && dst_blk_x > 0;
|
||||||
|
src_blk_x--, dst_blk_x--) {
|
||||||
|
dst_ptr = *dst_row_ptr++; /* destination goes right */
|
||||||
|
src_ptr = *(--src_row_ptr); /* source goes left */
|
||||||
|
/* This unrolled loop doesn't need to know which row it's on. */
|
||||||
|
for (k = 0; k < DCTSIZE2; k += 2) {
|
||||||
|
*dst_ptr++ = *src_ptr++; /* copy even column */
|
||||||
|
*dst_ptr++ = -(*src_ptr++); /* copy odd column with sign
|
||||||
|
change */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LOCAL(void)
|
||||||
|
do_wipe(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
|
||||||
|
JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
|
||||||
|
jvirt_barray_ptr *src_coef_arrays,
|
||||||
|
JDIMENSION drop_width, JDIMENSION drop_height)
|
||||||
|
/* Wipe - discard image contents of specified region and fill with zero
|
||||||
|
* (neutral gray)
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
JDIMENSION x_wipe_blocks, wipe_width;
|
||||||
|
JDIMENSION y_wipe_blocks, wipe_bottom;
|
||||||
|
int ci, offset_y;
|
||||||
|
JBLOCKARRAY buffer;
|
||||||
|
jpeg_component_info *compptr;
|
||||||
|
|
||||||
|
for (ci = 0; ci < dstinfo->num_components; ci++) {
|
||||||
|
compptr = dstinfo->comp_info + ci;
|
||||||
|
x_wipe_blocks = x_crop_offset * compptr->h_samp_factor;
|
||||||
|
wipe_width = drop_width * compptr->h_samp_factor;
|
||||||
|
y_wipe_blocks = y_crop_offset * compptr->v_samp_factor;
|
||||||
|
wipe_bottom = drop_height * compptr->v_samp_factor + y_wipe_blocks;
|
||||||
|
for (; y_wipe_blocks < wipe_bottom;
|
||||||
|
y_wipe_blocks += compptr->v_samp_factor) {
|
||||||
|
buffer = (*srcinfo->mem->access_virt_barray)
|
||||||
|
((j_common_ptr)srcinfo, src_coef_arrays[ci], y_wipe_blocks,
|
||||||
|
(JDIMENSION)compptr->v_samp_factor, TRUE);
|
||||||
|
for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
|
||||||
|
MEMZERO(buffer[offset_y] + x_wipe_blocks, wipe_width * sizeof(JBLOCK));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LOCAL(void)
|
||||||
|
do_flatten(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
|
||||||
|
JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
|
||||||
|
jvirt_barray_ptr *src_coef_arrays,
|
||||||
|
JDIMENSION drop_width, JDIMENSION drop_height)
|
||||||
|
/* Flatten - discard image contents of specified region, similarly to wipe,
|
||||||
|
* but fill with the average of adjacent blocks instead of zero.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
JDIMENSION x_wipe_blocks, wipe_width, wipe_right;
|
||||||
|
JDIMENSION y_wipe_blocks, wipe_bottom, blk_x;
|
||||||
|
int ci, offset_y, dc_left_value, dc_right_value, average;
|
||||||
|
JBLOCKARRAY buffer;
|
||||||
|
jpeg_component_info *compptr;
|
||||||
|
|
||||||
|
for (ci = 0; ci < dstinfo->num_components; ci++) {
|
||||||
|
compptr = dstinfo->comp_info + ci;
|
||||||
|
x_wipe_blocks = x_crop_offset * compptr->h_samp_factor;
|
||||||
|
wipe_width = drop_width * compptr->h_samp_factor;
|
||||||
|
wipe_right = wipe_width + x_wipe_blocks;
|
||||||
|
y_wipe_blocks = y_crop_offset * compptr->v_samp_factor;
|
||||||
|
wipe_bottom = drop_height * compptr->v_samp_factor + y_wipe_blocks;
|
||||||
|
for (; y_wipe_blocks < wipe_bottom;
|
||||||
|
y_wipe_blocks += compptr->v_samp_factor) {
|
||||||
|
buffer = (*srcinfo->mem->access_virt_barray)
|
||||||
|
((j_common_ptr)srcinfo, src_coef_arrays[ci], y_wipe_blocks,
|
||||||
|
(JDIMENSION)compptr->v_samp_factor, TRUE);
|
||||||
|
for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
|
||||||
|
MEMZERO(buffer[offset_y] + x_wipe_blocks, wipe_width * sizeof(JBLOCK));
|
||||||
|
if (x_wipe_blocks > 0) {
|
||||||
|
dc_left_value = buffer[offset_y][x_wipe_blocks - 1][0];
|
||||||
|
if (wipe_right < compptr->width_in_blocks) {
|
||||||
|
dc_right_value = buffer[offset_y][wipe_right][0];
|
||||||
|
average = (dc_left_value + dc_right_value) >> 1;
|
||||||
|
} else {
|
||||||
|
average = dc_left_value;
|
||||||
|
}
|
||||||
|
} else if (wipe_right < compptr->width_in_blocks) {
|
||||||
|
average = buffer[offset_y][wipe_right][0];
|
||||||
|
} else continue;
|
||||||
|
for (blk_x = x_wipe_blocks; blk_x < wipe_right; blk_x++) {
|
||||||
|
buffer[offset_y][blk_x][0] = (JCOEF)average;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LOCAL(void)
|
||||||
|
do_reflect(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
|
||||||
|
JDIMENSION x_crop_offset, jvirt_barray_ptr *src_coef_arrays,
|
||||||
|
JDIMENSION drop_width, JDIMENSION drop_height)
|
||||||
|
/* Reflect - discard image contents of specified region, similarly to wipe,
|
||||||
|
* but fill with repeated reflections of the outside region instead of zero.
|
||||||
|
* NB: y_crop_offset is assumed to be zero.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
JDIMENSION x_wipe_blocks, wipe_width;
|
||||||
|
JDIMENSION y_wipe_blocks, wipe_bottom;
|
||||||
|
JDIMENSION src_blk_x, dst_blk_x;
|
||||||
|
int ci, k, offset_y;
|
||||||
|
JBLOCKARRAY buffer;
|
||||||
|
JBLOCKROW src_row_ptr, dst_row_ptr;
|
||||||
|
JCOEFPTR src_ptr, dst_ptr;
|
||||||
|
jpeg_component_info *compptr;
|
||||||
|
|
||||||
|
for (ci = 0; ci < dstinfo->num_components; ci++) {
|
||||||
|
compptr = dstinfo->comp_info + ci;
|
||||||
|
x_wipe_blocks = x_crop_offset * compptr->h_samp_factor;
|
||||||
|
wipe_width = drop_width * compptr->h_samp_factor;
|
||||||
|
wipe_bottom = drop_height * compptr->v_samp_factor;
|
||||||
|
for (y_wipe_blocks = 0; y_wipe_blocks < wipe_bottom;
|
||||||
|
y_wipe_blocks += compptr->v_samp_factor) {
|
||||||
|
buffer = (*srcinfo->mem->access_virt_barray)
|
||||||
|
((j_common_ptr)srcinfo, src_coef_arrays[ci], y_wipe_blocks,
|
||||||
|
(JDIMENSION)compptr->v_samp_factor, TRUE);
|
||||||
|
for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
|
||||||
|
if (x_wipe_blocks > 0) {
|
||||||
|
/* Reflect from left */
|
||||||
|
dst_row_ptr = buffer[offset_y] + x_wipe_blocks;
|
||||||
|
for (dst_blk_x = wipe_width; dst_blk_x > 0;) {
|
||||||
|
src_row_ptr = dst_row_ptr; /* (re)set axis of reflection */
|
||||||
|
for (src_blk_x = x_wipe_blocks;
|
||||||
|
src_blk_x > 0 && dst_blk_x > 0; src_blk_x--, dst_blk_x--) {
|
||||||
|
dst_ptr = *dst_row_ptr++; /* destination goes right */
|
||||||
|
src_ptr = *(--src_row_ptr); /* source goes left */
|
||||||
|
/* this unrolled loop doesn't need to know which row it's on... */
|
||||||
|
for (k = 0; k < DCTSIZE2; k += 2) {
|
||||||
|
*dst_ptr++ = *src_ptr++; /* copy even column */
|
||||||
|
*dst_ptr++ = -(*src_ptr++); /* copy odd column with sign change */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (compptr->width_in_blocks > x_wipe_blocks + wipe_width) {
|
||||||
|
/* Reflect from right */
|
||||||
|
dst_row_ptr = buffer[offset_y] + x_wipe_blocks + wipe_width;
|
||||||
|
for (dst_blk_x = wipe_width; dst_blk_x > 0;) {
|
||||||
|
src_row_ptr = dst_row_ptr; /* (re)set axis of reflection */
|
||||||
|
src_blk_x = compptr->width_in_blocks - x_wipe_blocks - wipe_width;
|
||||||
|
for (; src_blk_x > 0 && dst_blk_x > 0; src_blk_x--, dst_blk_x--) {
|
||||||
|
dst_ptr = *(--dst_row_ptr); /* destination goes left */
|
||||||
|
src_ptr = *src_row_ptr++; /* source goes right */
|
||||||
|
/* this unrolled loop doesn't need to know which row it's on... */
|
||||||
|
for (k = 0; k < DCTSIZE2; k += 2) {
|
||||||
|
*dst_ptr++ = *src_ptr++; /* copy even column */
|
||||||
|
*dst_ptr++ = -(*src_ptr++); /* copy odd column with sign change */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
MEMZERO(buffer[offset_y] + x_wipe_blocks,
|
||||||
|
wipe_width * sizeof(JBLOCK));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -239,7 +831,7 @@ do_flip_h(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
|
|||||||
/* this unrolled loop doesn't need to know which row it's on... */
|
/* this unrolled loop doesn't need to know which row it's on... */
|
||||||
for (k = 0; k < DCTSIZE2; k += 2) {
|
for (k = 0; k < DCTSIZE2; k += 2) {
|
||||||
*dst_ptr++ = *src_ptr++; /* copy even column */
|
*dst_ptr++ = *src_ptr++; /* copy even column */
|
||||||
*dst_ptr++ = - *src_ptr++; /* copy odd column with sign change */
|
*dst_ptr++ = -(*src_ptr++); /* copy odd column with sign change */
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Copy last partial block(s) verbatim */
|
/* Copy last partial block(s) verbatim */
|
||||||
@@ -318,7 +910,7 @@ do_flip_v(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
|
|||||||
*dst_ptr++ = *src_ptr++;
|
*dst_ptr++ = *src_ptr++;
|
||||||
/* copy odd row with sign change */
|
/* copy odd row with sign change */
|
||||||
for (j = 0; j < DCTSIZE; j++)
|
for (j = 0; j < DCTSIZE; j++)
|
||||||
*dst_ptr++ = - *src_ptr++;
|
*dst_ptr++ = -(*src_ptr++);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -599,11 +1191,11 @@ do_rot_180(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
|
|||||||
/* For even row, negate every odd column. */
|
/* For even row, negate every odd column. */
|
||||||
for (j = 0; j < DCTSIZE; j += 2) {
|
for (j = 0; j < DCTSIZE; j += 2) {
|
||||||
*dst_ptr++ = *src_ptr++;
|
*dst_ptr++ = *src_ptr++;
|
||||||
*dst_ptr++ = - *src_ptr++;
|
*dst_ptr++ = -(*src_ptr++);
|
||||||
}
|
}
|
||||||
/* For odd row, negate every even column. */
|
/* For odd row, negate every even column. */
|
||||||
for (j = 0; j < DCTSIZE; j += 2) {
|
for (j = 0; j < DCTSIZE; j += 2) {
|
||||||
*dst_ptr++ = - *src_ptr++;
|
*dst_ptr++ = -(*src_ptr++);
|
||||||
*dst_ptr++ = *src_ptr++;
|
*dst_ptr++ = *src_ptr++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -614,7 +1206,7 @@ do_rot_180(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
|
|||||||
for (j = 0; j < DCTSIZE; j++)
|
for (j = 0; j < DCTSIZE; j++)
|
||||||
*dst_ptr++ = *src_ptr++;
|
*dst_ptr++ = *src_ptr++;
|
||||||
for (j = 0; j < DCTSIZE; j++)
|
for (j = 0; j < DCTSIZE; j++)
|
||||||
*dst_ptr++ = - *src_ptr++;
|
*dst_ptr++ = -(*src_ptr++);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -630,7 +1222,7 @@ do_rot_180(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
|
|||||||
src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1];
|
src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1];
|
||||||
for (i = 0; i < DCTSIZE2; i += 2) {
|
for (i = 0; i < DCTSIZE2; i += 2) {
|
||||||
*dst_ptr++ = *src_ptr++;
|
*dst_ptr++ = *src_ptr++;
|
||||||
*dst_ptr++ = - *src_ptr++;
|
*dst_ptr++ = -(*src_ptr++);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Any remaining right-edge blocks are only copied. */
|
/* Any remaining right-edge blocks are only copied. */
|
||||||
@@ -786,7 +1378,7 @@ jt_read_integer(const char **strptr, JDIMENSION *result)
|
|||||||
* The routine returns TRUE if the spec string is valid, FALSE if not.
|
* The routine returns TRUE if the spec string is valid, FALSE if not.
|
||||||
*
|
*
|
||||||
* The crop spec string should have the format
|
* The crop spec string should have the format
|
||||||
* <width>[f]x<height>[f]{+-}<xoffset>{+-}<yoffset>
|
* <width>[{fr}]x<height>[{fr}]{+-}<xoffset>{+-}<yoffset>
|
||||||
* where width, height, xoffset, and yoffset are unsigned integers.
|
* where width, height, xoffset, and yoffset are unsigned integers.
|
||||||
* Each of the elements can be omitted to indicate a default value.
|
* Each of the elements can be omitted to indicate a default value.
|
||||||
* (A weakness of this style is that it is not possible to omit xoffset
|
* (A weakness of this style is that it is not possible to omit xoffset
|
||||||
@@ -811,6 +1403,9 @@ jtransform_parse_crop_spec(jpeg_transform_info *info, const char *spec)
|
|||||||
if (*spec == 'f' || *spec == 'F') {
|
if (*spec == 'f' || *spec == 'F') {
|
||||||
spec++;
|
spec++;
|
||||||
info->crop_width_set = JCROP_FORCE;
|
info->crop_width_set = JCROP_FORCE;
|
||||||
|
} else if (*spec == 'r' || *spec == 'R') {
|
||||||
|
spec++;
|
||||||
|
info->crop_width_set = JCROP_REFLECT;
|
||||||
} else
|
} else
|
||||||
info->crop_width_set = JCROP_POS;
|
info->crop_width_set = JCROP_POS;
|
||||||
}
|
}
|
||||||
@@ -822,6 +1417,9 @@ jtransform_parse_crop_spec(jpeg_transform_info *info, const char *spec)
|
|||||||
if (*spec == 'f' || *spec == 'F') {
|
if (*spec == 'f' || *spec == 'F') {
|
||||||
spec++;
|
spec++;
|
||||||
info->crop_height_set = JCROP_FORCE;
|
info->crop_height_set = JCROP_FORCE;
|
||||||
|
} else if (*spec == 'r' || *spec == 'R') {
|
||||||
|
spec++;
|
||||||
|
info->crop_height_set = JCROP_REFLECT;
|
||||||
} else
|
} else
|
||||||
info->crop_height_set = JCROP_POS;
|
info->crop_height_set = JCROP_POS;
|
||||||
}
|
}
|
||||||
@@ -896,10 +1494,10 @@ jtransform_request_workspace(j_decompress_ptr srcinfo,
|
|||||||
jvirt_barray_ptr *coef_arrays;
|
jvirt_barray_ptr *coef_arrays;
|
||||||
boolean need_workspace, transpose_it;
|
boolean need_workspace, transpose_it;
|
||||||
jpeg_component_info *compptr;
|
jpeg_component_info *compptr;
|
||||||
JDIMENSION xoffset, yoffset;
|
JDIMENSION xoffset, yoffset, dtemp;
|
||||||
JDIMENSION width_in_iMCUs, height_in_iMCUs;
|
JDIMENSION width_in_iMCUs, height_in_iMCUs;
|
||||||
JDIMENSION width_in_blocks, height_in_blocks;
|
JDIMENSION width_in_blocks, height_in_blocks;
|
||||||
int ci, h_samp_factor, v_samp_factor;
|
int itemp, ci, h_samp_factor, v_samp_factor;
|
||||||
|
|
||||||
/* Determine number of components in output image */
|
/* Determine number of components in output image */
|
||||||
if (info->force_grayscale &&
|
if (info->force_grayscale &&
|
||||||
@@ -985,39 +1583,129 @@ jtransform_request_workspace(j_decompress_ptr srcinfo,
|
|||||||
info->crop_xoffset = 0; /* default to +0 */
|
info->crop_xoffset = 0; /* default to +0 */
|
||||||
if (info->crop_yoffset_set == JCROP_UNSET)
|
if (info->crop_yoffset_set == JCROP_UNSET)
|
||||||
info->crop_yoffset = 0; /* default to +0 */
|
info->crop_yoffset = 0; /* default to +0 */
|
||||||
if (info->crop_xoffset >= info->output_width ||
|
if (info->crop_width_set == JCROP_UNSET) {
|
||||||
info->crop_yoffset >= info->output_height)
|
if (info->crop_xoffset >= info->output_width)
|
||||||
ERREXIT(srcinfo, JERR_BAD_CROP_SPEC);
|
ERREXIT(srcinfo, JERR_BAD_CROP_SPEC);
|
||||||
if (info->crop_width_set == JCROP_UNSET)
|
|
||||||
info->crop_width = info->output_width - info->crop_xoffset;
|
info->crop_width = info->output_width - info->crop_xoffset;
|
||||||
if (info->crop_height_set == JCROP_UNSET)
|
} else {
|
||||||
|
/* Check for crop extension */
|
||||||
|
if (info->crop_width > info->output_width) {
|
||||||
|
/* Crop extension does not work when transforming! */
|
||||||
|
if (info->transform != JXFORM_NONE ||
|
||||||
|
info->crop_xoffset >= info->crop_width ||
|
||||||
|
info->crop_xoffset > info->crop_width - info->output_width)
|
||||||
|
ERREXIT(srcinfo, JERR_BAD_CROP_SPEC);
|
||||||
|
} else {
|
||||||
|
if (info->crop_xoffset >= info->output_width ||
|
||||||
|
info->crop_width <= 0 ||
|
||||||
|
info->crop_xoffset > info->output_width - info->crop_width)
|
||||||
|
ERREXIT(srcinfo, JERR_BAD_CROP_SPEC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (info->crop_height_set == JCROP_UNSET) {
|
||||||
|
if (info->crop_yoffset >= info->output_height)
|
||||||
|
ERREXIT(srcinfo, JERR_BAD_CROP_SPEC);
|
||||||
info->crop_height = info->output_height - info->crop_yoffset;
|
info->crop_height = info->output_height - info->crop_yoffset;
|
||||||
/* Ensure parameters are valid */
|
} else {
|
||||||
if (info->crop_width <= 0 || info->crop_width > info->output_width ||
|
/* Check for crop extension */
|
||||||
info->crop_height <= 0 || info->crop_height > info->output_height ||
|
if (info->crop_height > info->output_height) {
|
||||||
info->crop_xoffset > info->output_width - info->crop_width ||
|
/* Crop extension does not work when transforming! */
|
||||||
info->crop_yoffset > info->output_height - info->crop_height)
|
if (info->transform != JXFORM_NONE ||
|
||||||
ERREXIT(srcinfo, JERR_BAD_CROP_SPEC);
|
info->crop_yoffset >= info->crop_height ||
|
||||||
|
info->crop_yoffset > info->crop_height - info->output_height)
|
||||||
|
ERREXIT(srcinfo, JERR_BAD_CROP_SPEC);
|
||||||
|
} else {
|
||||||
|
if (info->crop_yoffset >= info->output_height ||
|
||||||
|
info->crop_height <= 0 ||
|
||||||
|
info->crop_yoffset > info->output_height - info->crop_height)
|
||||||
|
ERREXIT(srcinfo, JERR_BAD_CROP_SPEC);
|
||||||
|
}
|
||||||
|
}
|
||||||
/* Convert negative crop offsets into regular offsets */
|
/* Convert negative crop offsets into regular offsets */
|
||||||
if (info->crop_xoffset_set == JCROP_NEG)
|
if (info->crop_xoffset_set != JCROP_NEG)
|
||||||
xoffset = info->output_width - info->crop_width - info->crop_xoffset;
|
|
||||||
else
|
|
||||||
xoffset = info->crop_xoffset;
|
xoffset = info->crop_xoffset;
|
||||||
if (info->crop_yoffset_set == JCROP_NEG)
|
else if (info->crop_width > info->output_width) /* crop extension */
|
||||||
yoffset = info->output_height - info->crop_height - info->crop_yoffset;
|
xoffset = info->crop_width - info->output_width - info->crop_xoffset;
|
||||||
else
|
else
|
||||||
|
xoffset = info->output_width - info->crop_width - info->crop_xoffset;
|
||||||
|
if (info->crop_yoffset_set != JCROP_NEG)
|
||||||
yoffset = info->crop_yoffset;
|
yoffset = info->crop_yoffset;
|
||||||
|
else if (info->crop_height > info->output_height) /* crop extension */
|
||||||
|
yoffset = info->crop_height - info->output_height - info->crop_yoffset;
|
||||||
|
else
|
||||||
|
yoffset = info->output_height - info->crop_height - info->crop_yoffset;
|
||||||
/* Now adjust so that upper left corner falls at an iMCU boundary */
|
/* Now adjust so that upper left corner falls at an iMCU boundary */
|
||||||
if (info->crop_width_set == JCROP_FORCE)
|
switch (info->transform) {
|
||||||
info->output_width = info->crop_width;
|
case JXFORM_DROP:
|
||||||
else
|
/* Ensure the effective drop region will not exceed the requested */
|
||||||
info->output_width =
|
itemp = info->iMCU_sample_width;
|
||||||
info->crop_width + (xoffset % info->iMCU_sample_width);
|
dtemp = itemp - 1 - ((xoffset + itemp - 1) % itemp);
|
||||||
if (info->crop_height_set == JCROP_FORCE)
|
xoffset += dtemp;
|
||||||
info->output_height = info->crop_height;
|
if (info->crop_width <= dtemp)
|
||||||
else
|
info->drop_width = 0;
|
||||||
info->output_height =
|
else if (xoffset + info->crop_width - dtemp == info->output_width)
|
||||||
info->crop_height + (yoffset % info->iMCU_sample_height);
|
/* Matching right edge: include partial iMCU */
|
||||||
|
info->drop_width = (info->crop_width - dtemp + itemp - 1) / itemp;
|
||||||
|
else
|
||||||
|
info->drop_width = (info->crop_width - dtemp) / itemp;
|
||||||
|
itemp = info->iMCU_sample_height;
|
||||||
|
dtemp = itemp - 1 - ((yoffset + itemp - 1) % itemp);
|
||||||
|
yoffset += dtemp;
|
||||||
|
if (info->crop_height <= dtemp)
|
||||||
|
info->drop_height = 0;
|
||||||
|
else if (yoffset + info->crop_height - dtemp == info->output_height)
|
||||||
|
/* Matching bottom edge: include partial iMCU */
|
||||||
|
info->drop_height = (info->crop_height - dtemp + itemp - 1) / itemp;
|
||||||
|
else
|
||||||
|
info->drop_height = (info->crop_height - dtemp) / itemp;
|
||||||
|
/* Check if sampling factors match for dropping */
|
||||||
|
if (info->drop_width != 0 && info->drop_height != 0)
|
||||||
|
for (ci = 0; ci < info->num_components &&
|
||||||
|
ci < info->drop_ptr->num_components; ci++) {
|
||||||
|
if (info->drop_ptr->comp_info[ci].h_samp_factor *
|
||||||
|
srcinfo->max_h_samp_factor !=
|
||||||
|
srcinfo->comp_info[ci].h_samp_factor *
|
||||||
|
info->drop_ptr->max_h_samp_factor)
|
||||||
|
ERREXIT6(srcinfo, JERR_BAD_DROP_SAMPLING, ci,
|
||||||
|
info->drop_ptr->comp_info[ci].h_samp_factor,
|
||||||
|
info->drop_ptr->max_h_samp_factor,
|
||||||
|
srcinfo->comp_info[ci].h_samp_factor,
|
||||||
|
srcinfo->max_h_samp_factor, 'h');
|
||||||
|
if (info->drop_ptr->comp_info[ci].v_samp_factor *
|
||||||
|
srcinfo->max_v_samp_factor !=
|
||||||
|
srcinfo->comp_info[ci].v_samp_factor *
|
||||||
|
info->drop_ptr->max_v_samp_factor)
|
||||||
|
ERREXIT6(srcinfo, JERR_BAD_DROP_SAMPLING, ci,
|
||||||
|
info->drop_ptr->comp_info[ci].v_samp_factor,
|
||||||
|
info->drop_ptr->max_v_samp_factor,
|
||||||
|
srcinfo->comp_info[ci].v_samp_factor,
|
||||||
|
srcinfo->max_v_samp_factor, 'v');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case JXFORM_WIPE:
|
||||||
|
/* Ensure the effective wipe region will cover the requested */
|
||||||
|
info->drop_width = (JDIMENSION)jdiv_round_up
|
||||||
|
((long)(info->crop_width + (xoffset % info->iMCU_sample_width)),
|
||||||
|
(long)info->iMCU_sample_width);
|
||||||
|
info->drop_height = (JDIMENSION)jdiv_round_up
|
||||||
|
((long)(info->crop_height + (yoffset % info->iMCU_sample_height)),
|
||||||
|
(long)info->iMCU_sample_height);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* Ensure the effective crop region will cover the requested */
|
||||||
|
if (info->crop_width_set == JCROP_FORCE ||
|
||||||
|
info->crop_width > info->output_width)
|
||||||
|
info->output_width = info->crop_width;
|
||||||
|
else
|
||||||
|
info->output_width =
|
||||||
|
info->crop_width + (xoffset % info->iMCU_sample_width);
|
||||||
|
if (info->crop_height_set == JCROP_FORCE ||
|
||||||
|
info->crop_height > info->output_height)
|
||||||
|
info->output_height = info->crop_height;
|
||||||
|
else
|
||||||
|
info->output_height =
|
||||||
|
info->crop_height + (yoffset % info->iMCU_sample_height);
|
||||||
|
}
|
||||||
/* Save x/y offsets measured in iMCUs */
|
/* Save x/y offsets measured in iMCUs */
|
||||||
info->x_crop_offset = xoffset / info->iMCU_sample_width;
|
info->x_crop_offset = xoffset / info->iMCU_sample_width;
|
||||||
info->y_crop_offset = yoffset / info->iMCU_sample_height;
|
info->y_crop_offset = yoffset / info->iMCU_sample_height;
|
||||||
@@ -1033,7 +1721,9 @@ jtransform_request_workspace(j_decompress_ptr srcinfo,
|
|||||||
transpose_it = FALSE;
|
transpose_it = FALSE;
|
||||||
switch (info->transform) {
|
switch (info->transform) {
|
||||||
case JXFORM_NONE:
|
case JXFORM_NONE:
|
||||||
if (info->x_crop_offset != 0 || info->y_crop_offset != 0)
|
if (info->x_crop_offset != 0 || info->y_crop_offset != 0 ||
|
||||||
|
info->output_width > srcinfo->output_width ||
|
||||||
|
info->output_height > srcinfo->output_height)
|
||||||
need_workspace = TRUE;
|
need_workspace = TRUE;
|
||||||
/* No workspace needed if neither cropping nor transforming */
|
/* No workspace needed if neither cropping nor transforming */
|
||||||
break;
|
break;
|
||||||
@@ -1087,6 +1777,10 @@ jtransform_request_workspace(j_decompress_ptr srcinfo,
|
|||||||
need_workspace = TRUE;
|
need_workspace = TRUE;
|
||||||
transpose_it = TRUE;
|
transpose_it = TRUE;
|
||||||
break;
|
break;
|
||||||
|
case JXFORM_WIPE:
|
||||||
|
break;
|
||||||
|
case JXFORM_DROP:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allocate workspace if needed.
|
/* Allocate workspace if needed.
|
||||||
@@ -1387,7 +2081,7 @@ jtransform_adjust_parameters(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
|
|||||||
dstinfo->jpeg_height = info->output_height;
|
dstinfo->jpeg_height = info->output_height;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Transpose destination image parameters */
|
/* Transpose destination image parameters, adjust quantization */
|
||||||
switch (info->transform) {
|
switch (info->transform) {
|
||||||
case JXFORM_TRANSPOSE:
|
case JXFORM_TRANSPOSE:
|
||||||
case JXFORM_TRANSVERSE:
|
case JXFORM_TRANSVERSE:
|
||||||
@@ -1399,6 +2093,12 @@ jtransform_adjust_parameters(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
|
|||||||
#endif
|
#endif
|
||||||
transpose_critical_parameters(dstinfo);
|
transpose_critical_parameters(dstinfo);
|
||||||
break;
|
break;
|
||||||
|
case JXFORM_DROP:
|
||||||
|
if (info->drop_width != 0 && info->drop_height != 0)
|
||||||
|
adjust_quant(srcinfo, src_coef_arrays,
|
||||||
|
info->drop_ptr, info->drop_coef_arrays,
|
||||||
|
info->trim, dstinfo);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
#if JPEG_LIB_VERSION < 80
|
#if JPEG_LIB_VERSION < 80
|
||||||
dstinfo->image_width = info->output_width;
|
dstinfo->image_width = info->output_width;
|
||||||
@@ -1465,7 +2165,23 @@ jtransform_execute_transform(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
|
|||||||
*/
|
*/
|
||||||
switch (info->transform) {
|
switch (info->transform) {
|
||||||
case JXFORM_NONE:
|
case JXFORM_NONE:
|
||||||
if (info->x_crop_offset != 0 || info->y_crop_offset != 0)
|
if (info->output_width > srcinfo->output_width ||
|
||||||
|
info->output_height > srcinfo->output_height) {
|
||||||
|
if (info->output_width > srcinfo->output_width &&
|
||||||
|
info->crop_width_set == JCROP_REFLECT)
|
||||||
|
do_crop_ext_reflect(srcinfo, dstinfo,
|
||||||
|
info->x_crop_offset, info->y_crop_offset,
|
||||||
|
src_coef_arrays, dst_coef_arrays);
|
||||||
|
else if (info->output_width > srcinfo->output_width &&
|
||||||
|
info->crop_width_set == JCROP_FORCE)
|
||||||
|
do_crop_ext_flat(srcinfo, dstinfo,
|
||||||
|
info->x_crop_offset, info->y_crop_offset,
|
||||||
|
src_coef_arrays, dst_coef_arrays);
|
||||||
|
else
|
||||||
|
do_crop_ext_zero(srcinfo, dstinfo,
|
||||||
|
info->x_crop_offset, info->y_crop_offset,
|
||||||
|
src_coef_arrays, dst_coef_arrays);
|
||||||
|
} else if (info->x_crop_offset != 0 || info->y_crop_offset != 0)
|
||||||
do_crop(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
|
do_crop(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
|
||||||
src_coef_arrays, dst_coef_arrays);
|
src_coef_arrays, dst_coef_arrays);
|
||||||
break;
|
break;
|
||||||
@@ -1501,6 +2217,30 @@ jtransform_execute_transform(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
|
|||||||
do_rot_270(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
|
do_rot_270(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
|
||||||
src_coef_arrays, dst_coef_arrays);
|
src_coef_arrays, dst_coef_arrays);
|
||||||
break;
|
break;
|
||||||
|
case JXFORM_WIPE:
|
||||||
|
if (info->crop_width_set == JCROP_REFLECT &&
|
||||||
|
info->y_crop_offset == 0 && info->drop_height ==
|
||||||
|
(JDIMENSION)jdiv_round_up
|
||||||
|
((long)info->output_height, (long)info->iMCU_sample_height) &&
|
||||||
|
(info->x_crop_offset == 0 ||
|
||||||
|
info->x_crop_offset + info->drop_width ==
|
||||||
|
(JDIMENSION)jdiv_round_up
|
||||||
|
((long)info->output_width, (long)info->iMCU_sample_width)))
|
||||||
|
do_reflect(srcinfo, dstinfo, info->x_crop_offset,
|
||||||
|
src_coef_arrays, info->drop_width, info->drop_height);
|
||||||
|
else if (info->crop_width_set == JCROP_FORCE)
|
||||||
|
do_flatten(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
|
||||||
|
src_coef_arrays, info->drop_width, info->drop_height);
|
||||||
|
else
|
||||||
|
do_wipe(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
|
||||||
|
src_coef_arrays, info->drop_width, info->drop_height);
|
||||||
|
break;
|
||||||
|
case JXFORM_DROP:
|
||||||
|
if (info->drop_width != 0 && info->drop_height != 0)
|
||||||
|
do_drop(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
|
||||||
|
src_coef_arrays, info->drop_ptr, info->drop_coef_arrays,
|
||||||
|
info->drop_width, info->drop_height);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
34
transupp.h
34
transupp.h
@@ -2,7 +2,7 @@
|
|||||||
* transupp.h
|
* transupp.h
|
||||||
*
|
*
|
||||||
* This file was part of the Independent JPEG Group's software:
|
* This file was part of the Independent JPEG Group's software:
|
||||||
* Copyright (C) 1997-2011, Thomas G. Lane, Guido Vollbeding.
|
* Copyright (C) 1997-2019, Thomas G. Lane, Guido Vollbeding.
|
||||||
* libjpeg-turbo Modifications:
|
* libjpeg-turbo Modifications:
|
||||||
* Copyright (C) 2017, D. R. Commander.
|
* Copyright (C) 2017, D. R. Commander.
|
||||||
* For conditions of distribution and use, see the accompanying README.ijg
|
* For conditions of distribution and use, see the accompanying README.ijg
|
||||||
@@ -62,6 +62,17 @@
|
|||||||
* output image covers at least the requested region, but may cover more.)
|
* output image covers at least the requested region, but may cover more.)
|
||||||
* The adjustment of the region dimensions may be optionally disabled.
|
* The adjustment of the region dimensions may be optionally disabled.
|
||||||
*
|
*
|
||||||
|
* A complementary lossless wipe option is provided to discard (gray out) data
|
||||||
|
* inside a given image region while losslessly preserving what is outside.
|
||||||
|
* A lossless drop option is also provided, which allows another JPEG image to
|
||||||
|
* be inserted ("dropped") into the source image data at a given position,
|
||||||
|
* replacing the existing image data at that position. Both the source image
|
||||||
|
* and the drop image must have the same subsampling level. It is best if they
|
||||||
|
* also have the same quantization (quality.) Otherwise, the quantization of
|
||||||
|
* the output image will be adapted to accommodate the higher of the source
|
||||||
|
* image quality and the drop image quality. The trim option can be used with
|
||||||
|
* the drop option to requantize the drop image to match the source image.
|
||||||
|
*
|
||||||
* We also provide a lossless-resize option, which is kind of a lossless-crop
|
* We also provide a lossless-resize option, which is kind of a lossless-crop
|
||||||
* operation in the DCT coefficient block domain - it discards higher-order
|
* operation in the DCT coefficient block domain - it discards higher-order
|
||||||
* coefficients and losslessly preserves lower-order coefficients of a
|
* coefficients and losslessly preserves lower-order coefficients of a
|
||||||
@@ -92,20 +103,23 @@ typedef enum {
|
|||||||
JXFORM_TRANSVERSE, /* transpose across UR-to-LL axis */
|
JXFORM_TRANSVERSE, /* transpose across UR-to-LL axis */
|
||||||
JXFORM_ROT_90, /* 90-degree clockwise rotation */
|
JXFORM_ROT_90, /* 90-degree clockwise rotation */
|
||||||
JXFORM_ROT_180, /* 180-degree rotation */
|
JXFORM_ROT_180, /* 180-degree rotation */
|
||||||
JXFORM_ROT_270 /* 270-degree clockwise (or 90 ccw) */
|
JXFORM_ROT_270, /* 270-degree clockwise (or 90 ccw) */
|
||||||
|
JXFORM_WIPE, /* wipe */
|
||||||
|
JXFORM_DROP /* drop */
|
||||||
} JXFORM_CODE;
|
} JXFORM_CODE;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Codes for crop parameters, which can individually be unspecified,
|
* Codes for crop parameters, which can individually be unspecified,
|
||||||
* positive or negative for xoffset or yoffset,
|
* positive or negative for xoffset or yoffset,
|
||||||
* positive or forced for width or height.
|
* positive or force or reflect for width or height.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
JCROP_UNSET,
|
JCROP_UNSET,
|
||||||
JCROP_POS,
|
JCROP_POS,
|
||||||
JCROP_NEG,
|
JCROP_NEG,
|
||||||
JCROP_FORCE
|
JCROP_FORCE,
|
||||||
|
JCROP_REFLECT
|
||||||
} JCROP_CODE;
|
} JCROP_CODE;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -120,7 +134,7 @@ typedef struct {
|
|||||||
boolean perfect; /* if TRUE, fail if partial MCUs are requested */
|
boolean perfect; /* if TRUE, fail if partial MCUs are requested */
|
||||||
boolean trim; /* if TRUE, trim partial MCUs as needed */
|
boolean trim; /* if TRUE, trim partial MCUs as needed */
|
||||||
boolean force_grayscale; /* if TRUE, convert color image to grayscale */
|
boolean force_grayscale; /* if TRUE, convert color image to grayscale */
|
||||||
boolean crop; /* if TRUE, crop source image */
|
boolean crop; /* if TRUE, crop or wipe source image, or drop */
|
||||||
boolean slow_hflip; /* For best performance, the JXFORM_FLIP_H transform
|
boolean slow_hflip; /* For best performance, the JXFORM_FLIP_H transform
|
||||||
normally modifies the source coefficients in place.
|
normally modifies the source coefficients in place.
|
||||||
Setting this to TRUE will instead use a slower,
|
Setting this to TRUE will instead use a slower,
|
||||||
@@ -133,14 +147,18 @@ typedef struct {
|
|||||||
* These can be filled in by jtransform_parse_crop_spec().
|
* These can be filled in by jtransform_parse_crop_spec().
|
||||||
*/
|
*/
|
||||||
JDIMENSION crop_width; /* Width of selected region */
|
JDIMENSION crop_width; /* Width of selected region */
|
||||||
JCROP_CODE crop_width_set; /* (forced disables adjustment) */
|
JCROP_CODE crop_width_set; /* (force-disables adjustment) */
|
||||||
JDIMENSION crop_height; /* Height of selected region */
|
JDIMENSION crop_height; /* Height of selected region */
|
||||||
JCROP_CODE crop_height_set; /* (forced disables adjustment) */
|
JCROP_CODE crop_height_set; /* (force-disables adjustment) */
|
||||||
JDIMENSION crop_xoffset; /* X offset of selected region */
|
JDIMENSION crop_xoffset; /* X offset of selected region */
|
||||||
JCROP_CODE crop_xoffset_set; /* (negative measures from right edge) */
|
JCROP_CODE crop_xoffset_set; /* (negative measures from right edge) */
|
||||||
JDIMENSION crop_yoffset; /* Y offset of selected region */
|
JDIMENSION crop_yoffset; /* Y offset of selected region */
|
||||||
JCROP_CODE crop_yoffset_set; /* (negative measures from bottom edge) */
|
JCROP_CODE crop_yoffset_set; /* (negative measures from bottom edge) */
|
||||||
|
|
||||||
|
/* Drop parameters: set by caller for drop request */
|
||||||
|
j_decompress_ptr drop_ptr;
|
||||||
|
jvirt_barray_ptr *drop_coef_arrays;
|
||||||
|
|
||||||
/* Internal workspace: caller should not touch these */
|
/* Internal workspace: caller should not touch these */
|
||||||
int num_components; /* # of components in workspace */
|
int num_components; /* # of components in workspace */
|
||||||
jvirt_barray_ptr *workspace_coef_arrays; /* workspace for transformations */
|
jvirt_barray_ptr *workspace_coef_arrays; /* workspace for transformations */
|
||||||
@@ -148,6 +166,8 @@ typedef struct {
|
|||||||
JDIMENSION output_height;
|
JDIMENSION output_height;
|
||||||
JDIMENSION x_crop_offset; /* destination crop offsets measured in iMCUs */
|
JDIMENSION x_crop_offset; /* destination crop offsets measured in iMCUs */
|
||||||
JDIMENSION y_crop_offset;
|
JDIMENSION y_crop_offset;
|
||||||
|
JDIMENSION drop_width; /* drop/wipe dimensions measured in iMCUs */
|
||||||
|
JDIMENSION drop_height;
|
||||||
int iMCU_sample_width; /* destination iMCU size */
|
int iMCU_sample_width; /* destination iMCU size */
|
||||||
int iMCU_sample_height;
|
int iMCU_sample_height;
|
||||||
} jpeg_transform_info;
|
} jpeg_transform_info;
|
||||||
|
|||||||
75
usage.txt
75
usage.txt
@@ -50,9 +50,9 @@ or
|
|||||||
This syntax works on all systems, so it is useful for scripts.
|
This syntax works on all systems, so it is useful for scripts.
|
||||||
|
|
||||||
The currently supported image file formats are: PPM (PBMPLUS color format),
|
The currently supported image file formats are: PPM (PBMPLUS color format),
|
||||||
PGM (PBMPLUS grayscale format), BMP, and Targa. cjpeg recognizes the input
|
PGM (PBMPLUS grayscale format), BMP, GIF, and Targa. cjpeg recognizes the
|
||||||
image format automatically, with the exception of some Targa files. You have
|
input image format automatically, with the exception of some Targa files. You
|
||||||
to tell djpeg which format to generate.
|
have to tell djpeg which format to generate.
|
||||||
|
|
||||||
JPEG files are in the defacto standard JFIF file format. There are other,
|
JPEG files are in the defacto standard JFIF file format. There are other,
|
||||||
less widely used JPEG-based file formats, but we don't support them.
|
less widely used JPEG-based file formats, but we don't support them.
|
||||||
@@ -74,10 +74,10 @@ The basic command line switches for cjpeg are:
|
|||||||
|
|
||||||
-grayscale Create monochrome JPEG file from color input.
|
-grayscale Create monochrome JPEG file from color input.
|
||||||
Be sure to use this switch when compressing a grayscale
|
Be sure to use this switch when compressing a grayscale
|
||||||
BMP file, because cjpeg isn't bright enough to notice
|
BMP or GIF file, because cjpeg isn't bright enough to
|
||||||
whether a BMP file uses only shades of gray. By
|
notice whether a BMP or GIF file uses only shades of
|
||||||
saying -grayscale, you'll get a smaller JPEG file that
|
gray. By saying -grayscale, you'll get a smaller JPEG
|
||||||
takes less time to process.
|
file that takes less time to process.
|
||||||
|
|
||||||
-rgb Create RGB JPEG file.
|
-rgb Create RGB JPEG file.
|
||||||
Using this switch suppresses the conversion from RGB
|
Using this switch suppresses the conversion from RGB
|
||||||
@@ -288,10 +288,17 @@ The basic command line switches for djpeg are:
|
|||||||
is specified, or if the JPEG file is grayscale;
|
is specified, or if the JPEG file is grayscale;
|
||||||
otherwise, 24-bit full-color format is emitted.
|
otherwise, 24-bit full-color format is emitted.
|
||||||
|
|
||||||
-gif Select GIF output format. Since GIF does not support
|
-gif Select GIF output format (LZW-compressed). Since GIF
|
||||||
more than 256 colors, -colors 256 is assumed (unless
|
does not support more than 256 colors, -colors 256 is
|
||||||
you specify a smaller number of colors). If you
|
assumed (unless you specify a smaller number of
|
||||||
specify -fast, the default number of colors is 216.
|
colors). If you specify -fast, the default number of
|
||||||
|
colors is 216.
|
||||||
|
|
||||||
|
-gif0 Select GIF output format (uncompressed). Since GIF
|
||||||
|
does not support more than 256 colors, -colors 256 is
|
||||||
|
assumed (unless you specify a smaller number of
|
||||||
|
colors). If you specify -fast, the default number of
|
||||||
|
colors is 216.
|
||||||
|
|
||||||
-os2 Select BMP output format (OS/2 1.x flavor). 8-bit
|
-os2 Select BMP output format (OS/2 1.x flavor). 8-bit
|
||||||
colormapped format is emitted if -colors or -grayscale
|
colormapped format is emitted if -colors or -grayscale
|
||||||
@@ -400,11 +407,6 @@ quality settings to make very small JPEG files; the percentage improvement
|
|||||||
is often a lot more than it is on larger files. (At present, -optimize
|
is often a lot more than it is on larger files. (At present, -optimize
|
||||||
mode is always selected when generating progressive JPEG files.)
|
mode is always selected when generating progressive JPEG files.)
|
||||||
|
|
||||||
Support for GIF input files was removed in cjpeg v6b due to concerns over
|
|
||||||
the Unisys LZW patent. Although this patent expired in 2006, cjpeg still
|
|
||||||
lacks GIF support, for these historical reasons. (Conversion of GIF files to
|
|
||||||
JPEG is usually a bad idea anyway.)
|
|
||||||
|
|
||||||
|
|
||||||
HINTS FOR DJPEG
|
HINTS FOR DJPEG
|
||||||
|
|
||||||
@@ -419,10 +421,6 @@ When producing a color-quantized image, "-onepass -dither ordered" is fast but
|
|||||||
much lower quality than the default behavior. "-dither none" may give
|
much lower quality than the default behavior. "-dither none" may give
|
||||||
acceptable results in two-pass mode, but is seldom tolerable in one-pass mode.
|
acceptable results in two-pass mode, but is seldom tolerable in one-pass mode.
|
||||||
|
|
||||||
To avoid the Unisys LZW patent (now expired), djpeg produces uncompressed GIF
|
|
||||||
files. These are larger than they should be, but are readable by standard GIF
|
|
||||||
decoders.
|
|
||||||
|
|
||||||
|
|
||||||
HINTS FOR BOTH PROGRAMS
|
HINTS FOR BOTH PROGRAMS
|
||||||
|
|
||||||
@@ -529,6 +527,43 @@ The image can be losslessly cropped by giving the switch:
|
|||||||
-crop WxH+X+Y Crop to a rectangular region of width W and height H,
|
-crop WxH+X+Y Crop to a rectangular region of width W and height H,
|
||||||
starting at point X,Y.
|
starting at point X,Y.
|
||||||
|
|
||||||
|
If W or H is larger than the width/height of the input image, then the output
|
||||||
|
image is expanded in size, and the expanded region is filled in with zeros
|
||||||
|
(neutral gray). Attaching an 'f' character ("flatten") to the width number
|
||||||
|
will cause each block in the expanded region to be filled in with the DC
|
||||||
|
coefficient of the nearest block in the input image rather than grayed out.
|
||||||
|
Attaching an 'r' character ("reflect") to the width number will cause the
|
||||||
|
expanded region to be filled in with repeated reflections of the input image
|
||||||
|
rather than grayed out.
|
||||||
|
|
||||||
|
A complementary lossless wipe option is provided to discard (gray out) data
|
||||||
|
inside a given image region while losslessly preserving what is outside:
|
||||||
|
-wipe WxH+X+Y Wipe (gray out) a rectangular region of width W and
|
||||||
|
height H from the input image, starting at point X,Y.
|
||||||
|
|
||||||
|
Attaching an 'f' character ("flatten") to the width number will cause the
|
||||||
|
region to be filled with the average of adjacent blocks rather than grayed out.
|
||||||
|
If the wipe region and the region outside the wipe region, when adjusted to the
|
||||||
|
nearest iMCU boundary, form two horizontally adjacent rectangles, then
|
||||||
|
attaching an 'r' character ("reflect") to the width number will cause the wipe
|
||||||
|
region to be filled with repeated reflections of the outside region rather than
|
||||||
|
grayed out.
|
||||||
|
|
||||||
|
A lossless drop option is also provided, which allows another JPEG image to be
|
||||||
|
inserted ("dropped") into the input image data at a given position, replacing
|
||||||
|
the existing image data at that position:
|
||||||
|
-drop +X+Y filename Drop (insert) another image at point X,Y
|
||||||
|
|
||||||
|
Both the input image and the drop image must have the same subsampling level.
|
||||||
|
It is best if they also have the same quantization (quality.) Otherwise, the
|
||||||
|
quantization of the output image will be adapted to accommodate the higher of
|
||||||
|
the input image quality and the drop image quality. The trim option can be
|
||||||
|
used with the drop option to requantize the drop image to match the input
|
||||||
|
image. Note that a grayscale image can be dropped into a full-color image or
|
||||||
|
vice versa, as long as the full-color image has no vertical subsampling. If
|
||||||
|
the input image is grayscale and the drop image is full-color, then the
|
||||||
|
chrominance channels from the drop image will be discarded.
|
||||||
|
|
||||||
Other not-strictly-lossless transformation switches are:
|
Other not-strictly-lossless transformation switches are:
|
||||||
|
|
||||||
-grayscale Force grayscale output.
|
-grayscale Force grayscale output.
|
||||||
|
|||||||
315
wrgif.c
315
wrgif.c
@@ -3,6 +3,7 @@
|
|||||||
*
|
*
|
||||||
* This file was part of the Independent JPEG Group's software:
|
* This file was part of the Independent JPEG Group's software:
|
||||||
* Copyright (C) 1991-1997, Thomas G. Lane.
|
* Copyright (C) 1991-1997, Thomas G. Lane.
|
||||||
|
* Modified 2015-2019 by Guido Vollbeding.
|
||||||
* libjpeg-turbo Modifications:
|
* libjpeg-turbo Modifications:
|
||||||
* Copyright (C) 2015, 2017, D. R. Commander.
|
* Copyright (C) 2015, 2017, D. R. Commander.
|
||||||
* For conditions of distribution and use, see the accompanying README.ijg
|
* For conditions of distribution and use, see the accompanying README.ijg
|
||||||
@@ -10,12 +11,6 @@
|
|||||||
*
|
*
|
||||||
* This file contains routines to write output images in GIF format.
|
* This file contains routines to write output images in GIF format.
|
||||||
*
|
*
|
||||||
**************************************************************************
|
|
||||||
* NOTE: to avoid entanglements with Unisys' patent on LZW compression, *
|
|
||||||
* this code has been modified to output "uncompressed GIF" files. *
|
|
||||||
* There is no trace of the LZW algorithm in this file. *
|
|
||||||
**************************************************************************
|
|
||||||
*
|
|
||||||
* These routines may need modification for non-Unix environments or
|
* These routines may need modification for non-Unix environments or
|
||||||
* specialized applications. As they stand, they assume output to
|
* specialized applications. As they stand, they assume output to
|
||||||
* an ordinary stdio stream.
|
* an ordinary stdio stream.
|
||||||
@@ -33,11 +28,6 @@
|
|||||||
* copyright notice and this permission notice appear in supporting
|
* copyright notice and this permission notice appear in supporting
|
||||||
* documentation. This software is provided "as is" without express or
|
* documentation. This software is provided "as is" without express or
|
||||||
* implied warranty.
|
* implied warranty.
|
||||||
*
|
|
||||||
* We are also required to state that
|
|
||||||
* "The Graphics Interchange Format(c) is the Copyright property of
|
|
||||||
* CompuServe Incorporated. GIF(sm) is a Service Mark property of
|
|
||||||
* CompuServe Incorporated."
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
|
#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
|
||||||
@@ -45,6 +35,37 @@
|
|||||||
#ifdef GIF_SUPPORTED
|
#ifdef GIF_SUPPORTED
|
||||||
|
|
||||||
|
|
||||||
|
#define MAX_LZW_BITS 12 /* maximum LZW code size (4096 symbols) */
|
||||||
|
|
||||||
|
typedef INT16 code_int; /* must hold -1 .. 2**MAX_LZW_BITS */
|
||||||
|
|
||||||
|
#define LZW_TABLE_SIZE ((code_int)1 << MAX_LZW_BITS)
|
||||||
|
|
||||||
|
#define HSIZE 5003 /* hash table size for 80% occupancy */
|
||||||
|
|
||||||
|
typedef int hash_int; /* must hold -2*HSIZE..2*HSIZE */
|
||||||
|
|
||||||
|
#define MAXCODE(n_bits) (((code_int)1 << (n_bits)) - 1)
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The LZW hash table consists of two parallel arrays:
|
||||||
|
* hash_code[i] code of symbol in slot i, or 0 if empty slot
|
||||||
|
* hash_value[i] symbol's value; undefined if empty slot
|
||||||
|
* where slot values (i) range from 0 to HSIZE-1. The symbol value is
|
||||||
|
* its prefix symbol's code concatenated with its suffix character.
|
||||||
|
*
|
||||||
|
* Algorithm: use open addressing double hashing (no chaining) on the
|
||||||
|
* prefix code / suffix character combination. We do a variant of Knuth's
|
||||||
|
* algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
|
||||||
|
* secondary probe.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef int hash_entry; /* must hold (code_int << 8) | byte */
|
||||||
|
|
||||||
|
#define HASH_ENTRY(prefix, suffix) ((((hash_entry)(prefix)) << 8) | (suffix))
|
||||||
|
|
||||||
|
|
||||||
/* Private version of data destination object */
|
/* Private version of data destination object */
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -54,14 +75,24 @@ typedef struct {
|
|||||||
|
|
||||||
/* State for packing variable-width codes into a bitstream */
|
/* State for packing variable-width codes into a bitstream */
|
||||||
int n_bits; /* current number of bits/code */
|
int n_bits; /* current number of bits/code */
|
||||||
int maxcode; /* maximum code, given n_bits */
|
code_int maxcode; /* maximum code, given n_bits */
|
||||||
long cur_accum; /* holds bits not yet output */
|
int init_bits; /* initial n_bits ... restored after clear */
|
||||||
|
int cur_accum; /* holds bits not yet output */
|
||||||
int cur_bits; /* # of bits in cur_accum */
|
int cur_bits; /* # of bits in cur_accum */
|
||||||
|
|
||||||
|
/* LZW string construction */
|
||||||
|
code_int waiting_code; /* symbol not yet output; may be extendable */
|
||||||
|
boolean first_byte; /* if TRUE, waiting_code is not valid */
|
||||||
|
|
||||||
/* State for GIF code assignment */
|
/* State for GIF code assignment */
|
||||||
int ClearCode; /* clear code (doesn't change) */
|
code_int ClearCode; /* clear code (doesn't change) */
|
||||||
int EOFCode; /* EOF code (ditto) */
|
code_int EOFCode; /* EOF code (ditto) */
|
||||||
int code_counter; /* counts output symbols */
|
code_int free_code; /* LZW: first not-yet-used symbol code */
|
||||||
|
code_int code_counter; /* not LZW: counts output symbols */
|
||||||
|
|
||||||
|
/* LZW hash table */
|
||||||
|
code_int *hash_code; /* => hash table of symbol codes */
|
||||||
|
hash_entry *hash_value; /* => hash table of symbol values */
|
||||||
|
|
||||||
/* GIF data packet construction buffer */
|
/* GIF data packet construction buffer */
|
||||||
int bytesinpkt; /* # of bytes in current packet */
|
int bytesinpkt; /* # of bytes in current packet */
|
||||||
@@ -71,9 +102,6 @@ typedef struct {
|
|||||||
|
|
||||||
typedef gif_dest_struct *gif_dest_ptr;
|
typedef gif_dest_struct *gif_dest_ptr;
|
||||||
|
|
||||||
/* Largest value that will fit in N bits */
|
|
||||||
#define MAXCODE(n_bits) ((1 << (n_bits)) - 1)
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Routines to package finished data bytes into GIF data blocks.
|
* Routines to package finished data bytes into GIF data blocks.
|
||||||
@@ -105,7 +133,7 @@ flush_packet(gif_dest_ptr dinfo)
|
|||||||
/* Routine to convert variable-width codes into a byte stream */
|
/* Routine to convert variable-width codes into a byte stream */
|
||||||
|
|
||||||
LOCAL(void)
|
LOCAL(void)
|
||||||
output(gif_dest_ptr dinfo, int code)
|
output(gif_dest_ptr dinfo, code_int code)
|
||||||
/* Emit a code of n_bits bits */
|
/* Emit a code of n_bits bits */
|
||||||
/* Uses cur_accum and cur_bits to reblock into 8-bit bytes */
|
/* Uses cur_accum and cur_bits to reblock into 8-bit bytes */
|
||||||
{
|
{
|
||||||
@@ -117,74 +145,76 @@ output(gif_dest_ptr dinfo, int code)
|
|||||||
dinfo->cur_accum >>= 8;
|
dinfo->cur_accum >>= 8;
|
||||||
dinfo->cur_bits -= 8;
|
dinfo->cur_bits -= 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the next entry is going to be too big for the code size,
|
||||||
|
* then increase it, if possible. We do this here to ensure
|
||||||
|
* that it's done in sync with the decoder's codesize increases.
|
||||||
|
*/
|
||||||
|
if (dinfo->free_code > dinfo->maxcode) {
|
||||||
|
dinfo->n_bits++;
|
||||||
|
if (dinfo->n_bits == MAX_LZW_BITS)
|
||||||
|
dinfo->maxcode = LZW_TABLE_SIZE; /* free_code will never exceed this */
|
||||||
|
else
|
||||||
|
dinfo->maxcode = MAXCODE(dinfo->n_bits);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* The pseudo-compression algorithm.
|
/* Compression initialization & termination */
|
||||||
*
|
|
||||||
* In this module we simply output each pixel value as a separate symbol;
|
|
||||||
* thus, no compression occurs. In fact, there is expansion of one bit per
|
LOCAL(void)
|
||||||
* pixel, because we use a symbol width one bit wider than the pixel width.
|
clear_hash(gif_dest_ptr dinfo)
|
||||||
*
|
/* Fill the hash table with empty entries */
|
||||||
* GIF ordinarily uses variable-width symbols, and the decoder will expect
|
{
|
||||||
* to ratchet up the symbol width after a fixed number of symbols.
|
/* It's sufficient to zero hash_code[] */
|
||||||
* To simplify the logic and keep the expansion penalty down, we emit a
|
MEMZERO(dinfo->hash_code, HSIZE * sizeof(code_int));
|
||||||
* GIF Clear code to reset the decoder just before the width would ratchet up.
|
}
|
||||||
* Thus, all the symbols in the output file will have the same bit width.
|
|
||||||
* Note that emitting the Clear codes at the right times is a mere matter of
|
|
||||||
* counting output symbols and is in no way dependent on the LZW patent.
|
LOCAL(void)
|
||||||
*
|
clear_block(gif_dest_ptr dinfo)
|
||||||
* With a small basic pixel width (low color count), Clear codes will be
|
/* Reset compressor and issue a Clear code */
|
||||||
* needed very frequently, causing the file to expand even more. So this
|
{
|
||||||
* simplistic approach wouldn't work too well on bilevel images, for example.
|
clear_hash(dinfo); /* delete all the symbols */
|
||||||
* But for output of JPEG conversions the pixel width will usually be 8 bits
|
dinfo->free_code = dinfo->ClearCode + 2;
|
||||||
* (129 to 256 colors), so the overhead added by Clear symbols is only about
|
output(dinfo, dinfo->ClearCode); /* inform decoder */
|
||||||
* one symbol in every 256.
|
dinfo->n_bits = dinfo->init_bits; /* reset code size */
|
||||||
*/
|
dinfo->maxcode = MAXCODE(dinfo->n_bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
LOCAL(void)
|
LOCAL(void)
|
||||||
compress_init(gif_dest_ptr dinfo, int i_bits)
|
compress_init(gif_dest_ptr dinfo, int i_bits)
|
||||||
/* Initialize pseudo-compressor */
|
/* Initialize compressor */
|
||||||
{
|
{
|
||||||
/* init all the state variables */
|
/* init all the state variables */
|
||||||
dinfo->n_bits = i_bits;
|
dinfo->n_bits = dinfo->init_bits = i_bits;
|
||||||
dinfo->maxcode = MAXCODE(dinfo->n_bits);
|
dinfo->maxcode = MAXCODE(dinfo->n_bits);
|
||||||
dinfo->ClearCode = (1 << (i_bits - 1));
|
dinfo->ClearCode = ((code_int) 1 << (i_bits - 1));
|
||||||
dinfo->EOFCode = dinfo->ClearCode + 1;
|
dinfo->EOFCode = dinfo->ClearCode + 1;
|
||||||
dinfo->code_counter = dinfo->ClearCode + 2;
|
dinfo->code_counter = dinfo->free_code = dinfo->ClearCode + 2;
|
||||||
|
dinfo->first_byte = TRUE; /* no waiting symbol yet */
|
||||||
/* init output buffering vars */
|
/* init output buffering vars */
|
||||||
dinfo->bytesinpkt = 0;
|
dinfo->bytesinpkt = 0;
|
||||||
dinfo->cur_accum = 0;
|
dinfo->cur_accum = 0;
|
||||||
dinfo->cur_bits = 0;
|
dinfo->cur_bits = 0;
|
||||||
|
/* clear hash table */
|
||||||
|
if (dinfo->hash_code != NULL)
|
||||||
|
clear_hash(dinfo);
|
||||||
/* GIF specifies an initial Clear code */
|
/* GIF specifies an initial Clear code */
|
||||||
output(dinfo, dinfo->ClearCode);
|
output(dinfo, dinfo->ClearCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LOCAL(void)
|
|
||||||
compress_pixel(gif_dest_ptr dinfo, int c)
|
|
||||||
/* Accept and "compress" one pixel value.
|
|
||||||
* The given value must be less than n_bits wide.
|
|
||||||
*/
|
|
||||||
{
|
|
||||||
/* Output the given pixel value as a symbol. */
|
|
||||||
output(dinfo, c);
|
|
||||||
/* Issue Clear codes often enough to keep the reader from ratcheting up
|
|
||||||
* its symbol size.
|
|
||||||
*/
|
|
||||||
if (dinfo->code_counter < dinfo->maxcode) {
|
|
||||||
dinfo->code_counter++;
|
|
||||||
} else {
|
|
||||||
output(dinfo, dinfo->ClearCode);
|
|
||||||
dinfo->code_counter = dinfo->ClearCode + 2; /* reset the counter */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
LOCAL(void)
|
LOCAL(void)
|
||||||
compress_term(gif_dest_ptr dinfo)
|
compress_term(gif_dest_ptr dinfo)
|
||||||
/* Clean up at end */
|
/* Clean up at end */
|
||||||
{
|
{
|
||||||
|
/* Flush out the buffered LZW code */
|
||||||
|
if (!dinfo->first_byte)
|
||||||
|
output(dinfo, dinfo->waiting_code);
|
||||||
/* Send an EOF code */
|
/* Send an EOF code */
|
||||||
output(dinfo, dinfo->EOFCode);
|
output(dinfo, dinfo->EOFCode);
|
||||||
/* Flush the bit-packing buffer */
|
/* Flush the bit-packing buffer */
|
||||||
@@ -221,7 +251,7 @@ put_3bytes(gif_dest_ptr dinfo, int val)
|
|||||||
LOCAL(void)
|
LOCAL(void)
|
||||||
emit_header(gif_dest_ptr dinfo, int num_colors, JSAMPARRAY colormap)
|
emit_header(gif_dest_ptr dinfo, int num_colors, JSAMPARRAY colormap)
|
||||||
/* Output the GIF file header, including color map */
|
/* Output the GIF file header, including color map */
|
||||||
/* If colormap==NULL, synthesize a grayscale colormap */
|
/* If colormap == NULL, synthesize a grayscale colormap */
|
||||||
{
|
{
|
||||||
int BitsPerPixel, ColorMapSize, InitCodeSize, FlagByte;
|
int BitsPerPixel, ColorMapSize, InitCodeSize, FlagByte;
|
||||||
int cshift = dinfo->cinfo->data_precision - 8;
|
int cshift = dinfo->cinfo->data_precision - 8;
|
||||||
@@ -278,7 +308,7 @@ emit_header(gif_dest_ptr dinfo, int num_colors, JSAMPARRAY colormap)
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* fill out the map to a power of 2 */
|
/* fill out the map to a power of 2 */
|
||||||
put_3bytes(dinfo, 0);
|
put_3bytes(dinfo, CENTERJSAMPLE >> cshift);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Write image separator and Image Descriptor */
|
/* Write image separator and Image Descriptor */
|
||||||
@@ -292,7 +322,7 @@ emit_header(gif_dest_ptr dinfo, int num_colors, JSAMPARRAY colormap)
|
|||||||
/* Write Initial Code Size byte */
|
/* Write Initial Code Size byte */
|
||||||
putc(InitCodeSize, dinfo->pub.output_file);
|
putc(InitCodeSize, dinfo->pub.output_file);
|
||||||
|
|
||||||
/* Initialize for "compression" of image data */
|
/* Initialize for compression of image data */
|
||||||
compress_init(dinfo, InitCodeSize + 1);
|
compress_init(dinfo, InitCodeSize + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -318,17 +348,139 @@ start_output_gif(j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
|
|||||||
* In this module rows_supplied will always be 1.
|
* In this module rows_supplied will always be 1.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The LZW algorithm proper
|
||||||
|
*/
|
||||||
|
|
||||||
METHODDEF(void)
|
METHODDEF(void)
|
||||||
put_pixel_rows(j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
|
put_LZW_pixel_rows(j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
|
||||||
JDIMENSION rows_supplied)
|
JDIMENSION rows_supplied)
|
||||||
{
|
{
|
||||||
gif_dest_ptr dest = (gif_dest_ptr)dinfo;
|
gif_dest_ptr dest = (gif_dest_ptr)dinfo;
|
||||||
register JSAMPROW ptr;
|
register JSAMPROW ptr;
|
||||||
register JDIMENSION col;
|
register JDIMENSION col;
|
||||||
|
code_int c;
|
||||||
|
register hash_int i;
|
||||||
|
register hash_int disp;
|
||||||
|
register hash_entry probe_value;
|
||||||
|
|
||||||
ptr = dest->pub.buffer[0];
|
ptr = dest->pub.buffer[0];
|
||||||
for (col = cinfo->output_width; col > 0; col--) {
|
for (col = cinfo->output_width; col > 0; col--) {
|
||||||
compress_pixel(dest, *ptr++);
|
/* Accept and compress one 8-bit byte */
|
||||||
|
c = (code_int)(*ptr++);
|
||||||
|
|
||||||
|
if (dest->first_byte) { /* need to initialize waiting_code */
|
||||||
|
dest->waiting_code = c;
|
||||||
|
dest->first_byte = FALSE;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Probe hash table to see if a symbol exists for
|
||||||
|
* waiting_code followed by c.
|
||||||
|
* If so, replace waiting_code by that symbol and continue.
|
||||||
|
*/
|
||||||
|
i = ((hash_int)c << (MAX_LZW_BITS - 8)) + dest->waiting_code;
|
||||||
|
/* i is less than twice 2**MAX_LZW_BITS, therefore less than twice HSIZE */
|
||||||
|
if (i >= HSIZE)
|
||||||
|
i -= HSIZE;
|
||||||
|
|
||||||
|
probe_value = HASH_ENTRY(dest->waiting_code, c);
|
||||||
|
|
||||||
|
if (dest->hash_code[i] == 0) {
|
||||||
|
/* hit empty slot; desired symbol not in table */
|
||||||
|
output(dest, dest->waiting_code);
|
||||||
|
if (dest->free_code < LZW_TABLE_SIZE) {
|
||||||
|
dest->hash_code[i] = dest->free_code++; /* add symbol to hashtable */
|
||||||
|
dest->hash_value[i] = probe_value;
|
||||||
|
} else
|
||||||
|
clear_block(dest);
|
||||||
|
dest->waiting_code = c;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (dest->hash_value[i] == probe_value) {
|
||||||
|
dest->waiting_code = dest->hash_code[i];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == 0) /* secondary hash (after G. Knott) */
|
||||||
|
disp = 1;
|
||||||
|
else
|
||||||
|
disp = HSIZE - i;
|
||||||
|
for (;;) {
|
||||||
|
i -= disp;
|
||||||
|
if (i < 0)
|
||||||
|
i += HSIZE;
|
||||||
|
if (dest->hash_code[i] == 0) {
|
||||||
|
/* hit empty slot; desired symbol not in table */
|
||||||
|
output(dest, dest->waiting_code);
|
||||||
|
if (dest->free_code < LZW_TABLE_SIZE) {
|
||||||
|
dest->hash_code[i] = dest->free_code++; /* add symbol to hashtable */
|
||||||
|
dest->hash_value[i] = probe_value;
|
||||||
|
} else
|
||||||
|
clear_block(dest);
|
||||||
|
dest->waiting_code = c;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (dest->hash_value[i] == probe_value) {
|
||||||
|
dest->waiting_code = dest->hash_code[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The pseudo-compression algorithm.
|
||||||
|
*
|
||||||
|
* In this version we simply output each pixel value as a separate symbol;
|
||||||
|
* thus, no compression occurs. In fact, there is expansion of one bit per
|
||||||
|
* pixel, because we use a symbol width one bit wider than the pixel width.
|
||||||
|
*
|
||||||
|
* GIF ordinarily uses variable-width symbols, and the decoder will expect
|
||||||
|
* to ratchet up the symbol width after a fixed number of symbols.
|
||||||
|
* To simplify the logic and keep the expansion penalty down, we emit a
|
||||||
|
* GIF Clear code to reset the decoder just before the width would ratchet up.
|
||||||
|
* Thus, all the symbols in the output file will have the same bit width.
|
||||||
|
* Note that emitting the Clear codes at the right times is a mere matter of
|
||||||
|
* counting output symbols and is in no way dependent on the LZW algorithm.
|
||||||
|
*
|
||||||
|
* With a small basic pixel width (low color count), Clear codes will be
|
||||||
|
* needed very frequently, causing the file to expand even more. So this
|
||||||
|
* simplistic approach wouldn't work too well on bilevel images, for example.
|
||||||
|
* But for output of JPEG conversions the pixel width will usually be 8 bits
|
||||||
|
* (129 to 256 colors), so the overhead added by Clear symbols is only about
|
||||||
|
* one symbol in every 256.
|
||||||
|
*/
|
||||||
|
|
||||||
|
METHODDEF(void)
|
||||||
|
put_raw_pixel_rows(j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
|
||||||
|
JDIMENSION rows_supplied)
|
||||||
|
{
|
||||||
|
gif_dest_ptr dest = (gif_dest_ptr)dinfo;
|
||||||
|
register JSAMPROW ptr;
|
||||||
|
register JDIMENSION col;
|
||||||
|
code_int c;
|
||||||
|
|
||||||
|
ptr = dest->pub.buffer[0];
|
||||||
|
for (col = cinfo->output_width; col > 0; col--) {
|
||||||
|
c = (code_int)(*ptr++);
|
||||||
|
/* Accept and output one pixel value.
|
||||||
|
* The given value must be less than n_bits wide.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Output the given pixel value as a symbol. */
|
||||||
|
output(dest, c);
|
||||||
|
/* Issue Clear codes often enough to keep the reader from ratcheting up
|
||||||
|
* its symbol size.
|
||||||
|
*/
|
||||||
|
if (dest->code_counter < dest->maxcode) {
|
||||||
|
dest->code_counter++;
|
||||||
|
} else {
|
||||||
|
output(dest, dest->ClearCode);
|
||||||
|
dest->code_counter = dest->ClearCode + 2; /* reset the counter */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -342,7 +494,7 @@ finish_output_gif(j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
|
|||||||
{
|
{
|
||||||
gif_dest_ptr dest = (gif_dest_ptr)dinfo;
|
gif_dest_ptr dest = (gif_dest_ptr)dinfo;
|
||||||
|
|
||||||
/* Flush "compression" mechanism */
|
/* Flush compression mechanism */
|
||||||
compress_term(dest);
|
compress_term(dest);
|
||||||
/* Write a zero-length data block to end the series */
|
/* Write a zero-length data block to end the series */
|
||||||
putc(0, dest->pub.output_file);
|
putc(0, dest->pub.output_file);
|
||||||
@@ -370,7 +522,7 @@ calc_buffer_dimensions_gif(j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
GLOBAL(djpeg_dest_ptr)
|
GLOBAL(djpeg_dest_ptr)
|
||||||
jinit_write_gif(j_decompress_ptr cinfo)
|
jinit_write_gif(j_decompress_ptr cinfo, boolean is_lzw)
|
||||||
{
|
{
|
||||||
gif_dest_ptr dest;
|
gif_dest_ptr dest;
|
||||||
|
|
||||||
@@ -380,7 +532,6 @@ jinit_write_gif(j_decompress_ptr cinfo)
|
|||||||
sizeof(gif_dest_struct));
|
sizeof(gif_dest_struct));
|
||||||
dest->cinfo = cinfo; /* make back link for subroutines */
|
dest->cinfo = cinfo; /* make back link for subroutines */
|
||||||
dest->pub.start_output = start_output_gif;
|
dest->pub.start_output = start_output_gif;
|
||||||
dest->pub.put_pixel_rows = put_pixel_rows;
|
|
||||||
dest->pub.finish_output = finish_output_gif;
|
dest->pub.finish_output = finish_output_gif;
|
||||||
dest->pub.calc_buffer_dimensions = calc_buffer_dimensions_gif;
|
dest->pub.calc_buffer_dimensions = calc_buffer_dimensions_gif;
|
||||||
|
|
||||||
@@ -407,6 +558,22 @@ jinit_write_gif(j_decompress_ptr cinfo)
|
|||||||
((j_common_ptr)cinfo, JPOOL_IMAGE, cinfo->output_width, (JDIMENSION)1);
|
((j_common_ptr)cinfo, JPOOL_IMAGE, cinfo->output_width, (JDIMENSION)1);
|
||||||
dest->pub.buffer_height = 1;
|
dest->pub.buffer_height = 1;
|
||||||
|
|
||||||
|
if (is_lzw) {
|
||||||
|
dest->pub.put_pixel_rows = put_LZW_pixel_rows;
|
||||||
|
/* Allocate space for hash table */
|
||||||
|
dest->hash_code = (code_int *)
|
||||||
|
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
|
||||||
|
HSIZE * sizeof(code_int));
|
||||||
|
dest->hash_value = (hash_entry *)
|
||||||
|
(*cinfo->mem->alloc_large) ((j_common_ptr)cinfo, JPOOL_IMAGE,
|
||||||
|
HSIZE * sizeof(hash_entry));
|
||||||
|
} else {
|
||||||
|
dest->pub.put_pixel_rows = put_raw_pixel_rows;
|
||||||
|
/* Mark tables unused */
|
||||||
|
dest->hash_code = NULL;
|
||||||
|
dest->hash_value = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
return (djpeg_dest_ptr)dest;
|
return (djpeg_dest_ptr)dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user