2
/* This file is part of the KDE libraries
3
Copyright (C) 2008 Andre Gemünd <scroogie@gmail.com>
5
This library is free software; you can redistribute it and/or
6
modify it under the terms of the GNU Library General Public
7
License as published by the Free Software Foundation; either
8
version 2 of the License, or (at your option) any later version.
10
This library is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
Library General Public License for more details.
15
You should have received a copy of the GNU Library General Public License
16
along with this library; see the file COPYING.LIB. If not, write to
17
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18
Boston, MA 02110-1301, USA.
21
#include "jpegcreatorhelper.h"
32
struct jpeg_custom_error_mgr
34
struct jpeg_error_mgr builtin;
35
jmp_buf setjmp_buffer;
38
void jpeg_custom_error_callback(j_common_ptr jpegDecompress)
40
jpeg_custom_error_mgr *custom_err = (jpeg_custom_error_mgr *)jpegDecompress->err;
42
// jump to error recovery (fallback to old method)
43
longjmp(custom_err->setjmp_buffer, 1);
49
struct jpeg_source_mgr pub;
51
} jpeg_custom_source_mgr;
53
void init_source (j_decompress_ptr cinfo)
57
boolean fill_input_buffer (j_decompress_ptr cinfo)
59
jpeg_custom_source_mgr* src = (jpeg_custom_source_mgr*) cinfo->src;
61
/* Create a fake EOI marker */
62
src->eoi[0] = (JOCTET) 0xFF;
63
src->eoi[1] = (JOCTET) JPEG_EOI;
64
src->pub.next_input_byte = src->eoi;
65
src->pub.bytes_in_buffer = 2;
70
void skip_input_data (j_decompress_ptr cinfo, long nbytes)
72
jpeg_custom_source_mgr* src = (jpeg_custom_source_mgr*) cinfo->src;
76
while (nbytes > (long) src->pub.bytes_in_buffer)
78
nbytes -= (long) src->pub.bytes_in_buffer;
79
(void) fill_input_buffer(cinfo);
81
src->pub.next_input_byte += (size_t) nbytes;
82
src->pub.bytes_in_buffer -= (size_t) nbytes;
86
void term_source (j_decompress_ptr cinfo)
90
void jpeg_memory_src (j_decompress_ptr cinfo, const JOCTET * buffer, size_t bufsize)
92
jpeg_custom_source_mgr* src;
94
if (cinfo->src == NULL)
96
cinfo->src = (struct jpeg_source_mgr *) (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
97
sizeof(jpeg_custom_source_mgr));
100
src = (jpeg_custom_source_mgr*) cinfo->src;
101
src->pub.init_source = init_source;
102
src->pub.fill_input_buffer = fill_input_buffer;
103
src->pub.skip_input_data = skip_input_data;
104
src->pub.resync_to_restart = jpeg_resync_to_restart; // default
105
src->pub.term_source = term_source;
107
src->pub.next_input_byte = buffer;
108
src->pub.bytes_in_buffer = bufsize;
113
* This is a faster thumbnail creation specifically for JPEG images, as it uses the libjpeg feature of
114
* calculating the inverse dct for a part of coefficients for lower resolutions.
115
* Interesting parameters are the quality settings of libjpeg
116
* jpegDecompress.do_fancy_upsampling (TRUE, FALSE)
117
* jpegDecompress.do_block_smoothing (TRUE, FALSE)
118
* jpegDecompress.dct_method (JDCT_IFAST, JDCT_ISLOW, JDCT_IFLOAT)
119
* and the resampling parameter of QImage.
121
* Important: We do not need to scaled to exact dimesions, as thumbnail.cpp will check dimensions and
124
bool JpegCreatorHelper::create(const QString &path, int width, int height, QImage &image)
127
const QByteArray name = QFile::encodeName(path);
128
FILE *jpegFile = fopen(name.constData(), "rb");
133
// create jpeglib data structures and calculate scale denominator
134
struct jpeg_decompress_struct jpegDecompress;
135
struct jpeg_custom_error_mgr jpegError;
136
jpegDecompress.err = jpeg_std_error(&jpegError.builtin);
137
jpeg_create_decompress(&jpegDecompress);
141
if(inFile.open(QIODevice::ReadOnly)) {
142
while(!inFile.atEnd()) {
143
buf += inFile.readLine();
148
jpeg_memory_src(&jpegDecompress, (JOCTET*)buf.data(), buf.size());
150
jpeg_stdio_src(&jpegDecompress, jpegFile);
152
jpeg_read_header(&jpegDecompress, TRUE);
154
const double ratioWidth = jpegDecompress.image_width / (double)width;
155
const double ratioHeight = jpegDecompress.image_height / (double)height;
157
if (ratioWidth > 7 || ratioHeight > 7) {
159
} else if (ratioWidth > 3.5 || ratioHeight > 3.5) {
161
} else if (ratioWidth > 1.75 || ratioHeight > 1.75) {
165
// set jpeglib decompression parameters
166
jpegDecompress.scale_num = 1;
167
jpegDecompress.scale_denom = scale;
168
jpegDecompress.do_fancy_upsampling = FALSE;
169
jpegDecompress.do_block_smoothing = FALSE;
170
jpegDecompress.dct_method = JDCT_IFAST;
171
jpegDecompress.err->error_exit = jpeg_custom_error_callback;
172
jpegDecompress.out_color_space = JCS_RGB;
174
jpeg_calc_output_dimensions(&jpegDecompress);
176
if (setjmp(jpegError.setjmp_buffer)) {
177
jpeg_abort_decompress(&jpegDecompress);
179
// libjpeg version failed, fall back to direct loading of QImage
180
if (!img.load(path)) {
183
if (img.depth() != 32) {
184
img = img.convertToFormat(QImage::Format_RGB32);
187
jpeg_start_decompress(&jpegDecompress);
188
img = QImage(jpegDecompress.output_width, jpegDecompress.output_height, QImage::Format_RGB32);
189
uchar *buffer = img.bits();
190
const int bpl = img.bytesPerLine();
191
while (jpegDecompress.output_scanline < jpegDecompress.output_height) {
192
// advance line-pointer to next line
193
uchar *line = buffer + jpegDecompress.output_scanline * bpl;
194
jpeg_read_scanlines(&jpegDecompress, &line, 1);
196
jpeg_finish_decompress(&jpegDecompress);
198
// align correctly for QImage
199
// code copied from Gwenview and digiKam
200
for (int i = 0; i < int(jpegDecompress.output_height); ++i) {
201
uchar *in = img.scanLine(i) + jpegDecompress.output_width * 3;
202
QRgb *out = (QRgb*)img.scanLine(i);
203
for (int j = jpegDecompress.output_width - 1; j >= 0; --j) {
205
out[j] = qRgb(in[0], in[1], in[2]);
209
jpeg_destroy_decompress(&jpegDecompress);