Subversion Repositories Scribus

Rev

Rev 5949 | Rev 6158 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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