Skip to content

Commit

Permalink
Implement lossless crop feature from jpeg v7 and v8
Browse files Browse the repository at this point in the history
git-svn-id: svn+ssh://svn.code.sf.net/p/libjpeg-turbo/code/trunk@243 632fc199-4ca6-4c93-a231-07263d6284db
  • Loading branch information
dcommander committed Oct 10, 2010
2 parents c54275c + a4ecaac commit c04bd3c
Show file tree
Hide file tree
Showing 10 changed files with 1,153 additions and 312 deletions.
4 changes: 4 additions & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,8 @@ test: testclean all
cmp $(srcdir)/testimgp.jpg testoutp.jpg
./jpegtran -outfile testoutt.jpg testoutp.jpg
cmp $(srcdir)/testimgint.jpg testoutt.jpg
./jpegtran -crop 100x100+10+10 -transpose -perfect -outfile testoutcrop.jpg $(srcdir)/testorig.jpg
cmp $(srcdir)/testimgcrop.jpg testoutcrop.jpg

else

Expand All @@ -141,6 +143,8 @@ test: testclean all
cmp $(srcdir)/testimgp.jpg testoutp.jpg
./jpegtran -outfile testoutt.jpg testoutp.jpg
cmp $(srcdir)/testimgint.jpg testoutt.jpg
./jpegtran -crop 100x100+10+10 -transpose -perfect -outfile testoutcrop.jpg $(srcdir)/testorig.jpg
cmp $(srcdir)/testimgcrop.jpg testoutcrop.jpg

endif

Expand Down
10 changes: 6 additions & 4 deletions jcmarker.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
* jcmarker.c
*
* Copyright (C) 1991-1998, Thomas G. Lane.
* Copyright (C) 2010, D. R. Commander.
* This file is part of the Independent JPEG Group's software.
* For conditions of distribution and use, see the accompanying README file.
*
Expand All @@ -11,6 +12,7 @@
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
#include "jpegcomp.h"


typedef enum { /* JPEG marker codes */
Expand Down Expand Up @@ -285,13 +287,13 @@ emit_sof (j_compress_ptr cinfo, JPEG_MARKER code)
emit_2bytes(cinfo, 3 * cinfo->num_components + 2 + 5 + 1); /* length */

/* Make sure image isn't bigger than SOF field can handle */
if ((long) cinfo->image_height > 65535L ||
(long) cinfo->image_width > 65535L)
if ((long) cinfo->_jpeg_height > 65535L ||
(long) cinfo->_jpeg_width > 65535L)
ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) 65535);

emit_byte(cinfo, cinfo->data_precision);
emit_2bytes(cinfo, (int) cinfo->image_height);
emit_2bytes(cinfo, (int) cinfo->image_width);
emit_2bytes(cinfo, (int) cinfo->_jpeg_height);
emit_2bytes(cinfo, (int) cinfo->_jpeg_width);

emit_byte(cinfo, cinfo->num_components);

Expand Down
28 changes: 15 additions & 13 deletions jcmaster.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
#include "jpegcomp.h"


/* Private state */
Expand Down Expand Up @@ -65,7 +66,7 @@ jpeg_calc_jpeg_dimensions (j_compress_ptr cinfo)


LOCAL(void)
initial_setup (j_compress_ptr cinfo)
initial_setup (j_compress_ptr cinfo, boolean transcode_only)
/* Do computations that are needed before master selection phase */
{
int ci;
Expand All @@ -74,17 +75,18 @@ initial_setup (j_compress_ptr cinfo)
JDIMENSION jd_samplesperrow;

#if JPEG_LIB_VERSION >= 70
jpeg_calc_jpeg_dimensions(cinfo);
if (!transcode_only)
jpeg_calc_jpeg_dimensions(cinfo);
#endif

/* Sanity check on image dimensions */
if (cinfo->image_height <= 0 || cinfo->image_width <= 0
if (cinfo->_jpeg_height <= 0 || cinfo->_jpeg_width <= 0
|| cinfo->num_components <= 0 || cinfo->input_components <= 0)
ERREXIT(cinfo, JERR_EMPTY_IMAGE);

/* Make sure image isn't bigger than I can handle */
if ((long) cinfo->image_height > (long) JPEG_MAX_DIMENSION ||
(long) cinfo->image_width > (long) JPEG_MAX_DIMENSION)
if ((long) cinfo->_jpeg_height > (long) JPEG_MAX_DIMENSION ||
(long) cinfo->_jpeg_width > (long) JPEG_MAX_DIMENSION)
ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) JPEG_MAX_DIMENSION);

/* Width of an input scanline must be representable as JDIMENSION. */
Expand Down Expand Up @@ -129,17 +131,17 @@ initial_setup (j_compress_ptr cinfo)
#endif
/* Size in DCT blocks */
compptr->width_in_blocks = (JDIMENSION)
jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor,
jdiv_round_up((long) cinfo->_jpeg_width * (long) compptr->h_samp_factor,
(long) (cinfo->max_h_samp_factor * DCTSIZE));
compptr->height_in_blocks = (JDIMENSION)
jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor,
jdiv_round_up((long) cinfo->_jpeg_height * (long) compptr->v_samp_factor,
(long) (cinfo->max_v_samp_factor * DCTSIZE));
/* Size in samples */
compptr->downsampled_width = (JDIMENSION)
jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor,
jdiv_round_up((long) cinfo->_jpeg_width * (long) compptr->h_samp_factor,
(long) cinfo->max_h_samp_factor);
compptr->downsampled_height = (JDIMENSION)
jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor,
jdiv_round_up((long) cinfo->_jpeg_height * (long) compptr->v_samp_factor,
(long) cinfo->max_v_samp_factor);
/* Mark component needed (this flag isn't actually used for compression) */
compptr->component_needed = TRUE;
Expand All @@ -149,7 +151,7 @@ initial_setup (j_compress_ptr cinfo)
* main controller will call coefficient controller).
*/
cinfo->total_iMCU_rows = (JDIMENSION)
jdiv_round_up((long) cinfo->image_height,
jdiv_round_up((long) cinfo->_jpeg_height,
(long) (cinfo->max_v_samp_factor*DCTSIZE));
}

Expand Down Expand Up @@ -377,10 +379,10 @@ per_scan_setup (j_compress_ptr cinfo)

/* Overall image size in MCUs */
cinfo->MCUs_per_row = (JDIMENSION)
jdiv_round_up((long) cinfo->image_width,
jdiv_round_up((long) cinfo->_jpeg_width,
(long) (cinfo->max_h_samp_factor*DCTSIZE));
cinfo->MCU_rows_in_scan = (JDIMENSION)
jdiv_round_up((long) cinfo->image_height,
jdiv_round_up((long) cinfo->_jpeg_height,
(long) (cinfo->max_v_samp_factor*DCTSIZE));

cinfo->blocks_in_MCU = 0;
Expand Down Expand Up @@ -584,7 +586,7 @@ jinit_c_master_control (j_compress_ptr cinfo, boolean transcode_only)
master->pub.is_last_pass = FALSE;

/* Validate parameters, determine derived values */
initial_setup(cinfo);
initial_setup(cinfo, transcode_only);

if (cinfo->scan_info != NULL) {
#ifdef C_MULTISCAN_FILES_SUPPORTED
Expand Down
2 changes: 2 additions & 0 deletions jerror.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
* jerror.h
*
* Copyright (C) 1994-1997, Thomas G. Lane.
* Modified 1997-2009 by Guido Vollbeding.
* This file is part of the Independent JPEG Group's software.
* For conditions of distribution and use, see the accompanying README file.
*
Expand Down Expand Up @@ -45,6 +46,7 @@ JMESSAGE(JERR_BAD_ALIGN_TYPE, "ALIGN_TYPE is wrong, please fix")
JMESSAGE(JERR_BAD_ALLOC_CHUNK, "MAX_ALLOC_CHUNK is wrong, please fix")
JMESSAGE(JERR_BAD_BUFFER_MODE, "Bogus buffer control mode")
JMESSAGE(JERR_BAD_COMPONENT_ID, "Invalid component ID %d in SOS")
JMESSAGE(JERR_BAD_CROP_SPEC, "Invalid crop request")
JMESSAGE(JERR_BAD_DCT_COEF, "DCT coefficient out of range")
JMESSAGE(JERR_BAD_DCTSIZE, "IDCT output block size %d not supported")
JMESSAGE(JERR_BAD_HUFF_TABLE, "Bogus Huffman table definition")
Expand Down
8 changes: 8 additions & 0 deletions jpegcomp.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,15 @@
#if JPEG_LIB_VERSION >= 70
#define _DCT_scaled_size DCT_h_scaled_size
#define _min_DCT_scaled_size min_DCT_h_scaled_size
#define _min_DCT_h_scaled_size min_DCT_h_scaled_size
#define _min_DCT_v_scaled_size min_DCT_v_scaled_size
#define _jpeg_width jpeg_width
#define _jpeg_height jpeg_height
#else
#define _DCT_scaled_size DCT_scaled_size
#define _min_DCT_scaled_size min_DCT_scaled_size
#define _min_DCT_h_scaled_size min_DCT_scaled_size
#define _min_DCT_v_scaled_size min_DCT_scaled_size
#define _jpeg_width image_width
#define _jpeg_height image_height
#endif
57 changes: 45 additions & 12 deletions jpegtran.1
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.TH JPEGTRAN 1 "3 August 1997"
.TH JPEGTRAN 1 "28 December 2009"
.SH NAME
jpegtran \- lossless transformation of JPEG files
.SH SYNOPSIS
Expand Down Expand Up @@ -91,12 +91,12 @@ Transpose image (across UL-to-LR axis).
.TP
.B \-transverse
Transverse transpose (across UR-to-LL axis).
.PP
.IP
The transpose transformation has no restrictions regarding image dimensions.
The other transformations operate rather oddly if the image dimensions are not
a multiple of the iMCU size (usually 8 or 16 pixels), because they can only
transform complete blocks of DCT coefficient data in the desired way.
.PP
.IP
.BR jpegtran 's
default behavior when transforming an odd-size image is designed
to preserve exact reversibility and mathematical consistency of the
Expand All @@ -108,7 +108,7 @@ able to flip all columns. The other transforms can be built up as sequences
of transpose and flip operations; for consistency, their actions on edge
pixels are defined to be the same as the end result of the corresponding
transpose-and-flip sequence.
.PP
.IP
For practical use, you may prefer to discard any untransformable edge pixels
rather than having a strange-looking strip along the right and/or bottom edges
of a transformed image. To do this, add the
Expand All @@ -117,7 +117,7 @@ switch:
.TP
.B \-trim
Drop non-transformable edge blocks.
.PP
.IP
Obviously, a transformation with
.B \-trim
is not reversible, so strictly speaking
Expand All @@ -130,12 +130,43 @@ trims only the bottom edge, but
followed by
.B \-rot 180 -trim
trims both edges.
.IP
If you are only interested in perfect transformation, add the
.B \-perfect
switch:
.TP
.B \-perfect
Fails with an error if the transformation is not perfect.
.IP
For example you may want to do
.IP
.B (jpegtran \-rot 90 -perfect
.I foo.jpg
.B || djpeg
.I foo.jpg
.B | pnmflip \-r90 | cjpeg)
.IP
to do a perfect rotation if available or an approximated one if not.
.PP
We also offer a lossless-crop option, which discards data outside a given
image region but losslessly preserves what is inside. Like the rotate and
flip transforms, lossless crop is restricted by the current JPEG format: the
upper left corner of the selected region must fall on an iMCU boundary. If
this does not hold for the given crop parameters, we silently move the upper
left corner up and/or left to make it so, simultaneously increasing the region
dimensions to keep the lower right crop corner unchanged. (Thus, the output
image covers at least the requested region, but may cover more.)

The image can be losslessly cropped by giving the switch:
.TP
.B \-crop WxH+X+Y
Crop to a rectangular subarea of width W, height H starting at point X,Y.
.PP
Another not-strictly-lossless transformation switch is:
Other not-strictly-lossless transformation switches are:
.TP
.B \-grayscale
Force grayscale output.
.PP
.IP
This option discards the chrominance channels if the input image is YCbCr
(ie, a standard color JPEG), resulting in a grayscale JPEG file. The
luminance channel is preserved exactly, so this is a better method of reducing
Expand All @@ -155,13 +186,13 @@ comments and other excess baggage present in the source file.
.TP
.B \-copy comments
Copy only comment markers. This setting copies comments from the source file,
but discards any other inessential data.
but discards any other inessential (for image display) data.
.TP
.B \-copy all
Copy all extra markers. This setting preserves miscellaneous markers
found in the source file, such as JFIF thumbnails and Photoshop settings.
In some files these extra markers can be sizable.
.PP
found in the source file, such as JFIF thumbnails, Exif data, and Photoshop
settings. In some files these extra markers can be sizable.
.IP
The default behavior is
.BR "\-copy comments" .
(Note: in IJG releases v6 and v6a,
Expand Down Expand Up @@ -231,7 +262,9 @@ Arithmetic coding is not supported for legal reasons.
.PP
The transform options can't transform odd-size images perfectly. Use
.B \-trim
if you don't like the results without it.
or
.B \-perfect
if you don't like the results.
.PP
The entire image is read into memory and then written out again, even in
cases where this isn't really necessary. Expect swapping on large images,
Expand Down
Loading

0 comments on commit c04bd3c

Please sign in to comment.