~ubuntu-branches/ubuntu/natty/kdebase-runtime/natty-proposed

« back to all changes in this revision

Viewing changes to kioslave/thumbnail/jpegcreatorhelper.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jonathan Riddell
  • Date: 2010-11-24 11:07:10 UTC
  • mto: (0.8.7 upstream)
  • mto: This revision was merged to the branch mainline in revision 129.
  • Revision ID: james.westby@ubuntu.com-20101124110710-6dbsyw0yh21qvn82
Tags: upstream-4.5.80
Import upstream version 4.5.80

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
 
 
2
/*  This file is part of the KDE libraries
 
3
    Copyright (C) 2008 Andre Gemünd <scroogie@gmail.com>
 
4
 
 
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.
 
9
 
 
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.
 
14
 
 
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.
 
19
*/
 
20
 
 
21
#include "jpegcreatorhelper.h"
 
22
 
 
23
#include <cstdio>
 
24
#include <csetjmp>
 
25
#include <QFile>
 
26
#include <QImage>
 
27
 
 
28
extern "C" {
 
29
    #include <jpeglib.h>
 
30
}
 
31
 
 
32
struct jpeg_custom_error_mgr
 
33
{
 
34
   struct jpeg_error_mgr builtin;
 
35
   jmp_buf setjmp_buffer;
 
36
};
 
37
 
 
38
void jpeg_custom_error_callback(j_common_ptr jpegDecompress)
 
39
{
 
40
   jpeg_custom_error_mgr *custom_err = (jpeg_custom_error_mgr *)jpegDecompress->err;
 
41
 
 
42
   // jump to error recovery (fallback to old method)
 
43
   longjmp(custom_err->setjmp_buffer, 1);
 
44
}
 
45
 
 
46
#ifdef Q_CC_MSVC
 
47
typedef struct
 
48
{
 
49
    struct jpeg_source_mgr pub;
 
50
    JOCTET eoi[2];
 
51
} jpeg_custom_source_mgr;
 
52
 
 
53
void init_source (j_decompress_ptr cinfo)
 
54
{
 
55
}
 
56
 
 
57
boolean fill_input_buffer (j_decompress_ptr cinfo)
 
58
{
 
59
    jpeg_custom_source_mgr* src = (jpeg_custom_source_mgr*) cinfo->src;
 
60
 
 
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;
 
66
 
 
67
    return true;
 
68
}
 
69
 
 
70
void skip_input_data (j_decompress_ptr cinfo, long nbytes)
 
71
{
 
72
    jpeg_custom_source_mgr* src = (jpeg_custom_source_mgr*) cinfo->src;
 
73
 
 
74
    if (nbytes > 0)
 
75
    {
 
76
        while (nbytes > (long) src->pub.bytes_in_buffer)
 
77
        {
 
78
            nbytes -= (long) src->pub.bytes_in_buffer;
 
79
            (void) fill_input_buffer(cinfo);
 
80
        }
 
81
        src->pub.next_input_byte += (size_t) nbytes;
 
82
        src->pub.bytes_in_buffer -= (size_t) nbytes;
 
83
    }
 
84
}
 
85
 
 
86
void term_source (j_decompress_ptr cinfo)
 
87
{
 
88
}
 
89
 
 
90
void jpeg_memory_src (j_decompress_ptr cinfo, const JOCTET * buffer, size_t bufsize)
 
91
{
 
92
    jpeg_custom_source_mgr* src;
 
93
 
 
94
    if (cinfo->src == NULL)
 
95
    {
 
96
        cinfo->src = (struct jpeg_source_mgr *) (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
 
97
        sizeof(jpeg_custom_source_mgr));
 
98
    }
 
99
 
 
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;
 
106
 
 
107
    src->pub.next_input_byte = buffer;
 
108
    src->pub.bytes_in_buffer = bufsize;
 
109
}
 
110
#endif
 
111
 
 
112
/**
 
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.
 
120
 *
 
121
 * Important: We do not need to scaled to exact dimesions, as thumbnail.cpp will check dimensions and
 
122
 * rescale anyway.
 
123
 */
 
124
bool JpegCreatorHelper::create(const QString &path, int width, int height, QImage &image)
 
125
{
 
126
    QImage img;
 
127
    const QByteArray name = QFile::encodeName(path);
 
128
    FILE *jpegFile = fopen(name.constData(), "rb");
 
129
    if (jpegFile  == 0) {
 
130
       return false;
 
131
    }
 
132
 
 
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);
 
138
#ifdef Q_CC_MSVC
 
139
    QFile inFile(path);
 
140
    QByteArray buf;
 
141
    if(inFile.open(QIODevice::ReadOnly)) {
 
142
        while(!inFile.atEnd()) {
 
143
            buf += inFile.readLine();
 
144
        }
 
145
        inFile.close();
 
146
    }
 
147
 
 
148
    jpeg_memory_src(&jpegDecompress, (JOCTET*)buf.data(), buf.size());
 
149
#else
 
150
    jpeg_stdio_src(&jpegDecompress, jpegFile);
 
151
#endif
 
152
    jpeg_read_header(&jpegDecompress, TRUE);
 
153
 
 
154
    const double ratioWidth = jpegDecompress.image_width / (double)width;
 
155
    const double ratioHeight = jpegDecompress.image_height / (double)height;
 
156
    int scale = 1;
 
157
    if (ratioWidth > 7 || ratioHeight > 7) {
 
158
        scale = 8;
 
159
    } else if (ratioWidth > 3.5 || ratioHeight > 3.5) {
 
160
        scale = 4;
 
161
    } else if (ratioWidth > 1.75 || ratioHeight > 1.75) {
 
162
        scale = 2;
 
163
    }
 
164
 
 
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;
 
173
 
 
174
    jpeg_calc_output_dimensions(&jpegDecompress);
 
175
 
 
176
    if (setjmp(jpegError.setjmp_buffer)) {
 
177
        jpeg_abort_decompress(&jpegDecompress);
 
178
        fclose(jpegFile);
 
179
        // libjpeg version failed, fall back to direct loading of QImage
 
180
        if (!img.load(path)) {
 
181
            return false;
 
182
        }
 
183
        if (img.depth() != 32) {
 
184
            img = img.convertToFormat(QImage::Format_RGB32);
 
185
        }
 
186
    } else {
 
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);
 
195
        }
 
196
        jpeg_finish_decompress(&jpegDecompress);
 
197
 
 
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) {
 
204
                in -= 3;
 
205
                out[j] = qRgb(in[0], in[1], in[2]);
 
206
            }
 
207
        }
 
208
        fclose(jpegFile);
 
209
        jpeg_destroy_decompress(&jpegDecompress);
 
210
    }
 
211
 
 
212
    image = img;
 
213
    return true;
 
214
}
 
215