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