~ubuntu-branches/ubuntu/precise/gwenview/precise-proposed

« back to all changes in this revision

Viewing changes to lib/imageformats/jpeghandler.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2011-12-15 14:17:54 UTC
  • mto: This revision was merged to the branch mainline in revision 12.
  • Revision ID: package-import@ubuntu.com-20111215141754-z043hyx69dulbggf
Tags: upstream-4.7.90
ImportĀ upstreamĀ versionĀ 4.7.90

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
// vim: set tabstop=4 shiftwidth=4 noexpandtab:
 
1
// vim: set tabstop=4 shiftwidth=4 expandtab:
2
2
/*
3
3
Gwenview: an image viewer
4
4
Copyright 2008 AurĆ©lien GĆ¢teau <agateau@kde.org>
44
44
// Local
45
45
#include "../iodevicejpegsourcemanager.h"
46
46
 
47
 
namespace Gwenview {
 
47
namespace Gwenview
 
48
{
48
49
 
49
50
#undef ENABLE_LOG
50
51
#undef LOG
55
56
#define LOG(x) ;
56
57
#endif
57
58
 
58
 
 
59
59
struct JpegFatalError : public jpeg_error_mgr {
60
 
        jmp_buf mJmpBuffer;
 
60
    jmp_buf mJmpBuffer;
61
61
 
62
 
        static void handler(j_common_ptr cinfo) {
63
 
                JpegFatalError* error=static_cast<JpegFatalError*>(cinfo->err);
64
 
                (error->output_message)(cinfo);
65
 
                longjmp(error->mJmpBuffer,1);
66
 
        }
 
62
    static void handler(j_common_ptr cinfo)
 
63
    {
 
64
        JpegFatalError* error = static_cast<JpegFatalError*>(cinfo->err);
 
65
        (error->output_message)(cinfo);
 
66
        longjmp(error->mJmpBuffer, 1);
 
67
    }
67
68
};
68
69
 
69
 
 
70
 
static void expand24to32bpp(QImage* image) {
71
 
        for (int j = 0; j < image->height(); ++j) {
72
 
                uchar *in = image->scanLine(j) + (image->width() - 1)*3;
73
 
                QRgb *out = (QRgb*)( image->scanLine(j) ) + image->width() - 1;
74
 
 
75
 
                for (int i=image->width() - 1; i>=0; --i, --out, in -= 3) {
76
 
                        *out = qRgb(in[0], in[1], in[2]);
77
 
                }
78
 
        }
79
 
}
80
 
 
81
 
 
82
 
static void convertCmykToRgb(QImage* image) {
83
 
        for (int j = 0; j < image->height(); ++j) {
84
 
                uchar *in = image->scanLine(j) + image->width() * 4;
85
 
                QRgb *out = (QRgb*)image->scanLine(j);
86
 
 
87
 
                for (int i = image->width() - 1; i>=0; --i) {
88
 
                        in-=4;
89
 
                        int k = in[3];
90
 
                        out[i] = qRgb(k * in[0] / 255, k * in[1] / 255, k * in[2] / 255);
91
 
                }
92
 
        }
93
 
}
94
 
 
95
 
 
96
 
static QSize getJpegSize(QIODevice* ioDevice) {
97
 
        struct jpeg_decompress_struct cinfo;
98
 
        QSize size;
99
 
 
100
 
        // Error handling
101
 
        struct JpegFatalError jerr;
102
 
        cinfo.err = jpeg_std_error(&jerr);
103
 
        cinfo.err->error_exit = JpegFatalError::handler;
104
 
        if (setjmp(jerr.mJmpBuffer)) {
105
 
                jpeg_destroy_decompress(&cinfo);
106
 
                return size;
107
 
        }
108
 
 
109
 
        // Init decompression
110
 
        jpeg_create_decompress(&cinfo);
111
 
        Gwenview::IODeviceJpegSourceManager::setup(&cinfo, ioDevice);
112
 
        jpeg_read_header(&cinfo, true);
113
 
 
114
 
        size = QSize(cinfo.image_width, cinfo.image_height);
115
 
        jpeg_destroy_decompress(&cinfo);
116
 
        return size;
117
 
}
118
 
 
119
 
 
120
 
static bool loadJpeg(QImage* image, QIODevice* ioDevice, QSize scaledSize) {
121
 
        struct jpeg_decompress_struct cinfo;
122
 
 
123
 
        // Error handling
124
 
        struct JpegFatalError jerr;
125
 
        cinfo.err = jpeg_std_error(&jerr);
126
 
        cinfo.err->error_exit = JpegFatalError::handler;
127
 
        if (setjmp(jerr.mJmpBuffer)) {
128
 
                jpeg_destroy_decompress(&cinfo);
129
 
                return false;
130
 
        }
131
 
 
132
 
        // Init decompression
133
 
        jpeg_create_decompress(&cinfo);
134
 
        Gwenview::IODeviceJpegSourceManager::setup(&cinfo, ioDevice);
135
 
        jpeg_read_header(&cinfo, true);
136
 
 
137
 
        // Compute scale value
138
 
        cinfo.scale_num=1;
139
 
        if (!scaledSize.isEmpty()) {
140
 
                // Use !scaledSize.isEmpty(), not scaledSize.isValid() because
141
 
                // isValid() returns true if both the width and height is equal to or
142
 
                // greater than 0, so it is possible to get a division by 0.
143
 
                cinfo.scale_denom = qMin(cinfo.image_width / scaledSize.width(),
144
 
                                                                cinfo.image_height / scaledSize.height());
145
 
                if (cinfo.scale_denom < 2) {
146
 
                        cinfo.scale_denom = 1;
147
 
                } else if (cinfo.scale_denom < 4) {
148
 
                        cinfo.scale_denom = 2;
149
 
                } else if (cinfo.scale_denom < 8) {
150
 
                        cinfo.scale_denom = 4;
151
 
                } else {
152
 
                        cinfo.scale_denom = 8;
153
 
                }
154
 
        } else {
155
 
                cinfo.scale_denom = 1;
156
 
        }
157
 
        LOG("cinfo.scale_denom=" << cinfo.scale_denom);
158
 
 
159
 
        // Init image
160
 
        jpeg_start_decompress(&cinfo);
161
 
        switch(cinfo.output_components) {
162
 
        case 3:
163
 
        case 4:
164
 
                *image = QImage(cinfo.output_width, cinfo.output_height, QImage::Format_RGB32);
165
 
                break;
166
 
        case 1: // B&W image
167
 
                *image = QImage(cinfo.output_width, cinfo.output_height, QImage::Format_Indexed8);
168
 
                image->setNumColors(256);
169
 
                for (int i=0; i<256; ++i) {
170
 
                        image->setColor(i, qRgba(i, i, i, 255));
171
 
                }
172
 
                break;
173
 
        default:
174
 
                jpeg_destroy_decompress(&cinfo);
175
 
                return false;
176
 
        }
177
 
 
178
 
        while (cinfo.output_scanline < cinfo.output_height) {
179
 
                uchar *line = image->scanLine(cinfo.output_scanline);
180
 
                jpeg_read_scanlines(&cinfo, &line, 1);
181
 
        }
182
 
 
183
 
        switch (cinfo.out_color_space) {
184
 
        case JCS_CMYK:
185
 
                convertCmykToRgb(image);
186
 
                break;
187
 
        case JCS_RGB:
188
 
        case JCS_GRAYSCALE:
189
 
                break;
190
 
        default:
191
 
                kWarning() << "Unhandled JPEG colorspace" << cinfo.out_color_space;
192
 
                break;
193
 
        }
194
 
 
195
 
        if ( cinfo.output_components == 3 ) {
196
 
                expand24to32bpp(image);
197
 
        }
198
 
 
199
 
        if (scaledSize.isValid()) {
200
 
                *image = image->scaled(scaledSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
201
 
        }
202
 
 
203
 
        jpeg_finish_decompress(&cinfo);
204
 
        jpeg_destroy_decompress(&cinfo);
205
 
 
206
 
        return true;
207
 
}
208
 
 
 
70
static void expand24to32bpp(QImage* image)
 
71
{
 
72
    for (int j = 0; j < image->height(); ++j) {
 
73
        uchar *in = image->scanLine(j) + (image->width() - 1) * 3;
 
74
        QRgb *out = (QRgb*)(image->scanLine(j)) + image->width() - 1;
 
75
 
 
76
        for (int i = image->width() - 1; i >= 0; --i, --out, in -= 3) {
 
77
            *out = qRgb(in[0], in[1], in[2]);
 
78
        }
 
79
    }
 
80
}
 
81
 
 
82
static void convertCmykToRgb(QImage* image)
 
83
{
 
84
    for (int j = 0; j < image->height(); ++j) {
 
85
        uchar *in = image->scanLine(j) + image->width() * 4;
 
86
        QRgb *out = (QRgb*)image->scanLine(j);
 
87
 
 
88
        for (int i = image->width() - 1; i >= 0; --i) {
 
89
            in -= 4;
 
90
            int k = in[3];
 
91
            out[i] = qRgb(k * in[0] / 255, k * in[1] / 255, k * in[2] / 255);
 
92
        }
 
93
    }
 
94
}
 
95
 
 
96
static QSize getJpegSize(QIODevice* ioDevice)
 
97
{
 
98
    struct jpeg_decompress_struct cinfo;
 
99
    QSize size;
 
100
 
 
101
    // Error handling
 
102
    struct JpegFatalError jerr;
 
103
    cinfo.err = jpeg_std_error(&jerr);
 
104
    cinfo.err->error_exit = JpegFatalError::handler;
 
105
    if (setjmp(jerr.mJmpBuffer)) {
 
106
        jpeg_destroy_decompress(&cinfo);
 
107
        return size;
 
108
    }
 
109
 
 
110
    // Init decompression
 
111
    jpeg_create_decompress(&cinfo);
 
112
    Gwenview::IODeviceJpegSourceManager::setup(&cinfo, ioDevice);
 
113
    jpeg_read_header(&cinfo, true);
 
114
 
 
115
    size = QSize(cinfo.image_width, cinfo.image_height);
 
116
    jpeg_destroy_decompress(&cinfo);
 
117
    return size;
 
118
}
 
119
 
 
120
static bool loadJpeg(QImage* image, QIODevice* ioDevice, QSize scaledSize)
 
121
{
 
122
    struct jpeg_decompress_struct cinfo;
 
123
 
 
124
    // Error handling
 
125
    struct JpegFatalError jerr;
 
126
    cinfo.err = jpeg_std_error(&jerr);
 
127
    cinfo.err->error_exit = JpegFatalError::handler;
 
128
    if (setjmp(jerr.mJmpBuffer)) {
 
129
        jpeg_destroy_decompress(&cinfo);
 
130
        return false;
 
131
    }
 
132
 
 
133
    // Init decompression
 
134
    jpeg_create_decompress(&cinfo);
 
135
    Gwenview::IODeviceJpegSourceManager::setup(&cinfo, ioDevice);
 
136
    jpeg_read_header(&cinfo, true);
 
137
 
 
138
    // Compute scale value
 
139
    cinfo.scale_num = 1;
 
140
    if (!scaledSize.isEmpty()) {
 
141
        // Use !scaledSize.isEmpty(), not scaledSize.isValid() because
 
142
        // isValid() returns true if both the width and height is equal to or
 
143
        // greater than 0, so it is possible to get a division by 0.
 
144
        cinfo.scale_denom = qMin(cinfo.image_width / scaledSize.width(),
 
145
                                 cinfo.image_height / scaledSize.height());
 
146
        if (cinfo.scale_denom < 2) {
 
147
            cinfo.scale_denom = 1;
 
148
        } else if (cinfo.scale_denom < 4) {
 
149
            cinfo.scale_denom = 2;
 
150
        } else if (cinfo.scale_denom < 8) {
 
151
            cinfo.scale_denom = 4;
 
152
        } else {
 
153
            cinfo.scale_denom = 8;
 
154
        }
 
155
    } else {
 
156
        cinfo.scale_denom = 1;
 
157
    }
 
158
    LOG("cinfo.scale_denom=" << cinfo.scale_denom);
 
159
 
 
160
    // Init image
 
161
    jpeg_start_decompress(&cinfo);
 
162
    switch (cinfo.output_components) {
 
163
    case 3:
 
164
    case 4:
 
165
        *image = QImage(cinfo.output_width, cinfo.output_height, QImage::Format_RGB32);
 
166
        break;
 
167
    case 1: // B&W image
 
168
        *image = QImage(cinfo.output_width, cinfo.output_height, QImage::Format_Indexed8);
 
169
        image->setNumColors(256);
 
170
        for (int i = 0; i < 256; ++i) {
 
171
            image->setColor(i, qRgba(i, i, i, 255));
 
172
        }
 
173
        break;
 
174
    default:
 
175
        jpeg_destroy_decompress(&cinfo);
 
176
        return false;
 
177
    }
 
178
 
 
179
    while (cinfo.output_scanline < cinfo.output_height) {
 
180
        uchar *line = image->scanLine(cinfo.output_scanline);
 
181
        jpeg_read_scanlines(&cinfo, &line, 1);
 
182
    }
 
183
 
 
184
    switch (cinfo.out_color_space) {
 
185
    case JCS_CMYK:
 
186
        convertCmykToRgb(image);
 
187
        break;
 
188
    case JCS_RGB:
 
189
    case JCS_GRAYSCALE:
 
190
        break;
 
191
    default:
 
192
        kWarning() << "Unhandled JPEG colorspace" << cinfo.out_color_space;
 
193
        break;
 
194
    }
 
195
 
 
196
    if (cinfo.output_components == 3) {
 
197
        expand24to32bpp(image);
 
198
    }
 
199
 
 
200
    if (scaledSize.isValid()) {
 
201
        *image = image->scaled(scaledSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
 
202
    }
 
203
 
 
204
    jpeg_finish_decompress(&cinfo);
 
205
    jpeg_destroy_decompress(&cinfo);
 
206
 
 
207
    return true;
 
208
}
209
209
 
210
210
/****************************************************************************
211
211
This code is a copy of qjpeghandler.cpp because I can't find a way to fallback
220
220
extern "C" {
221
221
#endif
222
222
 
223
 
static void my_error_exit (j_common_ptr cinfo)
224
 
{
225
 
    my_error_mgr* myerr = (my_error_mgr*) cinfo->err;
226
 
    char buffer[JMSG_LENGTH_MAX];
227
 
    (*cinfo->err->format_message)(cinfo, buffer);
228
 
    qWarning("%s", buffer);
229
 
    longjmp(myerr->setjmp_buffer, 1);
230
 
}
 
223
    static void my_error_exit(j_common_ptr cinfo)
 
224
    {
 
225
        my_error_mgr* myerr = (my_error_mgr*) cinfo->err;
 
226
        char buffer[JMSG_LENGTH_MAX];
 
227
        (*cinfo->err->format_message)(cinfo, buffer);
 
228
        qWarning("%s", buffer);
 
229
        longjmp(myerr->setjmp_buffer, 1);
 
230
    }
231
231
 
232
232
#if defined(Q_C_CALLBACKS)
233
233
}
234
234
#endif
235
235
 
236
 
 
237
236
static const int max_buf = 4096;
238
237
 
239
238
struct my_jpeg_destination_mgr : public jpeg_destination_mgr {
245
244
    my_jpeg_destination_mgr(QIODevice *);
246
245
};
247
246
 
248
 
 
249
247
#if defined(Q_C_CALLBACKS)
250
248
extern "C" {
251
249
#endif
252
250
 
253
 
static void qt_init_destination(j_compress_ptr)
254
 
{
255
 
}
256
 
 
257
 
static boolean qt_empty_output_buffer(j_compress_ptr cinfo)
258
 
{
259
 
    my_jpeg_destination_mgr* dest = (my_jpeg_destination_mgr*)cinfo->dest;
260
 
 
261
 
    int written = dest->device->write((char*)dest->buffer, max_buf);
262
 
    if (written == -1)
263
 
        (*cinfo->err->error_exit)((j_common_ptr)cinfo);
264
 
 
265
 
    dest->next_output_byte = dest->buffer;
266
 
    dest->free_in_buffer = max_buf;
 
251
    static void qt_init_destination(j_compress_ptr)
 
252
    {
 
253
    }
 
254
 
 
255
    static boolean qt_empty_output_buffer(j_compress_ptr cinfo)
 
256
    {
 
257
        my_jpeg_destination_mgr* dest = (my_jpeg_destination_mgr*)cinfo->dest;
 
258
 
 
259
        int written = dest->device->write((char*)dest->buffer, max_buf);
 
260
        if (written == -1)
 
261
            (*cinfo->err->error_exit)((j_common_ptr)cinfo);
 
262
 
 
263
        dest->next_output_byte = dest->buffer;
 
264
        dest->free_in_buffer = max_buf;
267
265
 
268
266
#if defined(Q_OS_UNIXWARE)
269
 
    return B_TRUE;
 
267
        return B_TRUE;
270
268
#else
271
 
    return true;
 
269
        return true;
272
270
#endif
273
 
}
274
 
 
275
 
static void qt_term_destination(j_compress_ptr cinfo)
276
 
{
277
 
    my_jpeg_destination_mgr* dest = (my_jpeg_destination_mgr*)cinfo->dest;
278
 
    qint64 n = max_buf - dest->free_in_buffer;
279
 
 
280
 
    qint64 written = dest->device->write((char*)dest->buffer, n);
281
 
    if (written == -1)
282
 
        (*cinfo->err->error_exit)((j_common_ptr)cinfo);
283
 
}
 
271
    }
 
272
 
 
273
    static void qt_term_destination(j_compress_ptr cinfo)
 
274
    {
 
275
        my_jpeg_destination_mgr* dest = (my_jpeg_destination_mgr*)cinfo->dest;
 
276
        qint64 n = max_buf - dest->free_in_buffer;
 
277
 
 
278
        qint64 written = dest->device->write((char*)dest->buffer, n);
 
279
        if (written == -1)
 
280
            (*cinfo->err->error_exit)((j_common_ptr)cinfo);
 
281
    }
284
282
 
285
283
#if defined(Q_C_CALLBACKS)
286
284
}
296
294
    free_in_buffer = max_buf;
297
295
}
298
296
 
299
 
 
300
297
static bool write_jpeg_image(const QImage &sourceImage, QIODevice *device, int sourceQuality)
301
298
{
302
299
    bool success = false;
325
322
        cinfo.image_width = image.width();
326
323
        cinfo.image_height = image.height();
327
324
 
328
 
        bool gray=false;
 
325
        bool gray = false;
329
326
        switch (image.depth()) {
330
327
        case 1:
331
328
        case 8:
344
341
 
345
342
        jpeg_set_defaults(&cinfo);
346
343
 
347
 
        qreal diffInch = qAbs(image.dotsPerMeterX()*2.54/100. - qRound(image.dotsPerMeterX()*2.54/100.))
348
 
                         + qAbs(image.dotsPerMeterY()*2.54/100. - qRound(image.dotsPerMeterY()*2.54/100.));
349
 
        qreal diffCm = (qAbs(image.dotsPerMeterX()/100. - qRound(image.dotsPerMeterX()/100.))
350
 
                        + qAbs(image.dotsPerMeterY()/100. - qRound(image.dotsPerMeterY()/100.)))*2.54;
 
344
        qreal diffInch = qAbs(image.dotsPerMeterX() * 2.54 / 100. - qRound(image.dotsPerMeterX() * 2.54 / 100.))
 
345
                         + qAbs(image.dotsPerMeterY() * 2.54 / 100. - qRound(image.dotsPerMeterY() * 2.54 / 100.));
 
346
        qreal diffCm = (qAbs(image.dotsPerMeterX() / 100. - qRound(image.dotsPerMeterX() / 100.))
 
347
                        + qAbs(image.dotsPerMeterY() / 100. - qRound(image.dotsPerMeterY() / 100.))) * 2.54;
351
348
        if (diffInch < diffCm) {
352
349
            cinfo.density_unit = 1; // dots/inch
353
 
            cinfo.X_density = qRound(image.dotsPerMeterX()*2.54/100.);
354
 
            cinfo.Y_density = qRound(image.dotsPerMeterY()*2.54/100.);
 
350
            cinfo.X_density = qRound(image.dotsPerMeterX() * 2.54 / 100.);
 
351
            cinfo.Y_density = qRound(image.dotsPerMeterY() * 2.54 / 100.);
355
352
        } else {
356
353
            cinfo.density_unit = 2; // dots/cm
357
 
            cinfo.X_density = (image.dotsPerMeterX()+50) / 100;
358
 
            cinfo.Y_density = (image.dotsPerMeterY()+50) / 100;
 
354
            cinfo.X_density = (image.dotsPerMeterX() + 50) / 100;
 
355
            cinfo.Y_density = (image.dotsPerMeterY() + 50) / 100;
359
356
        }
360
357
 
361
 
 
362
 
        int quality = sourceQuality >= 0 ? qMin(sourceQuality,100) : 75;
 
358
        int quality = sourceQuality >= 0 ? qMin(sourceQuality, 100) : 75;
363
359
#if defined(Q_OS_UNIXWARE)
364
360
        jpeg_set_quality(&cinfo, quality, B_TRUE /* limit to baseline-JPEG values */);
365
361
        jpeg_start_compress(&cinfo, B_TRUE);
368
364
        jpeg_start_compress(&cinfo, true);
369
365
#endif
370
366
 
371
 
        row_pointer[0] = new uchar[cinfo.image_width*cinfo.input_components];
 
367
        row_pointer[0] = new uchar[cinfo.image_width * cinfo.input_components];
372
368
        int w = cinfo.image_width;
373
369
        while (cinfo.next_scanline < cinfo.image_height) {
374
370
            uchar *row = row_pointer[0];
377
373
                if (gray) {
378
374
                    const uchar* data = image.scanLine(cinfo.next_scanline);
379
375
                    if (image.format() == QImage::Format_MonoLSB) {
380
 
                        for (int i=0; i<w; i++) {
 
376
                        for (int i = 0; i < w; i++) {
381
377
                            bool bit = !!(*(data + (i >> 3)) & (1 << (i & 7)));
382
378
                            row[i] = qRed(cmap[bit]);
383
379
                        }
384
380
                    } else {
385
 
                        for (int i=0; i<w; i++) {
386
 
                            bool bit = !!(*(data + (i >> 3)) & (1 << (7 -(i & 7))));
 
381
                        for (int i = 0; i < w; i++) {
 
382
                            bool bit = !!(*(data + (i >> 3)) & (1 << (7 - (i & 7))));
387
383
                            row[i] = qRed(cmap[bit]);
388
384
                        }
389
385
                    }
390
386
                } else {
391
387
                    const uchar* data = image.scanLine(cinfo.next_scanline);
392
388
                    if (image.format() == QImage::Format_MonoLSB) {
393
 
                        for (int i=0; i<w; i++) {
 
389
                        for (int i = 0; i < w; i++) {
394
390
                            bool bit = !!(*(data + (i >> 3)) & (1 << (i & 7)));
395
391
                            *row++ = qRed(cmap[bit]);
396
392
                            *row++ = qGreen(cmap[bit]);
397
393
                            *row++ = qBlue(cmap[bit]);
398
394
                        }
399
395
                    } else {
400
 
                        for (int i=0; i<w; i++) {
401
 
                            bool bit = !!(*(data + (i >> 3)) & (1 << (7 -(i & 7))));
 
396
                        for (int i = 0; i < w; i++) {
 
397
                            bool bit = !!(*(data + (i >> 3)) & (1 << (7 - (i & 7))));
402
398
                            *row++ = qRed(cmap[bit]);
403
399
                            *row++ = qGreen(cmap[bit]);
404
400
                            *row++ = qBlue(cmap[bit]);
409
405
            case 8:
410
406
                if (gray) {
411
407
                    const uchar* pix = image.scanLine(cinfo.next_scanline);
412
 
                    for (int i=0; i<w; i++) {
 
408
                    for (int i = 0; i < w; i++) {
413
409
                        *row = qRed(cmap[*pix]);
414
410
                        ++row; ++pix;
415
411
                    }
416
412
                } else {
417
413
                    const uchar* pix = image.scanLine(cinfo.next_scanline);
418
 
                    for (int i=0; i<w; i++) {
 
414
                    for (int i = 0; i < w; i++) {
419
415
                        *row++ = qRed(cmap[*pix]);
420
416
                        *row++ = qGreen(cmap[*pix]);
421
417
                        *row++ = qBlue(cmap[*pix]);
425
421
                break;
426
422
            case 32: {
427
423
                QRgb* rgb = (QRgb*)image.scanLine(cinfo.next_scanline);
428
 
                for (int i=0; i<w; i++) {
 
424
                for (int i = 0; i < w; i++) {
429
425
                    *row++ = qRed(*rgb);
430
426
                    *row++ = qGreen(*rgb);
431
427
                    *row++ = qBlue(*rgb);
452
448
END_COPY
453
449
****************************************************************************/
454
450
 
455
 
 
456
 
 
457
451
struct JpegHandlerPrivate {
458
 
        QSize mScaledSize;
459
 
        int mQuality;
 
452
    QSize mScaledSize;
 
453
    int mQuality;
460
454
};
461
455
 
462
 
 
463
456
JpegHandler::JpegHandler()
464
 
: d(new JpegHandlerPrivate) {
465
 
        d->mQuality = 75;
466
 
}
467
 
 
468
 
 
469
 
JpegHandler::~JpegHandler() {
470
 
        delete d;
471
 
}
472
 
 
473
 
 
474
 
bool JpegHandler::canRead() const {
475
 
        if (canRead(device())) {
476
 
                setFormat("jpeg");
477
 
                return true;
478
 
        }
479
 
        return false;
480
 
}
481
 
 
482
 
 
483
 
bool JpegHandler::canRead(QIODevice* device) {
484
 
        if (!device) {
485
 
                kWarning() << "called with no device";
486
 
                return false;
487
 
        }
488
 
 
489
 
        return device->peek(2) == "\xFF\xD8";
490
 
}
491
 
 
492
 
 
493
 
bool JpegHandler::read(QImage* image) {
494
 
        LOG("");
495
 
        if (!canRead()) {
496
 
                return false;
497
 
        }
498
 
        return loadJpeg(image, device(), d->mScaledSize);
499
 
}
500
 
 
501
 
 
502
 
bool JpegHandler::write(const QImage& image) {
503
 
        LOG("");
504
 
        return write_jpeg_image(image, device(), d->mQuality);
505
 
}
506
 
 
507
 
 
508
 
bool JpegHandler::supportsOption(ImageOption option) const {
 
457
: d(new JpegHandlerPrivate)
 
458
{
 
459
    d->mQuality = 75;
 
460
}
 
461
 
 
462
JpegHandler::~JpegHandler()
 
463
{
 
464
    delete d;
 
465
}
 
466
 
 
467
bool JpegHandler::canRead() const
 
468
{
 
469
    if (canRead(device())) {
 
470
        setFormat("jpeg");
 
471
        return true;
 
472
    }
 
473
    return false;
 
474
}
 
475
 
 
476
bool JpegHandler::canRead(QIODevice* device)
 
477
{
 
478
    if (!device) {
 
479
        kWarning() << "called with no device";
 
480
        return false;
 
481
    }
 
482
 
 
483
    return device->peek(2) == "\xFF\xD8";
 
484
}
 
485
 
 
486
bool JpegHandler::read(QImage* image)
 
487
{
 
488
    LOG("");
 
489
    if (!canRead()) {
 
490
        return false;
 
491
    }
 
492
    return loadJpeg(image, device(), d->mScaledSize);
 
493
}
 
494
 
 
495
bool JpegHandler::write(const QImage& image)
 
496
{
 
497
    LOG("");
 
498
    return write_jpeg_image(image, device(), d->mQuality);
 
499
}
 
500
 
 
501
bool JpegHandler::supportsOption(ImageOption option) const
 
502
{
509
503
    return option == ScaledSize || option == Size || option == Quality;
510
504
}
511
505
 
512
 
 
513
 
QVariant JpegHandler::option(ImageOption option) const {
514
 
        if (option == ScaledSize) {
515
 
                return d->mScaledSize;
516
 
        } else if (option == Size) {
517
 
                if (canRead() && !device()->isSequential()) {
518
 
                        qint64 pos = device()->pos();
519
 
                        QSize size = getJpegSize(device());
520
 
                        device()->seek(pos);
521
 
                        return size;
522
 
                }
523
 
        } else if (option == Quality) {
524
 
                return d->mQuality;
525
 
        }
526
 
        return QVariant();
527
 
}
528
 
 
529
 
 
530
 
void JpegHandler::setOption(ImageOption option, const QVariant &value) {
531
 
        if (option == ScaledSize) {
532
 
                d->mScaledSize = value.toSize();
533
 
        } else if (option == Quality) {
534
 
                d->mQuality = value.toInt();
535
 
        }
536
 
}
537
 
 
 
506
QVariant JpegHandler::option(ImageOption option) const
 
507
{
 
508
    if (option == ScaledSize) {
 
509
        return d->mScaledSize;
 
510
    } else if (option == Size) {
 
511
        if (canRead() && !device()->isSequential()) {
 
512
            qint64 pos = device()->pos();
 
513
            QSize size = getJpegSize(device());
 
514
            device()->seek(pos);
 
515
            return size;
 
516
        }
 
517
    } else if (option == Quality) {
 
518
        return d->mQuality;
 
519
    }
 
520
    return QVariant();
 
521
}
 
522
 
 
523
void JpegHandler::setOption(ImageOption option, const QVariant &value)
 
524
{
 
525
    if (option == ScaledSize) {
 
526
        d->mScaledSize = value.toSize();
 
527
    } else if (option == Quality) {
 
528
        d->mQuality = value.toInt();
 
529
    }
 
530
}
538
531
 
539
532
} // namespace