Subversion Repositories Scribus

Rev

Rev 5947 | Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
5937 jghali 1
#include <qfile.h>
2
#include <setjmp.h>
3
#include "scconfig.h"
4
#include "scimgdataloader_jpeg.h"
5
#include "exif.h"
6
 
7
#ifdef HAVE_CMS
8
        #include CMS_INC
9
#endif
10
 
11
typedef struct my_error_mgr
12
{
13
        struct jpeg_error_mgr pub;            /* "public" fields */
14
        jmp_buf setjmp_buffer;  /* for return to caller */
15
} *my_error_ptr;
16
 
17
static void my_error_exit (j_common_ptr cinfo)
18
{
19
        my_error_ptr myerr = (my_error_ptr) cinfo->err;
20
        (*cinfo->err->output_message) (cinfo);
21
        longjmp (myerr->setjmp_buffer, 1);
22
}
23
 
24
#define ICC_MARKER  (JPEG_APP0 + 2)     /* JPEG marker code for ICC */
25
#define PHOTOSHOP_MARKER  (JPEG_APP0 + 13)      /* JPEG marker code for PHOTOSHOP */
26
#define ICC_OVERHEAD_LEN  14            /* size of non-profile data in APP2 */
27
#define MAX_BYTES_IN_MARKER  65533      /* maximum data len of a JPEG marker */
28
#define MAX_DATA_BYTES_IN_MARKER  (MAX_BYTES_IN_MARKER - ICC_OVERHEAD_LEN)
29
 
30
 
31
ScImgDataLoader_JPEG::ScImgDataLoader_JPEG(void)
32
{
33
        initSupportedFormatList();
34
}
35
 
36
void ScImgDataLoader_JPEG::initSupportedFormatList(void)
37
{
38
        m_supportedFormats.clear();
39
        m_supportedFormats.append( "jpg" );
40
        m_supportedFormats.append( "jpeg" );
41
}
42
 
43
void ScImgDataLoader_JPEG::loadEmbeddedProfile(const QString& fn)
44
{
45
        m_embeddedProfile.resize(0);
46
        m_profileComponents = 0;
47
#ifdef HAVE_CMS
48
        if (!QFile::exists(fn))
49
                return;
50
        struct jpeg_decompress_struct cinfo;
51
        struct my_error_mgr         jerr;
52
        FILE     *infile;
53
        cinfo.err = jpeg_std_error (&jerr.pub);
54
        jerr.pub.error_exit = my_error_exit;
55
        infile = NULL;
56
        if (setjmp (jerr.setjmp_buffer))
57
        {
58
                jpeg_destroy_decompress (&cinfo);
59
                if (infile)
60
                        fclose (infile);
61
                return;
62
        }
63
        jpeg_create_decompress (&cinfo);
64
        if ((infile = fopen (fn.local8Bit(), "rb")) == NULL)
65
                return;
66
        jpeg_stdio_src(&cinfo, infile);
67
        jpeg_save_markers(&cinfo, ICC_MARKER, 0xFFFF);
68
        jpeg_read_header(&cinfo, true);
69
        jpeg_start_decompress(&cinfo);
70
        unsigned int EmbedLen = 0;
71
        unsigned char* EmbedBuffer;
72
        if (read_jpeg_marker(ICC_MARKER,&cinfo, &EmbedBuffer, &EmbedLen))
73
        {
74
                cmsHPROFILE prof = cmsOpenProfileFromMem(EmbedBuffer, EmbedLen);
75
                if (prof)
76
                {
77
                        if (static_cast<int>(cmsGetColorSpace(prof)) == icSigRgbData)
78
                                m_profileComponents = 3;
79
                        if (static_cast<int>(cmsGetColorSpace(prof)) == icSigCmykData)
80
                                m_profileComponents = 4;
81
                        m_embeddedProfile.duplicate((const char*) EmbedBuffer, EmbedLen);
82
                }
83
                cmsCloseProfile(prof);
84
                free(EmbedBuffer);
85
        }
86
        (void) jpeg_finish_decompress(&cinfo);
87
        fclose (infile);
88
        jpeg_destroy_decompress (&cinfo);
89
#endif
90
}
91
 
92
void ScImgDataLoader_JPEG::preloadAlphaChannel(const QString& fn, int res)
93
{
94
        // No support for aplha in jpeg pictures
95
        initialize();
96
}
97
 
98
bool ScImgDataLoader_JPEG::loadPicture(const QString& fn, int res, bool thumbnail)
99
{
100
        bool isCMYK = false;
101
        float xres = 72.0, yres = 72.0;
102
        if (!QFile::exists(fn))
103
                return false;
104
        ExifData ExifInf;
105
        struct jpeg_decompress_struct cinfo;
106
        struct my_error_mgr         jerr;
107
        FILE     *infile;
108
        cinfo.err = jpeg_std_error (&jerr.pub);
109
        jerr.pub.error_exit = my_error_exit;
110
        infile = NULL;
111
 
112
        initialize();
113
        m_imageInfoRecord.type = 0;
114
        m_imageInfoRecord.exifInfo.thumbnail = QImage();
115
        if (setjmp (jerr.setjmp_buffer))
116
        {
117
                jpeg_destroy_decompress (&cinfo);
118
                if (infile)
119
                        fclose (infile);
120
                return false;
121
        }
122
        jpeg_create_decompress (&cinfo);
123
        if ((infile = fopen (fn.local8Bit(), "rb")) == NULL)
124
                return false;
125
        jpeg_stdio_src(&cinfo, infile);
126
        jpeg_save_markers(&cinfo, ICC_MARKER, 0xFFFF);
127
        jpeg_save_markers(&cinfo, PHOTOSHOP_MARKER, 0xFFFF);
128
        jpeg_read_header(&cinfo, true);
129
        jpeg_start_decompress(&cinfo);
130
        bool exi = ExifInf.scan(fn);
131
        if ((exi) && (ExifInf.exifDataValid))
132
        {
133
                if ((!ExifInf.isNullThumbnail()) && thumbnail)
134
                        m_image = ExifInf.getThumbnail();
135
                m_imageInfoRecord.exifInfo.cameraName = ExifInf.getCameraModel();
136
                m_imageInfoRecord.exifInfo.cameraVendor = ExifInf.getCameraMake();
137
                m_imageInfoRecord.exifInfo.thumbnail = ExifInf.getThumbnail();
138
                m_imageInfoRecord.exifInfo.comment = ExifInf.getComment();
139
                m_imageInfoRecord.exifInfo.width = ExifInf.getWidth();
140
                m_imageInfoRecord.exifInfo.height = ExifInf.getHeight();
141
                m_imageInfoRecord.exifInfo.userComment = ExifInf.getUserComment();
142
                m_imageInfoRecord.exifInfo.dateTime = ExifInf.getDateTime();
143
                m_imageInfoRecord.exifDataValid = true;
144
                if (cinfo.density_unit == 0)
145
                {
146
                        xres = 72;
147
                        yres = 72;
148
                }
149
                else if ( cinfo.density_unit == 1 )
150
                {
151
                        xres = cinfo.X_density;
152
                        yres = cinfo.Y_density;
153
                }
154
                else if ( cinfo.density_unit == 2 )
155
                {
156
                        xres = cinfo.X_density * 2.54;
157
                        yres = cinfo.Y_density * 2.54;
158
                }
159
                m_imageInfoRecord.xres = qRound(xres);
160
                m_imageInfoRecord.yres = qRound(yres);
161
                if (cinfo.output_components == 4)
162
                        m_imageInfoRecord.colorspace = 1;
163
                else if (cinfo.output_components == 3)
164
                        m_imageInfoRecord.colorspace = 0;
165
                else if (cinfo.output_components == 1)
166
                        m_imageInfoRecord.colorspace = 2;
167
                m_imageInfoRecord.progressive = jpeg_has_multiple_scans(&cinfo);
168
                if ((!ExifInf.isNullThumbnail()) && thumbnail)
169
                {
170
                        jpeg_destroy_decompress(&cinfo);
171
                        fclose(infile);
172
                        return true;
173
                }
174
        }
175
        else
176
                m_imageInfoRecord.exifDataValid = false;
177
#ifdef HAVE_CMS
178
        unsigned int EmbedLen = 0;
179
        unsigned char* EmbedBuffer;
180
        if (read_jpeg_marker(ICC_MARKER,&cinfo, &EmbedBuffer, &EmbedLen))
181
        {
182
                const char *Descriptor;
183
                cmsHPROFILE prof = cmsOpenProfileFromMem(EmbedBuffer, EmbedLen);
184
                Descriptor = cmsTakeProductDesc(prof);
185
                m_embeddedProfile.duplicate((const char*) EmbedBuffer, EmbedLen);
186
                m_imageInfoRecord.profileName = QString(Descriptor);
187
                m_imageInfoRecord.isEmbedded = true;
188
                free(EmbedBuffer);
189
        }
190
        else
191
        {
192
                m_imageInfoRecord.isEmbedded = false;
193
                m_imageInfoRecord.profileName = "";
194
        }
195
#endif // HAVE_CMS
196
        unsigned int PhotoshopLen = 0;
197
        unsigned char * PhotoshopBuffer;
198
        if (cinfo.density_unit == 0)
199
        {
200
                xres = 72;
201
                yres = 72;
202
                m_image.setDotsPerMeterX(2834);
203
                m_image.setDotsPerMeterY(2834);
204
        }
205
        else if ( cinfo.density_unit == 1 )
206
        {
207
                xres = cinfo.X_density;
208
                yres = cinfo.Y_density;
209
                m_image.setDotsPerMeterX( int(100. * cinfo.X_density / 2.54) );
210
                m_image.setDotsPerMeterY( int(100. * cinfo.Y_density / 2.54) );
211
        }
212
        else if ( cinfo.density_unit == 2 )
213
        {
214
                xres = cinfo.X_density * 2.54;
215
                yres = cinfo.Y_density * 2.54;
216
                m_image.setDotsPerMeterX( int(100. * cinfo.X_density) );
217
                m_image.setDotsPerMeterY( int(100. * cinfo.Y_density) );
218
        }
219
        m_imageInfoRecord.xres = qRound(xres);
220
        m_imageInfoRecord.yres = qRound(yres);
221
        if (cinfo.output_components == 4)
222
        {
223
                isCMYK = true;
224
                m_imageInfoRecord.colorspace = 1;
225
        }
226
        else if (cinfo.output_components == 3)
227
                m_imageInfoRecord.colorspace = 0;
228
        else if (cinfo.output_components == 1)
229
                m_imageInfoRecord.colorspace = 2;
230
        m_imageInfoRecord.progressive = jpeg_has_multiple_scans(&cinfo);
231
 
232
        if (read_jpeg_marker(PHOTOSHOP_MARKER,&cinfo, &PhotoshopBuffer, &PhotoshopLen) )
233
        {
234
                if (PhotoshopLen != 0)
235
                {
236
                        bool savEx = m_imageInfoRecord.exifDataValid;
237
                        QByteArray arrayPhot(PhotoshopLen);
238
                        arrayPhot.setRawData((const char*)PhotoshopBuffer,PhotoshopLen);
239
                        QDataStream strPhot(arrayPhot,IO_ReadOnly);
240
                        strPhot.setByteOrder( QDataStream::BigEndian );
241
                        PSDHeader fakeHeader;
242
                        fakeHeader.width = cinfo.output_width;
243
                        fakeHeader.height = cinfo.output_height;
244
                        if (cinfo.output_components == 4)
245
                                m_imageInfoRecord.colorspace = 1;
246
                        else if (cinfo.output_components == 3)
247
                                m_imageInfoRecord.colorspace = 0;
248
                        else if (cinfo.output_components == 1)
249
                                m_imageInfoRecord.colorspace = 2;
250
                        m_imageInfoRecord.progressive = jpeg_has_multiple_scans(&cinfo);
251
                        parseRessourceData(strPhot, fakeHeader, PhotoshopLen);
252
                        // Photoshop resolution is more accurate than jpeg header resolution
253
                        xres = m_imageInfoRecord.xres;
254
                        yres = m_imageInfoRecord.yres;
255
                        m_image.setDotsPerMeterX( int(100. * m_imageInfoRecord.xres / 2.54) );
256
                        m_image.setDotsPerMeterY( int(100. * m_imageInfoRecord.yres / 2.54) );
257
                        m_imageInfoRecord.valid = (m_imageInfoRecord.PDSpathData.size())>0?true:false; // The only interest is vectormask
258
                        arrayPhot.resetRawData((const char*)PhotoshopBuffer,PhotoshopLen);
259
                        free( PhotoshopBuffer );
260
                        m_imageInfoRecord.exifDataValid = savEx;
261
                }
262
        }
263
        if ( cinfo.output_components == 3 || cinfo.output_components == 4)
264
                m_image.create( cinfo.output_width, cinfo.output_height, 32 );
265
        else if ( cinfo.output_components == 1 )
266
        {
267
                m_image.create( cinfo.output_width, cinfo.output_height, 8, 256 );
268
                for (int i=0; i<256; i++)
269
                        m_image.setColor(i, qRgb(i,i,i));
270
        }
271
        if (!m_image.isNull())
272
        {
273
                uchar** lines = m_image.jumpTable();
274
                while (cinfo.output_scanline < cinfo.output_height)
275
                        (void) jpeg_read_scanlines(&cinfo, lines + cinfo.output_scanline, cinfo.output_height);
276
                if ( cinfo.output_components == 3 )
277
                {
278
                        for (uint j=0; j<cinfo.output_height; j++)
279
                        {
280
                                uchar *in = m_image.scanLine(j) + cinfo.output_width * 3;
281
                                QRgb *out = (QRgb*) m_image.scanLine(j);
282
                                for (uint i=cinfo.output_width; i--; )
283
                                {
284
                                        in -= 3;
285
                                        out[i] = qRgb(in[0], in[1], in[2]);
286
                                }
287
                        }
288
                }
289
                if ( cinfo.output_components == 4 )
290
                {
291
                        for (int i = 0; i < m_image.height(); i++)
292
                        {
293
                                QRgb *ptr = (QRgb*)  m_image.scanLine(i);
294
                                unsigned char c, m, y ,k;
295
                                if ((cinfo.jpeg_color_space == JCS_YCCK) || ((cinfo.jpeg_color_space == JCS_CMYK) && (cinfo.saw_Adobe_marker)))
296
                                {
297
                                        for (int j = 0; j <  m_image.width(); j++)
298
                                        {
299
                                                unsigned char *p = (unsigned char *) ptr;
300
                                                c = p[0];
301
                                                m = p[1];
302
                                                y =  p[2];
303
                                                k =  p[3];
304
                                                *ptr = qRgba(255 - c, 255 - m, 255 - y, 255 - k);
305
                                                ptr++;
306
                                        }
307
                                }
308
                                else
309
                                {
310
                                        for (int j = 0; j <  m_image.width(); j++)
311
                                        {
312
                                                unsigned char *p = (unsigned char *) ptr;
313
                                                c = p[0];
314
                                                m = p[1];
315
                                                y =  p[2];
316
                                                k =  p[3];
317
                                                *ptr = qRgba(y, m, c, k);
318
                                                ptr++;
319
                                        }
320
                                }
321
                        }
322
                        isCMYK = true;
323
                }
324
                else
325
                        isCMYK = false;
326
                if ( cinfo.output_components == 1 )
327
                {
328
                        QImage tmpImg = m_image.convertDepth(32);
329
                         m_image.create( cinfo.output_width, cinfo.output_height, 32 );
330
                        for( int yi=0; yi < tmpImg.height(); ++yi )
331
                        {
332
                                QRgb *s = (QRgb*)(tmpImg.scanLine( yi ));
333
                                QRgb *d = (QRgb*)(m_image.scanLine( yi ));
334
                                for(int xi=0; xi < tmpImg.width(); ++xi )
335
                                {
336
                                        (*d) = (*s);
337
                                        s++;
338
                                        d++;
339
                                }
340
                        }
341
                }
342
                m_image.setAlphaBuffer(true);
343
        }
344
        (void) jpeg_finish_decompress(&cinfo);
345
        fclose (infile);
346
        jpeg_destroy_decompress (&cinfo);
347
        m_imageInfoRecord.layerInfo.clear();
348
        m_imageInfoRecord.BBoxX = 0;
349
        m_imageInfoRecord.BBoxH = m_image.height();
350
        return (!m_image.isNull());
351
}
352
 
353
bool ScImgDataLoader_JPEG::marker_is_icc (jpeg_saved_marker_ptr marker)
354
{
355
        return
356
            marker->marker == ICC_MARKER &&
357
            marker->data_length >= ICC_OVERHEAD_LEN &&
358
            /* verify the identifying string */
359
            GETJOCTET(marker->data[0]) == 0x49 &&
360
            GETJOCTET(marker->data[1]) == 0x43 &&
361
            GETJOCTET(marker->data[2]) == 0x43 &&
362
            GETJOCTET(marker->data[3]) == 0x5F &&
363
            GETJOCTET(marker->data[4]) == 0x50 &&
364
            GETJOCTET(marker->data[5]) == 0x52 &&
365
            GETJOCTET(marker->data[6]) == 0x4F &&
366
            GETJOCTET(marker->data[7]) == 0x46 &&
367
            GETJOCTET(marker->data[8]) == 0x49 &&
368
            GETJOCTET(marker->data[9]) == 0x4C &&
369
            GETJOCTET(marker->data[10]) == 0x45 &&
370
            GETJOCTET(marker->data[11]) == 0x0;
371
}
372
 
373
bool ScImgDataLoader_JPEG::marker_is_photoshop (jpeg_saved_marker_ptr marker)
374
{
375
        return
376
            marker->marker == PHOTOSHOP_MARKER &&
377
            marker->data_length >= ICC_OVERHEAD_LEN &&
378
            /* verify the identifying string */
379
            GETJOCTET(marker->data[0]) == 0x50 &&
380
            GETJOCTET(marker->data[1]) == 0x68 &&
381
            GETJOCTET(marker->data[2]) == 0x6F &&
382
            GETJOCTET(marker->data[3]) == 0x74 &&
383
            GETJOCTET(marker->data[4]) == 0x6F &&
384
            GETJOCTET(marker->data[5]) == 0x73 &&
385
            GETJOCTET(marker->data[6]) == 0x68 &&
386
            GETJOCTET(marker->data[7]) == 0x6F &&
387
            GETJOCTET(marker->data[8]) == 0x70 &&
388
            GETJOCTET(marker->data[9]) == 0x20 &&
389
            GETJOCTET(marker->data[10]) == 0x33 &&
390
            GETJOCTET(marker->data[11]) == 0x2E &&
391
            GETJOCTET(marker->data[12]) == 0x30 &&
392
            GETJOCTET(marker->data[13]) == 0x0;
393
}
394
 
395
/* Small modification of original read_icc_profile method from jpegicc of lcms project
396
 * to enable read of Photoshop marker
397
 */
398
bool ScImgDataLoader_JPEG::read_jpeg_marker (UINT8 requestmarker, j_decompress_ptr cinfo, JOCTET **icc_data_ptr, unsigned int *icc_data_len)
399
{
400
        jpeg_saved_marker_ptr marker;
401
        int num_markers = 0;
402
        int seq_no;
403
        JOCTET *icc_data;
404
        unsigned int total_length;
405
#define MAX_SEQ_NO  255         /* sufficient since marker numbers are bytes */
406
        char marker_present[MAX_SEQ_NO+1];        /* 1 if marker found */
407
        unsigned int data_length[MAX_SEQ_NO+1]; /* size of profile data in marker */
408
        unsigned int data_offset[MAX_SEQ_NO+1]; /* offset for data in marker */
409
 
410
        *icc_data_ptr = NULL;           /* avoid confusion if false return */
411
        *icc_data_len = 0;
412
 
413
        /* This first pass over the saved markers discovers whether there are
414
         * any ICC markers and verifies the consistency of the marker numbering.
415
         */
416
 
417
        for (seq_no = 1; seq_no <= MAX_SEQ_NO; seq_no++)
418
                marker_present[seq_no] = 0;
419
        seq_no = 0;
420
        for (marker = cinfo->marker_list; marker != NULL; marker = marker->next)
421
        {
422
                if (requestmarker == ICC_MARKER && marker_is_icc(marker))
423
                {
424
                        if (num_markers == 0)
425
                                num_markers = GETJOCTET(marker->data[13]);
426
                        else if (num_markers != GETJOCTET(marker->data[13]))
427
                                return false;           /* inconsistent num_markers fields */
428
                        seq_no = GETJOCTET(marker->data[12]);
429
                        if (seq_no <= 0 || seq_no > num_markers)
430
                                return false;           /* bogus sequence number */
431
                        if (marker_present[seq_no])
432
                                return false;           /* duplicate sequence numbers */
433
                        marker_present[seq_no] = 1;
434
                        data_length[seq_no] = marker->data_length - ICC_OVERHEAD_LEN;
435
                }
436
                else if(requestmarker == PHOTOSHOP_MARKER && marker_is_photoshop(marker))
437
                {
438
                        num_markers = ++seq_no;
439
                        marker_present[seq_no] = 1;
440
                        data_length[seq_no] = marker->data_length - ICC_OVERHEAD_LEN;
441
                }
442
        }
443
 
444
        if (num_markers == 0)
445
                return false;
446
 
447
        /* Check for missing markers, count total space needed,
448
         * compute offset of each marker's part of the data.
449
         */
450
 
451
        total_length = 0;
452
        for (seq_no = 1; seq_no <= num_markers; seq_no++)
453
        {
454
                if (marker_present[seq_no] == 0)
455
                        return false;           /* missing sequence number */
456
                data_offset[seq_no] = total_length;
457
                total_length += data_length[seq_no];
458
        }
459
 
460
        if (total_length <= 0)
461
                return false;           /* found only empty markers? */
462
 
463
        /* Allocate space for assembled data */
464
        icc_data = (JOCTET *) malloc(total_length * sizeof(JOCTET));
465
        if (icc_data == NULL)
466
                return false;           /* oops, out of memory */
467
        seq_no=0;
468
        /* and fill it in */
469
        for (marker = cinfo->marker_list; marker != NULL; marker = marker->next)
470
        {
471
                if ( (requestmarker == ICC_MARKER && marker_is_icc(marker)) ||
472
                        (requestmarker == PHOTOSHOP_MARKER && marker_is_photoshop(marker)) || (requestmarker == 0xE1))
473
                {
474
                        JOCTET FAR *src_ptr;
475
                        JOCTET *dst_ptr;
476
                        unsigned int length;
477
                        if(requestmarker == ICC_MARKER)
478
                                seq_no = GETJOCTET(marker->data[12]);
479
                        else if(requestmarker == PHOTOSHOP_MARKER)
480
                                seq_no++;
481
                        dst_ptr = icc_data + data_offset[seq_no];
482
                        src_ptr = marker->data + ICC_OVERHEAD_LEN;
483
                        length = data_length[seq_no];
484
                        while (length--)
485
                        {
486
                                *dst_ptr++ = *src_ptr++;
487
                        }
488
                }
489
        }
490
 
491
        *icc_data_ptr = icc_data;
492
        *icc_data_len = total_length;
493
 
494
        return true;
495
}