Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(42)

Unified Diff: src/images/SkImageDecoder_libjpeg.cpp

Issue 1820503002: Delete SkImageDecoder (Closed) Base URL: https://skia.googlesource.com/skia.git@fix-animator
Patch Set: Include SkImage Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/images/SkImageDecoder_libico.cpp ('k') | src/images/SkImageDecoder_libpng.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/images/SkImageDecoder_libjpeg.cpp
diff --git a/src/images/SkImageDecoder_libjpeg.cpp b/src/images/SkImageDecoder_libjpeg.cpp
index 89bfefcd45f2ae68b98a7d6030fbac7f9a7f0eef..fd10bdbdf602cba14602f00476192ff23e32a312 100644
--- a/src/images/SkImageDecoder_libjpeg.cpp
+++ b/src/images/SkImageDecoder_libjpeg.cpp
@@ -6,13 +6,10 @@
*/
-#include "SkImageDecoder.h"
#include "SkImageEncoder.h"
#include "SkJpegUtility.h"
#include "SkColorPriv.h"
#include "SkDither.h"
-#include "SkMSAN.h"
-#include "SkScaledBitmapSampler.h"
#include "SkStream.h"
#include "SkTemplates.h"
#include "SkTime.h"
@@ -28,730 +25,12 @@ extern "C" {
#include "jerror.h"
}
-// These enable timing code that report milliseconds for an encoding/decoding
+// These enable timing code that report milliseconds for an encoding
//#define TIME_ENCODE
-//#define TIME_DECODE
// this enables our rgb->yuv code, which is faster than libjpeg on ARM
#define WE_CONVERT_TO_YUV
-// If ANDROID_RGB is defined by in the jpeg headers it indicates that jpeg offers
-// support for two additional formats (1) JCS_RGBA_8888 and (2) JCS_RGB_565.
-
-#define DEFAULT_FOR_SUPPRESS_JPEG_IMAGE_DECODER_WARNINGS true
-#define DEFAULT_FOR_SUPPRESS_JPEG_IMAGE_DECODER_ERRORS true
-SK_CONF_DECLARE(bool, c_suppressJPEGImageDecoderWarnings,
- "images.jpeg.suppressDecoderWarnings",
- DEFAULT_FOR_SUPPRESS_JPEG_IMAGE_DECODER_WARNINGS,
- "Suppress most JPG warnings when calling decode functions.");
-SK_CONF_DECLARE(bool, c_suppressJPEGImageDecoderErrors,
- "images.jpeg.suppressDecoderErrors",
- DEFAULT_FOR_SUPPRESS_JPEG_IMAGE_DECODER_ERRORS,
- "Suppress most JPG error messages when decode "
- "function fails.");
-
-//////////////////////////////////////////////////////////////////////////
-//////////////////////////////////////////////////////////////////////////
-
-static void do_nothing_emit_message(jpeg_common_struct*, int) {
- /* do nothing */
-}
-static void do_nothing_output_message(j_common_ptr) {
- /* do nothing */
-}
-
-static void initialize_info(jpeg_decompress_struct* cinfo, skjpeg_source_mgr* src_mgr) {
- SkASSERT(cinfo != nullptr);
- SkASSERT(src_mgr != nullptr);
- jpeg_create_decompress(cinfo);
- cinfo->src = src_mgr;
- /* To suppress warnings with a SK_DEBUG binary, set the
- * environment variable "skia_images_jpeg_suppressDecoderWarnings"
- * to "true". Inside a program that links to skia:
- * SK_CONF_SET("images.jpeg.suppressDecoderWarnings", true); */
- if (c_suppressJPEGImageDecoderWarnings) {
- cinfo->err->emit_message = &do_nothing_emit_message;
- }
- /* To suppress error messages with a SK_DEBUG binary, set the
- * environment variable "skia_images_jpeg_suppressDecoderErrors"
- * to "true". Inside a program that links to skia:
- * SK_CONF_SET("images.jpeg.suppressDecoderErrors", true); */
- if (c_suppressJPEGImageDecoderErrors) {
- cinfo->err->output_message = &do_nothing_output_message;
- }
-}
-
-class SkJPEGImageDecoder : public SkImageDecoder {
-public:
-
- Format getFormat() const override {
- return kJPEG_Format;
- }
-
-protected:
- Result onDecode(SkStream* stream, SkBitmap* bm, Mode) override;
- bool onDecodeYUV8Planes(SkStream* stream, SkISize componentSizes[3],
- void* planes[3], size_t rowBytes[3],
- SkYUVColorSpace* colorSpace) override;
-
-private:
-
- /**
- * Determine the appropriate bitmap colortype and out_color_space based on
- * both the preference of the caller and the jpeg_color_space on the
- * jpeg_decompress_struct passed in.
- * Must be called after jpeg_read_header.
- */
- SkColorType getBitmapColorType(jpeg_decompress_struct*);
-
- typedef SkImageDecoder INHERITED;
-};
-
-//////////////////////////////////////////////////////////////////////////
-
-/* Automatically clean up after throwing an exception */
-class JPEGAutoClean {
-public:
- JPEGAutoClean(): cinfo_ptr(nullptr) {}
- ~JPEGAutoClean() {
- if (cinfo_ptr) {
- jpeg_destroy_decompress(cinfo_ptr);
- }
- }
- void set(jpeg_decompress_struct* info) {
- cinfo_ptr = info;
- }
-private:
- jpeg_decompress_struct* cinfo_ptr;
-};
-
-///////////////////////////////////////////////////////////////////////////////
-
-/* If we need to better match the request, we might examine the image and
- output dimensions, and determine if the downsampling jpeg provided is
- not sufficient. If so, we can recompute a modified sampleSize value to
- make up the difference.
-
- To skip this additional scaling, just set sampleSize = 1; below.
- */
-static int recompute_sampleSize(int sampleSize,
- const jpeg_decompress_struct& cinfo) {
- return sampleSize * cinfo.output_width / cinfo.image_width;
-}
-
-static bool valid_output_dimensions(const jpeg_decompress_struct& cinfo) {
- /* These are initialized to 0, so if they have non-zero values, we assume
- they are "valid" (i.e. have been computed by libjpeg)
- */
- return 0 != cinfo.output_width && 0 != cinfo.output_height;
-}
-
-static bool skip_src_rows(jpeg_decompress_struct* cinfo, void* buffer, int count) {
- for (int i = 0; i < count; i++) {
- JSAMPLE* rowptr = (JSAMPLE*)buffer;
- int row_count = jpeg_read_scanlines(cinfo, &rowptr, 1);
- if (1 != row_count) {
- return false;
- }
- }
- return true;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-// This guy exists just to aid in debugging, as it allows debuggers to just
-// set a break-point in one place to see all error exists.
-static void print_jpeg_decoder_errors(const jpeg_decompress_struct& cinfo,
- int width, int height, const char caller[]) {
- if (!(c_suppressJPEGImageDecoderErrors)) {
- char buffer[JMSG_LENGTH_MAX];
- cinfo.err->format_message((const j_common_ptr)&cinfo, buffer);
- SkDebugf("libjpeg error %d <%s> from %s [%d %d]\n",
- cinfo.err->msg_code, buffer, caller, width, height);
- }
-}
-
-static bool return_false(const jpeg_decompress_struct& cinfo,
- const char caller[]) {
- print_jpeg_decoder_errors(cinfo, 0, 0, caller);
- return false;
-}
-
-static SkImageDecoder::Result return_failure(const jpeg_decompress_struct& cinfo,
- const SkBitmap& bm, const char caller[]) {
- print_jpeg_decoder_errors(cinfo, bm.width(), bm.height(), caller);
- return SkImageDecoder::kFailure;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-// Convert a scanline of CMYK samples to RGBX in place. Note that this
-// method moves the "scanline" pointer in its processing
-static void convert_CMYK_to_RGB(uint8_t* scanline, unsigned int width) {
- // At this point we've received CMYK pixels from libjpeg. We
- // perform a crude conversion to RGB (based on the formulae
- // from easyrgb.com):
- // CMYK -> CMY
- // C = ( C * (1 - K) + K ) // for each CMY component
- // CMY -> RGB
- // R = ( 1 - C ) * 255 // for each RGB component
- // Unfortunately we are seeing inverted CMYK so all the original terms
- // are 1-. This yields:
- // CMYK -> CMY
- // C = ( (1-C) * (1 - (1-K) + (1-K) ) -> C = 1 - C*K
- // The conversion from CMY->RGB remains the same
- for (unsigned int x = 0; x < width; ++x, scanline += 4) {
- scanline[0] = SkMulDiv255Round(scanline[0], scanline[3]);
- scanline[1] = SkMulDiv255Round(scanline[1], scanline[3]);
- scanline[2] = SkMulDiv255Round(scanline[2], scanline[3]);
- scanline[3] = 255;
- }
-}
-
-/**
- * Common code for setting the error manager.
- */
-static void set_error_mgr(jpeg_decompress_struct* cinfo, skjpeg_error_mgr* errorManager) {
- SkASSERT(cinfo != nullptr);
- SkASSERT(errorManager != nullptr);
- cinfo->err = jpeg_std_error(errorManager);
- errorManager->error_exit = skjpeg_error_exit;
-}
-
-/**
- * Common code for setting the dct method.
- */
-static void set_dct_method(const SkImageDecoder& decoder, jpeg_decompress_struct* cinfo) {
- SkASSERT(cinfo != nullptr);
- cinfo->dct_method = JDCT_ISLOW;
-}
-
-SkColorType SkJPEGImageDecoder::getBitmapColorType(jpeg_decompress_struct* cinfo) {
- SkASSERT(cinfo != nullptr);
-
- SrcDepth srcDepth = k32Bit_SrcDepth;
- if (JCS_GRAYSCALE == cinfo->jpeg_color_space) {
- srcDepth = k8BitGray_SrcDepth;
- }
-
- SkColorType colorType = this->getPrefColorType(srcDepth, /*hasAlpha*/ false);
- switch (colorType) {
- case kAlpha_8_SkColorType:
- // Only respect A8 colortype if the original is grayscale,
- // in which case we will treat the grayscale as alpha
- // values.
- if (cinfo->jpeg_color_space != JCS_GRAYSCALE) {
- colorType = kN32_SkColorType;
- }
- break;
- case kN32_SkColorType:
- // Fall through.
- case kARGB_4444_SkColorType:
- // Fall through.
- case kRGB_565_SkColorType:
- // These are acceptable destination colortypes.
- break;
- default:
- // Force all other colortypes to 8888.
- colorType = kN32_SkColorType;
- break;
- }
-
- switch (cinfo->jpeg_color_space) {
- case JCS_CMYK:
- // Fall through.
- case JCS_YCCK:
- // libjpeg cannot convert from CMYK or YCCK to RGB - here we set up
- // so libjpeg will give us CMYK samples back and we will later
- // manually convert them to RGB
- cinfo->out_color_space = JCS_CMYK;
- break;
- case JCS_GRAYSCALE:
- if (kAlpha_8_SkColorType == colorType) {
- cinfo->out_color_space = JCS_GRAYSCALE;
- break;
- }
- // The data is JCS_GRAYSCALE, but the caller wants some sort of RGB
- // colortype. Fall through to set to the default.
- default:
- cinfo->out_color_space = JCS_RGB;
- break;
- }
- return colorType;
-}
-
-/**
- * Based on the colortype and dither mode, adjust out_color_space and
- * dither_mode of cinfo. Only does work in ANDROID_RGB
- */
-static void adjust_out_color_space_and_dither(jpeg_decompress_struct* cinfo,
- SkColorType colorType,
- const SkImageDecoder& decoder) {
- SkASSERT(cinfo != nullptr);
-#ifdef ANDROID_RGB
- cinfo->dither_mode = JDITHER_NONE;
- if (JCS_CMYK == cinfo->out_color_space) {
- return;
- }
- switch (colorType) {
- case kN32_SkColorType:
- cinfo->out_color_space = JCS_RGBA_8888;
- break;
- case kRGB_565_SkColorType:
- cinfo->out_color_space = JCS_RGB_565;
- if (decoder.getDitherImage()) {
- cinfo->dither_mode = JDITHER_ORDERED;
- }
- break;
- default:
- break;
- }
-#endif
-}
-
-/**
- Sets all pixels in given bitmap to SK_ColorWHITE for all rows >= y.
- Used when decoding fails partway through reading scanlines to fill
- remaining lines. */
-static void fill_below_level(int y, SkBitmap* bitmap) {
- SkIRect rect = SkIRect::MakeLTRB(0, y, bitmap->width(), bitmap->height());
- SkCanvas canvas(*bitmap);
- canvas.clipRect(SkRect::Make(rect));
- canvas.drawColor(SK_ColorWHITE);
-}
-
-/**
- * Get the config and bytes per pixel of the source data. Return
- * whether the data is supported.
- */
-static bool get_src_config(const jpeg_decompress_struct& cinfo,
- SkScaledBitmapSampler::SrcConfig* sc,
- int* srcBytesPerPixel) {
- SkASSERT(sc != nullptr && srcBytesPerPixel != nullptr);
- if (JCS_CMYK == cinfo.out_color_space) {
- // In this case we will manually convert the CMYK values to RGB
- *sc = SkScaledBitmapSampler::kRGBX;
- // The CMYK work-around relies on 4 components per pixel here
- *srcBytesPerPixel = 4;
- } else if (3 == cinfo.out_color_components && JCS_RGB == cinfo.out_color_space) {
- *sc = SkScaledBitmapSampler::kRGB;
- *srcBytesPerPixel = 3;
-#ifdef ANDROID_RGB
- } else if (JCS_RGBA_8888 == cinfo.out_color_space) {
- *sc = SkScaledBitmapSampler::kRGBX;
- *srcBytesPerPixel = 4;
- } else if (JCS_RGB_565 == cinfo.out_color_space) {
- *sc = SkScaledBitmapSampler::kRGB_565;
- *srcBytesPerPixel = 2;
-#endif
- } else if (1 == cinfo.out_color_components &&
- JCS_GRAYSCALE == cinfo.out_color_space) {
- *sc = SkScaledBitmapSampler::kGray;
- *srcBytesPerPixel = 1;
- } else {
- return false;
- }
- return true;
-}
-
-SkImageDecoder::Result SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
-#ifdef TIME_DECODE
- SkAutoTime atm("JPEG Decode");
-#endif
-
- JPEGAutoClean autoClean;
-
- jpeg_decompress_struct cinfo;
- skjpeg_source_mgr srcManager(stream, this);
-
- skjpeg_error_mgr errorManager;
- set_error_mgr(&cinfo, &errorManager);
-
- // All objects need to be instantiated before this setjmp call so that
- // they will be cleaned up properly if an error occurs.
- if (setjmp(errorManager.fJmpBuf)) {
- return return_failure(cinfo, *bm, "setjmp");
- }
-
- initialize_info(&cinfo, &srcManager);
- autoClean.set(&cinfo);
-
- int status = jpeg_read_header(&cinfo, true);
- if (status != JPEG_HEADER_OK) {
- return return_failure(cinfo, *bm, "read_header");
- }
-
- /* Try to fulfill the requested sampleSize. Since jpeg can do it (when it
- can) much faster that we, just use their num/denom api to approximate
- the size.
- */
- int sampleSize = this->getSampleSize();
-
- set_dct_method(*this, &cinfo);
-
- SkASSERT(1 == cinfo.scale_num);
- cinfo.scale_denom = sampleSize;
-
- const SkColorType colorType = this->getBitmapColorType(&cinfo);
- const SkAlphaType alphaType = kAlpha_8_SkColorType == colorType ?
- kPremul_SkAlphaType : kOpaque_SkAlphaType;
-
- adjust_out_color_space_and_dither(&cinfo, colorType, *this);
-
- if (1 == sampleSize && SkImageDecoder::kDecodeBounds_Mode == mode) {
- // Assume an A8 bitmap is not opaque to avoid the check of each
- // individual pixel. It is very unlikely to be opaque, since
- // an opaque A8 bitmap would not be very interesting.
- // Otherwise, a jpeg image is opaque.
- bool success = bm->setInfo(SkImageInfo::Make(cinfo.image_width, cinfo.image_height,
- colorType, alphaType));
- return success ? kSuccess : kFailure;
- }
-
- /* image_width and image_height are the original dimensions, available
- after jpeg_read_header(). To see the scaled dimensions, we have to call
- jpeg_start_decompress(), and then read output_width and output_height.
- */
- if (!jpeg_start_decompress(&cinfo)) {
- /* If we failed here, we may still have enough information to return
- to the caller if they just wanted (subsampled bounds). If sampleSize
- was 1, then we would have already returned. Thus we just check if
- we're in kDecodeBounds_Mode, and that we have valid output sizes.
-
- One reason to fail here is that we have insufficient stream data
- to complete the setup. However, output dimensions seem to get
- computed very early, which is why this special check can pay off.
- */
- if (SkImageDecoder::kDecodeBounds_Mode == mode && valid_output_dimensions(cinfo)) {
- SkScaledBitmapSampler smpl(cinfo.output_width, cinfo.output_height,
- recompute_sampleSize(sampleSize, cinfo));
- // Assume an A8 bitmap is not opaque to avoid the check of each
- // individual pixel. It is very unlikely to be opaque, since
- // an opaque A8 bitmap would not be very interesting.
- // Otherwise, a jpeg image is opaque.
- bool success = bm->setInfo(SkImageInfo::Make(smpl.scaledWidth(), smpl.scaledHeight(),
- colorType, alphaType));
- return success ? kSuccess : kFailure;
- } else {
- return return_failure(cinfo, *bm, "start_decompress");
- }
- }
- sampleSize = recompute_sampleSize(sampleSize, cinfo);
-
- SkScaledBitmapSampler sampler(cinfo.output_width, cinfo.output_height, sampleSize);
- // Assume an A8 bitmap is not opaque to avoid the check of each
- // individual pixel. It is very unlikely to be opaque, since
- // an opaque A8 bitmap would not be very interesting.
- // Otherwise, a jpeg image is opaque.
- bm->setInfo(SkImageInfo::Make(sampler.scaledWidth(), sampler.scaledHeight(),
- colorType, alphaType));
- if (SkImageDecoder::kDecodeBounds_Mode == mode) {
- return kSuccess;
- }
- if (!this->allocPixelRef(bm, nullptr)) {
- return return_failure(cinfo, *bm, "allocPixelRef");
- }
-
- SkAutoLockPixels alp(*bm);
-
-#ifdef ANDROID_RGB
- /* short-circuit the SkScaledBitmapSampler when possible, as this gives
- a significant performance boost.
- */
- if (sampleSize == 1 &&
- ((kN32_SkColorType == colorType && cinfo.out_color_space == JCS_RGBA_8888) ||
- (kRGB_565_SkColorType == colorType && cinfo.out_color_space == JCS_RGB_565)))
- {
- JSAMPLE* rowptr = (JSAMPLE*)bm->getPixels();
- INT32 const bpr = bm->rowBytes();
-
- while (cinfo.output_scanline < cinfo.output_height) {
- int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1);
- if (0 == row_count) {
- // if row_count == 0, then we didn't get a scanline,
- // so return early. We will return a partial image.
- fill_below_level(cinfo.output_scanline, bm);
- cinfo.output_scanline = cinfo.output_height;
- jpeg_finish_decompress(&cinfo);
- return kPartialSuccess;
- }
- if (this->shouldCancelDecode()) {
- return return_failure(cinfo, *bm, "shouldCancelDecode");
- }
- rowptr += bpr;
- }
- jpeg_finish_decompress(&cinfo);
- return kSuccess;
- }
-#endif
-
- // check for supported formats
- SkScaledBitmapSampler::SrcConfig sc;
- int srcBytesPerPixel;
-
- if (!get_src_config(cinfo, &sc, &srcBytesPerPixel)) {
- return return_failure(cinfo, *bm, "jpeg colorspace");
- }
-
- if (!sampler.begin(bm, sc, *this)) {
- return return_failure(cinfo, *bm, "sampler.begin");
- }
-
- SkAutoTMalloc<uint8_t> srcStorage(cinfo.output_width * srcBytesPerPixel);
- uint8_t* srcRow = srcStorage.get();
-
- // Possibly skip initial rows [sampler.srcY0]
- if (!skip_src_rows(&cinfo, srcRow, sampler.srcY0())) {
- return return_failure(cinfo, *bm, "skip rows");
- }
-
- // now loop through scanlines until y == bm->height() - 1
- for (int y = 0;; y++) {
- JSAMPLE* rowptr = (JSAMPLE*)srcRow;
- int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1);
- sk_msan_mark_initialized(srcRow, srcRow + cinfo.output_width * srcBytesPerPixel,
- "skbug.com/4550");
- if (0 == row_count) {
- // if row_count == 0, then we didn't get a scanline,
- // so return early. We will return a partial image.
- fill_below_level(y, bm);
- cinfo.output_scanline = cinfo.output_height;
- jpeg_finish_decompress(&cinfo);
- return kPartialSuccess;
- }
- if (this->shouldCancelDecode()) {
- return return_failure(cinfo, *bm, "shouldCancelDecode");
- }
-
- if (JCS_CMYK == cinfo.out_color_space) {
- convert_CMYK_to_RGB(srcRow, cinfo.output_width);
- }
-
-
- sampler.next(srcRow);
- if (bm->height() - 1 == y) {
- // we're done
- break;
- }
-
- if (!skip_src_rows(&cinfo, srcRow, sampler.srcDY() - 1)) {
- return return_failure(cinfo, *bm, "skip rows");
- }
- }
-
- // we formally skip the rest, so we don't get a complaint from libjpeg
- if (!skip_src_rows(&cinfo, srcRow,
- cinfo.output_height - cinfo.output_scanline)) {
- return return_failure(cinfo, *bm, "skip rows");
- }
- jpeg_finish_decompress(&cinfo);
-
- return kSuccess;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-enum SizeType {
- kSizeForMemoryAllocation_SizeType,
- kActualSize_SizeType
-};
-
-static SkISize compute_yuv_size(const jpeg_decompress_struct& info, int component,
- SizeType sizeType) {
- if (sizeType == kSizeForMemoryAllocation_SizeType) {
- return SkISize::Make(info.cur_comp_info[component]->width_in_blocks * DCTSIZE,
- info.cur_comp_info[component]->height_in_blocks * DCTSIZE);
- }
- return SkISize::Make(info.cur_comp_info[component]->downsampled_width,
- info.cur_comp_info[component]->downsampled_height);
-}
-
-static bool appears_to_be_yuv(const jpeg_decompress_struct& info) {
- return (info.jpeg_color_space == JCS_YCbCr)
- && (DCTSIZE == 8)
- && (info.num_components == 3)
- && (info.comps_in_scan >= info.num_components)
- && (info.scale_denom <= 8)
- && (info.cur_comp_info[0])
- && (info.cur_comp_info[1])
- && (info.cur_comp_info[2])
- && (info.cur_comp_info[1]->h_samp_factor == 1)
- && (info.cur_comp_info[1]->v_samp_factor == 1)
- && (info.cur_comp_info[2]->h_samp_factor == 1)
- && (info.cur_comp_info[2]->v_samp_factor == 1);
-}
-
-static void update_components_sizes(const jpeg_decompress_struct& cinfo, SkISize componentSizes[3],
- SizeType sizeType) {
- SkASSERT(appears_to_be_yuv(cinfo));
- for (int i = 0; i < 3; ++i) {
- componentSizes[i] = compute_yuv_size(cinfo, i, sizeType);
- }
-}
-
-static bool output_raw_data(jpeg_decompress_struct& cinfo, void* planes[3], size_t rowBytes[3]) {
- SkASSERT(appears_to_be_yuv(cinfo));
- // U size and V size have to be the same if we're calling output_raw_data()
- SkISize uvSize = compute_yuv_size(cinfo, 1, kSizeForMemoryAllocation_SizeType);
- SkASSERT(uvSize == compute_yuv_size(cinfo, 2, kSizeForMemoryAllocation_SizeType));
-
- JSAMPARRAY bufferraw[3];
- JSAMPROW bufferraw2[32];
- bufferraw[0] = &bufferraw2[0]; // Y channel rows (8 or 16)
- bufferraw[1] = &bufferraw2[16]; // U channel rows (8)
- bufferraw[2] = &bufferraw2[24]; // V channel rows (8)
- int yWidth = cinfo.output_width;
- int yHeight = cinfo.output_height;
- int yMaxH = yHeight - 1;
- int v = cinfo.cur_comp_info[0]->v_samp_factor;
- int uvMaxH = uvSize.height() - 1;
- JSAMPROW outputY = static_cast<JSAMPROW>(planes[0]);
- JSAMPROW outputU = static_cast<JSAMPROW>(planes[1]);
- JSAMPROW outputV = static_cast<JSAMPROW>(planes[2]);
- size_t rowBytesY = rowBytes[0];
- size_t rowBytesU = rowBytes[1];
- size_t rowBytesV = rowBytes[2];
-
- int yScanlinesToRead = DCTSIZE * v;
- SkAutoMalloc lastRowStorage(rowBytesY * 4);
- JSAMPROW yLastRow = (JSAMPROW)lastRowStorage.get();
- JSAMPROW uLastRow = yLastRow + rowBytesY;
- JSAMPROW vLastRow = uLastRow + rowBytesY;
- JSAMPROW dummyRow = vLastRow + rowBytesY;
-
- while (cinfo.output_scanline < cinfo.output_height) {
- // Request 8 or 16 scanlines: returns 0 or more scanlines.
- bool hasYLastRow(false), hasUVLastRow(false);
- // Assign 8 or 16 rows of memory to read the Y channel.
- for (int i = 0; i < yScanlinesToRead; ++i) {
- int scanline = (cinfo.output_scanline + i);
- if (scanline < yMaxH) {
- bufferraw2[i] = &outputY[scanline * rowBytesY];
- } else if (scanline == yMaxH) {
- bufferraw2[i] = yLastRow;
- hasYLastRow = true;
- } else {
- bufferraw2[i] = dummyRow;
- }
- }
- int scaledScanline = cinfo.output_scanline / v;
- // Assign 8 rows of memory to read the U and V channels.
- for (int i = 0; i < 8; ++i) {
- int scanline = (scaledScanline + i);
- if (scanline < uvMaxH) {
- bufferraw2[16 + i] = &outputU[scanline * rowBytesU];
- bufferraw2[24 + i] = &outputV[scanline * rowBytesV];
- } else if (scanline == uvMaxH) {
- bufferraw2[16 + i] = uLastRow;
- bufferraw2[24 + i] = vLastRow;
- hasUVLastRow = true;
- } else {
- bufferraw2[16 + i] = dummyRow;
- bufferraw2[24 + i] = dummyRow;
- }
- }
- JDIMENSION scanlinesRead = jpeg_read_raw_data(&cinfo, bufferraw, yScanlinesToRead);
-
- if (scanlinesRead == 0) {
- return false;
- }
-
- if (hasYLastRow) {
- memcpy(&outputY[yMaxH * rowBytesY], yLastRow, yWidth);
- }
- if (hasUVLastRow) {
- memcpy(&outputU[uvMaxH * rowBytesU], uLastRow, uvSize.width());
- memcpy(&outputV[uvMaxH * rowBytesV], vLastRow, uvSize.width());
- }
- }
-
- cinfo.output_scanline = SkMin32(cinfo.output_scanline, cinfo.output_height);
-
- return true;
-}
-
-bool SkJPEGImageDecoder::onDecodeYUV8Planes(SkStream* stream, SkISize componentSizes[3],
- void* planes[3], size_t rowBytes[3],
- SkYUVColorSpace* colorSpace) {
-#ifdef TIME_DECODE
- SkAutoTime atm("JPEG YUV8 Decode");
-#endif
- if (this->getSampleSize() != 1) {
- return false; // Resizing not supported
- }
-
- JPEGAutoClean autoClean;
-
- jpeg_decompress_struct cinfo;
- skjpeg_source_mgr srcManager(stream, this);
-
- skjpeg_error_mgr errorManager;
- set_error_mgr(&cinfo, &errorManager);
-
- // All objects need to be instantiated before this setjmp call so that
- // they will be cleaned up properly if an error occurs.
- if (setjmp(errorManager.fJmpBuf)) {
- return return_false(cinfo, "setjmp YUV8");
- }
-
- initialize_info(&cinfo, &srcManager);
- autoClean.set(&cinfo);
-
- int status = jpeg_read_header(&cinfo, true);
- if (status != JPEG_HEADER_OK) {
- return return_false(cinfo, "read_header YUV8");
- }
-
- if (!appears_to_be_yuv(cinfo)) {
- // It's not an error to not be encoded in YUV, so no need to use return_false()
- return false;
- }
-
- cinfo.out_color_space = JCS_YCbCr;
- cinfo.raw_data_out = TRUE;
-
- if (!planes || !planes[0] || !rowBytes || !rowBytes[0]) { // Compute size only
- update_components_sizes(cinfo, componentSizes, kSizeForMemoryAllocation_SizeType);
- return true;
- }
-
- set_dct_method(*this, &cinfo);
-
- SkASSERT(1 == cinfo.scale_num);
- cinfo.scale_denom = 1;
-
-#ifdef ANDROID_RGB
- cinfo.dither_mode = JDITHER_NONE;
-#endif
-
- /* image_width and image_height are the original dimensions, available
- after jpeg_read_header(). To see the scaled dimensions, we have to call
- jpeg_start_decompress(), and then read output_width and output_height.
- */
- if (!jpeg_start_decompress(&cinfo)) {
- return return_false(cinfo, "start_decompress YUV8");
- }
-
- // Seems like jpeg_start_decompress is updating our opinion of whether cinfo represents YUV.
- // Again, not really an error.
- if (!appears_to_be_yuv(cinfo)) {
- return false;
- }
-
- if (!output_raw_data(cinfo, planes, rowBytes)) {
- return return_false(cinfo, "output_raw_data");
- }
-
- update_components_sizes(cinfo, componentSizes, kActualSize_SizeType);
- jpeg_finish_decompress(&cinfo);
-
- if (nullptr != colorSpace) {
- *colorSpace = kJPEG_SkYUVColorSpace;
- }
-
- return true;
-}
-
///////////////////////////////////////////////////////////////////////////////
#include "SkColorPriv.h"
@@ -993,45 +272,11 @@ protected:
};
///////////////////////////////////////////////////////////////////////////////
-DEFINE_DECODER_CREATOR(JPEGImageDecoder);
DEFINE_ENCODER_CREATOR(JPEGImageEncoder);
///////////////////////////////////////////////////////////////////////////////
-static bool is_jpeg(SkStreamRewindable* stream) {
- static const unsigned char gHeader[] = { 0xFF, 0xD8, 0xFF };
- static const size_t HEADER_SIZE = sizeof(gHeader);
-
- char buffer[HEADER_SIZE];
- size_t len = stream->read(buffer, HEADER_SIZE);
-
- if (len != HEADER_SIZE) {
- return false; // can't read enough
- }
- if (memcmp(buffer, gHeader, HEADER_SIZE)) {
- return false;
- }
- return true;
-}
-
-
-static SkImageDecoder* sk_libjpeg_dfactory(SkStreamRewindable* stream) {
- if (is_jpeg(stream)) {
- return new SkJPEGImageDecoder;
- }
- return nullptr;
-}
-
-static SkImageDecoder::Format get_format_jpeg(SkStreamRewindable* stream) {
- if (is_jpeg(stream)) {
- return SkImageDecoder::kJPEG_Format;
- }
- return SkImageDecoder::kUnknown_Format;
-}
-
static SkImageEncoder* sk_libjpeg_efactory(SkImageEncoder::Type t) {
return (SkImageEncoder::kJPEG_Type == t) ? new SkJPEGImageEncoder : nullptr;
}
-static SkImageDecoder_DecodeReg gDReg(sk_libjpeg_dfactory);
-static SkImageDecoder_FormatReg gFormatReg(get_format_jpeg);
static SkImageEncoder_EncodeReg gEReg(sk_libjpeg_efactory);
« no previous file with comments | « src/images/SkImageDecoder_libico.cpp ('k') | src/images/SkImageDecoder_libpng.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698