1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 : *
3 : * ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
6 : * The contents of this file are subject to the Mozilla Public License Version
7 : * 1.1 (the "License"); you may not use this file except in compliance with
8 : * the License. You may obtain a copy of the License at
9 : * http://www.mozilla.org/MPL/
10 : *
11 : * Software distributed under the License is distributed on an "AS IS" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is mozilla.org code.
17 : *
18 : * The Initial Developer of the Original Code is
19 : * Netscape Communications Corporation.
20 : * Portions created by the Initial Developer are Copyright (C) 2001
21 : * the Initial Developer. All Rights Reserved.
22 : *
23 : * Contributor(s):
24 : * Stuart Parmenter <stuart@mozilla.com>
25 : * Federico Mena-Quintero <federico@novell.com>
26 : * Bobby Holley <bobbyholley@gmail.com>
27 : *
28 : * Alternatively, the contents of this file may be used under the terms of
29 : * either the GNU General Public License Version 2 or later (the "GPL"), or
30 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
31 : * in which case the provisions of the GPL or the LGPL are applicable instead
32 : * of those above. If you wish to allow use of your version of this file only
33 : * under the terms of either the GPL or the LGPL, and not to allow others to
34 : * use your version of this file under the terms of the MPL, indicate your
35 : * decision by deleting the provisions above and replace them with the notice
36 : * and other provisions required by the GPL or the LGPL. If you do not delete
37 : * the provisions above, a recipient may use your version of this file under
38 : * the terms of any one of the MPL, the GPL or the LGPL.
39 : *
40 : * ***** END LICENSE BLOCK ***** */
41 :
42 : #include "nsJPEGDecoder.h"
43 : #include "ImageLogging.h"
44 :
45 : #include "imgIContainerObserver.h"
46 :
47 : #include "nsIInputStream.h"
48 :
49 : #include "nspr.h"
50 : #include "nsCRT.h"
51 : #include "gfxColor.h"
52 :
53 : #include "jerror.h"
54 :
55 : #include "gfxPlatform.h"
56 :
57 : extern "C" {
58 : #include "iccjpeg.h"
59 :
60 : /* Colorspace conversion (copied from jpegint.h) */
61 : struct jpeg_color_deconverter {
62 : JMETHOD(void, start_pass, (j_decompress_ptr cinfo));
63 : JMETHOD(void, color_convert, (j_decompress_ptr cinfo,
64 : JSAMPIMAGE input_buf, JDIMENSION input_row,
65 : JSAMPARRAY output_buf, int num_rows));
66 : };
67 :
68 : METHODDEF(void)
69 : ycc_rgb_convert_argb (j_decompress_ptr cinfo,
70 : JSAMPIMAGE input_buf, JDIMENSION input_row,
71 : JSAMPARRAY output_buf, int num_rows);
72 : }
73 :
74 : static void cmyk_convert_rgb(JSAMPROW row, JDIMENSION width);
75 :
76 : namespace mozilla {
77 : namespace image {
78 :
79 : #if defined(PR_LOGGING)
80 1464 : PRLogModuleInfo *gJPEGlog = PR_NewLogModule("JPEGDecoder");
81 1464 : static PRLogModuleInfo *gJPEGDecoderAccountingLog = PR_NewLogModule("JPEGDecoderAccounting");
82 : #else
83 : #define gJPEGlog
84 : #define gJPEGDecoderAccountingLog
85 : #endif
86 :
87 : static qcms_profile*
88 5 : GetICCProfile(struct jpeg_decompress_struct &info)
89 : {
90 : JOCTET* profilebuf;
91 : PRUint32 profileLength;
92 5 : qcms_profile* profile = nsnull;
93 :
94 5 : if (read_icc_profile(&info, &profilebuf, &profileLength)) {
95 0 : profile = qcms_profile_from_memory(profilebuf, profileLength);
96 0 : free(profilebuf);
97 : }
98 :
99 5 : return profile;
100 : }
101 :
102 : METHODDEF(void) init_source (j_decompress_ptr jd);
103 : METHODDEF(boolean) fill_input_buffer (j_decompress_ptr jd);
104 : METHODDEF(void) skip_input_data (j_decompress_ptr jd, long num_bytes);
105 : METHODDEF(void) term_source (j_decompress_ptr jd);
106 : METHODDEF(void) my_error_exit (j_common_ptr cinfo);
107 :
108 : /* Normal JFIF markers can't have more bytes than this. */
109 : #define MAX_JPEG_MARKER_LENGTH (((PRUint32)1 << 16) - 1)
110 :
111 :
112 5 : nsJPEGDecoder::nsJPEGDecoder(RasterImage &aImage, imgIDecoderObserver* aObserver)
113 5 : : Decoder(aImage, aObserver)
114 : {
115 5 : mState = JPEG_HEADER;
116 5 : mReading = true;
117 5 : mImageData = nsnull;
118 :
119 5 : mBytesToSkip = 0;
120 5 : memset(&mInfo, 0, sizeof(jpeg_decompress_struct));
121 5 : memset(&mSourceMgr, 0, sizeof(mSourceMgr));
122 5 : mInfo.client_data = (void*)this;
123 :
124 5 : mSegment = nsnull;
125 5 : mSegmentLen = 0;
126 :
127 5 : mBackBuffer = nsnull;
128 5 : mBackBufferLen = mBackBufferSize = mBackBufferUnreadLen = 0;
129 :
130 5 : mInProfile = nsnull;
131 5 : mTransform = nsnull;
132 :
133 5 : mCMSMode = 0;
134 :
135 5 : PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
136 : ("nsJPEGDecoder::nsJPEGDecoder: Creating JPEG decoder %p",
137 : this));
138 5 : }
139 :
140 15 : nsJPEGDecoder::~nsJPEGDecoder()
141 : {
142 : // Step 8: Release JPEG decompression object
143 5 : mInfo.src = nsnull;
144 5 : jpeg_destroy_decompress(&mInfo);
145 :
146 5 : PR_FREEIF(mBackBuffer);
147 5 : if (mTransform)
148 0 : qcms_transform_release(mTransform);
149 5 : if (mInProfile)
150 0 : qcms_profile_release(mInProfile);
151 :
152 5 : PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
153 : ("nsJPEGDecoder::~nsJPEGDecoder: Destroying JPEG decoder %p",
154 : this));
155 20 : }
156 :
157 : Telemetry::ID
158 0 : nsJPEGDecoder::SpeedHistogram()
159 : {
160 0 : return Telemetry::IMAGE_DECODE_SPEED_JPEG;
161 : }
162 :
163 : void
164 5 : nsJPEGDecoder::InitInternal()
165 : {
166 5 : mCMSMode = gfxPlatform::GetCMSMode();
167 5 : if ((mDecodeFlags & DECODER_NO_COLORSPACE_CONVERSION) != 0)
168 0 : mCMSMode = eCMSMode_Off;
169 :
170 : /* We set up the normal JPEG error routines, then override error_exit. */
171 5 : mInfo.err = jpeg_std_error(&mErr.pub);
172 : /* mInfo.err = jpeg_std_error(&mErr.pub); */
173 5 : mErr.pub.error_exit = my_error_exit;
174 : /* Establish the setjmp return context for my_error_exit to use. */
175 5 : if (setjmp(mErr.setjmp_buffer)) {
176 : /* If we get here, the JPEG code has signaled an error.
177 : * We need to clean up the JPEG object, close the input file, and return.
178 : */
179 0 : PostDecoderError(NS_ERROR_FAILURE);
180 0 : return;
181 : }
182 :
183 : /* Step 1: allocate and initialize JPEG decompression object */
184 5 : jpeg_create_decompress(&mInfo);
185 : /* Set the source manager */
186 5 : mInfo.src = &mSourceMgr;
187 :
188 : /* Step 2: specify data source (eg, a file) */
189 :
190 : /* Setup callback functions. */
191 5 : mSourceMgr.init_source = init_source;
192 5 : mSourceMgr.fill_input_buffer = fill_input_buffer;
193 5 : mSourceMgr.skip_input_data = skip_input_data;
194 5 : mSourceMgr.resync_to_restart = jpeg_resync_to_restart;
195 5 : mSourceMgr.term_source = term_source;
196 :
197 : /* Record app markers for ICC data */
198 85 : for (PRUint32 m = 0; m < 16; m++)
199 80 : jpeg_save_markers(&mInfo, JPEG_APP0 + m, 0xFFFF);
200 : }
201 :
202 : void
203 5 : nsJPEGDecoder::FinishInternal()
204 : {
205 : /* If we're not in any sort of error case, flush the decoder.
206 : *
207 : * XXXbholley - It seems wrong that this should be necessary, but at the
208 : * moment I'm just folding the contents of Flush() into Close() so that
209 : * we can get rid of it.
210 : */
211 5 : if ((mState != JPEG_DONE && mState != JPEG_SINK_NON_JPEG_TRAILER) &&
212 : (mState != JPEG_ERROR) &&
213 0 : !IsSizeDecode())
214 0 : this->Write(nsnull, 0);
215 5 : }
216 :
217 : void
218 8 : nsJPEGDecoder::WriteInternal(const char *aBuffer, PRUint32 aCount)
219 : {
220 8 : mSegment = (const JOCTET *)aBuffer;
221 8 : mSegmentLen = aCount;
222 :
223 8 : NS_ABORT_IF_FALSE(!HasError(), "Shouldn't call WriteInternal after error!");
224 :
225 : /* Return here if there is a fatal error within libjpeg. */
226 : nsresult error_code;
227 8 : if ((error_code = setjmp(mErr.setjmp_buffer)) != 0) {
228 0 : if (error_code == NS_ERROR_FAILURE) {
229 0 : PostDataError();
230 : /* Error due to corrupt stream - return NS_OK and consume silently
231 : so that libpr0n doesn't throw away a partial image load */
232 0 : mState = JPEG_SINK_NON_JPEG_TRAILER;
233 0 : PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
234 : ("} (setjmp returned NS_ERROR_FAILURE)"));
235 0 : return;
236 : } else {
237 : /* Error due to reasons external to the stream (probably out of
238 : memory) - let libpr0n attempt to clean up, even though
239 : mozilla is seconds away from falling flat on its face. */
240 0 : PostDecoderError(error_code);
241 0 : mState = JPEG_ERROR;
242 0 : PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
243 : ("} (setjmp returned an error)"));
244 0 : return;
245 : }
246 : }
247 :
248 8 : PR_LOG(gJPEGlog, PR_LOG_DEBUG,
249 : ("[this=%p] nsJPEGDecoder::Write -- processing JPEG data\n", this));
250 :
251 8 : switch (mState) {
252 : case JPEG_HEADER:
253 : {
254 12 : LOG_SCOPE(gJPEGlog, "nsJPEGDecoder::Write -- entering JPEG_HEADER case");
255 :
256 : /* Step 3: read file parameters with jpeg_read_header() */
257 6 : if (jpeg_read_header(&mInfo, TRUE) == JPEG_SUSPENDED) {
258 1 : PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
259 : ("} (JPEG_SUSPENDED)"));
260 : return; /* I/O suspension */
261 : }
262 :
263 : // Post our size to the superclass
264 5 : PostSize(mInfo.image_width, mInfo.image_height);
265 5 : if (HasError()) {
266 : // Setting the size lead to an error; this can happen when for example
267 : // a multipart channel sends an image of a different size.
268 0 : mState = JPEG_ERROR;
269 : return;
270 : }
271 :
272 : /* If we're doing a size decode, we're done. */
273 5 : if (IsSizeDecode())
274 : return;
275 :
276 : /* We're doing a full decode. */
277 10 : if (mCMSMode != eCMSMode_Off &&
278 5 : (mInProfile = GetICCProfile(mInfo)) != nsnull) {
279 0 : PRUint32 profileSpace = qcms_profile_get_color_space(mInProfile);
280 0 : bool mismatch = false;
281 :
282 : #ifdef DEBUG_tor
283 : fprintf(stderr, "JPEG profileSpace: 0x%08X\n", profileSpace);
284 : #endif
285 0 : switch (mInfo.jpeg_color_space) {
286 : case JCS_GRAYSCALE:
287 0 : if (profileSpace == icSigRgbData)
288 0 : mInfo.out_color_space = JCS_RGB;
289 0 : else if (profileSpace != icSigGrayData)
290 0 : mismatch = true;
291 0 : break;
292 : case JCS_RGB:
293 0 : if (profileSpace != icSigRgbData)
294 0 : mismatch = true;
295 0 : break;
296 : case JCS_YCbCr:
297 0 : if (profileSpace == icSigRgbData)
298 0 : mInfo.out_color_space = JCS_RGB;
299 : else
300 : // qcms doesn't support ycbcr
301 0 : mismatch = true;
302 0 : break;
303 : case JCS_CMYK:
304 : case JCS_YCCK:
305 : // qcms doesn't support cmyk
306 0 : mismatch = true;
307 0 : break;
308 : default:
309 0 : mState = JPEG_ERROR;
310 0 : PostDataError();
311 0 : PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
312 : ("} (unknown colorpsace (1))"));
313 : return;
314 : }
315 :
316 0 : if (!mismatch) {
317 : qcms_data_type type;
318 0 : switch (mInfo.out_color_space) {
319 : case JCS_GRAYSCALE:
320 0 : type = QCMS_DATA_GRAY_8;
321 0 : break;
322 : case JCS_RGB:
323 0 : type = QCMS_DATA_RGB_8;
324 0 : break;
325 : default:
326 0 : mState = JPEG_ERROR;
327 0 : PostDataError();
328 0 : PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
329 : ("} (unknown colorpsace (2))"));
330 : return;
331 : }
332 : #if 0
333 : /* We don't currently support CMYK profiles. The following
334 : * code dealt with lcms types. Add something like this
335 : * back when we gain support for CMYK.
336 : */
337 : /* Adobe Photoshop writes YCCK/CMYK files with inverted data */
338 : if (mInfo.out_color_space == JCS_CMYK)
339 : type |= FLAVOR_SH(mInfo.saw_Adobe_marker ? 1 : 0);
340 : #endif
341 :
342 0 : if (gfxPlatform::GetCMSOutputProfile()) {
343 :
344 : /* Calculate rendering intent. */
345 0 : int intent = gfxPlatform::GetRenderingIntent();
346 0 : if (intent == -1)
347 0 : intent = qcms_profile_get_rendering_intent(mInProfile);
348 :
349 : /* Create the color management transform. */
350 : mTransform = qcms_transform_create(mInProfile,
351 : type,
352 : gfxPlatform::GetCMSOutputProfile(),
353 : QCMS_DATA_RGB_8,
354 0 : (qcms_intent)intent);
355 : }
356 : } else {
357 : #ifdef DEBUG_tor
358 : fprintf(stderr, "ICM profile colorspace mismatch\n");
359 : #endif
360 : }
361 : }
362 :
363 5 : if (!mTransform) {
364 5 : switch (mInfo.jpeg_color_space) {
365 : case JCS_GRAYSCALE:
366 : case JCS_RGB:
367 : case JCS_YCbCr:
368 5 : mInfo.out_color_space = JCS_RGB;
369 5 : break;
370 : case JCS_CMYK:
371 : case JCS_YCCK:
372 : /* libjpeg can convert from YCCK to CMYK, but not to RGB */
373 0 : mInfo.out_color_space = JCS_CMYK;
374 0 : break;
375 : default:
376 0 : mState = JPEG_ERROR;
377 0 : PostDataError();
378 0 : PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
379 : ("} (unknown colorpsace (3))"));
380 : return;
381 : break;
382 : }
383 : }
384 :
385 : /*
386 : * Don't allocate a giant and superfluous memory buffer
387 : * when the image is a sequential JPEG.
388 : */
389 5 : mInfo.buffered_image = jpeg_has_multiple_scans(&mInfo);
390 :
391 : /* Used to set up image size so arrays can be allocated */
392 5 : jpeg_calc_output_dimensions(&mInfo);
393 :
394 : PRUint32 imagelength;
395 5 : if (NS_FAILED(mImage.EnsureFrame(0, 0, 0, mInfo.image_width, mInfo.image_height,
396 : gfxASurface::ImageFormatRGB24,
397 : &mImageData, &imagelength))) {
398 0 : mState = JPEG_ERROR;
399 0 : PostDecoderError(NS_ERROR_OUT_OF_MEMORY);
400 0 : PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
401 : ("} (could not initialize image frame)"));
402 : return;
403 : }
404 :
405 5 : PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
406 : (" JPEGDecoderAccounting: nsJPEGDecoder::Write -- created image frame with %ux%u pixels",
407 : mInfo.image_width, mInfo.image_height));
408 :
409 : // Tell the superclass we're starting a frame
410 5 : PostFrameStart();
411 :
412 11 : mState = JPEG_START_DECOMPRESS;
413 : }
414 :
415 : case JPEG_START_DECOMPRESS:
416 : {
417 10 : LOG_SCOPE(gJPEGlog, "nsJPEGDecoder::Write -- entering JPEG_START_DECOMPRESS case");
418 : /* Step 4: set parameters for decompression */
419 :
420 : /* FIXME -- Should reset dct_method and dither mode
421 : * for final pass of progressive JPEG
422 : */
423 5 : mInfo.dct_method = JDCT_ISLOW;
424 5 : mInfo.dither_mode = JDITHER_FS;
425 5 : mInfo.do_fancy_upsampling = TRUE;
426 5 : mInfo.enable_2pass_quant = FALSE;
427 5 : mInfo.do_block_smoothing = TRUE;
428 :
429 : /* Step 5: Start decompressor */
430 5 : if (jpeg_start_decompress(&mInfo) == FALSE) {
431 0 : PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
432 : ("} (I/O suspension after jpeg_start_decompress())"));
433 : return; /* I/O suspension */
434 : }
435 :
436 : /* Force to use our YCbCr to Packed RGB converter when possible */
437 5 : if (!mTransform && (mCMSMode != eCMSMode_All) &&
438 : mInfo.jpeg_color_space == JCS_YCbCr && mInfo.out_color_space == JCS_RGB) {
439 : /* Special case for the most common case: transform from YCbCr direct into packed ARGB */
440 5 : mInfo.out_color_components = 4; /* Packed ARGB pixels are always 4 bytes...*/
441 5 : mInfo.cconvert->color_convert = ycc_rgb_convert_argb;
442 : }
443 :
444 : /* If this is a progressive JPEG ... */
445 10 : mState = mInfo.buffered_image ? JPEG_DECOMPRESS_PROGRESSIVE : JPEG_DECOMPRESS_SEQUENTIAL;
446 : }
447 :
448 : case JPEG_DECOMPRESS_SEQUENTIAL:
449 : {
450 7 : if (mState == JPEG_DECOMPRESS_SEQUENTIAL)
451 : {
452 14 : LOG_SCOPE(gJPEGlog, "nsJPEGDecoder::Write -- JPEG_DECOMPRESS_SEQUENTIAL case");
453 :
454 : bool suspend;
455 7 : OutputScanlines(&suspend);
456 :
457 7 : if (suspend) {
458 2 : PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
459 : ("} (I/O suspension after OutputScanlines() - SEQUENTIAL)"));
460 : return; /* I/O suspension */
461 : }
462 :
463 : /* If we've completed image output ... */
464 5 : NS_ASSERTION(mInfo.output_scanline == mInfo.output_height, "We didn't process all of the data!");
465 12 : mState = JPEG_DONE;
466 : }
467 : }
468 :
469 : case JPEG_DECOMPRESS_PROGRESSIVE:
470 : {
471 5 : if (mState == JPEG_DECOMPRESS_PROGRESSIVE)
472 : {
473 0 : LOG_SCOPE(gJPEGlog, "nsJPEGDecoder::Write -- JPEG_DECOMPRESS_PROGRESSIVE case");
474 :
475 : int status;
476 0 : do {
477 0 : status = jpeg_consume_input(&mInfo);
478 : } while ((status != JPEG_SUSPENDED) &&
479 : (status != JPEG_REACHED_EOI));
480 :
481 0 : for (;;) {
482 0 : if (mInfo.output_scanline == 0) {
483 0 : int scan = mInfo.input_scan_number;
484 :
485 : /* if we haven't displayed anything yet (output_scan_number==0)
486 : and we have enough data for a complete scan, force output
487 : of the last full scan */
488 0 : if ((mInfo.output_scan_number == 0) &&
489 : (scan > 1) &&
490 : (status != JPEG_REACHED_EOI))
491 0 : scan--;
492 :
493 0 : if (!jpeg_start_output(&mInfo, scan)) {
494 0 : PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
495 : ("} (I/O suspension after jpeg_start_output() - PROGRESSIVE)"));
496 : return; /* I/O suspension */
497 : }
498 : }
499 :
500 0 : if (mInfo.output_scanline == 0xffffff)
501 0 : mInfo.output_scanline = 0;
502 :
503 : bool suspend;
504 0 : OutputScanlines(&suspend);
505 :
506 0 : if (suspend) {
507 0 : if (mInfo.output_scanline == 0) {
508 : /* didn't manage to read any lines - flag so we don't call
509 : jpeg_start_output() multiple times for the same scan */
510 0 : mInfo.output_scanline = 0xffffff;
511 : }
512 0 : PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
513 : ("} (I/O suspension after OutputScanlines() - PROGRESSIVE)"));
514 : return; /* I/O suspension */
515 : }
516 :
517 0 : if (mInfo.output_scanline == mInfo.output_height)
518 : {
519 0 : if (!jpeg_finish_output(&mInfo)) {
520 0 : PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
521 : ("} (I/O suspension after jpeg_finish_output() - PROGRESSIVE)"));
522 : return; /* I/O suspension */
523 : }
524 :
525 0 : if (jpeg_input_complete(&mInfo) &&
526 : (mInfo.input_scan_number == mInfo.output_scan_number))
527 : break;
528 :
529 0 : mInfo.output_scanline = 0;
530 : }
531 : }
532 :
533 0 : mState = JPEG_DONE;
534 : }
535 : }
536 :
537 : case JPEG_DONE:
538 : {
539 10 : LOG_SCOPE(gJPEGlog, "nsJPEGDecoder::ProcessData -- entering JPEG_DONE case");
540 :
541 : /* Step 7: Finish decompression */
542 :
543 5 : if (jpeg_finish_decompress(&mInfo) == FALSE) {
544 0 : PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
545 : ("} (I/O suspension after jpeg_finish_decompress() - DONE)"));
546 : return; /* I/O suspension */
547 : }
548 :
549 5 : mState = JPEG_SINK_NON_JPEG_TRAILER;
550 :
551 : /* we're done dude */
552 5 : break;
553 : }
554 : case JPEG_SINK_NON_JPEG_TRAILER:
555 0 : PR_LOG(gJPEGlog, PR_LOG_DEBUG,
556 : ("[this=%p] nsJPEGDecoder::ProcessData -- entering JPEG_SINK_NON_JPEG_TRAILER case\n", this));
557 :
558 0 : break;
559 :
560 : case JPEG_ERROR:
561 0 : NS_ABORT_IF_FALSE(0, "Should always return immediately after error and not re-enter decoder");
562 : }
563 :
564 5 : PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
565 : ("} (end of function)"));
566 5 : return;
567 : }
568 :
569 : void
570 5 : nsJPEGDecoder::NotifyDone()
571 : {
572 5 : PostFrameStop();
573 5 : PostDecodeDone();
574 5 : }
575 :
576 : void
577 7 : nsJPEGDecoder::OutputScanlines(bool* suspend)
578 : {
579 7 : *suspend = false;
580 :
581 7 : const PRUint32 top = mInfo.output_scanline;
582 :
583 245 : while ((mInfo.output_scanline < mInfo.output_height)) {
584 : /* Use the Cairo image buffer as scanline buffer */
585 : PRUint32 *imageRow = ((PRUint32*)mImageData) +
586 233 : (mInfo.output_scanline * mInfo.output_width);
587 :
588 233 : if (mInfo.cconvert->color_convert == ycc_rgb_convert_argb) {
589 : /* Special case: scanline will be directly converted into packed ARGB */
590 233 : if (jpeg_read_scanlines(&mInfo, (JSAMPARRAY)&imageRow, 1) != 1) {
591 2 : *suspend = true; /* suspend */
592 2 : break;
593 : }
594 231 : continue; /* all done for this row! */
595 : }
596 :
597 0 : JSAMPROW sampleRow = (JSAMPROW)imageRow;
598 0 : if (mInfo.output_components == 3) {
599 : /* Put the pixels at end of row to enable in-place expansion */
600 0 : sampleRow += mInfo.output_width;
601 : }
602 :
603 : /* Request one scanline. Returns 0 or 1 scanlines. */
604 0 : if (jpeg_read_scanlines(&mInfo, &sampleRow, 1) != 1) {
605 0 : *suspend = true; /* suspend */
606 0 : break;
607 : }
608 :
609 0 : if (mTransform) {
610 0 : JSAMPROW source = sampleRow;
611 0 : if (mInfo.out_color_space == JCS_GRAYSCALE) {
612 : /* Convert from the 1byte grey pixels at begin of row
613 : to the 3byte RGB byte pixels at 'end' of row */
614 0 : sampleRow += mInfo.output_width;
615 : }
616 0 : qcms_transform_data(mTransform, source, sampleRow, mInfo.output_width);
617 : /* Move 3byte RGB data to end of row */
618 0 : if (mInfo.out_color_space == JCS_CMYK) {
619 0 : memmove(sampleRow + mInfo.output_width,
620 : sampleRow,
621 0 : 3 * mInfo.output_width);
622 0 : sampleRow += mInfo.output_width;
623 : }
624 : } else {
625 0 : if (mInfo.out_color_space == JCS_CMYK) {
626 : /* Convert from CMYK to RGB */
627 : /* We cannot convert directly to Cairo, as the CMSRGBTransform may wants to do a RGB transform... */
628 : /* Would be better to have platform CMSenabled transformation from CMYK to (A)RGB... */
629 0 : cmyk_convert_rgb((JSAMPROW)imageRow, mInfo.output_width);
630 0 : sampleRow += mInfo.output_width;
631 : }
632 0 : if (mCMSMode == eCMSMode_All) {
633 : /* No embedded ICC profile - treat as sRGB */
634 0 : qcms_transform *transform = gfxPlatform::GetCMSRGBTransform();
635 0 : if (transform) {
636 0 : qcms_transform_data(transform, sampleRow, sampleRow, mInfo.output_width);
637 : }
638 : }
639 : }
640 :
641 : // counter for while() loops below
642 0 : PRUint32 idx = mInfo.output_width;
643 :
644 : // copy as bytes until source pointer is 32-bit-aligned
645 0 : for (; (NS_PTR_TO_UINT32(sampleRow) & 0x3) && idx; --idx) {
646 0 : *imageRow++ = GFX_PACKED_PIXEL(0xFF, sampleRow[0], sampleRow[1], sampleRow[2]);
647 0 : sampleRow += 3;
648 : }
649 :
650 : // copy pixels in blocks of 4
651 0 : while (idx >= 4) {
652 0 : GFX_BLOCK_RGB_TO_FRGB(sampleRow, imageRow);
653 0 : idx -= 4;
654 0 : sampleRow += 12;
655 0 : imageRow += 4;
656 : }
657 :
658 : // copy remaining pixel(s)
659 0 : while (idx--) {
660 : // 32-bit read of final pixel will exceed buffer, so read bytes
661 0 : *imageRow++ = GFX_PACKED_PIXEL(0xFF, sampleRow[0], sampleRow[1], sampleRow[2]);
662 0 : sampleRow += 3;
663 : }
664 : }
665 :
666 7 : if (top != mInfo.output_scanline) {
667 6 : nsIntRect r(0, top, mInfo.output_width, mInfo.output_scanline-top);
668 6 : PostInvalidation(r);
669 : }
670 :
671 7 : }
672 :
673 :
674 : /* Override the standard error method in the IJG JPEG decoder code. */
675 : METHODDEF(void)
676 0 : my_error_exit (j_common_ptr cinfo)
677 : {
678 0 : decoder_error_mgr *err = (decoder_error_mgr *) cinfo->err;
679 :
680 : /* Convert error to a browser error code */
681 : nsresult error_code = err->pub.msg_code == JERR_OUT_OF_MEMORY
682 : ? NS_ERROR_OUT_OF_MEMORY
683 0 : : NS_ERROR_FAILURE;
684 :
685 : #ifdef DEBUG
686 : char buffer[JMSG_LENGTH_MAX];
687 :
688 : /* Create the message */
689 0 : (*err->pub.format_message) (cinfo, buffer);
690 :
691 0 : fprintf(stderr, "JPEG decoding error:\n%s\n", buffer);
692 : #endif
693 :
694 : /* Return control to the setjmp point. */
695 0 : longjmp(err->setjmp_buffer, error_code);
696 : }
697 :
698 : /******************************************************************************/
699 : /*-----------------------------------------------------------------------------
700 : * This is the callback routine from the IJG JPEG library used to supply new
701 : * data to the decompressor when its input buffer is exhausted. It juggles
702 : * multiple buffers in an attempt to avoid unnecessary copying of input data.
703 : *
704 : * (A simpler scheme is possible: It's much easier to use only a single
705 : * buffer; when fill_input_buffer() is called, move any unconsumed data
706 : * (beyond the current pointer/count) down to the beginning of this buffer and
707 : * then load new data into the remaining buffer space. This approach requires
708 : * a little more data copying but is far easier to get right.)
709 : *
710 : * At any one time, the JPEG decompressor is either reading from the necko
711 : * input buffer, which is volatile across top-level calls to the IJG library,
712 : * or the "backtrack" buffer. The backtrack buffer contains the remaining
713 : * unconsumed data from the necko buffer after parsing was suspended due
714 : * to insufficient data in some previous call to the IJG library.
715 : *
716 : * When suspending, the decompressor will back up to a convenient restart
717 : * point (typically the start of the current MCU). The variables
718 : * next_input_byte & bytes_in_buffer indicate where the restart point will be
719 : * if the current call returns FALSE. Data beyond this point must be
720 : * rescanned after resumption, so it must be preserved in case the decompressor
721 : * decides to backtrack.
722 : *
723 : * Returns:
724 : * TRUE if additional data is available, FALSE if no data present and
725 : * the JPEG library should therefore suspend processing of input stream
726 : *---------------------------------------------------------------------------*/
727 :
728 : /******************************************************************************/
729 : /* data source manager method */
730 : /******************************************************************************/
731 :
732 :
733 : /******************************************************************************/
734 : /* data source manager method
735 : Initialize source. This is called by jpeg_read_header() before any
736 : data is actually read. May leave
737 : bytes_in_buffer set to 0 (in which case a fill_input_buffer() call
738 : will occur immediately).
739 : */
740 : METHODDEF(void)
741 5 : init_source (j_decompress_ptr jd)
742 : {
743 5 : }
744 :
745 : /******************************************************************************/
746 : /* data source manager method
747 : Skip num_bytes worth of data. The buffer pointer and count should
748 : be advanced over num_bytes input bytes, refilling the buffer as
749 : needed. This is used to skip over a potentially large amount of
750 : uninteresting data (such as an APPn marker). In some applications
751 : it may be possible to optimize away the reading of the skipped data,
752 : but it's not clear that being smart is worth much trouble; large
753 : skips are uncommon. bytes_in_buffer may be zero on return.
754 : A zero or negative skip count should be treated as a no-op.
755 : */
756 : METHODDEF(void)
757 3 : skip_input_data (j_decompress_ptr jd, long num_bytes)
758 : {
759 3 : struct jpeg_source_mgr *src = jd->src;
760 3 : nsJPEGDecoder *decoder = (nsJPEGDecoder *)(jd->client_data);
761 :
762 3 : if (num_bytes > (long)src->bytes_in_buffer) {
763 : /*
764 : * Can't skip it all right now until we get more data from
765 : * network stream. Set things up so that fill_input_buffer
766 : * will skip remaining amount.
767 : */
768 0 : decoder->mBytesToSkip = (size_t)num_bytes - src->bytes_in_buffer;
769 0 : src->next_input_byte += src->bytes_in_buffer;
770 0 : src->bytes_in_buffer = 0;
771 :
772 : } else {
773 : /* Simple case. Just advance buffer pointer */
774 :
775 3 : src->bytes_in_buffer -= (size_t)num_bytes;
776 3 : src->next_input_byte += num_bytes;
777 : }
778 3 : }
779 :
780 :
781 : /******************************************************************************/
782 : /* data source manager method
783 : This is called whenever bytes_in_buffer has reached zero and more
784 : data is wanted. In typical applications, it should read fresh data
785 : into the buffer (ignoring the current state of next_input_byte and
786 : bytes_in_buffer), reset the pointer & count to the start of the
787 : buffer, and return TRUE indicating that the buffer has been reloaded.
788 : It is not necessary to fill the buffer entirely, only to obtain at
789 : least one more byte. bytes_in_buffer MUST be set to a positive value
790 : if TRUE is returned. A FALSE return should only be used when I/O
791 : suspension is desired.
792 : */
793 : METHODDEF(boolean)
794 11 : fill_input_buffer (j_decompress_ptr jd)
795 : {
796 11 : struct jpeg_source_mgr *src = jd->src;
797 11 : nsJPEGDecoder *decoder = (nsJPEGDecoder *)(jd->client_data);
798 :
799 11 : if (decoder->mReading) {
800 8 : const JOCTET *new_buffer = decoder->mSegment;
801 8 : PRUint32 new_buflen = decoder->mSegmentLen;
802 :
803 8 : if (!new_buffer || new_buflen == 0)
804 0 : return false; /* suspend */
805 :
806 8 : decoder->mSegmentLen = 0;
807 :
808 8 : if (decoder->mBytesToSkip) {
809 0 : if (decoder->mBytesToSkip < new_buflen) {
810 : /* All done skipping bytes; Return what's left. */
811 0 : new_buffer += decoder->mBytesToSkip;
812 0 : new_buflen -= decoder->mBytesToSkip;
813 0 : decoder->mBytesToSkip = 0;
814 : } else {
815 : /* Still need to skip some more data in the future */
816 0 : decoder->mBytesToSkip -= (size_t)new_buflen;
817 0 : return false; /* suspend */
818 : }
819 : }
820 :
821 8 : decoder->mBackBufferUnreadLen = src->bytes_in_buffer;
822 :
823 8 : src->next_input_byte = new_buffer;
824 8 : src->bytes_in_buffer = (size_t)new_buflen;
825 8 : decoder->mReading = false;
826 :
827 8 : return true;
828 : }
829 :
830 3 : if (src->next_input_byte != decoder->mSegment) {
831 : /* Backtrack data has been permanently consumed. */
832 3 : decoder->mBackBufferUnreadLen = 0;
833 3 : decoder->mBackBufferLen = 0;
834 : }
835 :
836 : /* Save remainder of netlib buffer in backtrack buffer */
837 3 : const PRUint32 new_backtrack_buflen = src->bytes_in_buffer + decoder->mBackBufferLen;
838 :
839 : /* Make sure backtrack buffer is big enough to hold new data. */
840 3 : if (decoder->mBackBufferSize < new_backtrack_buflen) {
841 : /* Check for malformed MARKER segment lengths, before allocating space for it */
842 2 : if (new_backtrack_buflen > MAX_JPEG_MARKER_LENGTH) {
843 0 : my_error_exit((j_common_ptr)(&decoder->mInfo));
844 : }
845 :
846 : /* Round up to multiple of 256 bytes. */
847 2 : const size_t roundup_buflen = ((new_backtrack_buflen + 255) >> 8) << 8;
848 2 : JOCTET *buf = (JOCTET *)PR_REALLOC(decoder->mBackBuffer, roundup_buflen);
849 : /* Check for OOM */
850 2 : if (!buf) {
851 0 : decoder->mInfo.err->msg_code = JERR_OUT_OF_MEMORY;
852 0 : my_error_exit((j_common_ptr)(&decoder->mInfo));
853 : }
854 2 : decoder->mBackBuffer = buf;
855 2 : decoder->mBackBufferSize = roundup_buflen;
856 : }
857 :
858 : /* Copy remainder of netlib segment into backtrack buffer. */
859 3 : memmove(decoder->mBackBuffer + decoder->mBackBufferLen,
860 : src->next_input_byte,
861 6 : src->bytes_in_buffer);
862 :
863 : /* Point to start of data to be rescanned. */
864 3 : src->next_input_byte = decoder->mBackBuffer + decoder->mBackBufferLen - decoder->mBackBufferUnreadLen;
865 3 : src->bytes_in_buffer += decoder->mBackBufferUnreadLen;
866 3 : decoder->mBackBufferLen = (size_t)new_backtrack_buflen;
867 3 : decoder->mReading = true;
868 :
869 3 : return false;
870 : }
871 :
872 : /******************************************************************************/
873 : /* data source manager method */
874 : /*
875 : * Terminate source --- called by jpeg_finish_decompress() after all
876 : * data has been read to clean up JPEG source manager. NOT called by
877 : * jpeg_abort() or jpeg_destroy().
878 : */
879 : METHODDEF(void)
880 5 : term_source (j_decompress_ptr jd)
881 : {
882 5 : nsJPEGDecoder *decoder = (nsJPEGDecoder *)(jd->client_data);
883 :
884 : // This function shouldn't be called if we ran into an error we didn't
885 : // recover from.
886 5 : NS_ABORT_IF_FALSE(decoder->mState != JPEG_ERROR,
887 : "Calling term_source on a JPEG with mState == JPEG_ERROR!");
888 :
889 : // Notify using a helper method to get around protectedness issues.
890 5 : decoder->NotifyDone();
891 5 : }
892 :
893 : } // namespace image
894 : } // namespace mozilla
895 :
896 :
897 : /**************** YCbCr -> Cairo's RGB24/ARGB32 conversion: most common case **************/
898 :
899 : /*
900 : * YCbCr is defined per CCIR 601-1, except that Cb and Cr are
901 : * normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5.
902 : * The conversion equations to be implemented are therefore
903 : * R = Y + 1.40200 * Cr
904 : * G = Y - 0.34414 * Cb - 0.71414 * Cr
905 : * B = Y + 1.77200 * Cb
906 : * where Cb and Cr represent the incoming values less CENTERJSAMPLE.
907 : * (These numbers are derived from TIFF 6.0 section 21, dated 3-June-92.)
908 : *
909 : * To avoid floating-point arithmetic, we represent the fractional constants
910 : * as integers scaled up by 2^16 (about 4 digits precision); we have to divide
911 : * the products by 2^16, with appropriate rounding, to get the correct answer.
912 : * Notice that Y, being an integral input, does not contribute any fraction
913 : * so it need not participate in the rounding.
914 : *
915 : * For even more speed, we avoid doing any multiplications in the inner loop
916 : * by precalculating the constants times Cb and Cr for all possible values.
917 : * For 8-bit JSAMPLEs this is very reasonable (only 256 entries per table);
918 : * for 12-bit samples it is still acceptable. It's not very reasonable for
919 : * 16-bit samples, but if you want lossless storage you shouldn't be changing
920 : * colorspace anyway.
921 : * The Cr=>R and Cb=>B values can be rounded to integers in advance; the
922 : * values for the G calculation are left scaled up, since we must add them
923 : * together before rounding.
924 : */
925 :
926 : #define SCALEBITS 16 /* speediest right-shift on some machines */
927 :
928 : /* Use static tables for color processing. */
929 : /* Four tables, each 256 entries of 4 bytes totals 4K which is not bad... */
930 :
931 : const int Cr_r_tab[(MAXJSAMPLE+1) * sizeof(int)] ={
932 : -0xb3, -0xb2, -0xb1, -0xaf, -0xae, -0xac,
933 : -0xab, -0xaa, -0xa8, -0xa7, -0xa5, -0xa4,
934 : -0xa3, -0xa1, -0xa0, -0x9e, -0x9d, -0x9c,
935 : -0x9a, -0x99, -0x97, -0x96, -0x95, -0x93,
936 : -0x92, -0x90, -0x8f, -0x8e, -0x8c, -0x8b,
937 : -0x89, -0x88, -0x87, -0x85, -0x84, -0x82,
938 : -0x81, -0x80, -0x7e, -0x7d, -0x7b, -0x7a,
939 : -0x79, -0x77, -0x76, -0x74, -0x73, -0x72,
940 : -0x70, -0x6f, -0x6d, -0x6c, -0x6b, -0x69,
941 : -0x68, -0x66, -0x65, -0x64, -0x62, -0x61,
942 : -0x5f, -0x5e, -0x5d, -0x5b, -0x5a, -0x58,
943 : -0x57, -0x56, -0x54, -0x53, -0x51, -0x50,
944 : -0x4f, -0x4d, -0x4c, -0x4a, -0x49, -0x48,
945 : -0x46, -0x45, -0x43, -0x42, -0x40, -0x3f,
946 : -0x3e, -0x3c, -0x3b, -0x39, -0x38, -0x37,
947 : -0x35, -0x34, -0x32, -0x31, -0x30, -0x2e,
948 : -0x2d, -0x2b, -0x2a, -0x29, -0x27, -0x26,
949 : -0x24, -0x23, -0x22, -0x20, -0x1f, -0x1d,
950 : -0x1c, -0x1b, -0x19, -0x18, -0x16, -0x15,
951 : -0x14, -0x12, -0x11, -0x0f, -0x0e, -0x0d,
952 : -0x0b, -0x0a, -0x08, -0x07, -0x06, -0x04,
953 : -0x03, -0x01, 0x00, 0x01, 0x03, 0x04,
954 : 0x06, 0x07, 0x08, 0x0a, 0x0b, 0x0d,
955 : 0x0e, 0x0f, 0x11, 0x12, 0x14, 0x15,
956 : 0x16, 0x18, 0x19, 0x1b, 0x1c, 0x1d,
957 : 0x1f, 0x20, 0x22, 0x23, 0x24, 0x26,
958 : 0x27, 0x29, 0x2a, 0x2b, 0x2d, 0x2e,
959 : 0x30, 0x31, 0x32, 0x34, 0x35, 0x37,
960 : 0x38, 0x39, 0x3b, 0x3c, 0x3e, 0x3f,
961 : 0x40, 0x42, 0x43, 0x45, 0x46, 0x48,
962 : 0x49, 0x4a, 0x4c, 0x4d, 0x4f, 0x50,
963 : 0x51, 0x53, 0x54, 0x56, 0x57, 0x58,
964 : 0x5a, 0x5b, 0x5d, 0x5e, 0x5f, 0x61,
965 : 0x62, 0x64, 0x65, 0x66, 0x68, 0x69,
966 : 0x6b, 0x6c, 0x6d, 0x6f, 0x70, 0x72,
967 : 0x73, 0x74, 0x76, 0x77, 0x79, 0x7a,
968 : 0x7b, 0x7d, 0x7e, 0x80, 0x81, 0x82,
969 : 0x84, 0x85, 0x87, 0x88, 0x89, 0x8b,
970 : 0x8c, 0x8e, 0x8f, 0x90, 0x92, 0x93,
971 : 0x95, 0x96, 0x97, 0x99, 0x9a, 0x9c,
972 : 0x9d, 0x9e, 0xa0, 0xa1, 0xa3, 0xa4,
973 : 0xa5, 0xa7, 0xa8, 0xaa, 0xab, 0xac,
974 : 0xae, 0xaf, 0xb1, 0xb2,
975 : };
976 :
977 : const int Cb_b_tab[(MAXJSAMPLE+1) * sizeof(int)] ={
978 : -0xe3, -0xe1, -0xdf, -0xde, -0xdc, -0xda,
979 : -0xd8, -0xd6, -0xd5, -0xd3, -0xd1, -0xcf,
980 : -0xce, -0xcc, -0xca, -0xc8, -0xc6, -0xc5,
981 : -0xc3, -0xc1, -0xbf, -0xbe, -0xbc, -0xba,
982 : -0xb8, -0xb7, -0xb5, -0xb3, -0xb1, -0xaf,
983 : -0xae, -0xac, -0xaa, -0xa8, -0xa7, -0xa5,
984 : -0xa3, -0xa1, -0x9f, -0x9e, -0x9c, -0x9a,
985 : -0x98, -0x97, -0x95, -0x93, -0x91, -0x90,
986 : -0x8e, -0x8c, -0x8a, -0x88, -0x87, -0x85,
987 : -0x83, -0x81, -0x80, -0x7e, -0x7c, -0x7a,
988 : -0x78, -0x77, -0x75, -0x73, -0x71, -0x70,
989 : -0x6e, -0x6c, -0x6a, -0x69, -0x67, -0x65,
990 : -0x63, -0x61, -0x60, -0x5e, -0x5c, -0x5a,
991 : -0x59, -0x57, -0x55, -0x53, -0x52, -0x50,
992 : -0x4e, -0x4c, -0x4a, -0x49, -0x47, -0x45,
993 : -0x43, -0x42, -0x40, -0x3e, -0x3c, -0x3a,
994 : -0x39, -0x37, -0x35, -0x33, -0x32, -0x30,
995 : -0x2e, -0x2c, -0x2b, -0x29, -0x27, -0x25,
996 : -0x23, -0x22, -0x20, -0x1e, -0x1c, -0x1b,
997 : -0x19, -0x17, -0x15, -0x13, -0x12, -0x10,
998 : -0x0e, -0x0c, -0x0b, -0x09, -0x07, -0x05,
999 : -0x04, -0x02, 0x00, 0x02, 0x04, 0x05,
1000 : 0x07, 0x09, 0x0b, 0x0c, 0x0e, 0x10,
1001 : 0x12, 0x13, 0x15, 0x17, 0x19, 0x1b,
1002 : 0x1c, 0x1e, 0x20, 0x22, 0x23, 0x25,
1003 : 0x27, 0x29, 0x2b, 0x2c, 0x2e, 0x30,
1004 : 0x32, 0x33, 0x35, 0x37, 0x39, 0x3a,
1005 : 0x3c, 0x3e, 0x40, 0x42, 0x43, 0x45,
1006 : 0x47, 0x49, 0x4a, 0x4c, 0x4e, 0x50,
1007 : 0x52, 0x53, 0x55, 0x57, 0x59, 0x5a,
1008 : 0x5c, 0x5e, 0x60, 0x61, 0x63, 0x65,
1009 : 0x67, 0x69, 0x6a, 0x6c, 0x6e, 0x70,
1010 : 0x71, 0x73, 0x75, 0x77, 0x78, 0x7a,
1011 : 0x7c, 0x7e, 0x80, 0x81, 0x83, 0x85,
1012 : 0x87, 0x88, 0x8a, 0x8c, 0x8e, 0x90,
1013 : 0x91, 0x93, 0x95, 0x97, 0x98, 0x9a,
1014 : 0x9c, 0x9e, 0x9f, 0xa1, 0xa3, 0xa5,
1015 : 0xa7, 0xa8, 0xaa, 0xac, 0xae, 0xaf,
1016 : 0xb1, 0xb3, 0xb5, 0xb7, 0xb8, 0xba,
1017 : 0xbc, 0xbe, 0xbf, 0xc1, 0xc3, 0xc5,
1018 : 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xcf,
1019 : 0xd1, 0xd3, 0xd5, 0xd6, 0xd8, 0xda,
1020 : 0xdc, 0xde, 0xdf, 0xe1,
1021 : };
1022 :
1023 : const int Cr_g_tab[(MAXJSAMPLE+1) * sizeof(int)] ={
1024 : 0x5b6900, 0x5ab22e, 0x59fb5c, 0x59448a, 0x588db8, 0x57d6e6,
1025 : 0x572014, 0x566942, 0x55b270, 0x54fb9e, 0x5444cc, 0x538dfa,
1026 : 0x52d728, 0x522056, 0x516984, 0x50b2b2, 0x4ffbe0, 0x4f450e,
1027 : 0x4e8e3c, 0x4dd76a, 0x4d2098, 0x4c69c6, 0x4bb2f4, 0x4afc22,
1028 : 0x4a4550, 0x498e7e, 0x48d7ac, 0x4820da, 0x476a08, 0x46b336,
1029 : 0x45fc64, 0x454592, 0x448ec0, 0x43d7ee, 0x43211c, 0x426a4a,
1030 : 0x41b378, 0x40fca6, 0x4045d4, 0x3f8f02, 0x3ed830, 0x3e215e,
1031 : 0x3d6a8c, 0x3cb3ba, 0x3bfce8, 0x3b4616, 0x3a8f44, 0x39d872,
1032 : 0x3921a0, 0x386ace, 0x37b3fc, 0x36fd2a, 0x364658, 0x358f86,
1033 : 0x34d8b4, 0x3421e2, 0x336b10, 0x32b43e, 0x31fd6c, 0x31469a,
1034 : 0x308fc8, 0x2fd8f6, 0x2f2224, 0x2e6b52, 0x2db480, 0x2cfdae,
1035 : 0x2c46dc, 0x2b900a, 0x2ad938, 0x2a2266, 0x296b94, 0x28b4c2,
1036 : 0x27fdf0, 0x27471e, 0x26904c, 0x25d97a, 0x2522a8, 0x246bd6,
1037 : 0x23b504, 0x22fe32, 0x224760, 0x21908e, 0x20d9bc, 0x2022ea,
1038 : 0x1f6c18, 0x1eb546, 0x1dfe74, 0x1d47a2, 0x1c90d0, 0x1bd9fe,
1039 : 0x1b232c, 0x1a6c5a, 0x19b588, 0x18feb6, 0x1847e4, 0x179112,
1040 : 0x16da40, 0x16236e, 0x156c9c, 0x14b5ca, 0x13fef8, 0x134826,
1041 : 0x129154, 0x11da82, 0x1123b0, 0x106cde, 0x0fb60c, 0x0eff3a,
1042 : 0x0e4868, 0x0d9196, 0x0cdac4, 0x0c23f2, 0x0b6d20, 0x0ab64e,
1043 : 0x09ff7c, 0x0948aa, 0x0891d8, 0x07db06, 0x072434, 0x066d62,
1044 : 0x05b690, 0x04ffbe, 0x0448ec, 0x03921a, 0x02db48, 0x022476,
1045 : 0x016da4, 0x00b6d2, 0x000000, -0x00b6d2, -0x016da4, -0x022476,
1046 : -0x02db48, -0x03921a, -0x0448ec, -0x04ffbe, -0x05b690, -0x066d62,
1047 : -0x072434, -0x07db06, -0x0891d8, -0x0948aa, -0x09ff7c, -0x0ab64e,
1048 : -0x0b6d20, -0x0c23f2, -0x0cdac4, -0x0d9196, -0x0e4868, -0x0eff3a,
1049 : -0x0fb60c, -0x106cde, -0x1123b0, -0x11da82, -0x129154, -0x134826,
1050 : -0x13fef8, -0x14b5ca, -0x156c9c, -0x16236e, -0x16da40, -0x179112,
1051 : -0x1847e4, -0x18feb6, -0x19b588, -0x1a6c5a, -0x1b232c, -0x1bd9fe,
1052 : -0x1c90d0, -0x1d47a2, -0x1dfe74, -0x1eb546, -0x1f6c18, -0x2022ea,
1053 : -0x20d9bc, -0x21908e, -0x224760, -0x22fe32, -0x23b504, -0x246bd6,
1054 : -0x2522a8, -0x25d97a, -0x26904c, -0x27471e, -0x27fdf0, -0x28b4c2,
1055 : -0x296b94, -0x2a2266, -0x2ad938, -0x2b900a, -0x2c46dc, -0x2cfdae,
1056 : -0x2db480, -0x2e6b52, -0x2f2224, -0x2fd8f6, -0x308fc8, -0x31469a,
1057 : -0x31fd6c, -0x32b43e, -0x336b10, -0x3421e2, -0x34d8b4, -0x358f86,
1058 : -0x364658, -0x36fd2a, -0x37b3fc, -0x386ace, -0x3921a0, -0x39d872,
1059 : -0x3a8f44, -0x3b4616, -0x3bfce8, -0x3cb3ba, -0x3d6a8c, -0x3e215e,
1060 : -0x3ed830, -0x3f8f02, -0x4045d4, -0x40fca6, -0x41b378, -0x426a4a,
1061 : -0x43211c, -0x43d7ee, -0x448ec0, -0x454592, -0x45fc64, -0x46b336,
1062 : -0x476a08, -0x4820da, -0x48d7ac, -0x498e7e, -0x4a4550, -0x4afc22,
1063 : -0x4bb2f4, -0x4c69c6, -0x4d2098, -0x4dd76a, -0x4e8e3c, -0x4f450e,
1064 : -0x4ffbe0, -0x50b2b2, -0x516984, -0x522056, -0x52d728, -0x538dfa,
1065 : -0x5444cc, -0x54fb9e, -0x55b270, -0x566942, -0x572014, -0x57d6e6,
1066 : -0x588db8, -0x59448a, -0x59fb5c, -0x5ab22e,
1067 : };
1068 :
1069 : const int Cb_g_tab[(MAXJSAMPLE+1) * sizeof(int)] ={
1070 : 0x2c8d00, 0x2c34e6, 0x2bdccc, 0x2b84b2, 0x2b2c98, 0x2ad47e,
1071 : 0x2a7c64, 0x2a244a, 0x29cc30, 0x297416, 0x291bfc, 0x28c3e2,
1072 : 0x286bc8, 0x2813ae, 0x27bb94, 0x27637a, 0x270b60, 0x26b346,
1073 : 0x265b2c, 0x260312, 0x25aaf8, 0x2552de, 0x24fac4, 0x24a2aa,
1074 : 0x244a90, 0x23f276, 0x239a5c, 0x234242, 0x22ea28, 0x22920e,
1075 : 0x2239f4, 0x21e1da, 0x2189c0, 0x2131a6, 0x20d98c, 0x208172,
1076 : 0x202958, 0x1fd13e, 0x1f7924, 0x1f210a, 0x1ec8f0, 0x1e70d6,
1077 : 0x1e18bc, 0x1dc0a2, 0x1d6888, 0x1d106e, 0x1cb854, 0x1c603a,
1078 : 0x1c0820, 0x1bb006, 0x1b57ec, 0x1affd2, 0x1aa7b8, 0x1a4f9e,
1079 : 0x19f784, 0x199f6a, 0x194750, 0x18ef36, 0x18971c, 0x183f02,
1080 : 0x17e6e8, 0x178ece, 0x1736b4, 0x16de9a, 0x168680, 0x162e66,
1081 : 0x15d64c, 0x157e32, 0x152618, 0x14cdfe, 0x1475e4, 0x141dca,
1082 : 0x13c5b0, 0x136d96, 0x13157c, 0x12bd62, 0x126548, 0x120d2e,
1083 : 0x11b514, 0x115cfa, 0x1104e0, 0x10acc6, 0x1054ac, 0x0ffc92,
1084 : 0x0fa478, 0x0f4c5e, 0x0ef444, 0x0e9c2a, 0x0e4410, 0x0debf6,
1085 : 0x0d93dc, 0x0d3bc2, 0x0ce3a8, 0x0c8b8e, 0x0c3374, 0x0bdb5a,
1086 : 0x0b8340, 0x0b2b26, 0x0ad30c, 0x0a7af2, 0x0a22d8, 0x09cabe,
1087 : 0x0972a4, 0x091a8a, 0x08c270, 0x086a56, 0x08123c, 0x07ba22,
1088 : 0x076208, 0x0709ee, 0x06b1d4, 0x0659ba, 0x0601a0, 0x05a986,
1089 : 0x05516c, 0x04f952, 0x04a138, 0x04491e, 0x03f104, 0x0398ea,
1090 : 0x0340d0, 0x02e8b6, 0x02909c, 0x023882, 0x01e068, 0x01884e,
1091 : 0x013034, 0x00d81a, 0x008000, 0x0027e6, -0x003034, -0x00884e,
1092 : -0x00e068, -0x013882, -0x01909c, -0x01e8b6, -0x0240d0, -0x0298ea,
1093 : -0x02f104, -0x03491e, -0x03a138, -0x03f952, -0x04516c, -0x04a986,
1094 : -0x0501a0, -0x0559ba, -0x05b1d4, -0x0609ee, -0x066208, -0x06ba22,
1095 : -0x07123c, -0x076a56, -0x07c270, -0x081a8a, -0x0872a4, -0x08cabe,
1096 : -0x0922d8, -0x097af2, -0x09d30c, -0x0a2b26, -0x0a8340, -0x0adb5a,
1097 : -0x0b3374, -0x0b8b8e, -0x0be3a8, -0x0c3bc2, -0x0c93dc, -0x0cebf6,
1098 : -0x0d4410, -0x0d9c2a, -0x0df444, -0x0e4c5e, -0x0ea478, -0x0efc92,
1099 : -0x0f54ac, -0x0facc6, -0x1004e0, -0x105cfa, -0x10b514, -0x110d2e,
1100 : -0x116548, -0x11bd62, -0x12157c, -0x126d96, -0x12c5b0, -0x131dca,
1101 : -0x1375e4, -0x13cdfe, -0x142618, -0x147e32, -0x14d64c, -0x152e66,
1102 : -0x158680, -0x15de9a, -0x1636b4, -0x168ece, -0x16e6e8, -0x173f02,
1103 : -0x17971c, -0x17ef36, -0x184750, -0x189f6a, -0x18f784, -0x194f9e,
1104 : -0x19a7b8, -0x19ffd2, -0x1a57ec, -0x1ab006, -0x1b0820, -0x1b603a,
1105 : -0x1bb854, -0x1c106e, -0x1c6888, -0x1cc0a2, -0x1d18bc, -0x1d70d6,
1106 : -0x1dc8f0, -0x1e210a, -0x1e7924, -0x1ed13e, -0x1f2958, -0x1f8172,
1107 : -0x1fd98c, -0x2031a6, -0x2089c0, -0x20e1da, -0x2139f4, -0x21920e,
1108 : -0x21ea28, -0x224242, -0x229a5c, -0x22f276, -0x234a90, -0x23a2aa,
1109 : -0x23fac4, -0x2452de, -0x24aaf8, -0x250312, -0x255b2c, -0x25b346,
1110 : -0x260b60, -0x26637a, -0x26bb94, -0x2713ae, -0x276bc8, -0x27c3e2,
1111 : -0x281bfc, -0x287416, -0x28cc30, -0x29244a, -0x297c64, -0x29d47e,
1112 : -0x2a2c98, -0x2a84b2, -0x2adccc, -0x2b34e6,
1113 : };
1114 :
1115 :
1116 : /* We assume that right shift corresponds to signed division by 2 with
1117 : * rounding towards minus infinity. This is correct for typical "arithmetic
1118 : * shift" instructions that shift in copies of the sign bit. But some
1119 : * C compilers implement >> with an unsigned shift. For these machines you
1120 : * must define RIGHT_SHIFT_IS_UNSIGNED.
1121 : * RIGHT_SHIFT provides a proper signed right shift of an INT32 quantity.
1122 : * It is only applied with constant shift counts. SHIFT_TEMPS must be
1123 : * included in the variables of any routine using RIGHT_SHIFT.
1124 : */
1125 :
1126 : #ifdef RIGHT_SHIFT_IS_UNSIGNED
1127 : #define SHIFT_TEMPS INT32 shift_temp;
1128 : #define RIGHT_SHIFT(x,shft) \
1129 : ((shift_temp = (x)) < 0 ? \
1130 : (shift_temp >> (shft)) | ((~((INT32) 0)) << (32-(shft))) : \
1131 : (shift_temp >> (shft)))
1132 : #else
1133 : #define SHIFT_TEMPS
1134 : #define RIGHT_SHIFT(x,shft) ((x) >> (shft))
1135 : #endif
1136 :
1137 :
1138 : METHODDEF(void)
1139 231 : ycc_rgb_convert_argb (j_decompress_ptr cinfo,
1140 : JSAMPIMAGE input_buf, JDIMENSION input_row,
1141 : JSAMPARRAY output_buf, int num_rows)
1142 : {
1143 231 : JDIMENSION num_cols = cinfo->output_width;
1144 231 : JSAMPLE * range_limit = cinfo->sample_range_limit;
1145 :
1146 : SHIFT_TEMPS
1147 :
1148 : /* This is used if we don't have SSE2 */
1149 :
1150 693 : while (--num_rows >= 0) {
1151 231 : JSAMPROW inptr0 = input_buf[0][input_row];
1152 231 : JSAMPROW inptr1 = input_buf[1][input_row];
1153 231 : JSAMPROW inptr2 = input_buf[2][input_row];
1154 231 : input_row++;
1155 231 : PRUint32 *outptr = (PRUint32 *) *output_buf++;
1156 3255 : for (JDIMENSION col = 0; col < num_cols; col++) {
1157 3024 : int y = GETJSAMPLE(inptr0[col]);
1158 3024 : int cb = GETJSAMPLE(inptr1[col]);
1159 3024 : int cr = GETJSAMPLE(inptr2[col]);
1160 3024 : JSAMPLE * range_limit_y = range_limit + y;
1161 : /* Range-limiting is essential due to noise introduced by DCT losses. */
1162 3024 : outptr[col] = 0xFF000000 |
1163 3024 : ( range_limit_y[Cr_r_tab[cr]] << 16 ) |
1164 3024 : ( range_limit_y[((int) RIGHT_SHIFT(Cb_g_tab[cb] + Cr_g_tab[cr], SCALEBITS))] << 8 ) |
1165 6048 : ( range_limit_y[Cb_b_tab[cb]] );
1166 : }
1167 : }
1168 231 : }
1169 :
1170 :
1171 : /**************** Inverted CMYK -> RGB conversion **************/
1172 : /*
1173 : * Input is (Inverted) CMYK stored as 4 bytes per pixel.
1174 : * Output is RGB stored as 3 bytes per pixel.
1175 : * @param row Points to row buffer containing the CMYK bytes for each pixel in the row.
1176 : * @param width Number of pixels in the row.
1177 : */
1178 0 : static void cmyk_convert_rgb(JSAMPROW row, JDIMENSION width)
1179 : {
1180 : /* Work from end to front to shrink from 4 bytes per pixel to 3 */
1181 0 : JSAMPROW in = row + width*4;
1182 0 : JSAMPROW out = in;
1183 :
1184 0 : for (PRUint32 i = width; i > 0; i--) {
1185 0 : in -= 4;
1186 0 : out -= 3;
1187 :
1188 : // Source is 'Inverted CMYK', output is RGB.
1189 : // See: http://www.easyrgb.com/math.php?MATH=M12#text12
1190 : // Or: http://www.ilkeratalay.com/colorspacesfaq.php#rgb
1191 :
1192 : // From CMYK to CMY
1193 : // C = ( C * ( 1 - K ) + K )
1194 : // M = ( M * ( 1 - K ) + K )
1195 : // Y = ( Y * ( 1 - K ) + K )
1196 :
1197 : // From Inverted CMYK to CMY is thus:
1198 : // C = ( (1-iC) * (1 - (1-iK)) + (1-iK) ) => 1 - iC*iK
1199 : // Same for M and Y
1200 :
1201 : // Convert from CMY (0..1) to RGB (0..1)
1202 : // R = 1 - C => 1 - (1 - iC*iK) => iC*iK
1203 : // G = 1 - M => 1 - (1 - iM*iK) => iM*iK
1204 : // B = 1 - Y => 1 - (1 - iY*iK) => iY*iK
1205 :
1206 : // Convert from Inverted CMYK (0..255) to RGB (0..255)
1207 0 : const PRUint32 iC = in[0];
1208 0 : const PRUint32 iM = in[1];
1209 0 : const PRUint32 iY = in[2];
1210 0 : const PRUint32 iK = in[3];
1211 0 : out[0] = iC*iK/255; // Red
1212 0 : out[1] = iM*iK/255; // Green
1213 0 : out[2] = iY*iK/255; // Blue
1214 : }
1215 4392 : }
|