1 /* This file is part of the KDE libraries
2 Copyright (C) 2008 Andre Gemünd <scroogie@gmail.com>
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 Boston, MA 02110-1301, USA.
20 #include "jpegcreator.h"
26 #include <kdemacros.h>
32 KDE_EXPORT ThumbCreator
*new_creator()
34 return new JpegCreator
;
38 struct jpeg_custom_error_mgr
40 struct jpeg_error_mgr builtin
;
41 jmp_buf setjmp_buffer
;
44 void jpeg_custom_error_callback(j_common_ptr jpegDecompress
)
46 jpeg_custom_error_mgr
*custom_err
= (jpeg_custom_error_mgr
*)jpegDecompress
->err
;
48 // jump to error recovery (fallback to old method)
49 longjmp(custom_err
->setjmp_buffer
, 1);
52 JpegCreator::JpegCreator()
57 * This is a faster thumbnail creation specifically for JPEG images, as it uses the libjpeg feature of
58 * calculating the inverse dct for a part of coefficients for lower resolutions.
59 * Interesting parameters are the quality settings of libjpeg
60 * jpegDecompress.do_fancy_upsampling (TRUE, FALSE)
61 * jpegDecompress.do_block_smoothing (TRUE, FALSE)
62 * jpegDecompress.dct_method (JDCT_IFAST, JDCT_ISLOW, JDCT_IFLOAT)
63 * and the resampling parameter of QImage.
65 * Important: We do not need to scaled to exact dimesions, as thumbnail.cpp will check dimensions and
68 bool JpegCreator::create(const QString
&path
, int width
, int height
, QImage
&img
)
70 const QByteArray name
= QFile::encodeName(path
);
71 FILE *jpegFile
= fopen(name
.constData(), "rb");
76 // create jpeglib data structures and calculate scale denominator
77 struct jpeg_decompress_struct jpegDecompress
;
78 struct jpeg_custom_error_mgr jpegError
;
79 jpegDecompress
.err
= jpeg_std_error(&jpegError
.builtin
);
80 jpeg_create_decompress(&jpegDecompress
);
81 jpeg_stdio_src(&jpegDecompress
, jpegFile
);
82 jpeg_read_header(&jpegDecompress
, TRUE
);
84 const double ratioWidth
= jpegDecompress
.image_width
/ (double)width
;
85 const double ratioHeight
= jpegDecompress
.image_height
/ (double)height
;
87 if (ratioWidth
> 7 || ratioHeight
> 7) {
89 } else if (ratioWidth
> 3.5 || ratioHeight
> 3.5) {
91 } else if (ratioWidth
> 1.75 || ratioHeight
> 1.75) {
95 // set jpeglib decompression parameters
96 jpegDecompress
.scale_num
= 1;
97 jpegDecompress
.scale_denom
= scale
;
98 jpegDecompress
.do_fancy_upsampling
= FALSE
;
99 jpegDecompress
.do_block_smoothing
= FALSE
;
100 jpegDecompress
.dct_method
= JDCT_IFAST
;
101 jpegDecompress
.err
->error_exit
= jpeg_custom_error_callback
;
102 jpegDecompress
.out_color_space
= JCS_RGB
;
104 jpeg_calc_output_dimensions(&jpegDecompress
);
106 if (setjmp(jpegError
.setjmp_buffer
)) {
107 jpeg_abort_decompress(&jpegDecompress
);
109 // libjpeg version failed, fall back to direct loading of QImage
110 if (!img
.load(path
)) {
113 if (img
.depth() != 32) {
114 img
= img
.convertToFormat(QImage::Format_RGB32
);
119 jpeg_start_decompress(&jpegDecompress
);
120 img
= QImage(jpegDecompress
.output_width
, jpegDecompress
.output_height
, QImage::Format_RGB32
);
121 uchar
*buffer
= img
.bits();
122 const int bpl
= img
.bytesPerLine();
123 while (jpegDecompress
.output_scanline
< jpegDecompress
.output_height
) {
124 // advance line-pointer to next line
125 uchar
*line
= buffer
+ jpegDecompress
.output_scanline
* bpl
;
126 jpeg_read_scanlines(&jpegDecompress
, &line
, 1);
128 jpeg_finish_decompress(&jpegDecompress
);
130 // align correctly for QImage
131 // code copied from Gwenview and digiKam
132 for (int i
= 0; i
< jpegDecompress
.output_height
; ++i
) {
133 uchar
*in
= img
.scanLine(i
) + jpegDecompress
.output_width
* 3;
134 QRgb
*out
= (QRgb
*)img
.scanLine(i
);
135 for (int j
= jpegDecompress
.output_width
- 1; j
>= 0; --j
) {
137 out
[j
] = qRgb(in
[0], in
[1], in
[2]);
142 jpeg_destroy_decompress(&jpegDecompress
);
146 ThumbCreator::Flags
JpegCreator::flags() const