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"
21 #include "mozilla/Endian.h"
22 #include "mozilla/Telemetry.h"
29 #define MOZ_JCS_EXT_NATIVE_ENDIAN_XRGB JCS_EXT_XRGB
31 #define MOZ_JCS_EXT_NATIVE_ENDIAN_XRGB JCS_EXT_BGRX
34 static void cmyk_convert_rgb(JSAMPROW row
, JDIMENSION width
);
39 static PRLogModuleInfo
*
42 static PRLogModuleInfo
* sJPEGLog
;
44 sJPEGLog
= PR_NewLogModule("JPEGDecoder");
49 static PRLogModuleInfo
*
50 GetJPEGDecoderAccountingLog()
52 static PRLogModuleInfo
* sJPEGDecoderAccountingLog
;
53 if (!sJPEGDecoderAccountingLog
) {
54 sJPEGDecoderAccountingLog
= PR_NewLogModule("JPEGDecoderAccounting");
56 return sJPEGDecoderAccountingLog
;
60 GetICCProfile(struct jpeg_decompress_struct
& info
)
63 uint32_t profileLength
;
64 qcms_profile
* profile
= nullptr;
66 if (read_icc_profile(&info
, &profilebuf
, &profileLength
)) {
67 profile
= qcms_profile_from_memory(profilebuf
, profileLength
);
74 METHODDEF(void) init_source (j_decompress_ptr jd
);
75 METHODDEF(boolean
) fill_input_buffer (j_decompress_ptr jd
);
76 METHODDEF(void) skip_input_data (j_decompress_ptr jd
, long num_bytes
);
77 METHODDEF(void) term_source (j_decompress_ptr jd
);
78 METHODDEF(void) my_error_exit (j_common_ptr cinfo
);
80 // Normal JFIF markers can't have more bytes than this.
81 #define MAX_JPEG_MARKER_LENGTH (((uint32_t)1 << 16) - 1)
83 nsJPEGDecoder::nsJPEGDecoder(RasterImage
* aImage
,
84 Decoder::DecodeStyle aDecodeStyle
)
86 , 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 MOZ_LOG(GetJPEGDecoderAccountingLog(), LogLevel::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
);
125 qcms_profile_release(mInProfile
);
128 MOZ_LOG(GetJPEGDecoderAccountingLog(), LogLevel::Debug
,
129 ("nsJPEGDecoder::~nsJPEGDecoder: Destroying JPEG decoder %p",
134 nsJPEGDecoder::SpeedHistogram()
136 return Telemetry::IMAGE_DECODE_SPEED_JPEG
;
140 nsJPEGDecoder::InitInternal()
142 mCMSMode
= gfxPlatform::GetCMSMode();
143 if (GetSurfaceFlags() & SurfaceFlags::NO_COLORSPACE_CONVERSION
) {
144 mCMSMode
= eCMSMode_Off
;
147 // We set up the normal JPEG error routines, then override error_exit.
148 mInfo
.err
= jpeg_std_error(&mErr
.pub
);
149 // mInfo.err = jpeg_std_error(&mErr.pub);
150 mErr
.pub
.error_exit
= my_error_exit
;
151 // Establish the setjmp return context for my_error_exit to use.
152 if (setjmp(mErr
.setjmp_buffer
)) {
153 // If we get here, the JPEG code has signaled an error.
154 // We need to clean up the JPEG object, close the input file, and return.
155 PostDecoderError(NS_ERROR_FAILURE
);
159 // Step 1: allocate and initialize JPEG decompression object
160 jpeg_create_decompress(&mInfo
);
161 // Set the source manager
162 mInfo
.src
= &mSourceMgr
;
164 // Step 2: specify data source (eg, a file)
166 // Setup callback functions.
167 mSourceMgr
.init_source
= init_source
;
168 mSourceMgr
.fill_input_buffer
= fill_input_buffer
;
169 mSourceMgr
.skip_input_data
= skip_input_data
;
170 mSourceMgr
.resync_to_restart
= jpeg_resync_to_restart
;
171 mSourceMgr
.term_source
= term_source
;
173 // Record app markers for ICC data
174 for (uint32_t m
= 0; m
< 16; m
++) {
175 jpeg_save_markers(&mInfo
, JPEG_APP0
+ m
, 0xFFFF);
180 nsJPEGDecoder::FinishInternal()
182 // If we're not in any sort of error case, force our state to JPEG_DONE.
183 if ((mState
!= JPEG_DONE
&& mState
!= JPEG_SINK_NON_JPEG_TRAILER
) &&
184 (mState
!= JPEG_ERROR
) &&
185 !IsMetadataDecode()) {
191 nsJPEGDecoder::WriteInternal(const char* aBuffer
, uint32_t aCount
)
193 mSegment
= (const JOCTET
*)aBuffer
;
194 mSegmentLen
= aCount
;
196 MOZ_ASSERT(!HasError(), "Shouldn't call WriteInternal after error!");
198 // Return here if there is a fatal error within libjpeg.
200 // This cast to nsresult makes sense because setjmp() returns whatever we
201 // passed to longjmp(), which was actually an nsresult.
202 if ((error_code
= (nsresult
)setjmp(mErr
.setjmp_buffer
)) != NS_OK
) {
203 if (error_code
== NS_ERROR_FAILURE
) {
205 // Error due to corrupt stream - return NS_OK and consume silently
206 // so that ImageLib doesn't throw away a partial image load
207 mState
= JPEG_SINK_NON_JPEG_TRAILER
;
208 MOZ_LOG(GetJPEGDecoderAccountingLog(), LogLevel::Debug
,
209 ("} (setjmp returned NS_ERROR_FAILURE)"));
212 // Error due to reasons external to the stream (probably out of
213 // memory) - let ImageLib attempt to clean up, even though
214 // mozilla is seconds away from falling flat on its face.
215 PostDecoderError(error_code
);
217 MOZ_LOG(GetJPEGDecoderAccountingLog(), LogLevel::Debug
,
218 ("} (setjmp returned an error)"));
223 MOZ_LOG(GetJPEGLog(), LogLevel::Debug
,
224 ("[this=%p] nsJPEGDecoder::Write -- processing JPEG data\n", this));
228 LOG_SCOPE(GetJPEGLog(), "nsJPEGDecoder::Write -- entering JPEG_HEADER"
231 // Step 3: read file parameters with jpeg_read_header()
232 if (jpeg_read_header(&mInfo
, TRUE
) == JPEG_SUSPENDED
) {
233 MOZ_LOG(GetJPEGDecoderAccountingLog(), LogLevel::Debug
,
234 ("} (JPEG_SUSPENDED)"));
235 return; // I/O suspension
238 // If we have a sample size specified for -moz-sample-size, use it.
239 if (mSampleSize
> 0) {
241 mInfo
.scale_denom
= mSampleSize
;
244 // Used to set up image size so arrays can be allocated
245 jpeg_calc_output_dimensions(&mInfo
);
247 // Post our size to the superclass
248 PostSize(mInfo
.output_width
, mInfo
.output_height
,
249 ReadOrientationFromEXIF());
251 // Setting the size led to an error.
256 // If we're doing a metadata decode, we're done.
257 if (IsMetadataDecode()) {
261 // We're doing a full decode.
262 if (mCMSMode
!= eCMSMode_Off
&&
263 (mInProfile
= GetICCProfile(mInfo
)) != nullptr) {
264 uint32_t profileSpace
= qcms_profile_get_color_space(mInProfile
);
265 bool mismatch
= false;
268 fprintf(stderr
, "JPEG profileSpace: 0x%08X\n", profileSpace
);
270 switch (mInfo
.jpeg_color_space
) {
272 if (profileSpace
== icSigRgbData
) {
273 mInfo
.out_color_space
= JCS_RGB
;
274 } else if (profileSpace
!= icSigGrayData
) {
279 if (profileSpace
!= icSigRgbData
) {
284 if (profileSpace
== icSigRgbData
) {
285 mInfo
.out_color_space
= JCS_RGB
;
287 // qcms doesn't support ycbcr
293 // qcms doesn't support cmyk
299 MOZ_LOG(GetJPEGDecoderAccountingLog(), LogLevel::Debug
,
300 ("} (unknown colorpsace (1))"));
306 switch (mInfo
.out_color_space
) {
308 type
= QCMS_DATA_GRAY_8
;
311 type
= QCMS_DATA_RGB_8
;
316 MOZ_LOG(GetJPEGDecoderAccountingLog(), LogLevel::Debug
,
317 ("} (unknown colorpsace (2))"));
321 // We don't currently support CMYK profiles. The following
322 // code dealt with lcms types. Add something like this
323 // back when we gain support for CMYK.
325 // Adobe Photoshop writes YCCK/CMYK files with inverted data
326 if (mInfo
.out_color_space
== JCS_CMYK
) {
327 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
);
339 // Create the color management transform.
340 mTransform
= qcms_transform_create(mInProfile
,
342 gfxPlatform::GetCMSOutputProfile(),
344 (qcms_intent
)intent
);
348 fprintf(stderr
, "ICM profile colorspace mismatch\n");
354 switch (mInfo
.jpeg_color_space
) {
358 // if we're not color managing we can decode directly to
359 // MOZ_JCS_EXT_NATIVE_ENDIAN_XRGB
360 if (mCMSMode
!= eCMSMode_All
) {
361 mInfo
.out_color_space
= MOZ_JCS_EXT_NATIVE_ENDIAN_XRGB
;
362 mInfo
.out_color_components
= 4;
364 mInfo
.out_color_space
= JCS_RGB
;
369 // libjpeg can convert from YCCK to CMYK, but not to RGB
370 mInfo
.out_color_space
= JCS_CMYK
;
375 MOZ_LOG(GetJPEGDecoderAccountingLog(), LogLevel::Debug
,
376 ("} (unknown colorpsace (3))"));
381 // Don't allocate a giant and superfluous memory buffer
382 // when not doing a progressive decode.
383 mInfo
.buffered_image
= mDecodeStyle
== PROGRESSIVE
&&
384 jpeg_has_multiple_scans(&mInfo
);
386 MOZ_ASSERT(!mImageData
, "Already have a buffer allocated?");
387 nsIntSize targetSize
= mDownscaler
? mDownscaler
->TargetSize() : GetSize();
388 nsresult rv
= AllocateFrame(0, targetSize
,
389 nsIntRect(nsIntPoint(), targetSize
),
390 gfx::SurfaceFormat::B8G8R8A8
);
393 MOZ_LOG(GetJPEGDecoderAccountingLog(), LogLevel::Debug
,
394 ("} (could not initialize image frame)"));
398 MOZ_ASSERT(mImageData
, "Should have a buffer now");
401 nsresult rv
= mDownscaler
->BeginFrame(GetSize(), Nothing(),
403 /* aHasAlpha = */ false);
410 MOZ_LOG(GetJPEGDecoderAccountingLog(), LogLevel::Debug
,
411 (" JPEGDecoderAccounting: nsJPEGDecoder::"
412 "Write -- created image frame with %ux%u pixels",
413 mInfo
.output_width
, mInfo
.output_height
));
415 mState
= JPEG_START_DECOMPRESS
;
418 case JPEG_START_DECOMPRESS
: {
419 LOG_SCOPE(GetJPEGLog(), "nsJPEGDecoder::Write -- entering"
420 " JPEG_START_DECOMPRESS case");
421 // Step 4: set parameters for decompression
423 // FIXME -- Should reset dct_method and dither mode
424 // for final pass of progressive JPEG
426 mInfo
.dct_method
= JDCT_ISLOW
;
427 mInfo
.dither_mode
= JDITHER_FS
;
428 mInfo
.do_fancy_upsampling
= TRUE
;
429 mInfo
.enable_2pass_quant
= FALSE
;
430 mInfo
.do_block_smoothing
= TRUE
;
432 // Step 5: Start decompressor
433 if (jpeg_start_decompress(&mInfo
) == FALSE
) {
434 MOZ_LOG(GetJPEGDecoderAccountingLog(), LogLevel::Debug
,
435 ("} (I/O suspension after jpeg_start_decompress())"));
436 return; // I/O suspension
439 // If this is a progressive JPEG ...
440 mState
= mInfo
.buffered_image
?
441 JPEG_DECOMPRESS_PROGRESSIVE
: JPEG_DECOMPRESS_SEQUENTIAL
;
444 case JPEG_DECOMPRESS_SEQUENTIAL
: {
445 if (mState
== JPEG_DECOMPRESS_SEQUENTIAL
) {
446 LOG_SCOPE(GetJPEGLog(), "nsJPEGDecoder::Write -- "
447 "JPEG_DECOMPRESS_SEQUENTIAL case");
450 OutputScanlines(&suspend
);
453 MOZ_LOG(GetJPEGDecoderAccountingLog(), LogLevel::Debug
,
454 ("} (I/O suspension after OutputScanlines() - SEQUENTIAL)"));
455 return; // I/O suspension
458 // If we've completed image output ...
459 NS_ASSERTION(mInfo
.output_scanline
== mInfo
.output_height
,
460 "We didn't process all of the data!");
465 case JPEG_DECOMPRESS_PROGRESSIVE
: {
466 if (mState
== JPEG_DECOMPRESS_PROGRESSIVE
) {
467 LOG_SCOPE(GetJPEGLog(),
468 "nsJPEGDecoder::Write -- JPEG_DECOMPRESS_PROGRESSIVE case");
472 status
= jpeg_consume_input(&mInfo
);
473 } while ((status
!= JPEG_SUSPENDED
) &&
474 (status
!= JPEG_REACHED_EOI
));
477 if (mInfo
.output_scanline
== 0) {
478 int scan
= mInfo
.input_scan_number
;
480 // if we haven't displayed anything yet (output_scan_number==0)
481 // and we have enough data for a complete scan, force output
482 // of the last full scan
483 if ((mInfo
.output_scan_number
== 0) &&
485 (status
!= JPEG_REACHED_EOI
))
488 if (!jpeg_start_output(&mInfo
, scan
)) {
489 MOZ_LOG(GetJPEGDecoderAccountingLog(), LogLevel::Debug
,
490 ("} (I/O suspension after jpeg_start_output() -"
492 return; // I/O suspension
496 if (mInfo
.output_scanline
== 0xffffff) {
497 mInfo
.output_scanline
= 0;
501 OutputScanlines(&suspend
);
504 if (mInfo
.output_scanline
== 0) {
505 // didn't manage to read any lines - flag so we don't call
506 // jpeg_start_output() multiple times for the same scan
507 mInfo
.output_scanline
= 0xffffff;
509 MOZ_LOG(GetJPEGDecoderAccountingLog(), LogLevel::Debug
,
510 ("} (I/O suspension after OutputScanlines() - PROGRESSIVE)"));
511 return; // I/O suspension
514 if (mInfo
.output_scanline
== mInfo
.output_height
) {
515 if (!jpeg_finish_output(&mInfo
)) {
516 MOZ_LOG(GetJPEGDecoderAccountingLog(), LogLevel::Debug
,
517 ("} (I/O suspension after jpeg_finish_output() -"
519 return; // I/O suspension
522 if (jpeg_input_complete(&mInfo
) &&
523 (mInfo
.input_scan_number
== mInfo
.output_scan_number
))
526 mInfo
.output_scanline
= 0;
528 mDownscaler
->ResetForNextProgressivePass();
538 LOG_SCOPE(GetJPEGLog(), "nsJPEGDecoder::ProcessData -- entering"
541 // Step 7: Finish decompression
543 if (jpeg_finish_decompress(&mInfo
) == FALSE
) {
544 MOZ_LOG(GetJPEGDecoderAccountingLog(), LogLevel::Debug
,
545 ("} (I/O suspension after jpeg_finish_decompress() - DONE)"));
546 return; // I/O suspension
549 mState
= JPEG_SINK_NON_JPEG_TRAILER
;
554 case JPEG_SINK_NON_JPEG_TRAILER
:
555 MOZ_LOG(GetJPEGLog(), LogLevel::Debug
,
556 ("[this=%p] nsJPEGDecoder::ProcessData -- entering"
557 " JPEG_SINK_NON_JPEG_TRAILER case\n", this));
563 "Should always return immediately after error and not re-enter "
567 MOZ_LOG(GetJPEGDecoderAccountingLog(), LogLevel::Debug
,
568 ("} (end of function)"));
573 nsJPEGDecoder::ReadOrientationFromEXIF()
575 jpeg_saved_marker_ptr marker
;
577 // Locate the APP1 marker, where EXIF data is stored, in the marker list.
578 for (marker
= mInfo
.marker_list
; marker
!= nullptr ; marker
= marker
->next
) {
579 if (marker
->marker
== JPEG_APP0
+ 1) {
584 // If we're at the end of the list, there's no EXIF data.
586 return Orientation();
589 // Extract the orientation information.
590 EXIFData exif
= EXIFParser::Parse(marker
->data
,
591 static_cast<uint32_t>(marker
->data_length
));
592 return exif
.orientation
;
596 nsJPEGDecoder::NotifyDone()
598 PostFrameStop(Opacity::OPAQUE
);
603 nsJPEGDecoder::OutputScanlines(bool* suspend
)
607 const uint32_t top
= mInfo
.output_scanline
;
609 while ((mInfo
.output_scanline
< mInfo
.output_height
)) {
610 uint32_t* imageRow
= nullptr;
612 imageRow
= reinterpret_cast<uint32_t*>(mDownscaler
->RowBuffer());
614 imageRow
= reinterpret_cast<uint32_t*>(mImageData
) +
615 (mInfo
.output_scanline
* mInfo
.output_width
);
618 MOZ_ASSERT(imageRow
, "Should have a row buffer here");
620 if (mInfo
.out_color_space
== MOZ_JCS_EXT_NATIVE_ENDIAN_XRGB
) {
621 // Special case: scanline will be directly converted into packed ARGB
622 if (jpeg_read_scanlines(&mInfo
, (JSAMPARRAY
)&imageRow
, 1) != 1) {
623 *suspend
= true; // suspend
627 mDownscaler
->CommitRow();
629 continue; // all done for this row!
632 JSAMPROW sampleRow
= (JSAMPROW
)imageRow
;
633 if (mInfo
.output_components
== 3) {
634 // Put the pixels at end of row to enable in-place expansion
635 sampleRow
+= mInfo
.output_width
;
638 // Request one scanline. Returns 0 or 1 scanlines.
639 if (jpeg_read_scanlines(&mInfo
, &sampleRow
, 1) != 1) {
640 *suspend
= true; // suspend
645 JSAMPROW source
= sampleRow
;
646 if (mInfo
.out_color_space
== JCS_GRAYSCALE
) {
647 // Convert from the 1byte grey pixels at begin of row
648 // to the 3byte RGB byte pixels at 'end' of row
649 sampleRow
+= mInfo
.output_width
;
651 qcms_transform_data(mTransform
, source
, sampleRow
, mInfo
.output_width
);
652 // Move 3byte RGB data to end of row
653 if (mInfo
.out_color_space
== JCS_CMYK
) {
654 memmove(sampleRow
+ mInfo
.output_width
,
656 3 * mInfo
.output_width
);
657 sampleRow
+= mInfo
.output_width
;
660 if (mInfo
.out_color_space
== JCS_CMYK
) {
661 // Convert from CMYK to RGB
662 // We cannot convert directly to Cairo, as the CMSRGBTransform
663 // may wants to do a RGB transform...
664 // Would be better to have platform CMSenabled transformation
665 // from CMYK to (A)RGB...
666 cmyk_convert_rgb((JSAMPROW
)imageRow
, mInfo
.output_width
);
667 sampleRow
+= mInfo
.output_width
;
669 if (mCMSMode
== eCMSMode_All
) {
670 // No embedded ICC profile - treat as sRGB
671 qcms_transform
* transform
= gfxPlatform::GetCMSRGBTransform();
673 qcms_transform_data(transform
, sampleRow
, sampleRow
,
679 // counter for while() loops below
680 uint32_t idx
= mInfo
.output_width
;
682 // copy as bytes until source pointer is 32-bit-aligned
683 for (; (NS_PTR_TO_UINT32(sampleRow
) & 0x3) && idx
; --idx
) {
684 *imageRow
++ = gfxPackedPixel(0xFF, sampleRow
[0], sampleRow
[1],
689 // copy pixels in blocks of 4
691 GFX_BLOCK_RGB_TO_FRGB(sampleRow
, imageRow
);
697 // copy remaining pixel(s)
699 // 32-bit read of final pixel will exceed buffer, so read bytes
700 *imageRow
++ = gfxPackedPixel(0xFF, sampleRow
[0], sampleRow
[1],
706 mDownscaler
->CommitRow();
710 if (mDownscaler
&& mDownscaler
->HasInvalidation()) {
711 DownscalerInvalidRect invalidRect
= mDownscaler
->TakeInvalidRect();
712 PostInvalidation(invalidRect
.mOriginalSizeRect
,
713 Some(invalidRect
.mTargetSizeRect
));
714 MOZ_ASSERT(!mDownscaler
->HasInvalidation());
715 } else if (!mDownscaler
&& top
!= mInfo
.output_scanline
) {
716 PostInvalidation(nsIntRect(0, top
,
718 mInfo
.output_scanline
- top
));
722 // Override the standard error method in the IJG JPEG decoder code.
724 my_error_exit (j_common_ptr cinfo
)
726 decoder_error_mgr
* err
= (decoder_error_mgr
*) cinfo
->err
;
728 // Convert error to a browser error code
729 nsresult error_code
= err
->pub
.msg_code
== JERR_OUT_OF_MEMORY
730 ? NS_ERROR_OUT_OF_MEMORY
734 char buffer
[JMSG_LENGTH_MAX
];
736 // Create the message
737 (*err
->pub
.format_message
) (cinfo
, buffer
);
739 fprintf(stderr
, "JPEG decoding error:\n%s\n", buffer
);
742 // Return control to the setjmp point. We pass an nsresult masquerading as
743 // an int, which works because the setjmp() caller casts it back.
744 longjmp(err
->setjmp_buffer
, static_cast<int>(error_code
));
747 /*******************************************************************************
748 * This is the callback routine from the IJG JPEG library used to supply new
749 * data to the decompressor when its input buffer is exhausted. It juggles
750 * multiple buffers in an attempt to avoid unnecessary copying of input data.
752 * (A simpler scheme is possible: It's much easier to use only a single
753 * buffer; when fill_input_buffer() is called, move any unconsumed data
754 * (beyond the current pointer/count) down to the beginning of this buffer and
755 * then load new data into the remaining buffer space. This approach requires
756 * a little more data copying but is far easier to get right.)
758 * At any one time, the JPEG decompressor is either reading from the necko
759 * input buffer, which is volatile across top-level calls to the IJG library,
760 * or the "backtrack" buffer. The backtrack buffer contains the remaining
761 * unconsumed data from the necko buffer after parsing was suspended due
762 * to insufficient data in some previous call to the IJG library.
764 * When suspending, the decompressor will back up to a convenient restart
765 * point (typically the start of the current MCU). The variables
766 * next_input_byte & bytes_in_buffer indicate where the restart point will be
767 * if the current call returns FALSE. Data beyond this point must be
768 * rescanned after resumption, so it must be preserved in case the decompressor
769 * decides to backtrack.
772 * TRUE if additional data is available, FALSE if no data present and
773 * the JPEG library should therefore suspend processing of input stream
774 ******************************************************************************/
776 /******************************************************************************/
777 /* data source manager method */
778 /******************************************************************************/
780 /******************************************************************************/
781 /* data source manager method
782 Initialize source. This is called by jpeg_read_header() before any
783 data is actually read. May leave
784 bytes_in_buffer set to 0 (in which case a fill_input_buffer() call
785 will occur immediately).
788 init_source (j_decompress_ptr jd
)
792 /******************************************************************************/
793 /* data source manager method
794 Skip num_bytes worth of data. The buffer pointer and count should
795 be advanced over num_bytes input bytes, refilling the buffer as
796 needed. This is used to skip over a potentially large amount of
797 uninteresting data (such as an APPn marker). In some applications
798 it may be possible to optimize away the reading of the skipped data,
799 but it's not clear that being smart is worth much trouble; large
800 skips are uncommon. bytes_in_buffer may be zero on return.
801 A zero or negative skip count should be treated as a no-op.
804 skip_input_data (j_decompress_ptr jd
, long num_bytes
)
806 struct jpeg_source_mgr
* src
= jd
->src
;
807 nsJPEGDecoder
* decoder
= (nsJPEGDecoder
*)(jd
->client_data
);
809 if (num_bytes
> (long)src
->bytes_in_buffer
) {
810 // Can't skip it all right now until we get more data from
811 // network stream. Set things up so that fill_input_buffer
812 // will skip remaining amount.
813 decoder
->mBytesToSkip
= (size_t)num_bytes
- src
->bytes_in_buffer
;
814 src
->next_input_byte
+= src
->bytes_in_buffer
;
815 src
->bytes_in_buffer
= 0;
818 // Simple case. Just advance buffer pointer
820 src
->bytes_in_buffer
-= (size_t)num_bytes
;
821 src
->next_input_byte
+= num_bytes
;
825 /******************************************************************************/
826 /* data source manager method
827 This is called whenever bytes_in_buffer has reached zero and more
828 data is wanted. In typical applications, it should read fresh data
829 into the buffer (ignoring the current state of next_input_byte and
830 bytes_in_buffer), reset the pointer & count to the start of the
831 buffer, and return TRUE indicating that the buffer has been reloaded.
832 It is not necessary to fill the buffer entirely, only to obtain at
833 least one more byte. bytes_in_buffer MUST be set to a positive value
834 if TRUE is returned. A FALSE return should only be used when I/O
835 suspension is desired.
838 fill_input_buffer (j_decompress_ptr jd
)
840 struct jpeg_source_mgr
* src
= jd
->src
;
841 nsJPEGDecoder
* decoder
= (nsJPEGDecoder
*)(jd
->client_data
);
843 if (decoder
->mReading
) {
844 const JOCTET
* new_buffer
= decoder
->mSegment
;
845 uint32_t new_buflen
= decoder
->mSegmentLen
;
847 if (!new_buffer
|| new_buflen
== 0) {
848 return false; // suspend
851 decoder
->mSegmentLen
= 0;
853 if (decoder
->mBytesToSkip
) {
854 if (decoder
->mBytesToSkip
< new_buflen
) {
855 // All done skipping bytes; Return what's left.
856 new_buffer
+= decoder
->mBytesToSkip
;
857 new_buflen
-= decoder
->mBytesToSkip
;
858 decoder
->mBytesToSkip
= 0;
860 // Still need to skip some more data in the future
861 decoder
->mBytesToSkip
-= (size_t)new_buflen
;
862 return false; // suspend
866 decoder
->mBackBufferUnreadLen
= src
->bytes_in_buffer
;
868 src
->next_input_byte
= new_buffer
;
869 src
->bytes_in_buffer
= (size_t)new_buflen
;
870 decoder
->mReading
= false;
875 if (src
->next_input_byte
!= decoder
->mSegment
) {
876 // Backtrack data has been permanently consumed.
877 decoder
->mBackBufferUnreadLen
= 0;
878 decoder
->mBackBufferLen
= 0;
881 // Save remainder of netlib buffer in backtrack buffer
882 const uint32_t new_backtrack_buflen
= src
->bytes_in_buffer
+
883 decoder
->mBackBufferLen
;
885 // Make sure backtrack buffer is big enough to hold new data.
886 if (decoder
->mBackBufferSize
< new_backtrack_buflen
) {
887 // Check for malformed MARKER segment lengths, before allocating space
889 if (new_backtrack_buflen
> MAX_JPEG_MARKER_LENGTH
) {
890 my_error_exit((j_common_ptr
)(&decoder
->mInfo
));
893 // Round up to multiple of 256 bytes.
894 const size_t roundup_buflen
= ((new_backtrack_buflen
+ 255) >> 8) << 8;
895 JOCTET
* buf
= (JOCTET
*)PR_REALLOC(decoder
->mBackBuffer
, roundup_buflen
);
898 decoder
->mInfo
.err
->msg_code
= JERR_OUT_OF_MEMORY
;
899 my_error_exit((j_common_ptr
)(&decoder
->mInfo
));
901 decoder
->mBackBuffer
= buf
;
902 decoder
->mBackBufferSize
= roundup_buflen
;
905 // Copy remainder of netlib segment into backtrack buffer.
906 memmove(decoder
->mBackBuffer
+ decoder
->mBackBufferLen
,
907 src
->next_input_byte
,
908 src
->bytes_in_buffer
);
910 // Point to start of data to be rescanned.
911 src
->next_input_byte
= decoder
->mBackBuffer
+ decoder
->mBackBufferLen
-
912 decoder
->mBackBufferUnreadLen
;
913 src
->bytes_in_buffer
+= decoder
->mBackBufferUnreadLen
;
914 decoder
->mBackBufferLen
= (size_t)new_backtrack_buflen
;
915 decoder
->mReading
= true;
920 /******************************************************************************/
921 /* data source manager method */
923 * Terminate source --- called by jpeg_finish_decompress() after all
924 * data has been read to clean up JPEG source manager. NOT called by
925 * jpeg_abort() or jpeg_destroy().
928 term_source (j_decompress_ptr jd
)
930 nsJPEGDecoder
* decoder
= (nsJPEGDecoder
*)(jd
->client_data
);
932 // This function shouldn't be called if we ran into an error we didn't
934 MOZ_ASSERT(decoder
->mState
!= JPEG_ERROR
,
935 "Calling term_source on a JPEG with mState == JPEG_ERROR!");
937 // Notify using a helper method to get around protectedness issues.
938 decoder
->NotifyDone();
942 } // namespace mozilla
944 ///*************** Inverted CMYK -> RGB conversion *************************
945 /// Input is (Inverted) CMYK stored as 4 bytes per pixel.
946 /// Output is RGB stored as 3 bytes per pixel.
947 /// @param row Points to row buffer containing the CMYK bytes for each pixel
949 /// @param width Number of pixels in the row.
950 static void cmyk_convert_rgb(JSAMPROW row
, JDIMENSION width
)
952 // Work from end to front to shrink from 4 bytes per pixel to 3
953 JSAMPROW in
= row
+ width
*4;
956 for (uint32_t i
= width
; i
> 0; i
--) {
960 // Source is 'Inverted CMYK', output is RGB.
961 // See: http://www.easyrgb.com/math.php?MATH=M12#text12
962 // Or: http://www.ilkeratalay.com/colorspacesfaq.php#rgb
965 // C = ( C * ( 1 - K ) + K )
966 // M = ( M * ( 1 - K ) + K )
967 // Y = ( Y * ( 1 - K ) + K )
969 // From Inverted CMYK to CMY is thus:
970 // C = ( (1-iC) * (1 - (1-iK)) + (1-iK) ) => 1 - iC*iK
973 // Convert from CMY (0..1) to RGB (0..1)
974 // R = 1 - C => 1 - (1 - iC*iK) => iC*iK
975 // G = 1 - M => 1 - (1 - iM*iK) => iM*iK
976 // B = 1 - Y => 1 - (1 - iY*iK) => iY*iK
978 // Convert from Inverted CMYK (0..255) to RGB (0..255)
979 const uint32_t iC
= in
[0];
980 const uint32_t iM
= in
[1];
981 const uint32_t iY
= in
[2];
982 const uint32_t iK
= in
[3];
983 out
[0] = iC
*iK
/255; // Red
984 out
[1] = iM
*iK
/255; // Green
985 out
[2] = iY
*iK
/255; // Blue