1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "ImageLogging.h"
8 #include "nsJPEGDecoder.h"
9 #include "Orientation.h"
12 #include "nsIInputStream.h"
20 #include "gfxPlatform.h"
26 #if defined(IS_BIG_ENDIAN)
27 #define MOZ_JCS_EXT_NATIVE_ENDIAN_XRGB JCS_EXT_XRGB
29 #define MOZ_JCS_EXT_NATIVE_ENDIAN_XRGB JCS_EXT_BGRX
32 static void cmyk_convert_rgb(JSAMPROW row
, JDIMENSION width
);
37 #if defined(PR_LOGGING)
38 static PRLogModuleInfo
*
41 static PRLogModuleInfo
*sJPEGLog
;
43 sJPEGLog
= PR_NewLogModule("JPEGDecoder");
47 static PRLogModuleInfo
*
48 GetJPEGDecoderAccountingLog()
50 static PRLogModuleInfo
*sJPEGDecoderAccountingLog
;
51 if (!sJPEGDecoderAccountingLog
)
52 sJPEGDecoderAccountingLog
= PR_NewLogModule("JPEGDecoderAccounting");
53 return sJPEGDecoderAccountingLog
;
57 #define GetJPEGDecoderAccountingLog()
61 GetICCProfile(struct jpeg_decompress_struct
&info
)
64 uint32_t profileLength
;
65 qcms_profile
* profile
= nullptr;
67 if (read_icc_profile(&info
, &profilebuf
, &profileLength
)) {
68 profile
= qcms_profile_from_memory(profilebuf
, profileLength
);
75 METHODDEF(void) init_source (j_decompress_ptr jd
);
76 METHODDEF(boolean
) fill_input_buffer (j_decompress_ptr jd
);
77 METHODDEF(void) skip_input_data (j_decompress_ptr jd
, long num_bytes
);
78 METHODDEF(void) term_source (j_decompress_ptr jd
);
79 METHODDEF(void) my_error_exit (j_common_ptr cinfo
);
81 /* Normal JFIF markers can't have more bytes than this. */
82 #define MAX_JPEG_MARKER_LENGTH (((uint32_t)1 << 16) - 1)
85 nsJPEGDecoder::nsJPEGDecoder(RasterImage
& aImage
, Decoder::DecodeStyle aDecodeStyle
)
87 , mDecodeStyle(aDecodeStyle
)
94 memset(&mInfo
, 0, sizeof(jpeg_decompress_struct
));
95 memset(&mSourceMgr
, 0, sizeof(mSourceMgr
));
96 mInfo
.client_data
= (void*)this;
101 mBackBuffer
= nullptr;
102 mBackBufferLen
= mBackBufferSize
= mBackBufferUnreadLen
= 0;
104 mInProfile
= nullptr;
105 mTransform
= nullptr;
109 PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG
,
110 ("nsJPEGDecoder::nsJPEGDecoder: Creating JPEG decoder %p",
114 nsJPEGDecoder::~nsJPEGDecoder()
116 // Step 8: Release JPEG decompression object
118 jpeg_destroy_decompress(&mInfo
);
120 PR_FREEIF(mBackBuffer
);
122 qcms_transform_release(mTransform
);
124 qcms_profile_release(mInProfile
);
126 PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG
,
127 ("nsJPEGDecoder::~nsJPEGDecoder: Destroying JPEG decoder %p",
132 nsJPEGDecoder::SpeedHistogram()
134 return Telemetry::IMAGE_DECODE_SPEED_JPEG
;
138 nsJPEGDecoder::InitInternal()
140 mCMSMode
= gfxPlatform::GetCMSMode();
141 if ((mDecodeFlags
& DECODER_NO_COLORSPACE_CONVERSION
) != 0)
142 mCMSMode
= eCMSMode_Off
;
144 /* We set up the normal JPEG error routines, then override error_exit. */
145 mInfo
.err
= jpeg_std_error(&mErr
.pub
);
146 /* mInfo.err = jpeg_std_error(&mErr.pub); */
147 mErr
.pub
.error_exit
= my_error_exit
;
148 /* Establish the setjmp return context for my_error_exit to use. */
149 if (setjmp(mErr
.setjmp_buffer
)) {
150 /* If we get here, the JPEG code has signaled an error.
151 * We need to clean up the JPEG object, close the input file, and return.
153 PostDecoderError(NS_ERROR_FAILURE
);
157 /* Step 1: allocate and initialize JPEG decompression object */
158 jpeg_create_decompress(&mInfo
);
159 /* Set the source manager */
160 mInfo
.src
= &mSourceMgr
;
162 /* Step 2: specify data source (eg, a file) */
164 /* Setup callback functions. */
165 mSourceMgr
.init_source
= init_source
;
166 mSourceMgr
.fill_input_buffer
= fill_input_buffer
;
167 mSourceMgr
.skip_input_data
= skip_input_data
;
168 mSourceMgr
.resync_to_restart
= jpeg_resync_to_restart
;
169 mSourceMgr
.term_source
= term_source
;
171 /* Record app markers for ICC data */
172 for (uint32_t m
= 0; m
< 16; m
++)
173 jpeg_save_markers(&mInfo
, JPEG_APP0
+ m
, 0xFFFF);
177 nsJPEGDecoder::FinishInternal()
179 /* If we're not in any sort of error case, flush the decoder.
181 * XXXbholley - It seems wrong that this should be necessary, but at the
182 * moment I'm just folding the contents of Flush() into Close() so that
183 * we can get rid of it.
185 * XXX(seth): It'd be great to get rid of this. For now, we treat this as a
186 * write to a synchronous decoder, which means that this must be called only
187 * on the main thread. (That's asserted in Decoder::Finish and
188 * Decoder::FinishSharedDecoder.)
190 if ((mState
!= JPEG_DONE
&& mState
!= JPEG_SINK_NON_JPEG_TRAILER
) &&
191 (mState
!= JPEG_ERROR
) &&
193 this->Write(nullptr, 0, DECODE_SYNC
);
197 nsJPEGDecoder::WriteInternal(const char *aBuffer
, uint32_t aCount
, DecodeStrategy
)
199 mSegment
= (const JOCTET
*)aBuffer
;
200 mSegmentLen
= aCount
;
202 NS_ABORT_IF_FALSE(!HasError(), "Shouldn't call WriteInternal after error!");
204 /* Return here if there is a fatal error within libjpeg. */
206 // This cast to nsresult makes sense because setjmp() returns whatever we
207 // passed to longjmp(), which was actually an nsresult.
208 if ((error_code
= (nsresult
)setjmp(mErr
.setjmp_buffer
)) != NS_OK
) {
209 if (error_code
== NS_ERROR_FAILURE
) {
211 /* Error due to corrupt stream - return NS_OK and consume silently
212 so that libpr0n doesn't throw away a partial image load */
213 mState
= JPEG_SINK_NON_JPEG_TRAILER
;
214 PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG
,
215 ("} (setjmp returned NS_ERROR_FAILURE)"));
218 /* Error due to reasons external to the stream (probably out of
219 memory) - let libpr0n attempt to clean up, even though
220 mozilla is seconds away from falling flat on its face. */
221 PostDecoderError(error_code
);
223 PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG
,
224 ("} (setjmp returned an error)"));
229 PR_LOG(GetJPEGLog(), PR_LOG_DEBUG
,
230 ("[this=%p] nsJPEGDecoder::Write -- processing JPEG data\n", this));
235 LOG_SCOPE(GetJPEGLog(), "nsJPEGDecoder::Write -- entering JPEG_HEADER case");
237 /* Step 3: read file parameters with jpeg_read_header() */
238 if (jpeg_read_header(&mInfo
, TRUE
) == JPEG_SUSPENDED
) {
239 PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG
,
240 ("} (JPEG_SUSPENDED)"));
241 return; /* I/O suspension */
244 int sampleSize
= mImage
.GetRequestedSampleSize();
245 if (sampleSize
> 0) {
247 mInfo
.scale_denom
= sampleSize
;
250 /* Used to set up image size so arrays can be allocated */
251 jpeg_calc_output_dimensions(&mInfo
);
253 // Post our size to the superclass
254 PostSize(mInfo
.output_width
, mInfo
.output_height
, ReadOrientationFromEXIF());
256 // Setting the size led to an error.
261 /* If we're doing a size decode, we're done. */
265 /* We're doing a full decode. */
266 if (mCMSMode
!= eCMSMode_Off
&&
267 (mInProfile
= GetICCProfile(mInfo
)) != nullptr) {
268 uint32_t profileSpace
= qcms_profile_get_color_space(mInProfile
);
269 bool mismatch
= false;
272 fprintf(stderr
, "JPEG profileSpace: 0x%08X\n", profileSpace
);
274 switch (mInfo
.jpeg_color_space
) {
276 if (profileSpace
== icSigRgbData
)
277 mInfo
.out_color_space
= JCS_RGB
;
278 else if (profileSpace
!= icSigGrayData
)
282 if (profileSpace
!= icSigRgbData
)
286 if (profileSpace
== icSigRgbData
)
287 mInfo
.out_color_space
= JCS_RGB
;
289 // qcms doesn't support ycbcr
294 // qcms doesn't support cmyk
300 PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG
,
301 ("} (unknown colorpsace (1))"));
307 switch (mInfo
.out_color_space
) {
309 type
= QCMS_DATA_GRAY_8
;
312 type
= QCMS_DATA_RGB_8
;
317 PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG
,
318 ("} (unknown colorpsace (2))"));
322 /* We don't currently support CMYK profiles. The following
323 * code dealt with lcms types. Add something like this
324 * back when we gain support for CMYK.
326 /* Adobe Photoshop writes YCCK/CMYK files with inverted data */
327 if (mInfo
.out_color_space
== JCS_CMYK
)
328 type
|= FLAVOR_SH(mInfo
.saw_Adobe_marker
? 1 : 0);
331 if (gfxPlatform::GetCMSOutputProfile()) {
333 /* Calculate rendering intent. */
334 int intent
= gfxPlatform::GetRenderingIntent();
336 intent
= qcms_profile_get_rendering_intent(mInProfile
);
338 /* Create the color management transform. */
339 mTransform
= qcms_transform_create(mInProfile
,
341 gfxPlatform::GetCMSOutputProfile(),
343 (qcms_intent
)intent
);
347 fprintf(stderr
, "ICM profile colorspace mismatch\n");
353 switch (mInfo
.jpeg_color_space
) {
357 // if we're not color managing we can decode directly to
358 // MOZ_JCS_EXT_NATIVE_ENDIAN_XRGB
359 if (mCMSMode
!= eCMSMode_All
) {
360 mInfo
.out_color_space
= MOZ_JCS_EXT_NATIVE_ENDIAN_XRGB
;
361 mInfo
.out_color_components
= 4;
363 mInfo
.out_color_space
= JCS_RGB
;
368 /* libjpeg can convert from YCCK to CMYK, but not to RGB */
369 mInfo
.out_color_space
= JCS_CMYK
;
374 PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG
,
375 ("} (unknown colorpsace (3))"));
382 * Don't allocate a giant and superfluous memory buffer
383 * when not doing a progressive decode.
385 mInfo
.buffered_image
= mDecodeStyle
== PROGRESSIVE
&& jpeg_has_multiple_scans(&mInfo
);
389 PostDecoderError(NS_ERROR_OUT_OF_MEMORY
);
390 PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG
,
391 ("} (could not initialize image frame)"));
395 PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG
,
396 (" JPEGDecoderAccounting: nsJPEGDecoder::Write -- created image frame with %ux%u pixels",
397 mInfo
.output_width
, mInfo
.output_height
));
399 mState
= JPEG_START_DECOMPRESS
;
402 case JPEG_START_DECOMPRESS
:
404 LOG_SCOPE(GetJPEGLog(), "nsJPEGDecoder::Write -- entering JPEG_START_DECOMPRESS case");
405 /* Step 4: set parameters for decompression */
407 /* FIXME -- Should reset dct_method and dither mode
408 * for final pass of progressive JPEG
410 mInfo
.dct_method
= JDCT_ISLOW
;
411 mInfo
.dither_mode
= JDITHER_FS
;
412 mInfo
.do_fancy_upsampling
= TRUE
;
413 mInfo
.enable_2pass_quant
= FALSE
;
414 mInfo
.do_block_smoothing
= TRUE
;
416 /* Step 5: Start decompressor */
417 if (jpeg_start_decompress(&mInfo
) == FALSE
) {
418 PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG
,
419 ("} (I/O suspension after jpeg_start_decompress())"));
420 return; /* I/O suspension */
424 /* If this is a progressive JPEG ... */
425 mState
= mInfo
.buffered_image
? JPEG_DECOMPRESS_PROGRESSIVE
: JPEG_DECOMPRESS_SEQUENTIAL
;
428 case JPEG_DECOMPRESS_SEQUENTIAL
:
430 if (mState
== JPEG_DECOMPRESS_SEQUENTIAL
)
432 LOG_SCOPE(GetJPEGLog(), "nsJPEGDecoder::Write -- JPEG_DECOMPRESS_SEQUENTIAL case");
435 OutputScanlines(&suspend
);
438 PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG
,
439 ("} (I/O suspension after OutputScanlines() - SEQUENTIAL)"));
440 return; /* I/O suspension */
443 /* If we've completed image output ... */
444 NS_ASSERTION(mInfo
.output_scanline
== mInfo
.output_height
, "We didn't process all of the data!");
449 case JPEG_DECOMPRESS_PROGRESSIVE
:
451 if (mState
== JPEG_DECOMPRESS_PROGRESSIVE
)
453 LOG_SCOPE(GetJPEGLog(), "nsJPEGDecoder::Write -- JPEG_DECOMPRESS_PROGRESSIVE case");
457 status
= jpeg_consume_input(&mInfo
);
458 } while ((status
!= JPEG_SUSPENDED
) &&
459 (status
!= JPEG_REACHED_EOI
));
462 if (mInfo
.output_scanline
== 0) {
463 int scan
= mInfo
.input_scan_number
;
465 /* if we haven't displayed anything yet (output_scan_number==0)
466 and we have enough data for a complete scan, force output
467 of the last full scan */
468 if ((mInfo
.output_scan_number
== 0) &&
470 (status
!= JPEG_REACHED_EOI
))
473 if (!jpeg_start_output(&mInfo
, scan
)) {
474 PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG
,
475 ("} (I/O suspension after jpeg_start_output() - PROGRESSIVE)"));
476 return; /* I/O suspension */
480 if (mInfo
.output_scanline
== 0xffffff)
481 mInfo
.output_scanline
= 0;
484 OutputScanlines(&suspend
);
487 if (mInfo
.output_scanline
== 0) {
488 /* didn't manage to read any lines - flag so we don't call
489 jpeg_start_output() multiple times for the same scan */
490 mInfo
.output_scanline
= 0xffffff;
492 PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG
,
493 ("} (I/O suspension after OutputScanlines() - PROGRESSIVE)"));
494 return; /* I/O suspension */
497 if (mInfo
.output_scanline
== mInfo
.output_height
)
499 if (!jpeg_finish_output(&mInfo
)) {
500 PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG
,
501 ("} (I/O suspension after jpeg_finish_output() - PROGRESSIVE)"));
502 return; /* I/O suspension */
505 if (jpeg_input_complete(&mInfo
) &&
506 (mInfo
.input_scan_number
== mInfo
.output_scan_number
))
509 mInfo
.output_scanline
= 0;
519 LOG_SCOPE(GetJPEGLog(), "nsJPEGDecoder::ProcessData -- entering JPEG_DONE case");
521 /* Step 7: Finish decompression */
523 if (jpeg_finish_decompress(&mInfo
) == FALSE
) {
524 PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG
,
525 ("} (I/O suspension after jpeg_finish_decompress() - DONE)"));
526 return; /* I/O suspension */
529 mState
= JPEG_SINK_NON_JPEG_TRAILER
;
531 /* we're done dude */
534 case JPEG_SINK_NON_JPEG_TRAILER
:
535 PR_LOG(GetJPEGLog(), PR_LOG_DEBUG
,
536 ("[this=%p] nsJPEGDecoder::ProcessData -- entering JPEG_SINK_NON_JPEG_TRAILER case\n", this));
541 NS_ABORT_IF_FALSE(0, "Should always return immediately after error and not re-enter decoder");
544 PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG
,
545 ("} (end of function)"));
550 nsJPEGDecoder::ReadOrientationFromEXIF()
552 jpeg_saved_marker_ptr marker
;
554 // Locate the APP1 marker, where EXIF data is stored, in the marker list.
555 for (marker
= mInfo
.marker_list
; marker
!= nullptr ; marker
= marker
->next
) {
556 if (marker
->marker
== JPEG_APP0
+ 1)
560 // If we're at the end of the list, there's no EXIF data.
562 return Orientation();
564 // Extract the orientation information.
565 EXIFData exif
= EXIFParser::Parse(marker
->data
,
566 static_cast<uint32_t>(marker
->data_length
));
567 return exif
.orientation
;
571 nsJPEGDecoder::NotifyDone()
573 PostFrameStop(FrameBlender::kFrameOpaque
);
578 nsJPEGDecoder::OutputScanlines(bool* suspend
)
582 const uint32_t top
= mInfo
.output_scanline
;
584 while ((mInfo
.output_scanline
< mInfo
.output_height
)) {
585 /* Use the Cairo image buffer as scanline buffer */
586 uint32_t *imageRow
= ((uint32_t*)mImageData
) +
587 (mInfo
.output_scanline
* mInfo
.output_width
);
589 if (mInfo
.out_color_space
== MOZ_JCS_EXT_NATIVE_ENDIAN_XRGB
) {
590 /* Special case: scanline will be directly converted into packed ARGB */
591 if (jpeg_read_scanlines(&mInfo
, (JSAMPARRAY
)&imageRow
, 1) != 1) {
592 *suspend
= true; /* suspend */
595 continue; /* all done for this row! */
598 JSAMPROW sampleRow
= (JSAMPROW
)imageRow
;
599 if (mInfo
.output_components
== 3) {
600 /* Put the pixels at end of row to enable in-place expansion */
601 sampleRow
+= mInfo
.output_width
;
604 /* Request one scanline. Returns 0 or 1 scanlines. */
605 if (jpeg_read_scanlines(&mInfo
, &sampleRow
, 1) != 1) {
606 *suspend
= true; /* suspend */
611 JSAMPROW source
= sampleRow
;
612 if (mInfo
.out_color_space
== JCS_GRAYSCALE
) {
613 /* Convert from the 1byte grey pixels at begin of row
614 to the 3byte RGB byte pixels at 'end' of row */
615 sampleRow
+= mInfo
.output_width
;
617 qcms_transform_data(mTransform
, source
, sampleRow
, mInfo
.output_width
);
618 /* Move 3byte RGB data to end of row */
619 if (mInfo
.out_color_space
== JCS_CMYK
) {
620 memmove(sampleRow
+ mInfo
.output_width
,
622 3 * mInfo
.output_width
);
623 sampleRow
+= mInfo
.output_width
;
626 if (mInfo
.out_color_space
== JCS_CMYK
) {
627 /* Convert from CMYK to RGB */
628 /* We cannot convert directly to Cairo, as the CMSRGBTransform may wants to do a RGB transform... */
629 /* Would be better to have platform CMSenabled transformation from CMYK to (A)RGB... */
630 cmyk_convert_rgb((JSAMPROW
)imageRow
, mInfo
.output_width
);
631 sampleRow
+= mInfo
.output_width
;
633 if (mCMSMode
== eCMSMode_All
) {
634 /* No embedded ICC profile - treat as sRGB */
635 qcms_transform
*transform
= gfxPlatform::GetCMSRGBTransform();
637 qcms_transform_data(transform
, sampleRow
, sampleRow
, mInfo
.output_width
);
642 // counter for while() loops below
643 uint32_t idx
= mInfo
.output_width
;
645 // copy as bytes until source pointer is 32-bit-aligned
646 for (; (NS_PTR_TO_UINT32(sampleRow
) & 0x3) && idx
; --idx
) {
647 *imageRow
++ = gfxPackedPixel(0xFF, sampleRow
[0], sampleRow
[1], sampleRow
[2]);
651 // copy pixels in blocks of 4
653 GFX_BLOCK_RGB_TO_FRGB(sampleRow
, imageRow
);
659 // copy remaining pixel(s)
661 // 32-bit read of final pixel will exceed buffer, so read bytes
662 *imageRow
++ = gfxPackedPixel(0xFF, sampleRow
[0], sampleRow
[1], sampleRow
[2]);
667 if (top
!= mInfo
.output_scanline
) {
668 nsIntRect
r(0, top
, mInfo
.output_width
, mInfo
.output_scanline
-top
);
675 /* Override the standard error method in the IJG JPEG decoder code. */
677 my_error_exit (j_common_ptr cinfo
)
679 decoder_error_mgr
*err
= (decoder_error_mgr
*) cinfo
->err
;
681 /* Convert error to a browser error code */
682 nsresult error_code
= err
->pub
.msg_code
== JERR_OUT_OF_MEMORY
683 ? NS_ERROR_OUT_OF_MEMORY
687 char buffer
[JMSG_LENGTH_MAX
];
689 /* Create the message */
690 (*err
->pub
.format_message
) (cinfo
, buffer
);
692 fprintf(stderr
, "JPEG decoding error:\n%s\n", buffer
);
695 /* Return control to the setjmp point. We pass an nsresult masquerading as
696 * an int, which works because the setjmp() caller casts it back. */
697 longjmp(err
->setjmp_buffer
, static_cast<int>(error_code
));
700 /******************************************************************************/
701 /*-----------------------------------------------------------------------------
702 * This is the callback routine from the IJG JPEG library used to supply new
703 * data to the decompressor when its input buffer is exhausted. It juggles
704 * multiple buffers in an attempt to avoid unnecessary copying of input data.
706 * (A simpler scheme is possible: It's much easier to use only a single
707 * buffer; when fill_input_buffer() is called, move any unconsumed data
708 * (beyond the current pointer/count) down to the beginning of this buffer and
709 * then load new data into the remaining buffer space. This approach requires
710 * a little more data copying but is far easier to get right.)
712 * At any one time, the JPEG decompressor is either reading from the necko
713 * input buffer, which is volatile across top-level calls to the IJG library,
714 * or the "backtrack" buffer. The backtrack buffer contains the remaining
715 * unconsumed data from the necko buffer after parsing was suspended due
716 * to insufficient data in some previous call to the IJG library.
718 * When suspending, the decompressor will back up to a convenient restart
719 * point (typically the start of the current MCU). The variables
720 * next_input_byte & bytes_in_buffer indicate where the restart point will be
721 * if the current call returns FALSE. Data beyond this point must be
722 * rescanned after resumption, so it must be preserved in case the decompressor
723 * decides to backtrack.
726 * TRUE if additional data is available, FALSE if no data present and
727 * the JPEG library should therefore suspend processing of input stream
728 *---------------------------------------------------------------------------*/
730 /******************************************************************************/
731 /* data source manager method */
732 /******************************************************************************/
735 /******************************************************************************/
736 /* data source manager method
737 Initialize source. This is called by jpeg_read_header() before any
738 data is actually read. May leave
739 bytes_in_buffer set to 0 (in which case a fill_input_buffer() call
740 will occur immediately).
743 init_source (j_decompress_ptr jd
)
747 /******************************************************************************/
748 /* data source manager method
749 Skip num_bytes worth of data. The buffer pointer and count should
750 be advanced over num_bytes input bytes, refilling the buffer as
751 needed. This is used to skip over a potentially large amount of
752 uninteresting data (such as an APPn marker). In some applications
753 it may be possible to optimize away the reading of the skipped data,
754 but it's not clear that being smart is worth much trouble; large
755 skips are uncommon. bytes_in_buffer may be zero on return.
756 A zero or negative skip count should be treated as a no-op.
759 skip_input_data (j_decompress_ptr jd
, long num_bytes
)
761 struct jpeg_source_mgr
*src
= jd
->src
;
762 nsJPEGDecoder
*decoder
= (nsJPEGDecoder
*)(jd
->client_data
);
764 if (num_bytes
> (long)src
->bytes_in_buffer
) {
766 * Can't skip it all right now until we get more data from
767 * network stream. Set things up so that fill_input_buffer
768 * will skip remaining amount.
770 decoder
->mBytesToSkip
= (size_t)num_bytes
- src
->bytes_in_buffer
;
771 src
->next_input_byte
+= src
->bytes_in_buffer
;
772 src
->bytes_in_buffer
= 0;
775 /* Simple case. Just advance buffer pointer */
777 src
->bytes_in_buffer
-= (size_t)num_bytes
;
778 src
->next_input_byte
+= num_bytes
;
783 /******************************************************************************/
784 /* data source manager method
785 This is called whenever bytes_in_buffer has reached zero and more
786 data is wanted. In typical applications, it should read fresh data
787 into the buffer (ignoring the current state of next_input_byte and
788 bytes_in_buffer), reset the pointer & count to the start of the
789 buffer, and return TRUE indicating that the buffer has been reloaded.
790 It is not necessary to fill the buffer entirely, only to obtain at
791 least one more byte. bytes_in_buffer MUST be set to a positive value
792 if TRUE is returned. A FALSE return should only be used when I/O
793 suspension is desired.
796 fill_input_buffer (j_decompress_ptr jd
)
798 struct jpeg_source_mgr
*src
= jd
->src
;
799 nsJPEGDecoder
*decoder
= (nsJPEGDecoder
*)(jd
->client_data
);
801 if (decoder
->mReading
) {
802 const JOCTET
*new_buffer
= decoder
->mSegment
;
803 uint32_t new_buflen
= decoder
->mSegmentLen
;
805 if (!new_buffer
|| new_buflen
== 0)
806 return false; /* suspend */
808 decoder
->mSegmentLen
= 0;
810 if (decoder
->mBytesToSkip
) {
811 if (decoder
->mBytesToSkip
< new_buflen
) {
812 /* All done skipping bytes; Return what's left. */
813 new_buffer
+= decoder
->mBytesToSkip
;
814 new_buflen
-= decoder
->mBytesToSkip
;
815 decoder
->mBytesToSkip
= 0;
817 /* Still need to skip some more data in the future */
818 decoder
->mBytesToSkip
-= (size_t)new_buflen
;
819 return false; /* suspend */
823 decoder
->mBackBufferUnreadLen
= src
->bytes_in_buffer
;
825 src
->next_input_byte
= new_buffer
;
826 src
->bytes_in_buffer
= (size_t)new_buflen
;
827 decoder
->mReading
= false;
832 if (src
->next_input_byte
!= decoder
->mSegment
) {
833 /* Backtrack data has been permanently consumed. */
834 decoder
->mBackBufferUnreadLen
= 0;
835 decoder
->mBackBufferLen
= 0;
838 /* Save remainder of netlib buffer in backtrack buffer */
839 const uint32_t new_backtrack_buflen
= src
->bytes_in_buffer
+ decoder
->mBackBufferLen
;
841 /* Make sure backtrack buffer is big enough to hold new data. */
842 if (decoder
->mBackBufferSize
< new_backtrack_buflen
) {
843 /* Check for malformed MARKER segment lengths, before allocating space for it */
844 if (new_backtrack_buflen
> MAX_JPEG_MARKER_LENGTH
) {
845 my_error_exit((j_common_ptr
)(&decoder
->mInfo
));
848 /* Round up to multiple of 256 bytes. */
849 const size_t roundup_buflen
= ((new_backtrack_buflen
+ 255) >> 8) << 8;
850 JOCTET
*buf
= (JOCTET
*)PR_REALLOC(decoder
->mBackBuffer
, roundup_buflen
);
853 decoder
->mInfo
.err
->msg_code
= JERR_OUT_OF_MEMORY
;
854 my_error_exit((j_common_ptr
)(&decoder
->mInfo
));
856 decoder
->mBackBuffer
= buf
;
857 decoder
->mBackBufferSize
= roundup_buflen
;
860 /* Copy remainder of netlib segment into backtrack buffer. */
861 memmove(decoder
->mBackBuffer
+ decoder
->mBackBufferLen
,
862 src
->next_input_byte
,
863 src
->bytes_in_buffer
);
865 /* Point to start of data to be rescanned. */
866 src
->next_input_byte
= decoder
->mBackBuffer
+ decoder
->mBackBufferLen
- decoder
->mBackBufferUnreadLen
;
867 src
->bytes_in_buffer
+= decoder
->mBackBufferUnreadLen
;
868 decoder
->mBackBufferLen
= (size_t)new_backtrack_buflen
;
869 decoder
->mReading
= true;
874 /******************************************************************************/
875 /* data source manager method */
877 * Terminate source --- called by jpeg_finish_decompress() after all
878 * data has been read to clean up JPEG source manager. NOT called by
879 * jpeg_abort() or jpeg_destroy().
882 term_source (j_decompress_ptr jd
)
884 nsJPEGDecoder
*decoder
= (nsJPEGDecoder
*)(jd
->client_data
);
886 // This function shouldn't be called if we ran into an error we didn't
888 NS_ABORT_IF_FALSE(decoder
->mState
!= JPEG_ERROR
,
889 "Calling term_source on a JPEG with mState == JPEG_ERROR!");
891 // Notify using a helper method to get around protectedness issues.
892 decoder
->NotifyDone();
896 } // namespace mozilla
899 /**************** Inverted CMYK -> RGB conversion **************/
901 * Input is (Inverted) CMYK stored as 4 bytes per pixel.
902 * Output is RGB stored as 3 bytes per pixel.
903 * @param row Points to row buffer containing the CMYK bytes for each pixel in the row.
904 * @param width Number of pixels in the row.
906 static void cmyk_convert_rgb(JSAMPROW row
, JDIMENSION width
)
908 /* Work from end to front to shrink from 4 bytes per pixel to 3 */
909 JSAMPROW in
= row
+ width
*4;
912 for (uint32_t i
= width
; i
> 0; i
--) {
916 // Source is 'Inverted CMYK', output is RGB.
917 // See: http://www.easyrgb.com/math.php?MATH=M12#text12
918 // Or: http://www.ilkeratalay.com/colorspacesfaq.php#rgb
921 // C = ( C * ( 1 - K ) + K )
922 // M = ( M * ( 1 - K ) + K )
923 // Y = ( Y * ( 1 - K ) + K )
925 // From Inverted CMYK to CMY is thus:
926 // C = ( (1-iC) * (1 - (1-iK)) + (1-iK) ) => 1 - iC*iK
929 // Convert from CMY (0..1) to RGB (0..1)
930 // R = 1 - C => 1 - (1 - iC*iK) => iC*iK
931 // G = 1 - M => 1 - (1 - iM*iK) => iM*iK
932 // B = 1 - Y => 1 - (1 - iY*iK) => iY*iK
934 // Convert from Inverted CMYK (0..255) to RGB (0..255)
935 const uint32_t iC
= in
[0];
936 const uint32_t iM
= in
[1];
937 const uint32_t iY
= in
[2];
938 const uint32_t iK
= in
[3];
939 out
[0] = iC
*iK
/255; // Red
940 out
[1] = iM
*iK
/255; // Green
941 out
[2] = iY
*iK
/255; // Blue