SkImageDecoder_libjpeg.cpp revision 8d725b25a6287e49e2b0cb2965871186e716eded
1d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 2d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com/* 3d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com * Copyright 2007 The Android Open Source Project 4d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com * 5d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com * Use of this source code is governed by a BSD-style license that can be 6d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com * found in the LICENSE file. 7d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com */ 8d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 9d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 10d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#include "SkImageDecoder.h" 11d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#include "SkImageEncoder.h" 12d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#include "SkJpegUtility.h" 13d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#include "SkColorPriv.h" 14d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#include "SkDither.h" 15d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#include "SkScaledBitmapSampler.h" 16d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#include "SkStream.h" 17d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#include "SkTemplates.h" 18113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#include "SkTime.h" 19d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#include "SkUtils.h" 20113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#include "SkRect.h" 21113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#include "SkCanvas.h" 22d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 23d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#include <stdio.h> 24d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comextern "C" { 25d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #include "jpeglib.h" 26d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #include "jerror.h" 27d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com} 28d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 29113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com// Uncomment to enable the code path used by the Android framework with their 30113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com// custom image decoders. 31113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com//#if defined(SK_BUILD_FOR_ANDROID) && defined(SK_DEBUG) 32113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com// #define SK_BUILD_FOR_ANDROID_FRAMEWORK 33113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com//#endif 34113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 35113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com// These enable timing code that report milliseconds for an encoding/decoding 36d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com//#define TIME_ENCODE 37d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com//#define TIME_DECODE 38d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 39d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com// this enables our rgb->yuv code, which is faster than libjpeg on ARM 40d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com// disable for the moment, as we have some glitches when width != multiple of 4 41d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#define WE_CONVERT_TO_YUV 42d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 43113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com// If ANDROID_RGB is defined by in the jpeg headers it indicates that jpeg offers 44113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com// support for two additional formats (1) JCS_RGBA_8888 and (2) JCS_RGB_565. 45113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 46d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com////////////////////////////////////////////////////////////////////////// 47d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com////////////////////////////////////////////////////////////////////////// 48d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 49113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.comstatic void overwrite_mem_buffer_size(j_decompress_ptr cinfo) { 50113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#ifdef SK_BUILD_FOR_ANDROID 51113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com /* Check if the device indicates that it has a large amount of system memory 52113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com * if so, increase the memory allocation to 30MB instead of the default 5MB. 53113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com */ 54113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#ifdef ANDROID_LARGE_MEMORY_DEVICE 55113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com cinfo->mem->max_memory_to_use = 30 * 1024 * 1024; 56113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#else 57113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com cinfo->mem->max_memory_to_use = 5 * 1024 * 1024; 58113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#endif 59113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#endif // SK_BUILD_FOR_ANDROID 60113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com} 61113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 62113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com////////////////////////////////////////////////////////////////////////// 63113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com////////////////////////////////////////////////////////////////////////// 64113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 65113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.comclass SkJPEGImageIndex { 66d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.compublic: 67113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com SkJPEGImageIndex(SkStream* stream, SkImageDecoder* decoder) 68113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com : fSrcMgr(stream, decoder, true) {} 69113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 70113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com ~SkJPEGImageIndex() { 71113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK 72113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com jpeg_destroy_huffman_index(&fHuffmanIndex); 73113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#endif 74113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com jpeg_finish_decompress(&fCInfo); 75113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com jpeg_destroy_decompress(&fCInfo); 76d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 77d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 78113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com /** 79113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com * Init the cinfo struct using libjpeg and apply any necessary 80113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com * customizations. 81113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com */ 82113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com void initializeInfo() { 83113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com jpeg_create_decompress(&fCInfo); 84113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com overwrite_mem_buffer_size(&fCInfo); 85113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com fCInfo.src = &fSrcMgr; 86113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 87d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 88113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com jpeg_decompress_struct* cinfo() { return &fCInfo; } 89d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 90113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK 91113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com huffman_index* huffmanIndex() { return &fHuffmanIndex; } 92113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#endif 93113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 94113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.comprivate: 95113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com skjpeg_source_mgr fSrcMgr; 96113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com jpeg_decompress_struct fCInfo; 97113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK 98113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com huffman_index fHuffmanIndex; 99113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#endif 100113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com}; 101d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 102113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.comclass SkJPEGImageDecoder : public SkImageDecoder { 103d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.compublic: 104113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com SkJPEGImageDecoder() { 105113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com fImageIndex = NULL; 106113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com fImageWidth = 0; 107113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com fImageHeight = 0; 108d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 109113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 110113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com virtual ~SkJPEGImageDecoder() { 111113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com SkDELETE(fImageIndex); 112d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 113113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 114113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com virtual Format getFormat() const { 115113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return kJPEG_Format; 116113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 117113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 118113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.comprotected: 119113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK 120113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com virtual bool onBuildTileIndex(SkStream *stream, int *width, int *height) SK_OVERRIDE; 1217e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com virtual bool onDecodeSubset(SkBitmap* bitmap, const SkIRect& rect) SK_OVERRIDE; 122113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#endif 123113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE; 124113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 125d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comprivate: 126113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com SkJPEGImageIndex* fImageIndex; 127113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com int fImageWidth; 128113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com int fImageHeight; 129113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 130113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com typedef SkImageDecoder INHERITED; 131d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com}; 132d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 133113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com////////////////////////////////////////////////////////////////////////// 134113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 135d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com/* Automatically clean up after throwing an exception */ 136d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comclass JPEGAutoClean { 137d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.compublic: 138d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com JPEGAutoClean(): cinfo_ptr(NULL) {} 139d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com ~JPEGAutoClean() { 140d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com if (cinfo_ptr) { 141d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com jpeg_destroy_decompress(cinfo_ptr); 142d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 143d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 144d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com void set(jpeg_decompress_struct* info) { 145d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com cinfo_ptr = info; 146d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 147d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comprivate: 148d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com jpeg_decompress_struct* cinfo_ptr; 149d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com}; 150d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 151d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com/////////////////////////////////////////////////////////////////////////////// 152d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 153d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com/* If we need to better match the request, we might examine the image and 154d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com output dimensions, and determine if the downsampling jpeg provided is 155d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com not sufficient. If so, we can recompute a modified sampleSize value to 156d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com make up the difference. 157d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 158d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com To skip this additional scaling, just set sampleSize = 1; below. 159d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com */ 160d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comstatic int recompute_sampleSize(int sampleSize, 161d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com const jpeg_decompress_struct& cinfo) { 162d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return sampleSize * cinfo.output_width / cinfo.image_width; 163d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com} 164d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 165d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comstatic bool valid_output_dimensions(const jpeg_decompress_struct& cinfo) { 166d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com /* These are initialized to 0, so if they have non-zero values, we assume 167d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com they are "valid" (i.e. have been computed by libjpeg) 168d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com */ 169113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return 0 != cinfo.output_width && 0 != cinfo.output_height; 170d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com} 171d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 172113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.comstatic bool skip_src_rows(jpeg_decompress_struct* cinfo, void* buffer, int count) { 173d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com for (int i = 0; i < count; i++) { 174d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com JSAMPLE* rowptr = (JSAMPLE*)buffer; 175d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int row_count = jpeg_read_scanlines(cinfo, &rowptr, 1); 176113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (1 != row_count) { 177d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return false; 178d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 179d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 180d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return true; 181d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com} 182d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 183113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK 184113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.comstatic bool skip_src_rows_tile(jpeg_decompress_struct* cinfo, 185113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com huffman_index *index, void* buffer, int count) { 186113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com for (int i = 0; i < count; i++) { 187113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com JSAMPLE* rowptr = (JSAMPLE*)buffer; 188113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com int row_count = jpeg_read_tile_scanline(cinfo, index, &rowptr); 189113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (1 != row_count) { 190113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return false; 191113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 192113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 193113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return true; 194113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com} 195113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#endif 196113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 197d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com// This guy exists just to aid in debugging, as it allows debuggers to just 198d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com// set a break-point in one place to see all error exists. 199d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comstatic bool return_false(const jpeg_decompress_struct& cinfo, 200d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com const SkBitmap& bm, const char msg[]) { 201113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#ifdef SK_DEBUG 202e8f3471f94d7532484537c32d5b92e68018897c6scroggo@google.com SkDebugf("libjpeg error %d <%s> from %s [%d %d]\n", cinfo.err->msg_code, 203d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com cinfo.err->jpeg_message_table[cinfo.err->msg_code], msg, 204d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com bm.width(), bm.height()); 205d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#endif 206d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return false; // must always return false 207d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com} 208d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 2098570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com// Convert a scanline of CMYK samples to RGBX in place. Note that this 2108570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com// method moves the "scanline" pointer in its processing 2118570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.comstatic void convert_CMYK_to_RGB(uint8_t* scanline, unsigned int width) { 2128570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com // At this point we've received CMYK pixels from libjpeg. We 213d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com // perform a crude conversion to RGB (based on the formulae 2148570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com // from easyrgb.com): 2158570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com // CMYK -> CMY 2168570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com // C = ( C * (1 - K) + K ) // for each CMY component 2178570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com // CMY -> RGB 2188570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com // R = ( 1 - C ) * 255 // for each RGB component 2198570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com // Unfortunately we are seeing inverted CMYK so all the original terms 2208570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com // are 1-. This yields: 2218570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com // CMYK -> CMY 2228570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com // C = ( (1-C) * (1 - (1-K) + (1-K) ) -> C = 1 - C*K 2238570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com // The conversion from CMY->RGB remains the same 2248570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com for (unsigned int x = 0; x < width; ++x, scanline += 4) { 2258570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com scanline[0] = SkMulDiv255Round(scanline[0], scanline[3]); 2268570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com scanline[1] = SkMulDiv255Round(scanline[1], scanline[3]); 2278570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com scanline[2] = SkMulDiv255Round(scanline[2], scanline[3]); 2288570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com scanline[3] = 255; 2298570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com } 2308570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com} 2318570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com 232d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.combool SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { 233d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#ifdef TIME_DECODE 234113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com SkAutoTime atm("JPEG Decode"); 235d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#endif 236d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 237d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com JPEGAutoClean autoClean; 238d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 239d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com jpeg_decompress_struct cinfo; 240113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com skjpeg_error_mgr errorManager; 241113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com skjpeg_source_mgr srcManager(stream, this, false); 242d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 243113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com cinfo.err = jpeg_std_error(&errorManager); 244113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com errorManager.error_exit = skjpeg_error_exit; 245d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 246d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com // All objects need to be instantiated before this setjmp call so that 247d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com // they will be cleaned up properly if an error occurs. 248113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (setjmp(errorManager.fJmpBuf)) { 249d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return return_false(cinfo, *bm, "setjmp"); 250d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 251d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 252d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com jpeg_create_decompress(&cinfo); 253d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com autoClean.set(&cinfo); 254d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 255d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com overwrite_mem_buffer_size(&cinfo); 256d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 257d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com //jpeg_stdio_src(&cinfo, file); 258113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com cinfo.src = &srcManager; 259d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 260d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int status = jpeg_read_header(&cinfo, true); 261d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com if (status != JPEG_HEADER_OK) { 262d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return return_false(cinfo, *bm, "read_header"); 263d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 264d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 265d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com /* Try to fulfill the requested sampleSize. Since jpeg can do it (when it 266d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com can) much faster that we, just use their num/denom api to approximate 267d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com the size. 268d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com */ 269d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int sampleSize = this->getSampleSize(); 270d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 2713acd3fcfad2d3f7fa3379ea8d26c9b870298b6d0scroggo@google.com#ifdef DCT_IFAST_SUPPORTED 272113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (this->getPreferQualityOverSpeed()) { 273113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com cinfo.dct_method = JDCT_ISLOW; 274113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } else { 275113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com cinfo.dct_method = JDCT_IFAST; 276113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 2773acd3fcfad2d3f7fa3379ea8d26c9b870298b6d0scroggo@google.com#else 2783acd3fcfad2d3f7fa3379ea8d26c9b870298b6d0scroggo@google.com cinfo.dct_method = JDCT_ISLOW; 2793acd3fcfad2d3f7fa3379ea8d26c9b870298b6d0scroggo@google.com#endif 280113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 281d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com cinfo.scale_num = 1; 282d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com cinfo.scale_denom = sampleSize; 283d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 284d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com /* this gives about 30% performance improvement. In theory it may 285d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com reduce the visual quality, in practice I'm not seeing a difference 286d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com */ 287d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com cinfo.do_fancy_upsampling = 0; 288d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 289d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com /* this gives another few percents */ 290d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com cinfo.do_block_smoothing = 0; 291d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 292f698c8262df397a7015662e91b1a727e1134c418scroggo@google.com SrcDepth srcDepth = k32Bit_SrcDepth; 293d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com /* default format is RGB */ 2948570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com if (cinfo.jpeg_color_space == JCS_CMYK) { 2958570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com // libjpeg cannot convert from CMYK to RGB - here we set up 2968570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com // so libjpeg will give us CMYK samples back and we will 2978570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com // later manually convert them to RGB 2988570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com cinfo.out_color_space = JCS_CMYK; 299f698c8262df397a7015662e91b1a727e1134c418scroggo@google.com } else if (cinfo.jpeg_color_space == JCS_GRAYSCALE) { 300f698c8262df397a7015662e91b1a727e1134c418scroggo@google.com cinfo.out_color_space = JCS_GRAYSCALE; 301f698c8262df397a7015662e91b1a727e1134c418scroggo@google.com srcDepth = k8BitGray_SrcDepth; 3028570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com } else { 3038570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com cinfo.out_color_space = JCS_RGB; 3048570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com } 305d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 306f698c8262df397a7015662e91b1a727e1134c418scroggo@google.com SkBitmap::Config config = this->getPrefConfig(srcDepth, false); 307d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com // only these make sense for jpegs 308f698c8262df397a7015662e91b1a727e1134c418scroggo@google.com if (SkBitmap::kA8_Config == config) { 309f698c8262df397a7015662e91b1a727e1134c418scroggo@google.com if (cinfo.jpeg_color_space != JCS_GRAYSCALE) { 310f698c8262df397a7015662e91b1a727e1134c418scroggo@google.com // Converting from a non grayscale image to A8 is 311f698c8262df397a7015662e91b1a727e1134c418scroggo@google.com // not currently supported. 312f698c8262df397a7015662e91b1a727e1134c418scroggo@google.com config = SkBitmap::kARGB_8888_Config; 313f698c8262df397a7015662e91b1a727e1134c418scroggo@google.com // Change the output from jpeg back to RGB. 314f698c8262df397a7015662e91b1a727e1134c418scroggo@google.com cinfo.out_color_space = JCS_RGB; 315f698c8262df397a7015662e91b1a727e1134c418scroggo@google.com } 316f698c8262df397a7015662e91b1a727e1134c418scroggo@google.com } else if (config != SkBitmap::kARGB_8888_Config && 317f698c8262df397a7015662e91b1a727e1134c418scroggo@google.com config != SkBitmap::kARGB_4444_Config && 318f698c8262df397a7015662e91b1a727e1134c418scroggo@google.com config != SkBitmap::kRGB_565_Config) { 319d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com config = SkBitmap::kARGB_8888_Config; 320d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 321d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 322d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#ifdef ANDROID_RGB 323d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com cinfo.dither_mode = JDITHER_NONE; 3248570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com if (SkBitmap::kARGB_8888_Config == config && JCS_CMYK != cinfo.out_color_space) { 325d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com cinfo.out_color_space = JCS_RGBA_8888; 3268570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com } else if (SkBitmap::kRGB_565_Config == config && JCS_CMYK != cinfo.out_color_space) { 327d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com cinfo.out_color_space = JCS_RGB_565; 328d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com if (this->getDitherImage()) { 329d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com cinfo.dither_mode = JDITHER_ORDERED; 330d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 331d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 332d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#endif 333d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 334113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (1 == sampleSize && SkImageDecoder::kDecodeBounds_Mode == mode) { 335d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com bm->setConfig(config, cinfo.image_width, cinfo.image_height); 3361f6b995fab80a2a258df87d9e6bf953976f37e68scroggo@google.com bm->setIsOpaque(config != SkBitmap::kA8_Config); 337d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return true; 338d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 339d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 340d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com /* image_width and image_height are the original dimensions, available 341d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com after jpeg_read_header(). To see the scaled dimensions, we have to call 342d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com jpeg_start_decompress(), and then read output_width and output_height. 343d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com */ 344d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com if (!jpeg_start_decompress(&cinfo)) { 345d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com /* If we failed here, we may still have enough information to return 346d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com to the caller if they just wanted (subsampled bounds). If sampleSize 347d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com was 1, then we would have already returned. Thus we just check if 348d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com we're in kDecodeBounds_Mode, and that we have valid output sizes. 349d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 350d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com One reason to fail here is that we have insufficient stream data 351d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com to complete the setup. However, output dimensions seem to get 352d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com computed very early, which is why this special check can pay off. 353d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com */ 354113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (SkImageDecoder::kDecodeBounds_Mode == mode && valid_output_dimensions(cinfo)) { 355d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com SkScaledBitmapSampler smpl(cinfo.output_width, cinfo.output_height, 356d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com recompute_sampleSize(sampleSize, cinfo)); 357d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com bm->setConfig(config, smpl.scaledWidth(), smpl.scaledHeight()); 3581f6b995fab80a2a258df87d9e6bf953976f37e68scroggo@google.com bm->setIsOpaque(config != SkBitmap::kA8_Config); 359d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return true; 360d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } else { 361d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return return_false(cinfo, *bm, "start_decompress"); 362d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 363d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 364d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com sampleSize = recompute_sampleSize(sampleSize, cinfo); 365d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 366d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com // should we allow the Chooser (if present) to pick a config for us??? 367113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (!this->chooseFromOneChoice(config, cinfo.output_width, cinfo.output_height)) { 368d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return return_false(cinfo, *bm, "chooseFromOneChoice"); 369d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 370d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 371113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com SkScaledBitmapSampler sampler(cinfo.output_width, cinfo.output_height, sampleSize); 372bc69ce982f8374742ca910587485f0d741350c2dscroggo@google.com bm->setConfig(config, sampler.scaledWidth(), sampler.scaledHeight()); 3731f6b995fab80a2a258df87d9e6bf953976f37e68scroggo@google.com bm->setIsOpaque(config != SkBitmap::kA8_Config); 374bc69ce982f8374742ca910587485f0d741350c2dscroggo@google.com if (SkImageDecoder::kDecodeBounds_Mode == mode) { 375bc69ce982f8374742ca910587485f0d741350c2dscroggo@google.com return true; 376bc69ce982f8374742ca910587485f0d741350c2dscroggo@google.com } 377bc69ce982f8374742ca910587485f0d741350c2dscroggo@google.com if (!this->allocPixelRef(bm, NULL)) { 378bc69ce982f8374742ca910587485f0d741350c2dscroggo@google.com return return_false(cinfo, *bm, "allocPixelRef"); 379113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 380113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 381113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com SkAutoLockPixels alp(*bm); 382113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 383d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#ifdef ANDROID_RGB 384d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com /* short-circuit the SkScaledBitmapSampler when possible, as this gives 385d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com a significant performance boost. 386d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com */ 387d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com if (sampleSize == 1 && 388d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com ((config == SkBitmap::kARGB_8888_Config && 389d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com cinfo.out_color_space == JCS_RGBA_8888) || 390d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com (config == SkBitmap::kRGB_565_Config && 391d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com cinfo.out_color_space == JCS_RGB_565))) 392d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com { 393bc69ce982f8374742ca910587485f0d741350c2dscroggo@google.com JSAMPLE* rowptr = (JSAMPLE*)bm->getPixels(); 394d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com INT32 const bpr = bm->rowBytes(); 395d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com 396d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com while (cinfo.output_scanline < cinfo.output_height) { 397d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1); 398d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com // if row_count == 0, then we didn't get a scanline, so abort. 399d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com // if we supported partial images, we might return true in this case 400d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com if (0 == row_count) { 401d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return return_false(cinfo, *bm, "read_scanlines"); 402d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 403d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com if (this->shouldCancelDecode()) { 404d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return return_false(cinfo, *bm, "shouldCancelDecode"); 405d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 406d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com rowptr += bpr; 407d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 408d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com jpeg_finish_decompress(&cinfo); 409d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return true; 410d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 411d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#endif 4128570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com 413d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com // check for supported formats 414d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com SkScaledBitmapSampler::SrcConfig sc; 4158570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com if (JCS_CMYK == cinfo.out_color_space) { 4168570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com // In this case we will manually convert the CMYK values to RGB 4178570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com sc = SkScaledBitmapSampler::kRGBX; 4188570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com } else if (3 == cinfo.out_color_components && JCS_RGB == cinfo.out_color_space) { 419d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com sc = SkScaledBitmapSampler::kRGB; 420d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#ifdef ANDROID_RGB 421d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } else if (JCS_RGBA_8888 == cinfo.out_color_space) { 422d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com sc = SkScaledBitmapSampler::kRGBX; 423d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } else if (JCS_RGB_565 == cinfo.out_color_space) { 424d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com sc = SkScaledBitmapSampler::kRGB_565; 425d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#endif 426d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } else if (1 == cinfo.out_color_components && 427d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com JCS_GRAYSCALE == cinfo.out_color_space) { 428d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com sc = SkScaledBitmapSampler::kGray; 429d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } else { 430d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return return_false(cinfo, *bm, "jpeg colorspace"); 431d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 432d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 433d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com if (!sampler.begin(bm, sc, this->getDitherImage())) { 434d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return return_false(cinfo, *bm, "sampler.begin"); 435d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 436d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 4378570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com // The CMYK work-around relies on 4 components per pixel here 438113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com SkAutoMalloc srcStorage(cinfo.output_width * 4); 439113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com uint8_t* srcRow = (uint8_t*)srcStorage.get(); 440d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 441d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com // Possibly skip initial rows [sampler.srcY0] 442d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com if (!skip_src_rows(&cinfo, srcRow, sampler.srcY0())) { 443d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return return_false(cinfo, *bm, "skip rows"); 444d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 445d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 446d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com // now loop through scanlines until y == bm->height() - 1 447d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com for (int y = 0;; y++) { 448d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com JSAMPLE* rowptr = (JSAMPLE*)srcRow; 449d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1); 450d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com if (0 == row_count) { 451d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return return_false(cinfo, *bm, "read_scanlines"); 452d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 453d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com if (this->shouldCancelDecode()) { 454d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return return_false(cinfo, *bm, "shouldCancelDecode"); 455d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 4568570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com 4578570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com if (JCS_CMYK == cinfo.out_color_space) { 4588570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com convert_CMYK_to_RGB(srcRow, cinfo.output_width); 4598570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com } 4608570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com 461d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com sampler.next(srcRow); 462d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com if (bm->height() - 1 == y) { 463d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com // we're done 464d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com break; 465d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 466d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 467d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com if (!skip_src_rows(&cinfo, srcRow, sampler.srcDY() - 1)) { 468d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return return_false(cinfo, *bm, "skip rows"); 469d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 470d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 471d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 472d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com // we formally skip the rest, so we don't get a complaint from libjpeg 473d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com if (!skip_src_rows(&cinfo, srcRow, 474d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com cinfo.output_height - cinfo.output_scanline)) { 475d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return return_false(cinfo, *bm, "skip rows"); 476d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 477d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com jpeg_finish_decompress(&cinfo); 478d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 479d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return true; 480d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com} 481d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 482113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK 483113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.combool SkJPEGImageDecoder::onBuildTileIndex(SkStream* stream, int *width, int *height) { 484113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 485113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com SkJPEGImageIndex* imageIndex = SkNEW_ARGS(SkJPEGImageIndex, (stream, this)); 486113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com jpeg_decompress_struct* cinfo = imageIndex->cinfo(); 487113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com huffman_index* huffmanIndex = imageIndex->huffmanIndex(); 488113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 489113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com skjpeg_error_mgr sk_err; 490113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com cinfo->err = jpeg_std_error(&sk_err); 491113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com sk_err.error_exit = skjpeg_error_exit; 492113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 493113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com // All objects need to be instantiated before this setjmp call so that 494113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com // they will be cleaned up properly if an error occurs. 495113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (setjmp(sk_err.fJmpBuf)) { 496113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return false; 497113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 498113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 499113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com // create the cinfo used to create/build the huffmanIndex 500113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com imageIndex->initializeInfo(); 501113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com cinfo->do_fancy_upsampling = 0; 502113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com cinfo->do_block_smoothing = 0; 503113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 504113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com int status = jpeg_read_header(cinfo, true); 505113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (JPEG_HEADER_OK != status) { 506113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com SkDELETE(imageIndex); 507113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return false; 508113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 509113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 510113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com jpeg_create_huffman_index(cinfo, huffmanIndex); 511113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com cinfo->scale_num = 1; 512113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com cinfo->scale_denom = 1; 513113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (!jpeg_build_huffman_index(cinfo, huffmanIndex)) { 514113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com SkDELETE(imageIndex); 515113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return false; 516113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 517113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 518113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com // destroy the cinfo used to create/build the huffman index 519113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com jpeg_destroy_decompress(cinfo); 520113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 521113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com // Init decoder to image decode mode 522113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com imageIndex->initializeInfo(); 523113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 524113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com status = jpeg_read_header(cinfo, true); 525113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (JPEG_HEADER_OK != status) { 526113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com SkDELETE(imageIndex); 527113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return false; 528113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 529113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 530113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com cinfo->out_color_space = JCS_RGBA_8888; 531113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com cinfo->do_fancy_upsampling = 0; 532113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com cinfo->do_block_smoothing = 0; 533113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 534113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com // instead of jpeg_start_decompress() we start a tiled decompress 535113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com jpeg_start_tile_decompress(cinfo); 536113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 537113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com cinfo->scale_num = 1; 538113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com *height = cinfo->output_height; 539113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com *width = cinfo->output_width; 540113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com fImageWidth = *width; 541113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com fImageHeight = *height; 542113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 543113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com SkDELETE(fImageIndex); 544113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com fImageIndex = imageIndex; 545113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 546113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return true; 547113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com} 548113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 5497e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.combool SkJPEGImageDecoder::onDecodeSubset(SkBitmap* bm, const SkIRect& region) { 550113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (NULL == fImageIndex) { 551113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return false; 552113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 553113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com jpeg_decompress_struct* cinfo = fImageIndex->cinfo(); 554113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 555113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com SkIRect rect = SkIRect::MakeWH(fImageWidth, fImageHeight); 556113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (!rect.intersect(region)) { 557113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com // If the requested region is entirely outside the image return false 558113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return false; 559113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 560113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 561113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 562113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com skjpeg_error_mgr errorManager; 563113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com cinfo->err = jpeg_std_error(&errorManager); 564113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com errorManager.error_exit = skjpeg_error_exit; 565113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (setjmp(errorManager.fJmpBuf)) { 566113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return false; 567113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 568113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 569113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com int requestedSampleSize = this->getSampleSize(); 570113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com cinfo->scale_denom = requestedSampleSize; 571113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 572113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (this->getPreferQualityOverSpeed()) { 573113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com cinfo->dct_method = JDCT_ISLOW; 574113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } else { 575113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com cinfo->dct_method = JDCT_IFAST; 576113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 577113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 578113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com SkBitmap::Config config = this->getPrefConfig(k32Bit_SrcDepth, false); 579113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (config != SkBitmap::kARGB_8888_Config && 580113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com config != SkBitmap::kARGB_4444_Config && 581113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com config != SkBitmap::kRGB_565_Config) { 582113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com config = SkBitmap::kARGB_8888_Config; 583113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 584113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 585113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com /* default format is RGB */ 586113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com cinfo->out_color_space = JCS_RGB; 587113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 588113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#ifdef ANDROID_RGB 589113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com cinfo->dither_mode = JDITHER_NONE; 590113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (SkBitmap::kARGB_8888_Config == config) { 591113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com cinfo->out_color_space = JCS_RGBA_8888; 592113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } else if (SkBitmap::kRGB_565_Config == config) { 593113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com cinfo->out_color_space = JCS_RGB_565; 594113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (this->getDitherImage()) { 595113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com cinfo->dither_mode = JDITHER_ORDERED; 596113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 597113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 598113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#endif 599113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 600113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com int startX = rect.fLeft; 601113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com int startY = rect.fTop; 602113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com int width = rect.width(); 603113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com int height = rect.height(); 604113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 605113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com jpeg_init_read_tile_scanline(cinfo, fImageIndex->huffmanIndex(), 606113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com &startX, &startY, &width, &height); 607113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com int skiaSampleSize = recompute_sampleSize(requestedSampleSize, *cinfo); 608113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com int actualSampleSize = skiaSampleSize * (DCTSIZE / cinfo->min_DCT_scaled_size); 609113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 610113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com SkScaledBitmapSampler sampler(width, height, skiaSampleSize); 611113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 612113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com SkBitmap bitmap; 613113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com bitmap.setConfig(config, sampler.scaledWidth(), sampler.scaledHeight()); 614113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com bitmap.setIsOpaque(true); 615113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 616113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com // Check ahead of time if the swap(dest, src) is possible or not. 617113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com // If yes, then we will stick to AllocPixelRef since it's cheaper with the 618113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com // swap happening. If no, then we will use alloc to allocate pixels to 619113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com // prevent garbage collection. 620113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com int w = rect.width() / actualSampleSize; 621113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com int h = rect.height() / actualSampleSize; 622113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com bool swapOnly = (rect == region) && bm->isNull() && 623113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com (w == bitmap.width()) && (h == bitmap.height()) && 624113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com ((startX - rect.x()) / actualSampleSize == 0) && 625113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com ((startY - rect.y()) / actualSampleSize == 0); 626113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (swapOnly) { 627113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (!this->allocPixelRef(&bitmap, NULL)) { 628113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return return_false(*cinfo, bitmap, "allocPixelRef"); 629113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 630113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } else { 631113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (!bitmap.allocPixels()) { 632113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return return_false(*cinfo, bitmap, "allocPixels"); 633113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 634113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 635113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 636113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com SkAutoLockPixels alp(bitmap); 637113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 638113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#ifdef ANDROID_RGB 639113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com /* short-circuit the SkScaledBitmapSampler when possible, as this gives 640113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com a significant performance boost. 641113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com */ 642113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (skiaSampleSize == 1 && 643113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com ((config == SkBitmap::kARGB_8888_Config && 644113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com cinfo->out_color_space == JCS_RGBA_8888) || 645113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com (config == SkBitmap::kRGB_565_Config && 646113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com cinfo->out_color_space == JCS_RGB_565))) 647113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com { 648113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com JSAMPLE* rowptr = (JSAMPLE*)bitmap.getPixels(); 649113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com INT32 const bpr = bitmap.rowBytes(); 650113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com int rowTotalCount = 0; 651113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 652113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com while (rowTotalCount < height) { 653113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com int rowCount = jpeg_read_tile_scanline(cinfo, 654113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com fImageIndex->huffmanIndex(), 655113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com &rowptr); 656113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com // if row_count == 0, then we didn't get a scanline, so abort. 657113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com // if we supported partial images, we might return true in this case 658113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (0 == rowCount) { 659113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return return_false(*cinfo, bitmap, "read_scanlines"); 660113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 661113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (this->shouldCancelDecode()) { 662113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return return_false(*cinfo, bitmap, "shouldCancelDecode"); 663113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 664113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com rowTotalCount += rowCount; 665113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com rowptr += bpr; 666113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 667113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 668113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (swapOnly) { 669113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com bm->swap(bitmap); 670113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } else { 671113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com cropBitmap(bm, &bitmap, actualSampleSize, region.x(), region.y(), 672113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com region.width(), region.height(), startX, startY); 673113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 674113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return true; 675113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 676113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#endif 677113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 678113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com // check for supported formats 679113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com SkScaledBitmapSampler::SrcConfig sc; 680113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (JCS_CMYK == cinfo->out_color_space) { 681113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com // In this case we will manually convert the CMYK values to RGB 682113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com sc = SkScaledBitmapSampler::kRGBX; 683113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } else if (3 == cinfo->out_color_components && JCS_RGB == cinfo->out_color_space) { 684113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com sc = SkScaledBitmapSampler::kRGB; 685113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#ifdef ANDROID_RGB 686113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } else if (JCS_RGBA_8888 == cinfo->out_color_space) { 687113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com sc = SkScaledBitmapSampler::kRGBX; 688113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } else if (JCS_RGB_565 == cinfo->out_color_space) { 689113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com sc = SkScaledBitmapSampler::kRGB_565; 690113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#endif 691113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } else if (1 == cinfo->out_color_components && 692113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com JCS_GRAYSCALE == cinfo->out_color_space) { 693113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com sc = SkScaledBitmapSampler::kGray; 694113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } else { 695113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return return_false(*cinfo, *bm, "jpeg colorspace"); 696113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 697113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 698113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (!sampler.begin(&bitmap, sc, this->getDitherImage())) { 699113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return return_false(*cinfo, bitmap, "sampler.begin"); 700113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 701113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 702113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com // The CMYK work-around relies on 4 components per pixel here 703113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com SkAutoMalloc srcStorage(width * 4); 704113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com uint8_t* srcRow = (uint8_t*)srcStorage.get(); 705113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 706113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com // Possibly skip initial rows [sampler.srcY0] 707113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (!skip_src_rows_tile(cinfo, fImageIndex->huffmanIndex(), srcRow, sampler.srcY0())) { 708113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return return_false(*cinfo, bitmap, "skip rows"); 709113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 710113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 711113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com // now loop through scanlines until y == bitmap->height() - 1 712113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com for (int y = 0;; y++) { 713113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com JSAMPLE* rowptr = (JSAMPLE*)srcRow; 714113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com int row_count = jpeg_read_tile_scanline(cinfo, fImageIndex->huffmanIndex(), &rowptr); 715113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (0 == row_count) { 716113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return return_false(*cinfo, bitmap, "read_scanlines"); 717113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 718113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (this->shouldCancelDecode()) { 719113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return return_false(*cinfo, bitmap, "shouldCancelDecode"); 720113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 721113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 722113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (JCS_CMYK == cinfo->out_color_space) { 723113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com convert_CMYK_to_RGB(srcRow, width); 724113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 725113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 726113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com sampler.next(srcRow); 727113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (bitmap.height() - 1 == y) { 728113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com // we're done 729113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com break; 730113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 731113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 732113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (!skip_src_rows_tile(cinfo, fImageIndex->huffmanIndex(), srcRow, 733113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com sampler.srcDY() - 1)) { 734113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return return_false(*cinfo, bitmap, "skip rows"); 735113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 736113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 737113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (swapOnly) { 738113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com bm->swap(bitmap); 739113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } else { 740113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com cropBitmap(bm, &bitmap, actualSampleSize, region.x(), region.y(), 741113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com region.width(), region.height(), startX, startY); 742113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 743113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return true; 744113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com} 745113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#endif 746113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 747d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com/////////////////////////////////////////////////////////////////////////////// 748d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 749d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#include "SkColorPriv.h" 750d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 751d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com// taken from jcolor.c in libjpeg 752d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#if 0 // 16bit - precise but slow 753d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #define CYR 19595 // 0.299 754d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #define CYG 38470 // 0.587 755d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #define CYB 7471 // 0.114 756d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 757d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #define CUR -11059 // -0.16874 758d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #define CUG -21709 // -0.33126 759d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #define CUB 32768 // 0.5 760d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 761d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #define CVR 32768 // 0.5 762d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #define CVG -27439 // -0.41869 763d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #define CVB -5329 // -0.08131 764d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 765d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #define CSHIFT 16 766d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#else // 8bit - fast, slightly less precise 767d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #define CYR 77 // 0.299 768d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #define CYG 150 // 0.587 769d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #define CYB 29 // 0.114 770d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 771d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #define CUR -43 // -0.16874 772d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #define CUG -85 // -0.33126 773d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #define CUB 128 // 0.5 774d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 775d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #define CVR 128 // 0.5 776d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #define CVG -107 // -0.41869 777d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #define CVB -21 // -0.08131 778d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 779d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #define CSHIFT 8 780d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#endif 781d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 782d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comstatic void rgb2yuv_32(uint8_t dst[], SkPMColor c) { 783d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int r = SkGetPackedR32(c); 784d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int g = SkGetPackedG32(c); 785d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int b = SkGetPackedB32(c); 786d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 787d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int y = ( CYR*r + CYG*g + CYB*b ) >> CSHIFT; 788d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int u = ( CUR*r + CUG*g + CUB*b ) >> CSHIFT; 789d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int v = ( CVR*r + CVG*g + CVB*b ) >> CSHIFT; 790d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 791d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst[0] = SkToU8(y); 792d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst[1] = SkToU8(u + 128); 793d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst[2] = SkToU8(v + 128); 794d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com} 795d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 796d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comstatic void rgb2yuv_4444(uint8_t dst[], U16CPU c) { 797d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int r = SkGetPackedR4444(c); 798d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int g = SkGetPackedG4444(c); 799d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int b = SkGetPackedB4444(c); 800d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 801d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int y = ( CYR*r + CYG*g + CYB*b ) >> (CSHIFT - 4); 802d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int u = ( CUR*r + CUG*g + CUB*b ) >> (CSHIFT - 4); 803d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int v = ( CVR*r + CVG*g + CVB*b ) >> (CSHIFT - 4); 804d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 805d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst[0] = SkToU8(y); 806d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst[1] = SkToU8(u + 128); 807d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst[2] = SkToU8(v + 128); 808d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com} 809d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 810d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comstatic void rgb2yuv_16(uint8_t dst[], U16CPU c) { 811d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int r = SkGetPackedR16(c); 812d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int g = SkGetPackedG16(c); 813d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int b = SkGetPackedB16(c); 814d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 815d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int y = ( 2*CYR*r + CYG*g + 2*CYB*b ) >> (CSHIFT - 2); 816d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int u = ( 2*CUR*r + CUG*g + 2*CUB*b ) >> (CSHIFT - 2); 817d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int v = ( 2*CVR*r + CVG*g + 2*CVB*b ) >> (CSHIFT - 2); 818d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 819d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst[0] = SkToU8(y); 820d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst[1] = SkToU8(u + 128); 821d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst[2] = SkToU8(v + 128); 822d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com} 823d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 824d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com/////////////////////////////////////////////////////////////////////////////// 825d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 826d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comtypedef void (*WriteScanline)(uint8_t* SK_RESTRICT dst, 827d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com const void* SK_RESTRICT src, int width, 828d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com const SkPMColor* SK_RESTRICT ctable); 829d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 830d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comstatic void Write_32_YUV(uint8_t* SK_RESTRICT dst, 831d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com const void* SK_RESTRICT srcRow, int width, 832d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com const SkPMColor*) { 833d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com const uint32_t* SK_RESTRICT src = (const uint32_t*)srcRow; 834d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com while (--width >= 0) { 835d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#ifdef WE_CONVERT_TO_YUV 836d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com rgb2yuv_32(dst, *src++); 837d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#else 838d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com uint32_t c = *src++; 839d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst[0] = SkGetPackedR32(c); 840d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst[1] = SkGetPackedG32(c); 841d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst[2] = SkGetPackedB32(c); 842d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#endif 843d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst += 3; 844d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 845d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com} 846d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 847d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comstatic void Write_4444_YUV(uint8_t* SK_RESTRICT dst, 848d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com const void* SK_RESTRICT srcRow, int width, 849d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com const SkPMColor*) { 850d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com const SkPMColor16* SK_RESTRICT src = (const SkPMColor16*)srcRow; 851d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com while (--width >= 0) { 852d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#ifdef WE_CONVERT_TO_YUV 853d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com rgb2yuv_4444(dst, *src++); 854d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#else 855d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com SkPMColor16 c = *src++; 856d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst[0] = SkPacked4444ToR32(c); 857d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst[1] = SkPacked4444ToG32(c); 858d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst[2] = SkPacked4444ToB32(c); 859d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#endif 860d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst += 3; 861d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 862d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com} 863d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 864d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comstatic void Write_16_YUV(uint8_t* SK_RESTRICT dst, 865d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com const void* SK_RESTRICT srcRow, int width, 866d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com const SkPMColor*) { 867d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com const uint16_t* SK_RESTRICT src = (const uint16_t*)srcRow; 868d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com while (--width >= 0) { 869d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#ifdef WE_CONVERT_TO_YUV 870d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com rgb2yuv_16(dst, *src++); 871d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#else 872d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com uint16_t c = *src++; 873d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst[0] = SkPacked16ToR32(c); 874d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst[1] = SkPacked16ToG32(c); 875d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst[2] = SkPacked16ToB32(c); 876d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#endif 877d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst += 3; 878d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 879d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com} 880d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 881d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comstatic void Write_Index_YUV(uint8_t* SK_RESTRICT dst, 882d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com const void* SK_RESTRICT srcRow, int width, 883d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com const SkPMColor* SK_RESTRICT ctable) { 884d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com const uint8_t* SK_RESTRICT src = (const uint8_t*)srcRow; 885d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com while (--width >= 0) { 886d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#ifdef WE_CONVERT_TO_YUV 887d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com rgb2yuv_32(dst, ctable[*src++]); 888d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#else 889d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com uint32_t c = ctable[*src++]; 890d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst[0] = SkGetPackedR32(c); 891d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst[1] = SkGetPackedG32(c); 892d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst[2] = SkGetPackedB32(c); 893d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#endif 894d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst += 3; 895d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 896d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com} 897d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 898d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comstatic WriteScanline ChooseWriter(const SkBitmap& bm) { 899d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com switch (bm.config()) { 900d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com case SkBitmap::kARGB_8888_Config: 901d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return Write_32_YUV; 902d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com case SkBitmap::kRGB_565_Config: 903d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return Write_16_YUV; 904d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com case SkBitmap::kARGB_4444_Config: 905d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return Write_4444_YUV; 906d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com case SkBitmap::kIndex8_Config: 907d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return Write_Index_YUV; 908d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com default: 909d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return NULL; 910d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 911d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com} 912d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 913d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comclass SkJPEGImageEncoder : public SkImageEncoder { 914d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comprotected: 915d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) { 916d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#ifdef TIME_ENCODE 917113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com SkAutoTime atm("JPEG Encode"); 918d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#endif 919d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 920d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com SkAutoLockPixels alp(bm); 921d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com if (NULL == bm.getPixels()) { 922d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return false; 923d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 924d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 925d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com jpeg_compress_struct cinfo; 926d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com skjpeg_error_mgr sk_err; 927d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com skjpeg_destination_mgr sk_wstream(stream); 928d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 929d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com // allocate these before set call setjmp 930d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com SkAutoMalloc oneRow; 931d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com SkAutoLockColors ctLocker; 932d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 933d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com cinfo.err = jpeg_std_error(&sk_err); 934d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com sk_err.error_exit = skjpeg_error_exit; 935d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com if (setjmp(sk_err.fJmpBuf)) { 936d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return false; 937d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 938d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 9398d725b25a6287e49e2b0cb2965871186e716ededmtklein@google.com // Keep after setjmp or mark volatile. 9408d725b25a6287e49e2b0cb2965871186e716ededmtklein@google.com const WriteScanline writer = ChooseWriter(bm); 9418d725b25a6287e49e2b0cb2965871186e716ededmtklein@google.com if (NULL == writer) { 9428d725b25a6287e49e2b0cb2965871186e716ededmtklein@google.com return false; 9438d725b25a6287e49e2b0cb2965871186e716ededmtklein@google.com } 9448d725b25a6287e49e2b0cb2965871186e716ededmtklein@google.com 9458d725b25a6287e49e2b0cb2965871186e716ededmtklein@google.com jpeg_create_compress(&cinfo); 946d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com cinfo.dest = &sk_wstream; 947d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com cinfo.image_width = bm.width(); 948d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com cinfo.image_height = bm.height(); 949d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com cinfo.input_components = 3; 950d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#ifdef WE_CONVERT_TO_YUV 951d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com cinfo.in_color_space = JCS_YCbCr; 952d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#else 953d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com cinfo.in_color_space = JCS_RGB; 954d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#endif 955d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com cinfo.input_gamma = 1; 956d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 957d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com jpeg_set_defaults(&cinfo); 958d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */); 959b7decc539887069f3fb0f9fc80d543b437bdd624scroggo@google.com#ifdef DCT_IFAST_SUPPORTED 960d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com cinfo.dct_method = JDCT_IFAST; 961b7decc539887069f3fb0f9fc80d543b437bdd624scroggo@google.com#endif 962d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 963d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com jpeg_start_compress(&cinfo, TRUE); 964d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 965d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com const int width = bm.width(); 9668570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com uint8_t* oneRowP = (uint8_t*)oneRow.reset(width * 3); 967d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 968d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com const SkPMColor* colors = ctLocker.lockColors(bm); 969d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com const void* srcRow = bm.getPixels(); 970d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 971d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com while (cinfo.next_scanline < cinfo.image_height) { 972d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ 973d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 974d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com writer(oneRowP, srcRow, width, colors); 975d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com row_pointer[0] = oneRowP; 976d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); 977d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com srcRow = (const void*)((const char*)srcRow + bm.rowBytes()); 978d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 979d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 980d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com jpeg_finish_compress(&cinfo); 981d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com jpeg_destroy_compress(&cinfo); 982d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 983d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return true; 984d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 985d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com}; 986d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 987d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com/////////////////////////////////////////////////////////////////////////////// 988ec51cb863409e238b40c5beef458669d9a824481robertphillips@google.comDEFINE_DECODER_CREATOR(JPEGImageDecoder); 989ec51cb863409e238b40c5beef458669d9a824481robertphillips@google.comDEFINE_ENCODER_CREATOR(JPEGImageEncoder); 990ec51cb863409e238b40c5beef458669d9a824481robertphillips@google.com/////////////////////////////////////////////////////////////////////////////// 991d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 99239edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.comstatic bool is_jpeg(SkStream* stream) { 993ec51cb863409e238b40c5beef458669d9a824481robertphillips@google.com static const unsigned char gHeader[] = { 0xFF, 0xD8, 0xFF }; 994d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com static const size_t HEADER_SIZE = sizeof(gHeader); 995d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 996d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com char buffer[HEADER_SIZE]; 997d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com size_t len = stream->read(buffer, HEADER_SIZE); 998d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 999d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com if (len != HEADER_SIZE) { 100039edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com return false; // can't read enough 1001d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 1002d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com if (memcmp(buffer, gHeader, HEADER_SIZE)) { 100339edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com return false; 100439edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com } 100539edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com return true; 100639edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com} 100739edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com 100839edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com#include "SkTRegistry.h" 100939edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com 101039edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.comstatic SkImageDecoder* sk_libjpeg_dfactory(SkStream* stream) { 101139edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com if (is_jpeg(stream)) { 101239edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com return SkNEW(SkJPEGImageDecoder); 101339edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com } 101439edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com return NULL; 101539edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com} 101639edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com 101739edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.comstatic SkImageDecoder::Format get_format_jpeg(SkStream* stream) { 101839edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com if (is_jpeg(stream)) { 101939edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com return SkImageDecoder::kJPEG_Format; 1020d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 102139edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com return SkImageDecoder::kUnknown_Format; 1022d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com} 1023d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 10248570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.comstatic SkImageEncoder* sk_libjpeg_efactory(SkImageEncoder::Type t) { 1025d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return (SkImageEncoder::kJPEG_Type == t) ? SkNEW(SkJPEGImageEncoder) : NULL; 1026d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com} 1027d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 10288570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com 10298570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.comstatic SkTRegistry<SkImageDecoder*, SkStream*> gDReg(sk_libjpeg_dfactory); 103039edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.comstatic SkTRegistry<SkImageDecoder::Format, SkStream*> gFormatReg(get_format_jpeg); 10318570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.comstatic SkTRegistry<SkImageEncoder*, SkImageEncoder::Type> gEReg(sk_libjpeg_efactory); 1032