Commit 15ede265 authored by Birte Kristina Friesel's avatar Birte Kristina Friesel
Browse files

Fix lossless image rotation

Apparently, the old code was based on libjpeg6. However, most systems use
libjpeg8 now, which has a few new features like cropping, leading to a lot
of fuckup with feh on libjpeg8 systems. Now feh works with libjpeg8,
but probably doesn't support libjpeg6 anymore.

Also, this code copypasta really sucks :-)
parent cd4cf4ca
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -27,3 +27,6 @@ Control thumbnail mode (image selection, mainly) with keys.

Xinerama support is present, but far from perfect.
Some day I will debug that, I guess.

We have a lot of copypasta from libjpeg (jpegint.h, transupp.[ch]).
I wonder if they can be #included from somewhere.
+72 −42
Original line number Diff line number Diff line
@@ -2,6 +2,7 @@
 * jpegint.h
 *
 * Copyright (C) 1991-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.
 *
@@ -10,6 +11,7 @@
 * applications using the library shouldn't need to include this file.
 */


/* Declarations for both compression & decompression */

typedef enum {			/* Operating modes for buffer controllers */
@@ -37,6 +39,7 @@ typedef enum { /* Operating modes for buffer controllers */
#define DSTATE_RDCOEFS	209	/* reading file in jpeg_read_coefficients */
#define DSTATE_STOPPING	210	/* looking for EOI in jpeg_finish_decompress */


/* Declarations for compression modules */

/* Master control module */
@@ -53,17 +56,19 @@ struct jpeg_comp_master {
/* Main buffer control (downsampled-data buffer) */
struct jpeg_c_main_controller {
	JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode));
	 JMETHOD(void, process_data,
		 (j_compress_ptr cinfo, JSAMPARRAY input_buf, JDIMENSION * in_row_ctr, JDIMENSION in_rows_avail));
	 JMETHOD(void, process_data, (j_compress_ptr cinfo,
				      JSAMPARRAY input_buf, JDIMENSION * in_row_ctr, JDIMENSION in_rows_avail));
};

/* Compression preprocessing (downsampling input buffer control) */
struct jpeg_c_prep_controller {
	JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode));
	 JMETHOD(void, pre_process_data,
		 (j_compress_ptr cinfo, JSAMPARRAY input_buf,
		  JDIMENSION * in_row_ctr, JDIMENSION in_rows_avail,
		  JSAMPIMAGE output_buf, JDIMENSION * out_row_group_ctr, JDIMENSION out_row_groups_avail));
	 JMETHOD(void, pre_process_data, (j_compress_ptr cinfo,
					  JSAMPARRAY input_buf,
					  JDIMENSION * in_row_ctr,
					  JDIMENSION in_rows_avail,
					  JSAMPIMAGE output_buf,
					  JDIMENSION * out_row_group_ctr, JDIMENSION out_row_groups_avail));
};

/* Coefficient buffer control */
@@ -76,29 +81,30 @@ struct jpeg_c_coef_controller {
struct jpeg_color_converter {
	JMETHOD(void, start_pass, (j_compress_ptr cinfo));
	 JMETHOD(void, color_convert, (j_compress_ptr cinfo,
				       JSAMPARRAY input_buf,
				       JSAMPIMAGE output_buf, JDIMENSION output_row, int num_rows));
				       JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
				       JDIMENSION output_row, int num_rows));
};

/* Downsampling */
struct jpeg_downsampler {
	JMETHOD(void, start_pass, (j_compress_ptr cinfo));
	 JMETHOD(void, downsample, (j_compress_ptr cinfo,
				    JSAMPIMAGE input_buf,
				    JDIMENSION in_row_index, JSAMPIMAGE output_buf, JDIMENSION out_row_group_index));
				    JSAMPIMAGE input_buf, JDIMENSION in_row_index,
				    JSAMPIMAGE output_buf, JDIMENSION out_row_group_index));

	boolean need_context_rows;	/* TRUE if need rows above & below */
};

/* Forward DCT (also controls coefficient quantization) */
typedef JMETHOD(void, forward_DCT_ptr,
		(j_compress_ptr cinfo, jpeg_component_info * compptr,
		 JSAMPARRAY sample_data, JBLOCKROW coef_blocks,
		 JDIMENSION start_row, JDIMENSION start_col, JDIMENSION num_blocks));

struct jpeg_forward_dct {
	JMETHOD(void, start_pass, (j_compress_ptr cinfo));
	/* perhaps this should be an array??? */
	 JMETHOD(void, forward_DCT, (j_compress_ptr cinfo,
				     jpeg_component_info * compptr,
				     JSAMPARRAY sample_data,
				     JBLOCKROW coef_blocks,
				     JDIMENSION start_row, JDIMENSION start_col, JDIMENSION num_blocks));
	/* It is useful to allow each component to have a separate FDCT method. */
	forward_DCT_ptr forward_DCT[MAX_COMPONENTS];
};

/* Entropy encoding */
@@ -121,6 +127,7 @@ struct jpeg_marker_writer {
	 JMETHOD(void, write_marker_byte, (j_compress_ptr cinfo, int val));
};


/* Declarations for decompression modules */

/* Master control module */
@@ -147,8 +154,8 @@ struct jpeg_input_controller {
/* Main buffer control (downsampled-data buffer) */
struct jpeg_d_main_controller {
	JMETHOD(void, start_pass, (j_decompress_ptr cinfo, J_BUF_MODE pass_mode));
	 JMETHOD(void, process_data,
		 (j_decompress_ptr cinfo, JSAMPARRAY output_buf, JDIMENSION * out_row_ctr, JDIMENSION out_rows_avail));
	 JMETHOD(void, process_data, (j_decompress_ptr cinfo,
				      JSAMPARRAY output_buf, JDIMENSION * out_row_ctr, JDIMENSION out_rows_avail));
};

/* Coefficient buffer control */
@@ -164,11 +171,11 @@ struct jpeg_d_coef_controller {
/* Decompression postprocessing (color quantization buffer control) */
struct jpeg_d_post_controller {
	JMETHOD(void, start_pass, (j_decompress_ptr cinfo, J_BUF_MODE pass_mode));
	 JMETHOD(void, post_process_data,
		 (j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
	 JMETHOD(void, post_process_data, (j_decompress_ptr cinfo,
					   JSAMPIMAGE input_buf,
					   JDIMENSION * in_row_group_ctr,
		  JDIMENSION in_row_groups_avail, JSAMPARRAY output_buf,
		  JDIMENSION * out_row_ctr, JDIMENSION out_rows_avail));
					   JDIMENSION in_row_groups_avail,
					   JSAMPARRAY output_buf, JDIMENSION * out_row_ctr, JDIMENSION out_rows_avail));
};

/* Marker reading & parsing */
@@ -195,10 +202,6 @@ struct jpeg_marker_reader {
struct jpeg_entropy_decoder {
	JMETHOD(void, start_pass, (j_decompress_ptr cinfo));
	 JMETHOD(boolean, decode_mcu, (j_decompress_ptr cinfo, JBLOCKROW * MCU_data));

	/* This is here to share code between baseline and progressive decoders; */
	/* other modules probably should not use it */
	boolean insufficient_data;	/* set TRUE after emitting warning */
};

/* Inverse DCT (also performs dequantization) */
@@ -228,19 +231,20 @@ struct jpeg_upsampler {
struct jpeg_color_deconverter {
	JMETHOD(void, start_pass, (j_decompress_ptr cinfo));
	 JMETHOD(void, color_convert, (j_decompress_ptr cinfo,
				       JSAMPIMAGE input_buf,
				       JDIMENSION input_row, JSAMPARRAY output_buf, int num_rows));
				       JSAMPIMAGE input_buf, JDIMENSION input_row,
				       JSAMPARRAY output_buf, int num_rows));
};

/* Color quantization or color precision reduction */
struct jpeg_color_quantizer {
	JMETHOD(void, start_pass, (j_decompress_ptr cinfo, boolean is_pre_scan));
	 JMETHOD(void, color_quantize,
		 (j_decompress_ptr cinfo, JSAMPARRAY input_buf, JSAMPARRAY output_buf, int num_rows));
	 JMETHOD(void, color_quantize, (j_decompress_ptr cinfo,
					JSAMPARRAY input_buf, JSAMPARRAY output_buf, int num_rows));
	 JMETHOD(void, finish_pass, (j_decompress_ptr cinfo));
	 JMETHOD(void, new_color_map, (j_decompress_ptr cinfo));
};


/* Miscellaneous useful macros */

#undef MAX
@@ -248,6 +252,7 @@ struct jpeg_color_quantizer {
#undef MIN
#define MIN(a,b)	((a) < (b) ? (a) : (b))


/* We assume that right shift corresponds to signed division by 2 with
 * rounding towards minus infinity.  This is correct for typical "arithmetic
 * shift" instructions that shift in copies of the sign bit.  But some
@@ -269,6 +274,7 @@ struct jpeg_color_quantizer {
#define RIGHT_SHIFT(x,shft)	((x) >> (shft))
#endif


/* Short forms of external names for systems with brain-damaged linkers. */

#ifdef NEED_SHORT_EXTERNAL_NAMES
@@ -281,7 +287,7 @@ struct jpeg_color_quantizer {
#define jinit_downsampler	jIDownsampler
#define jinit_forward_dct	jIFDCT
#define jinit_huff_encoder	jIHEncoder
#define jinit_phuff_encoder	jIPHEncoder
#define jinit_arith_encoder	jIAEncoder
#define jinit_marker_writer	jIMWriter
#define jinit_master_decompress	jIDMaster
#define jinit_d_main_controller	jIDMainC
@@ -290,7 +296,7 @@ struct jpeg_color_quantizer {
#define jinit_input_controller	jIInCtlr
#define jinit_marker_reader	jIMReader
#define jinit_huff_decoder	jIHDecoder
#define jinit_phuff_decoder	jIPHDecoder
#define jinit_arith_decoder	jIADecoder
#define jinit_inverse_dct	jIIDCT
#define jinit_upsampler		jIUpsampler
#define jinit_color_deconverter	jIDColor
@@ -305,16 +311,27 @@ struct jpeg_color_quantizer {
#define jzero_far		jZeroFar
#define jpeg_zigzag_order	jZIGTable
#define jpeg_natural_order	jZAGTable
#define jpeg_natural_order7	jZAGTable7
#define jpeg_natural_order6	jZAGTable6
#define jpeg_natural_order5	jZAGTable5
#define jpeg_natural_order4	jZAGTable4
#define jpeg_natural_order3	jZAGTable3
#define jpeg_natural_order2	jZAGTable2
#define jpeg_aritab		jAriTab
#endif				/* NEED_SHORT_EXTERNAL_NAMES */


/* Compression module initialization routines */
EXTERN(void)
jinit_compress_master JPP((j_compress_ptr cinfo));
EXTERN(void)
jinit_c_master_control JPP((j_compress_ptr cinfo, boolean transcode_only));
EXTERN(void) jinit_c_main_controller JPP((j_compress_ptr cinfo, boolean need_full_buffer));
EXTERN(void) jinit_c_prep_controller JPP((j_compress_ptr cinfo, boolean need_full_buffer));
EXTERN(void) jinit_c_coef_controller JPP((j_compress_ptr cinfo, boolean need_full_buffer));
EXTERN(void)
jinit_c_main_controller JPP((j_compress_ptr cinfo, boolean need_full_buffer));
EXTERN(void)
jinit_c_prep_controller JPP((j_compress_ptr cinfo, boolean need_full_buffer));
EXTERN(void)
jinit_c_coef_controller JPP((j_compress_ptr cinfo, boolean need_full_buffer));
EXTERN(void)
jinit_color_converter JPP((j_compress_ptr cinfo));
EXTERN(void)
@@ -324,15 +341,18 @@ jinit_forward_dct JPP((j_compress_ptr cinfo));
EXTERN(void)
jinit_huff_encoder JPP((j_compress_ptr cinfo));
EXTERN(void)
jinit_phuff_encoder JPP((j_compress_ptr cinfo));
jinit_arith_encoder JPP((j_compress_ptr cinfo));
EXTERN(void)
jinit_marker_writer JPP((j_compress_ptr cinfo));
/* Decompression module initialization routines */
EXTERN(void)
jinit_master_decompress JPP((j_decompress_ptr cinfo));
EXTERN(void) jinit_d_main_controller JPP((j_decompress_ptr cinfo, boolean need_full_buffer));
EXTERN(void) jinit_d_coef_controller JPP((j_decompress_ptr cinfo, boolean need_full_buffer));
EXTERN(void) jinit_d_post_controller JPP((j_decompress_ptr cinfo, boolean need_full_buffer));
EXTERN(void)
jinit_d_main_controller JPP((j_decompress_ptr cinfo, boolean need_full_buffer));
EXTERN(void)
jinit_d_coef_controller JPP((j_decompress_ptr cinfo, boolean need_full_buffer));
EXTERN(void)
jinit_d_post_controller JPP((j_decompress_ptr cinfo, boolean need_full_buffer));
EXTERN(void)
jinit_input_controller JPP((j_decompress_ptr cinfo));
EXTERN(void)
@@ -340,7 +360,7 @@ jinit_marker_reader JPP((j_decompress_ptr cinfo));
EXTERN(void)
jinit_huff_decoder JPP((j_decompress_ptr cinfo));
EXTERN(void)
jinit_phuff_decoder JPP((j_decompress_ptr cinfo));
jinit_arith_decoder JPP((j_decompress_ptr cinfo));
EXTERN(void)
jinit_inverse_dct JPP((j_decompress_ptr cinfo));
EXTERN(void)
@@ -365,7 +385,8 @@ jround_up JPP((long a, long b));
EXTERN(void)
jcopy_sample_rows JPP((JSAMPARRAY input_array, int source_row,
		       JSAMPARRAY output_array, int dest_row, int num_rows, JDIMENSION num_cols));
EXTERN(void) jcopy_block_row JPP((JBLOCKROW input_row, JBLOCKROW output_row, JDIMENSION num_blocks));
EXTERN(void)
jcopy_block_row JPP((JBLOCKROW input_row, JBLOCKROW output_row, JDIMENSION num_blocks));
EXTERN(void)
jzero_far JPP((void FAR * target, size_t bytestozero));
/* Constant tables in jutils.c */
@@ -373,6 +394,15 @@ jzero_far JPP((void FAR * target, size_t bytestozero));
extern const int jpeg_zigzag_order[];	/* natural coef order to zigzag order */
#endif
extern const int jpeg_natural_order[];	/* zigzag coef order to natural order */
extern const int jpeg_natural_order7[];	/* zz to natural order for 7x7 block */
extern const int jpeg_natural_order6[];	/* zz to natural order for 6x6 block */
extern const int jpeg_natural_order5[];	/* zz to natural order for 5x5 block */
extern const int jpeg_natural_order4[];	/* zz to natural order for 4x4 block */
extern const int jpeg_natural_order3[];	/* zz to natural order for 3x3 block */
extern const int jpeg_natural_order2[];	/* zz to natural order for 2x2 block */

/* Arithmetic coding probability estimation tables in jaricom.c */
extern const INT32 jpeg_aritab[];

/* Suppress undefined-structure complaints if necessary. */

+606 −463

File changed.

Preview size limit exceeded, changes collapsed.

+99 −30
Original line number Diff line number Diff line
/*
 * transupp.h
 *
 * Copyright (C) 1997, Thomas G. Lane.
 * Copyright (C) 1997-2009, Thomas G. Lane, Guido Vollbeding.
 * This file is part of the Independent JPEG Group's software.
 * For conditions of distribution and use, see the accompanying README file.
 *
@@ -22,31 +22,6 @@
#define TRANSFORMS_SUPPORTED 1	/* 0 disables transform code */
#endif

/* Short forms of external names for systems with brain-damaged linkers. */

#ifdef NEED_SHORT_EXTERNAL_NAMES
#define jtransform_request_workspace		jTrRequest
#define jtransform_adjust_parameters		jTrAdjust
#define jtransform_execute_transformation	jTrExec
#define jcopy_markers_setup			jCMrkSetup
#define jcopy_markers_execute			jCMrkExec
#endif				/* NEED_SHORT_EXTERNAL_NAMES */

/*
 * Codes for supported types of image transformations.
 */

typedef enum {
	JXFORM_NONE,		/* no transformation */
	JXFORM_FLIP_H,		/* horizontal flip */
	JXFORM_FLIP_V,		/* vertical flip */
	JXFORM_TRANSPOSE,	/* transpose across UL-to-LR axis */
	JXFORM_TRANSVERSE,	/* transpose across UR-to-LL axis */
	JXFORM_ROT_90,		/* 90-degree clockwise rotation */
	JXFORM_ROT_180,		/* 180-degree rotation */
	JXFORM_ROT_270		/* 270-degree clockwise (or 90 ccw) */
} JXFORM_CODE;

/*
 * Although rotating and flipping data expressed as DCT coefficients is not
 * hard, there is an asymmetry in the JPEG format specification for images
@@ -74,6 +49,24 @@ typedef enum {
 * (For example, -rot 270 -trim trims only the bottom edge, but -rot 90 -trim
 * followed by -rot 180 -trim trims both edges.)
 *
 * 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 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.)
 *
 * 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
 * coefficients and losslessly preserves lower-order coefficients of a
 * sub-block.
 *
 * Rotate/flip transform, resize, and crop can be requested together in a
 * single invocation.  The crop is applied last --- that is, the crop region
 * is specified in terms of the destination image after transform/resize.
 *
 * We also offer a "force to grayscale" option, which simply discards the
 * chrominance channels of a YCbCr image.  This is lossless in the sense that
 * the luminance channel is preserved exactly.  It's not the same kind of
@@ -82,30 +75,107 @@ typedef enum {
 * be aware of the option to know how many components to work on.
 */


/* Short forms of external names for systems with brain-damaged linkers. */

#ifdef NEED_SHORT_EXTERNAL_NAMES
#define jtransform_parse_crop_spec	jTrParCrop
#define jtransform_request_workspace	jTrRequest
#define jtransform_adjust_parameters	jTrAdjust
#define jtransform_execute_transform	jTrExec
#define jtransform_perfect_transform	jTrPerfect
#define jcopy_markers_setup		jCMrkSetup
#define jcopy_markers_execute		jCMrkExec
#endif				/* NEED_SHORT_EXTERNAL_NAMES */


/*
 * Codes for supported types of image transformations.
 */

typedef enum {
	JXFORM_NONE,		/* no transformation */
	JXFORM_FLIP_H,		/* horizontal flip */
	JXFORM_FLIP_V,		/* vertical flip */
	JXFORM_TRANSPOSE,	/* transpose across UL-to-LR axis */
	JXFORM_TRANSVERSE,	/* transpose across UR-to-LL axis */
	JXFORM_ROT_90,		/* 90-degree clockwise rotation */
	JXFORM_ROT_180,		/* 180-degree rotation */
	JXFORM_ROT_270		/* 270-degree clockwise (or 90 ccw) */
} JXFORM_CODE;

/*
 * Codes for crop parameters, which can individually be unspecified,
 * positive, or negative.  (Negative width or height makes no sense, though.)
 */

typedef enum {
	JCROP_UNSET,
	JCROP_POS,
	JCROP_NEG
} JCROP_CODE;

/*
 * Transform parameters struct.
 * NB: application must not change any elements of this struct after
 * calling jtransform_request_workspace.
 */

typedef struct {
	/* Options: set by caller */
	JXFORM_CODE transform;	/* image transform operator */
	boolean perfect;	/* if TRUE, fail if partial MCUs are requested */
	boolean trim;		/* if TRUE, trim partial MCUs as needed */
	boolean force_grayscale;	/* if TRUE, convert color image to grayscale */
	boolean crop;		/* if TRUE, crop source image */

	/* Crop parameters: application need not set these unless crop is TRUE.
	 * These can be filled in by jtransform_parse_crop_spec().
	 */
	JDIMENSION crop_width;	/* Width of selected region */
	JCROP_CODE crop_width_set;
	JDIMENSION crop_height;	/* Height of selected region */
	JCROP_CODE crop_height_set;
	JDIMENSION crop_xoffset;	/* X offset of selected region */
	JCROP_CODE crop_xoffset_set;	/* (negative measures from right edge) */
	JDIMENSION crop_yoffset;	/* Y offset of selected region */
	JCROP_CODE crop_yoffset_set;	/* (negative measures from bottom edge) */

	/* Internal workspace: caller should not touch these */
	int num_components;	/* # of components in workspace */
	jvirt_barray_ptr *workspace_coef_arrays;	/* workspace for transformations */
	JDIMENSION output_width;	/* cropped destination dimensions */
	JDIMENSION output_height;
	JDIMENSION x_crop_offset;	/* destination crop offsets measured in iMCUs */
	JDIMENSION y_crop_offset;
	int iMCU_sample_width;	/* destination iMCU size */
	int iMCU_sample_height;
} jpeg_transform_info;


#if TRANSFORMS_SUPPORTED

/* Parse a crop specification (written in X11 geometry style) */
EXTERN(boolean) jtransform_parse_crop_spec JPP((jpeg_transform_info * info, const char *spec));
/* Request any required workspace */
EXTERN(void) jtransform_request_workspace JPP((j_decompress_ptr srcinfo, jpeg_transform_info * info));
EXTERN(boolean) jtransform_request_workspace JPP((j_decompress_ptr srcinfo, jpeg_transform_info * info));
/* Adjust output image parameters */
EXTERN(jvirt_barray_ptr *) jtransform_adjust_parameters
JPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo, jvirt_barray_ptr * src_coef_arrays, jpeg_transform_info * info));
/* Execute the actual transformation, if any */
EXTERN(void) jtransform_execute_transformation
EXTERN(void) jtransform_execute_transform
JPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo, jvirt_barray_ptr * src_coef_arrays, jpeg_transform_info * info));

/* jtransform_execute_transform used to be called
 * jtransform_execute_transformation, but some compilers complain about
 * routine names that long.  This macro is here to avoid breaking any
 * old source code that uses the original name...
 */
#define jtransform_execute_transformation	jtransform_execute_transform

#endif				/* TRANSFORMS_SUPPORTED */


/*
 * Support for copying optional markers from source to destination file.
 */
@@ -119,7 +189,6 @@ typedef enum {
#define JCOPYOPT_DEFAULT  JCOPYOPT_COMMENTS	/* recommended default */

/* Setup decompression object to save desired markers in memory */
EXTERN(void)
jcopy_markers_setup JPP((j_decompress_ptr srcinfo, JCOPY_OPTION option));
EXTERN(void) jcopy_markers_setup JPP((j_decompress_ptr srcinfo, JCOPY_OPTION option));
/* Copy markers saved in the given source object to the destination object */
EXTERN(void) jcopy_markers_execute JPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo, JCOPY_OPTION option));