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");
48 static PRLogModuleInfo
*
49 GetJPEGDecoderAccountingLog()
51 static PRLogModuleInfo
* sJPEGDecoderAccountingLog
;
52 if (!sJPEGDecoderAccountingLog
) {
53 sJPEGDecoderAccountingLog
= PR_NewLogModule("JPEGDecoderAccounting");
55 return sJPEGDecoderAccountingLog
;
59 #define GetJPEGDecoderAccountingLog()
63 GetICCProfile(struct jpeg_decompress_struct
& info
)
66 uint32_t profileLength
;
67 qcms_profile
* profile
= nullptr;
69 if (read_icc_profile(&info
, &profilebuf
, &profileLength
)) {
70 profile
= qcms_profile_from_memory(profilebuf
, profileLength
);
77 METHODDEF(void) init_source (j_decompress_ptr jd
);
78 METHODDEF(boolean
) fill_input_buffer (j_decompress_ptr jd
);
79 METHODDEF(void) skip_input_data (j_decompress_ptr jd
, long num_bytes
);
80 METHODDEF(void) term_source (j_decompress_ptr jd
);
81 METHODDEF(void) my_error_exit (j_common_ptr cinfo
);
83 // Normal JFIF markers can't have more bytes than this.
84 #define MAX_JPEG_MARKER_LENGTH (((uint32_t)1 << 16) - 1)
87 nsJPEGDecoder::nsJPEGDecoder(RasterImage
* aImage
,
88 Decoder::DecodeStyle aDecodeStyle
)
90 , mDecodeStyle(aDecodeStyle
)
97 memset(&mInfo
, 0, sizeof(jpeg_decompress_struct
));
98 memset(&mSourceMgr
, 0, sizeof(mSourceMgr
));
99 mInfo
.client_data
= (void*)this;
104 mBackBuffer
= nullptr;
105 mBackBufferLen
= mBackBufferSize
= mBackBufferUnreadLen
= 0;
107 mInProfile
= nullptr;
108 mTransform
= nullptr;
112 PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG
,
113 ("nsJPEGDecoder::nsJPEGDecoder: Creating JPEG decoder %p",
117 nsJPEGDecoder::~nsJPEGDecoder()
119 // Step 8: Release JPEG decompression object
121 jpeg_destroy_decompress(&mInfo
);
123 PR_FREEIF(mBackBuffer
);
125 qcms_transform_release(mTransform
);
128 qcms_profile_release(mInProfile
);
131 PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG
,
132 ("nsJPEGDecoder::~nsJPEGDecoder: Destroying JPEG decoder %p",
137 nsJPEGDecoder::SpeedHistogram()
139 return Telemetry::IMAGE_DECODE_SPEED_JPEG
;
143 nsJPEGDecoder::InitInternal()
145 mCMSMode
= gfxPlatform::GetCMSMode();
146 if (GetDecodeFlags() & imgIContainer::FLAG_DECODE_NO_COLORSPACE_CONVERSION
) {
147 mCMSMode
= eCMSMode_Off
;
150 // We set up the normal JPEG error routines, then override error_exit.
151 mInfo
.err
= jpeg_std_error(&mErr
.pub
);
152 // mInfo.err = jpeg_std_error(&mErr.pub);
153 mErr
.pub
.error_exit
= my_error_exit
;
154 // Establish the setjmp return context for my_error_exit to use.
155 if (setjmp(mErr
.setjmp_buffer
)) {
156 // If we get here, the JPEG code has signaled an error.
157 // We need to clean up the JPEG object, close the input file, and return.
158 PostDecoderError(NS_ERROR_FAILURE
);
162 // Step 1: allocate and initialize JPEG decompression object
163 jpeg_create_decompress(&mInfo
);
164 // Set the source manager
165 mInfo
.src
= &mSourceMgr
;
167 // Step 2: specify data source (eg, a file)
169 // Setup callback functions.
170 mSourceMgr
.init_source
= init_source
;
171 mSourceMgr
.fill_input_buffer
= fill_input_buffer
;
172 mSourceMgr
.skip_input_data
= skip_input_data
;
173 mSourceMgr
.resync_to_restart
= jpeg_resync_to_restart
;
174 mSourceMgr
.term_source
= term_source
;
176 // Record app markers for ICC data
177 for (uint32_t m
= 0; m
< 16; m
++)
178 jpeg_save_markers(&mInfo
, JPEG_APP0
+ m
, 0xFFFF);
182 nsJPEGDecoder::FinishInternal()
184 // If we're not in any sort of error case, force our state to JPEG_DONE.
185 if ((mState
!= JPEG_DONE
&& mState
!= JPEG_SINK_NON_JPEG_TRAILER
) &&
186 (mState
!= JPEG_ERROR
) &&
193 nsJPEGDecoder::WriteInternal(const char* aBuffer
, uint32_t aCount
)
195 mSegment
= (const JOCTET
*)aBuffer
;
196 mSegmentLen
= aCount
;
198 NS_ABORT_IF_FALSE(!HasError(), "Shouldn't call WriteInternal after error!");
200 // Return here if there is a fatal error within libjpeg.
202 // This cast to nsresult makes sense because setjmp() returns whatever we
203 // passed to longjmp(), which was actually an nsresult.
204 if ((error_code
= (nsresult
)setjmp(mErr
.setjmp_buffer
)) != NS_OK
) {
205 if (error_code
== NS_ERROR_FAILURE
) {
207 // Error due to corrupt stream - return NS_OK and consume silently
208 // so that ImageLib doesn't throw away a partial image load
209 mState
= JPEG_SINK_NON_JPEG_TRAILER
;
210 PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG
,
211 ("} (setjmp returned NS_ERROR_FAILURE)"));
214 // Error due to reasons external to the stream (probably out of
215 // memory) - let ImageLib attempt to clean up, even though
216 // mozilla is seconds away from falling flat on its face.
217 PostDecoderError(error_code
);
219 PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG
,
220 ("} (setjmp returned an error)"));
225 PR_LOG(GetJPEGLog(), PR_LOG_DEBUG
,
226 ("[this=%p] nsJPEGDecoder::Write -- processing JPEG data\n", this));
230 LOG_SCOPE(GetJPEGLog(), "nsJPEGDecoder::Write -- entering JPEG_HEADER"
233 // Step 3: read file parameters with jpeg_read_header()
234 if (jpeg_read_header(&mInfo
, TRUE
) == JPEG_SUSPENDED
) {
235 PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG
,
236 ("} (JPEG_SUSPENDED)"));
237 return; // I/O suspension
240 int sampleSize
= mImage
->GetRequestedSampleSize();
241 if (sampleSize
> 0) {
243 mInfo
.scale_denom
= sampleSize
;
246 // Used to set up image size so arrays can be allocated
247 jpeg_calc_output_dimensions(&mInfo
);
249 // Post our size to the superclass
250 PostSize(mInfo
.output_width
, mInfo
.output_height
,
251 ReadOrientationFromEXIF());
253 // Setting the size led to an error.
258 // If we're doing a size decode, we're done.
259 if (IsSizeDecode()) {
263 // We're doing a full decode.
264 if (mCMSMode
!= eCMSMode_Off
&&
265 (mInProfile
= GetICCProfile(mInfo
)) != nullptr) {
266 uint32_t profileSpace
= qcms_profile_get_color_space(mInProfile
);
267 bool mismatch
= false;
270 fprintf(stderr
, "JPEG profileSpace: 0x%08X\n", profileSpace
);
272 switch (mInfo
.jpeg_color_space
) {
274 if (profileSpace
== icSigRgbData
) {
275 mInfo
.out_color_space
= JCS_RGB
;
276 } else if (profileSpace
!= icSigGrayData
) {
281 if (profileSpace
!= icSigRgbData
) {
286 if (profileSpace
== icSigRgbData
) {
287 mInfo
.out_color_space
= JCS_RGB
;
289 // qcms doesn't support ycbcr
295 // qcms doesn't support cmyk
301 PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG
,
302 ("} (unknown colorpsace (1))"));
308 switch (mInfo
.out_color_space
) {
310 type
= QCMS_DATA_GRAY_8
;
313 type
= QCMS_DATA_RGB_8
;
318 PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG
,
319 ("} (unknown colorpsace (2))"));
323 // We don't currently support CMYK profiles. The following
324 // code dealt with lcms types. Add something like this
325 // back when we gain support for CMYK.
327 // Adobe Photoshop writes YCCK/CMYK files with inverted data
328 if (mInfo
.out_color_space
== JCS_CMYK
) {
329 type
|= FLAVOR_SH(mInfo
.saw_Adobe_marker
? 1 : 0);
333 if (gfxPlatform::GetCMSOutputProfile()) {
335 // Calculate rendering intent.
336 int intent
= gfxPlatform::GetRenderingIntent();
338 intent
= qcms_profile_get_rendering_intent(mInProfile
);
341 // Create the color management transform.
342 mTransform
= qcms_transform_create(mInProfile
,
344 gfxPlatform::GetCMSOutputProfile(),
346 (qcms_intent
)intent
);
350 fprintf(stderr
, "ICM profile colorspace mismatch\n");
356 switch (mInfo
.jpeg_color_space
) {
360 // if we're not color managing we can decode directly to
361 // MOZ_JCS_EXT_NATIVE_ENDIAN_XRGB
362 if (mCMSMode
!= eCMSMode_All
) {
363 mInfo
.out_color_space
= MOZ_JCS_EXT_NATIVE_ENDIAN_XRGB
;
364 mInfo
.out_color_components
= 4;
366 mInfo
.out_color_space
= JCS_RGB
;
371 // libjpeg can convert from YCCK to CMYK, but not to RGB
372 mInfo
.out_color_space
= JCS_CMYK
;
377 PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG
,
378 ("} (unknown colorpsace (3))"));
384 // Don't allocate a giant and superfluous memory buffer
385 // when not doing a progressive decode.
386 mInfo
.buffered_image
= mDecodeStyle
== PROGRESSIVE
&&
387 jpeg_has_multiple_scans(&mInfo
);
391 PostDecoderError(NS_ERROR_OUT_OF_MEMORY
);
392 PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG
,
393 ("} (could not initialize image frame)"));
397 PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG
,
398 (" JPEGDecoderAccounting: nsJPEGDecoder::"
399 "Write -- created image frame with %ux%u pixels",
400 mInfo
.output_width
, mInfo
.output_height
));
402 mState
= JPEG_START_DECOMPRESS
;
405 case JPEG_START_DECOMPRESS
: {
406 LOG_SCOPE(GetJPEGLog(), "nsJPEGDecoder::Write -- entering"
407 " JPEG_START_DECOMPRESS case");
408 // Step 4: set parameters for decompression
410 // FIXME -- Should reset dct_method and dither mode
411 // for final pass of progressive JPEG
413 mInfo
.dct_method
= JDCT_ISLOW
;
414 mInfo
.dither_mode
= JDITHER_FS
;
415 mInfo
.do_fancy_upsampling
= TRUE
;
416 mInfo
.enable_2pass_quant
= FALSE
;
417 mInfo
.do_block_smoothing
= TRUE
;
419 // Step 5: Start decompressor
420 if (jpeg_start_decompress(&mInfo
) == FALSE
) {
421 PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG
,
422 ("} (I/O suspension after jpeg_start_decompress())"));
423 return; // I/O suspension
427 // If this is a progressive JPEG ...
428 mState
= mInfo
.buffered_image
?
429 JPEG_DECOMPRESS_PROGRESSIVE
: JPEG_DECOMPRESS_SEQUENTIAL
;
432 case JPEG_DECOMPRESS_SEQUENTIAL
: {
433 if (mState
== JPEG_DECOMPRESS_SEQUENTIAL
) {
434 LOG_SCOPE(GetJPEGLog(), "nsJPEGDecoder::Write -- "
435 "JPEG_DECOMPRESS_SEQUENTIAL case");
438 OutputScanlines(&suspend
);
441 PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG
,
442 ("} (I/O suspension after OutputScanlines() - SEQUENTIAL)"));
443 return; // I/O suspension
446 // If we've completed image output ...
447 NS_ASSERTION(mInfo
.output_scanline
== mInfo
.output_height
,
448 "We didn't process all of the data!");
453 case JPEG_DECOMPRESS_PROGRESSIVE
: {
454 if (mState
== JPEG_DECOMPRESS_PROGRESSIVE
) {
455 LOG_SCOPE(GetJPEGLog(),
456 "nsJPEGDecoder::Write -- JPEG_DECOMPRESS_PROGRESSIVE case");
460 status
= jpeg_consume_input(&mInfo
);
461 } while ((status
!= JPEG_SUSPENDED
) &&
462 (status
!= JPEG_REACHED_EOI
));
465 if (mInfo
.output_scanline
== 0) {
466 int scan
= mInfo
.input_scan_number
;
468 // if we haven't displayed anything yet (output_scan_number==0)
469 // and we have enough data for a complete scan, force output
470 // of the last full scan
471 if ((mInfo
.output_scan_number
== 0) &&
473 (status
!= JPEG_REACHED_EOI
))
476 if (!jpeg_start_output(&mInfo
, scan
)) {
477 PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG
,
478 ("} (I/O suspension after jpeg_start_output() -"
480 return; // I/O suspension
484 if (mInfo
.output_scanline
== 0xffffff) {
485 mInfo
.output_scanline
= 0;
489 OutputScanlines(&suspend
);
492 if (mInfo
.output_scanline
== 0) {
493 // didn't manage to read any lines - flag so we don't call
494 // jpeg_start_output() multiple times for the same scan
495 mInfo
.output_scanline
= 0xffffff;
497 PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG
,
498 ("} (I/O suspension after OutputScanlines() - PROGRESSIVE)"));
499 return; // I/O suspension
502 if (mInfo
.output_scanline
== mInfo
.output_height
) {
503 if (!jpeg_finish_output(&mInfo
)) {
504 PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG
,
505 ("} (I/O suspension after jpeg_finish_output() -"
507 return; // I/O suspension
510 if (jpeg_input_complete(&mInfo
) &&
511 (mInfo
.input_scan_number
== mInfo
.output_scan_number
))
514 mInfo
.output_scanline
= 0;
523 LOG_SCOPE(GetJPEGLog(), "nsJPEGDecoder::ProcessData -- entering"
526 // Step 7: Finish decompression
528 if (jpeg_finish_decompress(&mInfo
) == FALSE
) {
529 PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG
,
530 ("} (I/O suspension after jpeg_finish_decompress() - DONE)"));
531 return; // I/O suspension
534 mState
= JPEG_SINK_NON_JPEG_TRAILER
;
539 case JPEG_SINK_NON_JPEG_TRAILER
:
540 PR_LOG(GetJPEGLog(), PR_LOG_DEBUG
,
541 ("[this=%p] nsJPEGDecoder::ProcessData -- entering"
542 " JPEG_SINK_NON_JPEG_TRAILER case\n", this));
547 NS_ABORT_IF_FALSE(0, "Should always return immediately after error and"
548 " not re-enter decoder");
551 PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG
,
552 ("} (end of function)"));
557 nsJPEGDecoder::ReadOrientationFromEXIF()
559 jpeg_saved_marker_ptr marker
;
561 // Locate the APP1 marker, where EXIF data is stored, in the marker list.
562 for (marker
= mInfo
.marker_list
; marker
!= nullptr ; marker
= marker
->next
) {
563 if (marker
->marker
== JPEG_APP0
+ 1) {
568 // If we're at the end of the list, there's no EXIF data.
570 return Orientation();
573 // Extract the orientation information.
574 EXIFData exif
= EXIFParser::Parse(marker
->data
,
575 static_cast<uint32_t>(marker
->data_length
));
576 return exif
.orientation
;
580 nsJPEGDecoder::NotifyDone()
582 PostFrameStop(Opacity::OPAQUE
);
587 nsJPEGDecoder::OutputScanlines(bool* suspend
)
591 const uint32_t top
= mInfo
.output_scanline
;
593 while ((mInfo
.output_scanline
< mInfo
.output_height
)) {
594 // Use the Cairo image buffer as scanline buffer
595 uint32_t* imageRow
= ((uint32_t*)mImageData
) +
596 (mInfo
.output_scanline
* mInfo
.output_width
);
598 if (mInfo
.out_color_space
== MOZ_JCS_EXT_NATIVE_ENDIAN_XRGB
) {
599 // Special case: scanline will be directly converted into packed ARGB
600 if (jpeg_read_scanlines(&mInfo
, (JSAMPARRAY
)&imageRow
, 1) != 1) {
601 *suspend
= true; // suspend
604 continue; // all done for this row!
607 JSAMPROW sampleRow
= (JSAMPROW
)imageRow
;
608 if (mInfo
.output_components
== 3) {
609 // Put the pixels at end of row to enable in-place expansion
610 sampleRow
+= mInfo
.output_width
;
613 // Request one scanline. Returns 0 or 1 scanlines.
614 if (jpeg_read_scanlines(&mInfo
, &sampleRow
, 1) != 1) {
615 *suspend
= true; // suspend
620 JSAMPROW source
= sampleRow
;
621 if (mInfo
.out_color_space
== JCS_GRAYSCALE
) {
622 // Convert from the 1byte grey pixels at begin of row
623 // to the 3byte RGB byte pixels at 'end' of row
624 sampleRow
+= mInfo
.output_width
;
626 qcms_transform_data(mTransform
, source
, sampleRow
, mInfo
.output_width
);
627 // Move 3byte RGB data to end of row
628 if (mInfo
.out_color_space
== JCS_CMYK
) {
629 memmove(sampleRow
+ mInfo
.output_width
,
631 3 * mInfo
.output_width
);
632 sampleRow
+= mInfo
.output_width
;
635 if (mInfo
.out_color_space
== JCS_CMYK
) {
636 // Convert from CMYK to RGB
637 // We cannot convert directly to Cairo, as the CMSRGBTransform
638 // may wants to do a RGB transform...
639 // Would be better to have platform CMSenabled transformation
640 // from CMYK to (A)RGB...
641 cmyk_convert_rgb((JSAMPROW
)imageRow
, mInfo
.output_width
);
642 sampleRow
+= mInfo
.output_width
;
644 if (mCMSMode
== eCMSMode_All
) {
645 // No embedded ICC profile - treat as sRGB
646 qcms_transform
* transform
= gfxPlatform::GetCMSRGBTransform();
648 qcms_transform_data(transform
, sampleRow
, sampleRow
,
654 // counter for while() loops below
655 uint32_t idx
= mInfo
.output_width
;
657 // copy as bytes until source pointer is 32-bit-aligned
658 for (; (NS_PTR_TO_UINT32(sampleRow
) & 0x3) && idx
; --idx
) {
659 *imageRow
++ = gfxPackedPixel(0xFF, sampleRow
[0], sampleRow
[1],
664 // copy pixels in blocks of 4
666 GFX_BLOCK_RGB_TO_FRGB(sampleRow
, imageRow
);
672 // copy remaining pixel(s)
674 // 32-bit read of final pixel will exceed buffer, so read bytes
675 *imageRow
++ = gfxPackedPixel(0xFF, sampleRow
[0], sampleRow
[1],
681 if (top
!= mInfo
.output_scanline
) {
682 nsIntRect
r(0, top
, mInfo
.output_width
, mInfo
.output_scanline
-top
);
689 // Override the standard error method in the IJG JPEG decoder code.
691 my_error_exit (j_common_ptr cinfo
)
693 decoder_error_mgr
* err
= (decoder_error_mgr
*) cinfo
->err
;
695 // Convert error to a browser error code
696 nsresult error_code
= err
->pub
.msg_code
== JERR_OUT_OF_MEMORY
697 ? NS_ERROR_OUT_OF_MEMORY
701 char buffer
[JMSG_LENGTH_MAX
];
703 // Create the message
704 (*err
->pub
.format_message
) (cinfo
, buffer
);
706 fprintf(stderr
, "JPEG decoding error:\n%s\n", buffer
);
709 // Return control to the setjmp point. We pass an nsresult masquerading as
710 // an int, which works because the setjmp() caller casts it back.
711 longjmp(err
->setjmp_buffer
, static_cast<int>(error_code
));
714 /*******************************************************************************
715 * This is the callback routine from the IJG JPEG library used to supply new
716 * data to the decompressor when its input buffer is exhausted. It juggles
717 * multiple buffers in an attempt to avoid unnecessary copying of input data.
719 * (A simpler scheme is possible: It's much easier to use only a single
720 * buffer; when fill_input_buffer() is called, move any unconsumed data
721 * (beyond the current pointer/count) down to the beginning of this buffer and
722 * then load new data into the remaining buffer space. This approach requires
723 * a little more data copying but is far easier to get right.)
725 * At any one time, the JPEG decompressor is either reading from the necko
726 * input buffer, which is volatile across top-level calls to the IJG library,
727 * or the "backtrack" buffer. The backtrack buffer contains the remaining
728 * unconsumed data from the necko buffer after parsing was suspended due
729 * to insufficient data in some previous call to the IJG library.
731 * When suspending, the decompressor will back up to a convenient restart
732 * point (typically the start of the current MCU). The variables
733 * next_input_byte & bytes_in_buffer indicate where the restart point will be
734 * if the current call returns FALSE. Data beyond this point must be
735 * rescanned after resumption, so it must be preserved in case the decompressor
736 * decides to backtrack.
739 * TRUE if additional data is available, FALSE if no data present and
740 * the JPEG library should therefore suspend processing of input stream
741 ******************************************************************************/
743 /******************************************************************************/
744 /* data source manager method */
745 /******************************************************************************/
747 /******************************************************************************/
748 /* data source manager method
749 Initialize source. This is called by jpeg_read_header() before any
750 data is actually read. May leave
751 bytes_in_buffer set to 0 (in which case a fill_input_buffer() call
752 will occur immediately).
755 init_source (j_decompress_ptr jd
)
759 /******************************************************************************/
760 /* data source manager method
761 Skip num_bytes worth of data. The buffer pointer and count should
762 be advanced over num_bytes input bytes, refilling the buffer as
763 needed. This is used to skip over a potentially large amount of
764 uninteresting data (such as an APPn marker). In some applications
765 it may be possible to optimize away the reading of the skipped data,
766 but it's not clear that being smart is worth much trouble; large
767 skips are uncommon. bytes_in_buffer may be zero on return.
768 A zero or negative skip count should be treated as a no-op.
771 skip_input_data (j_decompress_ptr jd
, long num_bytes
)
773 struct jpeg_source_mgr
* src
= jd
->src
;
774 nsJPEGDecoder
* decoder
= (nsJPEGDecoder
*)(jd
->client_data
);
776 if (num_bytes
> (long)src
->bytes_in_buffer
) {
777 // Can't skip it all right now until we get more data from
778 // network stream. Set things up so that fill_input_buffer
779 // will skip remaining amount.
780 decoder
->mBytesToSkip
= (size_t)num_bytes
- src
->bytes_in_buffer
;
781 src
->next_input_byte
+= src
->bytes_in_buffer
;
782 src
->bytes_in_buffer
= 0;
785 // Simple case. Just advance buffer pointer
787 src
->bytes_in_buffer
-= (size_t)num_bytes
;
788 src
->next_input_byte
+= num_bytes
;
793 /******************************************************************************/
794 /* data source manager method
795 This is called whenever bytes_in_buffer has reached zero and more
796 data is wanted. In typical applications, it should read fresh data
797 into the buffer (ignoring the current state of next_input_byte and
798 bytes_in_buffer), reset the pointer & count to the start of the
799 buffer, and return TRUE indicating that the buffer has been reloaded.
800 It is not necessary to fill the buffer entirely, only to obtain at
801 least one more byte. bytes_in_buffer MUST be set to a positive value
802 if TRUE is returned. A FALSE return should only be used when I/O
803 suspension is desired.
806 fill_input_buffer (j_decompress_ptr jd
)
808 struct jpeg_source_mgr
* src
= jd
->src
;
809 nsJPEGDecoder
* decoder
= (nsJPEGDecoder
*)(jd
->client_data
);
811 if (decoder
->mReading
) {
812 const JOCTET
* new_buffer
= decoder
->mSegment
;
813 uint32_t new_buflen
= decoder
->mSegmentLen
;
815 if (!new_buffer
|| new_buflen
== 0) {
816 return false; // suspend
819 decoder
->mSegmentLen
= 0;
821 if (decoder
->mBytesToSkip
) {
822 if (decoder
->mBytesToSkip
< new_buflen
) {
823 // All done skipping bytes; Return what's left.
824 new_buffer
+= decoder
->mBytesToSkip
;
825 new_buflen
-= decoder
->mBytesToSkip
;
826 decoder
->mBytesToSkip
= 0;
828 // Still need to skip some more data in the future
829 decoder
->mBytesToSkip
-= (size_t)new_buflen
;
830 return false; // suspend
834 decoder
->mBackBufferUnreadLen
= src
->bytes_in_buffer
;
836 src
->next_input_byte
= new_buffer
;
837 src
->bytes_in_buffer
= (size_t)new_buflen
;
838 decoder
->mReading
= false;
843 if (src
->next_input_byte
!= decoder
->mSegment
) {
844 // Backtrack data has been permanently consumed.
845 decoder
->mBackBufferUnreadLen
= 0;
846 decoder
->mBackBufferLen
= 0;
849 // Save remainder of netlib buffer in backtrack buffer
850 const uint32_t new_backtrack_buflen
= src
->bytes_in_buffer
+
851 decoder
->mBackBufferLen
;
853 // Make sure backtrack buffer is big enough to hold new data.
854 if (decoder
->mBackBufferSize
< new_backtrack_buflen
) {
855 // Check for malformed MARKER segment lengths, before allocating space
857 if (new_backtrack_buflen
> MAX_JPEG_MARKER_LENGTH
) {
858 my_error_exit((j_common_ptr
)(&decoder
->mInfo
));
861 // Round up to multiple of 256 bytes.
862 const size_t roundup_buflen
= ((new_backtrack_buflen
+ 255) >> 8) << 8;
863 JOCTET
* buf
= (JOCTET
*)PR_REALLOC(decoder
->mBackBuffer
, roundup_buflen
);
866 decoder
->mInfo
.err
->msg_code
= JERR_OUT_OF_MEMORY
;
867 my_error_exit((j_common_ptr
)(&decoder
->mInfo
));
869 decoder
->mBackBuffer
= buf
;
870 decoder
->mBackBufferSize
= roundup_buflen
;
873 // Copy remainder of netlib segment into backtrack buffer.
874 memmove(decoder
->mBackBuffer
+ decoder
->mBackBufferLen
,
875 src
->next_input_byte
,
876 src
->bytes_in_buffer
);
878 // Point to start of data to be rescanned.
879 src
->next_input_byte
= decoder
->mBackBuffer
+ decoder
->mBackBufferLen
-
880 decoder
->mBackBufferUnreadLen
;
881 src
->bytes_in_buffer
+= decoder
->mBackBufferUnreadLen
;
882 decoder
->mBackBufferLen
= (size_t)new_backtrack_buflen
;
883 decoder
->mReading
= true;
888 /******************************************************************************/
889 /* data source manager method */
891 * Terminate source --- called by jpeg_finish_decompress() after all
892 * data has been read to clean up JPEG source manager. NOT called by
893 * jpeg_abort() or jpeg_destroy().
896 term_source (j_decompress_ptr jd
)
898 nsJPEGDecoder
* decoder
= (nsJPEGDecoder
*)(jd
->client_data
);
900 // This function shouldn't be called if we ran into an error we didn't
902 NS_ABORT_IF_FALSE(decoder
->mState
!= JPEG_ERROR
,
903 "Calling term_source on a JPEG with mState == JPEG_ERROR!");
905 // Notify using a helper method to get around protectedness issues.
906 decoder
->NotifyDone();
910 } // namespace mozilla
913 ///*************** Inverted CMYK -> RGB conversion *************************
914 /// Input is (Inverted) CMYK stored as 4 bytes per pixel.
915 /// Output is RGB stored as 3 bytes per pixel.
916 /// @param row Points to row buffer containing the CMYK bytes for each pixel
918 /// @param width Number of pixels in the row.
919 static void cmyk_convert_rgb(JSAMPROW row
, JDIMENSION width
)
921 // Work from end to front to shrink from 4 bytes per pixel to 3
922 JSAMPROW in
= row
+ width
*4;
925 for (uint32_t i
= width
; i
> 0; i
--) {
929 // Source is 'Inverted CMYK', output is RGB.
930 // See: http://www.easyrgb.com/math.php?MATH=M12#text12
931 // Or: http://www.ilkeratalay.com/colorspacesfaq.php#rgb
934 // C = ( C * ( 1 - K ) + K )
935 // M = ( M * ( 1 - K ) + K )
936 // Y = ( Y * ( 1 - K ) + K )
938 // From Inverted CMYK to CMY is thus:
939 // C = ( (1-iC) * (1 - (1-iK)) + (1-iK) ) => 1 - iC*iK
942 // Convert from CMY (0..1) to RGB (0..1)
943 // R = 1 - C => 1 - (1 - iC*iK) => iC*iK
944 // G = 1 - M => 1 - (1 - iM*iK) => iM*iK
945 // B = 1 - Y => 1 - (1 - iY*iK) => iY*iK
947 // Convert from Inverted CMYK (0..255) to RGB (0..255)
948 const uint32_t iC
= in
[0];
949 const uint32_t iM
= in
[1];
950 const uint32_t iY
= in
[2];
951 const uint32_t iK
= in
[3];
952 out
[0] = iC
*iK
/255; // Red
953 out
[1] = iM
*iK
/255; // Green
954 out
[2] = iY
*iK
/255; // Blue