AlbumShaper 1.0a3
jpegTools.cpp
Go to the documentation of this file.
1//==============================================
2// copyright : (C) 2003-2005 by Will Stokes
3//==============================================
4// This program is free software; you can redistribute it
5// and/or modify it under the terms of the GNU General
6// Public License as published by the Free Software
7// Foundation; either version 2 of the License, or
8// (at your option) any later version.
9//==============================================
10
11//-----------------------------
12//On windows we must force boolean to be a unsigned char, why?
13//for some reason libjpeg tries to redefine it to int and causes
14//struct size mismatches when calling libjpeg functions :(
15#include <qglobal.h>
16
17//PLATFORM_SPECIFIC_CODE
18#ifdef Q_OS_WIN
19typedef unsigned char boolean;
20#define HAVE_BOOLEAN
21#endif
22//-----------------------------
23
24//Systemwide includes
25#include <stdio.h>
26#include <qfileinfo.h>
27#include <qstring.h>
28#include <qimage.h>
29#include <setjmp.h>
30#define XMD_H
31extern "C" {
32#include <jpeglib.h>
33#include "jpegInternal.h"
34}
35
36//Projectwide includes
37#include "../imageTools.h"
38#include "jpegTools.h"
39
40//=============================================
41//Code extracted from GwenView/KDE
43{
44 jmp_buf mJmpBuffer;
45
46 static void handler(j_common_ptr cinfo)
47 {
48 GVJPEGFatalError* error=static_cast<GVJPEGFatalError*>(cinfo->err);
49 (error->output_message)(cinfo);
50 longjmp(error->mJmpBuffer,1);
51 }
52};
53//=============================================
54bool scaleJPEG(QString fileIn, QImage& scaledImage,
55 int targetWidth, int targetHeight)
56{
57 //get jpeg info
58 struct jpeg_decompress_struct cinfo;
59
60 //open file
61 FILE* inputFile=fopen( fileIn.ascii(), "rb" );
62 if(!inputFile) return false;
63
64 //error checking on jpg file
65 struct GVJPEGFatalError jerr;
66 cinfo.err = jpeg_std_error(&jerr);
67 cinfo.err->error_exit = GVJPEGFatalError::handler;
68 if (setjmp(jerr.mJmpBuffer))
69 {
70 jpeg_destroy_decompress(&cinfo);
71 fclose(inputFile);
72 return false;
73 }
74
75 //get jpeg resolution
76 jpeg_create_decompress(&cinfo);
77 jpeg_stdio_src(&cinfo, inputFile);
78 jpeg_read_header(&cinfo, TRUE);
79
80 //find optimal scale fraction (must be power of two)
81 int origWidth = (int)cinfo.image_width;
82 int origHeight = (int)cinfo.image_height;
83 int num = 1;
84 int denom = 1;
85
86 //if image is bigger than target, scale down by adjusting the denominator
87 if( origWidth > targetWidth || origHeight > targetHeight )
88 {
89 while( denom < 8 &&
90 ( origWidth / (denom*2) >= targetWidth || origHeight / (denom*2) >= targetHeight )
91 )
92 { denom = denom*2; }
93 }
94
95 //set scaling fraction
96 cinfo.scale_num=num;
97 cinfo.scale_denom=denom;
98
99 //create intermediary image scaled by power of 2
100 jpeg_start_decompress(&cinfo);
101
102 switch(cinfo.output_components)
103 {
104 //Black and White Image
105 case 1:
106 {
107 scaledImage.create( cinfo.output_width, cinfo.output_height, 8, 256 );
108 for (int i=0; i<256; i++)
109 {
110 scaledImage.setColor(i, qRgb(i,i,i));
111 }
112 }
113 break;
114
115 //24 or 32 bit color image
116 case 3:
117 case 4:
118 scaledImage.create( cinfo.output_width, cinfo.output_height, 32 );
119 break;
120
121 //Unknown color depth
122 default:
123 jpeg_destroy_decompress(&cinfo);
124 fclose(inputFile);
125 return false;
126 }
127
128 //fast scale image
129 uchar** lines = scaledImage.jumpTable();
130 while (cinfo.output_scanline < cinfo.output_height)
131 {
132 jpeg_read_scanlines(&cinfo, lines + cinfo.output_scanline, cinfo.output_height);
133 }
134 jpeg_finish_decompress(&cinfo);
135
136
137 //expand 8 to 32bits per pixel since QImage wants 32
138 if ( cinfo.output_components == 1 )
139 {
140 scaledImage = scaledImage.convertDepth( 32, Qt::AutoColor );
141 }
142
143 //expand 24 to 32bits per pixel since QImage wants 32
144 if ( cinfo.output_components == 3 )
145 {
146 for (uint j=0; j<cinfo.output_height; j++)
147 {
148 uchar *in = scaledImage.scanLine(j) + cinfo.output_width*3;
149 QRgb *out = (QRgb*)( scaledImage.scanLine(j) );
150
151 for (uint i=cinfo.output_width; i--; )
152 {
153 in-=3;
154 out[i] = qRgb(in[0], in[1], in[2]);
155 }
156 }
157 }
158
159 //use slower smooth scale technique to scale to final size from intermediate image
160 if( scaledImage.width() != targetWidth || scaledImage.height() != targetHeight )
161 {
162 int clampedTargetWidth = targetWidth;
163 int clampedTargetHeight = targetHeight;
164 //clamp scaling up to < 2x
165 if(QMIN( ((float)targetWidth)/origWidth, ((float)targetHeight)/origHeight ) > 2)
166 {
167 clampedTargetWidth = 2*origWidth;
168 clampedTargetHeight = 2*origHeight;
169 }
170
171 scaledImage = scaledImage.smoothScale(clampedTargetWidth, clampedTargetHeight, Qt::KeepAspectRatio);
172 }
173 jpeg_destroy_decompress(&cinfo);
174 fclose(inputFile);
175 return true;
176}
177//=============================================
178bool transformJPEG( QString fileIn, QString fileOut, TRANSFORM_CODE transformation )
179{
180 struct jpeg_decompress_struct srcinfo;
181 struct jpeg_compress_struct dstinfo;
182 struct jpeg_error_mgr jsrcerr, jdsterr;
183 FILE * input_file;
184 FILE * output_file;
185 jpeg_transform_info transformoption;
186 jvirt_barray_ptr * src_coef_arrays;
187 jvirt_barray_ptr * dst_coef_arrays;
188
189 //setup transofrmation option struct, this was done in jpegtran by the
190 //parse_switches function in jpegtran.c
191 switch( transformation )
192 {
193 case ROTATE_90:
194 transformoption.transform = JXFORM_ROT_90;
195 break;
196 case ROTATE_270:
197 transformoption.transform = JXFORM_ROT_270;
198 break;
199 case FLIP_H:
200 transformoption.transform = JXFORM_FLIP_H;
201 break;
202 case FLIP_V:
203 transformoption.transform = JXFORM_FLIP_V;
204 break;
205 default:
206 return false;
207 }
208 transformoption.trim = TRUE;
209 transformoption.force_grayscale = FALSE;
210
211 // Initialize the JPEG decompression object with default error handling.
212 srcinfo.err = jpeg_std_error(&jsrcerr);
213 jpeg_create_decompress(&srcinfo);
214
215 // Initialize the JPEG compression object with default error handling.
216 dstinfo.err = jpeg_std_error(&jdsterr);
217 jpeg_create_compress(&dstinfo);
218
220 //what does this stuff do?
221 dstinfo.err->trace_level = 0;
222 jsrcerr.trace_level = jdsterr.trace_level;
223 srcinfo.mem->max_memory_to_use = dstinfo.mem->max_memory_to_use;
225
226 //open input and output files
227 if ((input_file = fopen(QFile::encodeName(fileIn), "rb")) == NULL) return false;
228 if ((output_file = fopen(QFile::encodeName(fileOut), "wb")) == NULL) return false;
229
230 // Specify data source for decompression
231 jpeg_stdio_src(&srcinfo, input_file);
232
233 // Enable saving of extra markers that we want to copy
235
236 // Read file header
237 (void) jpeg_read_header(&srcinfo, TRUE);
238
239 // Any space needed by a transform option must be requested before
240 // jpeg_read_coefficients so that memory allocation will be done right.
241 jtransform_request_workspace(&srcinfo, &transformoption);
242
243 // Read source file as DCT coefficients
244 src_coef_arrays = jpeg_read_coefficients(&srcinfo);
245
246 // Initialize destination compression parameters from source values
247 jpeg_copy_critical_parameters(&srcinfo, &dstinfo);
248
249 // Adjust destination parameters if required by transform options;
250 // also find out which set of coefficient arrays will hold the output.
251 dst_coef_arrays = jtransform_adjust_parameters(&dstinfo, src_coef_arrays,
252 &transformoption);
253
254 // Specify data destination for compression
255 jpeg_stdio_dest(&dstinfo, output_file);
256
257 // Start compressor (note no image data is actually written here)
258 jpeg_write_coefficients(&dstinfo, dst_coef_arrays);
259
260 // Copy to the output file any extra markers that we want to preserve
261 jcopy_markers_execute(&srcinfo, &dstinfo);
262
263 // Execute image transformation, if any
264 jtransform_execute_transformation(&srcinfo, &dstinfo,
265 src_coef_arrays,
266 &transformoption);
267
268 // Finish compression and release memory
269 jpeg_finish_compress(&dstinfo);
270 jpeg_destroy_compress(&dstinfo);
271 (void) jpeg_finish_decompress(&srcinfo);
272 jpeg_destroy_decompress(&srcinfo);
273
274 // Close files
275 fclose(input_file);
276 fclose(output_file);
277
278 //success
279 return true;
280}
281//=============================================
282
TRANSFORM_CODE
Definition imageTools.h:25
@ FLIP_V
Definition imageTools.h:29
@ ROTATE_270
Definition imageTools.h:27
@ ROTATE_90
Definition imageTools.h:26
@ FLIP_H
Definition imageTools.h:28
@ JXFORM_FLIP_H
@ JXFORM_ROT_270
@ JXFORM_FLIP_V
@ JXFORM_ROT_90
@ JCOPYOPT_COMMENTS
void jtransform_request_workspace(j_decompress_ptr srcinfo, jpeg_transform_info *info)
void jcopy_markers_execute(j_decompress_ptr srcinfo, j_compress_ptr dstinfo)
jvirt_barray_ptr * jtransform_adjust_parameters(j_compress_ptr dstinfo, jvirt_barray_ptr *src_coef_arrays, jpeg_transform_info *info)
void jtransform_execute_transformation(j_decompress_ptr srcinfo, j_compress_ptr dstinfo, jvirt_barray_ptr *src_coef_arrays, jpeg_transform_info *info)
void jcopy_markers_setup(j_decompress_ptr srcinfo, JCOPY_OPTION option)
bool scaleJPEG(QString fileIn, QImage &scaledImage, int targetWidth, int targetHeight)
Definition jpegTools.cpp:54
bool transformJPEG(QString fileIn, QString fileOut, TRANSFORM_CODE transformation)
static void handler(j_common_ptr cinfo)
Definition jpegTools.cpp:46
JXFORM_CODE transform