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 | } |