1d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com/* 2d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com * Copyright 2007 The Android Open Source Project 3d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com * 4d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com * Use of this source code is governed by a BSD-style license that can be 5d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com * found in the LICENSE file. 6d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com */ 7d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 8d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 9d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#include "SkImageDecoder.h" 10d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#include "SkImageEncoder.h" 11d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#include "SkJpegUtility.h" 12d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#include "SkColorPriv.h" 13d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#include "SkDither.h" 14d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#include "SkScaledBitmapSampler.h" 15d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#include "SkStream.h" 16d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#include "SkTemplates.h" 17113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#include "SkTime.h" 18d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#include "SkUtils.h" 192a10318814fa9f2dd70122bf58d994b19bb9a8cfhalcanary@google.com#include "SkRTConf.h" 20113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#include "SkRect.h" 21113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#include "SkCanvas.h" 22d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 23fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com 24d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#include <stdio.h> 25d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comextern "C" { 26d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #include "jpeglib.h" 27d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #include "jerror.h" 28d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com} 29d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 30113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com// These enable timing code that report milliseconds for an encoding/decoding 31d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com//#define TIME_ENCODE 32d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com//#define TIME_DECODE 33d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 34d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com// this enables our rgb->yuv code, which is faster than libjpeg on ARM 35d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#define WE_CONVERT_TO_YUV 36d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 37113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com// If ANDROID_RGB is defined by in the jpeg headers it indicates that jpeg offers 38113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com// support for two additional formats (1) JCS_RGBA_8888 and (2) JCS_RGB_565. 39113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 40fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com#if defined(SK_DEBUG) 412a10318814fa9f2dd70122bf58d994b19bb9a8cfhalcanary@google.com#define DEFAULT_FOR_SUPPRESS_JPEG_IMAGE_DECODER_WARNINGS false 4204b57f87ab6789f7fc302eda8a993d88d4feea8fhalcanary@google.com#define DEFAULT_FOR_SUPPRESS_JPEG_IMAGE_DECODER_ERRORS false 432a10318814fa9f2dd70122bf58d994b19bb9a8cfhalcanary@google.com#else // !defined(SK_DEBUG) 442a10318814fa9f2dd70122bf58d994b19bb9a8cfhalcanary@google.com#define DEFAULT_FOR_SUPPRESS_JPEG_IMAGE_DECODER_WARNINGS true 4504b57f87ab6789f7fc302eda8a993d88d4feea8fhalcanary@google.com#define DEFAULT_FOR_SUPPRESS_JPEG_IMAGE_DECODER_ERRORS true 46fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com#endif // defined(SK_DEBUG) 472a10318814fa9f2dd70122bf58d994b19bb9a8cfhalcanary@google.comSK_CONF_DECLARE(bool, c_suppressJPEGImageDecoderWarnings, 482a10318814fa9f2dd70122bf58d994b19bb9a8cfhalcanary@google.com "images.jpeg.suppressDecoderWarnings", 492a10318814fa9f2dd70122bf58d994b19bb9a8cfhalcanary@google.com DEFAULT_FOR_SUPPRESS_JPEG_IMAGE_DECODER_WARNINGS, 502a10318814fa9f2dd70122bf58d994b19bb9a8cfhalcanary@google.com "Suppress most JPG warnings when calling decode functions."); 5104b57f87ab6789f7fc302eda8a993d88d4feea8fhalcanary@google.comSK_CONF_DECLARE(bool, c_suppressJPEGImageDecoderErrors, 5204b57f87ab6789f7fc302eda8a993d88d4feea8fhalcanary@google.com "images.jpeg.suppressDecoderErrors", 5304b57f87ab6789f7fc302eda8a993d88d4feea8fhalcanary@google.com DEFAULT_FOR_SUPPRESS_JPEG_IMAGE_DECODER_ERRORS, 5404b57f87ab6789f7fc302eda8a993d88d4feea8fhalcanary@google.com "Suppress most JPG error messages when decode " 5504b57f87ab6789f7fc302eda8a993d88d4feea8fhalcanary@google.com "function fails."); 56fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com 57d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com////////////////////////////////////////////////////////////////////////// 58d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com////////////////////////////////////////////////////////////////////////// 59d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 60590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.comstatic void overwrite_mem_buffer_size(jpeg_decompress_struct* cinfo) { 61113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#ifdef SK_BUILD_FOR_ANDROID 62113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com /* Check if the device indicates that it has a large amount of system memory 63113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com * if so, increase the memory allocation to 30MB instead of the default 5MB. 64113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com */ 65113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#ifdef ANDROID_LARGE_MEMORY_DEVICE 66113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com cinfo->mem->max_memory_to_use = 30 * 1024 * 1024; 67113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#else 68113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com cinfo->mem->max_memory_to_use = 5 * 1024 * 1024; 69113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#endif 70113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#endif // SK_BUILD_FOR_ANDROID 71113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com} 72113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 73113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com////////////////////////////////////////////////////////////////////////// 74113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com////////////////////////////////////////////////////////////////////////// 75113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 76fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.comstatic void do_nothing_emit_message(jpeg_common_struct*, int) { 77fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com /* do nothing */ 78fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com} 7904b57f87ab6789f7fc302eda8a993d88d4feea8fhalcanary@google.comstatic void do_nothing_output_message(j_common_ptr) { 8004b57f87ab6789f7fc302eda8a993d88d4feea8fhalcanary@google.com /* do nothing */ 8104b57f87ab6789f7fc302eda8a993d88d4feea8fhalcanary@google.com} 82fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com 83590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.comstatic void initialize_info(jpeg_decompress_struct* cinfo, skjpeg_source_mgr* src_mgr) { 84590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com SkASSERT(cinfo != NULL); 85590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com SkASSERT(src_mgr != NULL); 86590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com jpeg_create_decompress(cinfo); 87590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com overwrite_mem_buffer_size(cinfo); 88590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com cinfo->src = src_mgr; 89fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com /* To suppress warnings with a SK_DEBUG binary, set the 90fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com * environment variable "skia_images_jpeg_suppressDecoderWarnings" 91fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com * to "true". Inside a program that links to skia: 92fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com * SK_CONF_SET("images.jpeg.suppressDecoderWarnings", true); */ 93fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com if (c_suppressJPEGImageDecoderWarnings) { 94fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com cinfo->err->emit_message = &do_nothing_emit_message; 95fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com } 9604b57f87ab6789f7fc302eda8a993d88d4feea8fhalcanary@google.com /* To suppress error messages with a SK_DEBUG binary, set the 9704b57f87ab6789f7fc302eda8a993d88d4feea8fhalcanary@google.com * environment variable "skia_images_jpeg_suppressDecoderErrors" 9804b57f87ab6789f7fc302eda8a993d88d4feea8fhalcanary@google.com * to "true". Inside a program that links to skia: 9904b57f87ab6789f7fc302eda8a993d88d4feea8fhalcanary@google.com * SK_CONF_SET("images.jpeg.suppressDecoderErrors", true); */ 10004b57f87ab6789f7fc302eda8a993d88d4feea8fhalcanary@google.com if (c_suppressJPEGImageDecoderErrors) { 10104b57f87ab6789f7fc302eda8a993d88d4feea8fhalcanary@google.com cinfo->err->output_message = &do_nothing_output_message; 10204b57f87ab6789f7fc302eda8a993d88d4feea8fhalcanary@google.com } 103590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com} 104590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com 105a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com#ifdef SK_BUILD_FOR_ANDROID 106113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.comclass SkJPEGImageIndex { 107d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.compublic: 108a1193e4b0e34a7e4e1bd33e9708d7341679f8321scroggo // Takes ownership of stream. 109b5571b3324cf18629a255ec85e189447069c9b14scroggo@google.com SkJPEGImageIndex(SkStreamRewindable* stream, SkImageDecoder* decoder) 110a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com : fSrcMgr(stream, decoder) 111a1193e4b0e34a7e4e1bd33e9708d7341679f8321scroggo , fStream(stream) 112a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com , fInfoInitialized(false) 113a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com , fHuffmanCreated(false) 114a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com , fDecompressStarted(false) 115a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com { 116a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com SkDEBUGCODE(fReadHeaderSucceeded = false;) 117a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com } 118113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 119113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com ~SkJPEGImageIndex() { 120a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com if (fHuffmanCreated) { 121590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com // Set to false before calling the libjpeg function, in case 122590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com // the libjpeg function calls longjmp. Our setjmp handler may 123590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com // attempt to delete this SkJPEGImageIndex, thus entering this 124590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com // destructor again. Setting fHuffmanCreated to false first 125590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com // prevents an infinite loop. 126a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com fHuffmanCreated = false; 127a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com jpeg_destroy_huffman_index(&fHuffmanIndex); 128a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com } 129a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com if (fDecompressStarted) { 130590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com // Like fHuffmanCreated, set to false before calling libjpeg 131590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com // function to prevent potential infinite loop. 132a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com fDecompressStarted = false; 133a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com jpeg_finish_decompress(&fCInfo); 134a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com } 135a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com if (fInfoInitialized) { 136a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com this->destroyInfo(); 137a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com } 138a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com } 139a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com 140a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com /** 141a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com * Destroy the cinfo struct. 142a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com * After this call, if a huffman index was already built, it 143a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com * can be used after calling initializeInfoAndReadHeader 144a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com * again. Must not be called after startTileDecompress except 145a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com * in the destructor. 146a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com */ 147a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com void destroyInfo() { 148a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com SkASSERT(fInfoInitialized); 149a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com SkASSERT(!fDecompressStarted); 150590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com // Like fHuffmanCreated, set to false before calling libjpeg 151590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com // function to prevent potential infinite loop. 152a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com fInfoInitialized = false; 153113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com jpeg_destroy_decompress(&fCInfo); 154a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com SkDEBUGCODE(fReadHeaderSucceeded = false;) 155d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 156d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 157113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com /** 158a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com * Initialize the cinfo struct. 159a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com * Calls jpeg_create_decompress, makes customizations, and 160a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com * finally calls jpeg_read_header. Returns true if jpeg_read_header 161a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com * returns JPEG_HEADER_OK. 162a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com * If cinfo was already initialized, destroyInfo must be called to 163a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com * destroy the old one. Must not be called after startTileDecompress. 164113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com */ 165a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com bool initializeInfoAndReadHeader() { 166a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com SkASSERT(!fInfoInitialized && !fDecompressStarted); 167590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com initialize_info(&fCInfo, &fSrcMgr); 168a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com fInfoInitialized = true; 169a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com const bool success = (JPEG_HEADER_OK == jpeg_read_header(&fCInfo, true)); 170a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com SkDEBUGCODE(fReadHeaderSucceeded = success;) 171a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com return success; 172113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 173d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 174113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com jpeg_decompress_struct* cinfo() { return &fCInfo; } 175d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 176113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com huffman_index* huffmanIndex() { return &fHuffmanIndex; } 177a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com 178a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com /** 179a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com * Build the index to be used for tile based decoding. 180a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com * Must only be called after a successful call to 181a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com * initializeInfoAndReadHeader and must not be called more 182a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com * than once. 183a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com */ 184a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com bool buildHuffmanIndex() { 185a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com SkASSERT(fReadHeaderSucceeded); 186a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com SkASSERT(!fHuffmanCreated); 187a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com jpeg_create_huffman_index(&fCInfo, &fHuffmanIndex); 188a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com SkASSERT(1 == fCInfo.scale_num && 1 == fCInfo.scale_denom); 18957a529877e65687de1fa4d19d52746427c6896dcscroggo@google.com fHuffmanCreated = jpeg_build_huffman_index(&fCInfo, &fHuffmanIndex); 19057a529877e65687de1fa4d19d52746427c6896dcscroggo@google.com return fHuffmanCreated; 191a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com } 192a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com 193a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com /** 194a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com * Start tile based decoding. Must only be called after a 195a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com * successful call to buildHuffmanIndex, and must only be 196a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com * called once. 197a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com */ 198a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com bool startTileDecompress() { 199a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com SkASSERT(fHuffmanCreated); 200a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com SkASSERT(fReadHeaderSucceeded); 201a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com SkASSERT(!fDecompressStarted); 202a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com if (jpeg_start_tile_decompress(&fCInfo)) { 203a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com fDecompressStarted = true; 204a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com return true; 205a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com } 206a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com return false; 207a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com } 208113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 209113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.comprivate: 210113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com skjpeg_source_mgr fSrcMgr; 211a1193e4b0e34a7e4e1bd33e9708d7341679f8321scroggo SkAutoTDelete<SkStream> fStream; 212113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com jpeg_decompress_struct fCInfo; 213113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com huffman_index fHuffmanIndex; 214a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com bool fInfoInitialized; 215a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com bool fHuffmanCreated; 216a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com bool fDecompressStarted; 217a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com SkDEBUGCODE(bool fReadHeaderSucceeded;) 218113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com}; 219a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com#endif 220d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 221113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.comclass SkJPEGImageDecoder : public SkImageDecoder { 222d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.compublic: 223a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com#ifdef SK_BUILD_FOR_ANDROID 224113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com SkJPEGImageDecoder() { 225113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com fImageIndex = NULL; 226113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com fImageWidth = 0; 227113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com fImageHeight = 0; 228d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 229113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 230113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com virtual ~SkJPEGImageDecoder() { 231113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com SkDELETE(fImageIndex); 232d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 233a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com#endif 234113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 23536352bf5e38f45a70ee4f4fc132a38048d38206dmtklein Format getFormat() const override { 236113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return kJPEG_Format; 237113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 238113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 239113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.comprotected: 240d79277f67824392876b82cf5635cc11f819e64dfscroggo@google.com#ifdef SK_BUILD_FOR_ANDROID 24136352bf5e38f45a70ee4f4fc132a38048d38206dmtklein bool onBuildTileIndex(SkStreamRewindable *stream, int *width, int *height) override; 24236352bf5e38f45a70ee4f4fc132a38048d38206dmtklein bool onDecodeSubset(SkBitmap* bitmap, const SkIRect& rect) override; 243113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#endif 24436352bf5e38f45a70ee4f4fc132a38048d38206dmtklein Result onDecode(SkStream* stream, SkBitmap* bm, Mode) override; 2457831a4bbb46a919316efc7c70808dcaaf8ee629atfarina bool onDecodeYUV8Planes(SkStream* stream, SkISize componentSizes[3], 2467831a4bbb46a919316efc7c70808dcaaf8ee629atfarina void* planes[3], size_t rowBytes[3], 2477831a4bbb46a919316efc7c70808dcaaf8ee629atfarina SkYUVColorSpace* colorSpace) override; 248113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 249d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comprivate: 250a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com#ifdef SK_BUILD_FOR_ANDROID 251113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com SkJPEGImageIndex* fImageIndex; 252113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com int fImageWidth; 253113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com int fImageHeight; 254a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com#endif 255113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 256590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com /** 2576c22573edb234ad14df947278cfed010669a39a7reed * Determine the appropriate bitmap colortype and out_color_space based on 258590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com * both the preference of the caller and the jpeg_color_space on the 259590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com * jpeg_decompress_struct passed in. 260590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com * Must be called after jpeg_read_header. 261590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com */ 2626c22573edb234ad14df947278cfed010669a39a7reed SkColorType getBitmapColorType(jpeg_decompress_struct*); 263590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com 264113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com typedef SkImageDecoder INHERITED; 265d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com}; 266d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 267113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com////////////////////////////////////////////////////////////////////////// 268113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 269d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com/* Automatically clean up after throwing an exception */ 270d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comclass JPEGAutoClean { 271d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.compublic: 272d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com JPEGAutoClean(): cinfo_ptr(NULL) {} 273d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com ~JPEGAutoClean() { 274d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com if (cinfo_ptr) { 275d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com jpeg_destroy_decompress(cinfo_ptr); 276d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 277d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 278d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com void set(jpeg_decompress_struct* info) { 279d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com cinfo_ptr = info; 280d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 281d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comprivate: 282d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com jpeg_decompress_struct* cinfo_ptr; 283d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com}; 284d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 285d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com/////////////////////////////////////////////////////////////////////////////// 286d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 287d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com/* If we need to better match the request, we might examine the image and 288d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com output dimensions, and determine if the downsampling jpeg provided is 289d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com not sufficient. If so, we can recompute a modified sampleSize value to 290d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com make up the difference. 291d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 292d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com To skip this additional scaling, just set sampleSize = 1; below. 293d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com */ 294d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comstatic int recompute_sampleSize(int sampleSize, 295d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com const jpeg_decompress_struct& cinfo) { 296d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return sampleSize * cinfo.output_width / cinfo.image_width; 297d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com} 298d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 299d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comstatic bool valid_output_dimensions(const jpeg_decompress_struct& cinfo) { 300d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com /* These are initialized to 0, so if they have non-zero values, we assume 301d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com they are "valid" (i.e. have been computed by libjpeg) 302d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com */ 303113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return 0 != cinfo.output_width && 0 != cinfo.output_height; 304d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com} 305d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 306113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.comstatic bool skip_src_rows(jpeg_decompress_struct* cinfo, void* buffer, int count) { 307d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com for (int i = 0; i < count; i++) { 308d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com JSAMPLE* rowptr = (JSAMPLE*)buffer; 309d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int row_count = jpeg_read_scanlines(cinfo, &rowptr, 1); 310113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (1 != row_count) { 311d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return false; 312d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 313d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 314d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return true; 315d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com} 316d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 317d79277f67824392876b82cf5635cc11f819e64dfscroggo@google.com#ifdef SK_BUILD_FOR_ANDROID 318113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.comstatic bool skip_src_rows_tile(jpeg_decompress_struct* cinfo, 319113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com huffman_index *index, void* buffer, int count) { 320113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com for (int i = 0; i < count; i++) { 321113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com JSAMPLE* rowptr = (JSAMPLE*)buffer; 322113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com int row_count = jpeg_read_tile_scanline(cinfo, index, &rowptr); 323113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (1 != row_count) { 324113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return false; 325113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 326113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 327113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return true; 328113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com} 329113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#endif 330113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 3312a1208017dd676f94a53bbb228197c3978dbdd8ascroggo/////////////////////////////////////////////////////////////////////////////// 3322a1208017dd676f94a53bbb228197c3978dbdd8ascroggo 333d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com// This guy exists just to aid in debugging, as it allows debuggers to just 334d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com// set a break-point in one place to see all error exists. 3352a1208017dd676f94a53bbb228197c3978dbdd8ascroggostatic void print_jpeg_decoder_errors(const jpeg_decompress_struct& cinfo, 336b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi int width, int height, const char caller[]) { 33704b57f87ab6789f7fc302eda8a993d88d4feea8fhalcanary@google.com if (!(c_suppressJPEGImageDecoderErrors)) { 33804b57f87ab6789f7fc302eda8a993d88d4feea8fhalcanary@google.com char buffer[JMSG_LENGTH_MAX]; 33904b57f87ab6789f7fc302eda8a993d88d4feea8fhalcanary@google.com cinfo.err->format_message((const j_common_ptr)&cinfo, buffer); 34004b57f87ab6789f7fc302eda8a993d88d4feea8fhalcanary@google.com SkDebugf("libjpeg error %d <%s> from %s [%d %d]\n", 341b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi cinfo.err->msg_code, buffer, caller, width, height); 34204b57f87ab6789f7fc302eda8a993d88d4feea8fhalcanary@google.com } 3432a1208017dd676f94a53bbb228197c3978dbdd8ascroggo} 3442a1208017dd676f94a53bbb228197c3978dbdd8ascroggo 3452a1208017dd676f94a53bbb228197c3978dbdd8ascroggostatic bool return_false(const jpeg_decompress_struct& cinfo, 3462a1208017dd676f94a53bbb228197c3978dbdd8ascroggo const char caller[]) { 3472a1208017dd676f94a53bbb228197c3978dbdd8ascroggo print_jpeg_decoder_errors(cinfo, 0, 0, caller); 3482a1208017dd676f94a53bbb228197c3978dbdd8ascroggo return false; 349d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com} 350d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 351df78d0a81cfada516fe98b1f02d954e831e5d9e7mtklein#ifdef SK_BUILD_FOR_ANDROID 352b227e37eae36ccf630c4baef00b1354d42b40fd1sugoistatic bool return_false(const jpeg_decompress_struct& cinfo, 353b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi const SkBitmap& bm, const char caller[]) { 3542a1208017dd676f94a53bbb228197c3978dbdd8ascroggo print_jpeg_decoder_errors(cinfo, bm.width(), bm.height(), caller); 3552a1208017dd676f94a53bbb228197c3978dbdd8ascroggo return false; 3562a1208017dd676f94a53bbb228197c3978dbdd8ascroggo} 357df78d0a81cfada516fe98b1f02d954e831e5d9e7mtklein#endif 3582a1208017dd676f94a53bbb228197c3978dbdd8ascroggo 3592a1208017dd676f94a53bbb228197c3978dbdd8ascroggostatic SkImageDecoder::Result return_failure(const jpeg_decompress_struct& cinfo, 3602a1208017dd676f94a53bbb228197c3978dbdd8ascroggo const SkBitmap& bm, const char caller[]) { 3612a1208017dd676f94a53bbb228197c3978dbdd8ascroggo print_jpeg_decoder_errors(cinfo, bm.width(), bm.height(), caller); 3622a1208017dd676f94a53bbb228197c3978dbdd8ascroggo return SkImageDecoder::kFailure; 363b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi} 364b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 3652a1208017dd676f94a53bbb228197c3978dbdd8ascroggo/////////////////////////////////////////////////////////////////////////////// 3662a1208017dd676f94a53bbb228197c3978dbdd8ascroggo 3678570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com// Convert a scanline of CMYK samples to RGBX in place. Note that this 3688570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com// method moves the "scanline" pointer in its processing 3698570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.comstatic void convert_CMYK_to_RGB(uint8_t* scanline, unsigned int width) { 3708570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com // At this point we've received CMYK pixels from libjpeg. We 371d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com // perform a crude conversion to RGB (based on the formulae 3728570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com // from easyrgb.com): 3738570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com // CMYK -> CMY 3748570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com // C = ( C * (1 - K) + K ) // for each CMY component 3758570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com // CMY -> RGB 3768570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com // R = ( 1 - C ) * 255 // for each RGB component 3778570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com // Unfortunately we are seeing inverted CMYK so all the original terms 3788570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com // are 1-. This yields: 3798570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com // CMYK -> CMY 3808570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com // C = ( (1-C) * (1 - (1-K) + (1-K) ) -> C = 1 - C*K 3818570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com // The conversion from CMY->RGB remains the same 3828570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com for (unsigned int x = 0; x < width; ++x, scanline += 4) { 3838570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com scanline[0] = SkMulDiv255Round(scanline[0], scanline[3]); 3848570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com scanline[1] = SkMulDiv255Round(scanline[1], scanline[3]); 3858570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com scanline[2] = SkMulDiv255Round(scanline[2], scanline[3]); 3868570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com scanline[3] = 255; 3878570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com } 3888570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com} 3898570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com 390590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com/** 391590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com * Common code for setting the error manager. 392590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com */ 393590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.comstatic void set_error_mgr(jpeg_decompress_struct* cinfo, skjpeg_error_mgr* errorManager) { 394590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com SkASSERT(cinfo != NULL); 395590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com SkASSERT(errorManager != NULL); 396590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com cinfo->err = jpeg_std_error(errorManager); 397590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com errorManager->error_exit = skjpeg_error_exit; 398590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com} 399590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com 400590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com/** 401590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com * Common code for turning off upsampling and smoothing. Turning these 402590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com * off helps performance without showing noticable differences in the 403590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com * resulting bitmap. 404590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com */ 405590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.comstatic void turn_off_visual_optimizations(jpeg_decompress_struct* cinfo) { 406590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com SkASSERT(cinfo != NULL); 407590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com /* this gives about 30% performance improvement. In theory it may 408590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com reduce the visual quality, in practice I'm not seeing a difference 409590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com */ 410590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com cinfo->do_fancy_upsampling = 0; 411590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com 412590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com /* this gives another few percents */ 413590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com cinfo->do_block_smoothing = 0; 414590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com} 415590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com 416590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com/** 417590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com * Common code for setting the dct method. 418590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com */ 419590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.comstatic void set_dct_method(const SkImageDecoder& decoder, jpeg_decompress_struct* cinfo) { 420590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com SkASSERT(cinfo != NULL); 421590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com#ifdef DCT_IFAST_SUPPORTED 422590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com if (decoder.getPreferQualityOverSpeed()) { 423590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com cinfo->dct_method = JDCT_ISLOW; 424590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com } else { 425590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com cinfo->dct_method = JDCT_IFAST; 426590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com } 427590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com#else 428590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com cinfo->dct_method = JDCT_ISLOW; 429590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com#endif 430590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com} 431590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com 4326c22573edb234ad14df947278cfed010669a39a7reedSkColorType SkJPEGImageDecoder::getBitmapColorType(jpeg_decompress_struct* cinfo) { 433590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com SkASSERT(cinfo != NULL); 434590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com 435590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com SrcDepth srcDepth = k32Bit_SrcDepth; 436590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com if (JCS_GRAYSCALE == cinfo->jpeg_color_space) { 437590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com srcDepth = k8BitGray_SrcDepth; 438590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com } 439590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com 4406c22573edb234ad14df947278cfed010669a39a7reed SkColorType colorType = this->getPrefColorType(srcDepth, /*hasAlpha*/ false); 4416c22573edb234ad14df947278cfed010669a39a7reed switch (colorType) { 4426c22573edb234ad14df947278cfed010669a39a7reed case kAlpha_8_SkColorType: 4436c22573edb234ad14df947278cfed010669a39a7reed // Only respect A8 colortype if the original is grayscale, 444590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com // in which case we will treat the grayscale as alpha 445590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com // values. 446590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com if (cinfo->jpeg_color_space != JCS_GRAYSCALE) { 4476c22573edb234ad14df947278cfed010669a39a7reed colorType = kN32_SkColorType; 448590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com } 449590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com break; 4506c22573edb234ad14df947278cfed010669a39a7reed case kN32_SkColorType: 451590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com // Fall through. 4526c22573edb234ad14df947278cfed010669a39a7reed case kARGB_4444_SkColorType: 453590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com // Fall through. 4546c22573edb234ad14df947278cfed010669a39a7reed case kRGB_565_SkColorType: 4556c22573edb234ad14df947278cfed010669a39a7reed // These are acceptable destination colortypes. 456590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com break; 457590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com default: 4586c22573edb234ad14df947278cfed010669a39a7reed // Force all other colortypes to 8888. 4596c22573edb234ad14df947278cfed010669a39a7reed colorType = kN32_SkColorType; 460590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com break; 461590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com } 462590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com 463590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com switch (cinfo->jpeg_color_space) { 464590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com case JCS_CMYK: 465590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com // Fall through. 466590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com case JCS_YCCK: 467590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com // libjpeg cannot convert from CMYK or YCCK to RGB - here we set up 468590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com // so libjpeg will give us CMYK samples back and we will later 469590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com // manually convert them to RGB 470590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com cinfo->out_color_space = JCS_CMYK; 471590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com break; 472590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com case JCS_GRAYSCALE: 4736c22573edb234ad14df947278cfed010669a39a7reed if (kAlpha_8_SkColorType == colorType) { 474590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com cinfo->out_color_space = JCS_GRAYSCALE; 475590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com break; 476590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com } 477590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com // The data is JCS_GRAYSCALE, but the caller wants some sort of RGB 4786c22573edb234ad14df947278cfed010669a39a7reed // colortype. Fall through to set to the default. 479590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com default: 480590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com cinfo->out_color_space = JCS_RGB; 481590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com break; 482590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com } 4836c22573edb234ad14df947278cfed010669a39a7reed return colorType; 484590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com} 485590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com 486590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com/** 4876c22573edb234ad14df947278cfed010669a39a7reed * Based on the colortype and dither mode, adjust out_color_space and 4886c22573edb234ad14df947278cfed010669a39a7reed * dither_mode of cinfo. Only does work in ANDROID_RGB 489590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com */ 490590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.comstatic void adjust_out_color_space_and_dither(jpeg_decompress_struct* cinfo, 4916c22573edb234ad14df947278cfed010669a39a7reed SkColorType colorType, 492590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com const SkImageDecoder& decoder) { 493590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com SkASSERT(cinfo != NULL); 4946c22573edb234ad14df947278cfed010669a39a7reed#ifdef ANDROID_RGB 495590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com cinfo->dither_mode = JDITHER_NONE; 496590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com if (JCS_CMYK == cinfo->out_color_space) { 497590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com return; 498590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com } 4996c22573edb234ad14df947278cfed010669a39a7reed switch (colorType) { 5006c22573edb234ad14df947278cfed010669a39a7reed case kN32_SkColorType: 501590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com cinfo->out_color_space = JCS_RGBA_8888; 502590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com break; 5036c22573edb234ad14df947278cfed010669a39a7reed case kRGB_565_SkColorType: 504590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com cinfo->out_color_space = JCS_RGB_565; 505590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com if (decoder.getDitherImage()) { 506590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com cinfo->dither_mode = JDITHER_ORDERED; 507590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com } 508590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com break; 509590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com default: 510590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com break; 511590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com } 512590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com#endif 5136c22573edb234ad14df947278cfed010669a39a7reed} 514590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com 515fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com/** 516fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com Sets all pixels in given bitmap to SK_ColorWHITE for all rows >= y. 517fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com Used when decoding fails partway through reading scanlines to fill 518fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com remaining lines. */ 519fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.comstatic void fill_below_level(int y, SkBitmap* bitmap) { 5202dcf36e25186bb0396eaa692bda402993252b88ahalcanary@google.com SkIRect rect = SkIRect::MakeLTRB(0, y, bitmap->width(), bitmap->height()); 521fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com SkCanvas canvas(*bitmap); 5222dcf36e25186bb0396eaa692bda402993252b88ahalcanary@google.com canvas.clipRect(SkRect::Make(rect)); 523fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com canvas.drawColor(SK_ColorWHITE); 524fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com} 525fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com 5265ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com/** 5275ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com * Get the config and bytes per pixel of the source data. Return 5285ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com * whether the data is supported. 5295ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com */ 5305ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.comstatic bool get_src_config(const jpeg_decompress_struct& cinfo, 5315ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com SkScaledBitmapSampler::SrcConfig* sc, 5325ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com int* srcBytesPerPixel) { 5335ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com SkASSERT(sc != NULL && srcBytesPerPixel != NULL); 5345ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com if (JCS_CMYK == cinfo.out_color_space) { 5355ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com // In this case we will manually convert the CMYK values to RGB 5365ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com *sc = SkScaledBitmapSampler::kRGBX; 5375ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com // The CMYK work-around relies on 4 components per pixel here 5385ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com *srcBytesPerPixel = 4; 5395ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com } else if (3 == cinfo.out_color_components && JCS_RGB == cinfo.out_color_space) { 5405ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com *sc = SkScaledBitmapSampler::kRGB; 5415ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com *srcBytesPerPixel = 3; 5425ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com#ifdef ANDROID_RGB 5435ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com } else if (JCS_RGBA_8888 == cinfo.out_color_space) { 5445ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com *sc = SkScaledBitmapSampler::kRGBX; 5455ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com *srcBytesPerPixel = 4; 5465ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com } else if (JCS_RGB_565 == cinfo.out_color_space) { 5475ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com *sc = SkScaledBitmapSampler::kRGB_565; 5485ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com *srcBytesPerPixel = 2; 5495ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com#endif 5505ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com } else if (1 == cinfo.out_color_components && 5515ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com JCS_GRAYSCALE == cinfo.out_color_space) { 5525ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com *sc = SkScaledBitmapSampler::kGray; 5535ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com *srcBytesPerPixel = 1; 5545ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com } else { 5555ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com return false; 5565ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com } 5575ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com return true; 5585ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com} 559fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com 5602a1208017dd676f94a53bbb228197c3978dbdd8ascroggoSkImageDecoder::Result SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { 561d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#ifdef TIME_DECODE 562113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com SkAutoTime atm("JPEG Decode"); 563d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#endif 564d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 565d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com JPEGAutoClean autoClean; 566d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 567d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com jpeg_decompress_struct cinfo; 568d4c3565aac5c83ff0008453abed4c6d6009bb394scroggo@google.com skjpeg_source_mgr srcManager(stream, this); 569d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 570590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com skjpeg_error_mgr errorManager; 571590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com set_error_mgr(&cinfo, &errorManager); 572d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 573d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com // All objects need to be instantiated before this setjmp call so that 574d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com // they will be cleaned up properly if an error occurs. 575113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (setjmp(errorManager.fJmpBuf)) { 5762a1208017dd676f94a53bbb228197c3978dbdd8ascroggo return return_failure(cinfo, *bm, "setjmp"); 577d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 578d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 579590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com initialize_info(&cinfo, &srcManager); 580d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com autoClean.set(&cinfo); 581d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 582d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int status = jpeg_read_header(&cinfo, true); 583d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com if (status != JPEG_HEADER_OK) { 5842a1208017dd676f94a53bbb228197c3978dbdd8ascroggo return return_failure(cinfo, *bm, "read_header"); 585d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 586d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 587d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com /* Try to fulfill the requested sampleSize. Since jpeg can do it (when it 588d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com can) much faster that we, just use their num/denom api to approximate 589d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com the size. 590d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com */ 591d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int sampleSize = this->getSampleSize(); 592d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 593590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com set_dct_method(*this, &cinfo); 594113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 595590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com SkASSERT(1 == cinfo.scale_num); 596d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com cinfo.scale_denom = sampleSize; 597d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 598590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com turn_off_visual_optimizations(&cinfo); 599d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 6006c22573edb234ad14df947278cfed010669a39a7reed const SkColorType colorType = this->getBitmapColorType(&cinfo); 6016c22573edb234ad14df947278cfed010669a39a7reed const SkAlphaType alphaType = kAlpha_8_SkColorType == colorType ? 6026c22573edb234ad14df947278cfed010669a39a7reed kPremul_SkAlphaType : kOpaque_SkAlphaType; 603d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 6046c22573edb234ad14df947278cfed010669a39a7reed adjust_out_color_space_and_dither(&cinfo, colorType, *this); 605d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 606113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (1 == sampleSize && SkImageDecoder::kDecodeBounds_Mode == mode) { 6075ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com // Assume an A8 bitmap is not opaque to avoid the check of each 6085ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com // individual pixel. It is very unlikely to be opaque, since 6095ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com // an opaque A8 bitmap would not be very interesting. 6105ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com // Otherwise, a jpeg image is opaque. 6112a1208017dd676f94a53bbb228197c3978dbdd8ascroggo bool success = bm->setInfo(SkImageInfo::Make(cinfo.image_width, cinfo.image_height, 6122a1208017dd676f94a53bbb228197c3978dbdd8ascroggo colorType, alphaType)); 6132a1208017dd676f94a53bbb228197c3978dbdd8ascroggo return success ? kSuccess : kFailure; 614d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 615d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 616d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com /* image_width and image_height are the original dimensions, available 617d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com after jpeg_read_header(). To see the scaled dimensions, we have to call 618d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com jpeg_start_decompress(), and then read output_width and output_height. 619d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com */ 620d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com if (!jpeg_start_decompress(&cinfo)) { 621d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com /* If we failed here, we may still have enough information to return 622d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com to the caller if they just wanted (subsampled bounds). If sampleSize 623d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com was 1, then we would have already returned. Thus we just check if 624d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com we're in kDecodeBounds_Mode, and that we have valid output sizes. 625d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 626d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com One reason to fail here is that we have insufficient stream data 627d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com to complete the setup. However, output dimensions seem to get 628d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com computed very early, which is why this special check can pay off. 629d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com */ 630113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (SkImageDecoder::kDecodeBounds_Mode == mode && valid_output_dimensions(cinfo)) { 631d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com SkScaledBitmapSampler smpl(cinfo.output_width, cinfo.output_height, 632d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com recompute_sampleSize(sampleSize, cinfo)); 6335ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com // Assume an A8 bitmap is not opaque to avoid the check of each 6345ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com // individual pixel. It is very unlikely to be opaque, since 6355ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com // an opaque A8 bitmap would not be very interesting. 6365ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com // Otherwise, a jpeg image is opaque. 6372a1208017dd676f94a53bbb228197c3978dbdd8ascroggo bool success = bm->setInfo(SkImageInfo::Make(smpl.scaledWidth(), smpl.scaledHeight(), 6382a1208017dd676f94a53bbb228197c3978dbdd8ascroggo colorType, alphaType)); 6392a1208017dd676f94a53bbb228197c3978dbdd8ascroggo return success ? kSuccess : kFailure; 640d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } else { 6412a1208017dd676f94a53bbb228197c3978dbdd8ascroggo return return_failure(cinfo, *bm, "start_decompress"); 642d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 643d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 644d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com sampleSize = recompute_sampleSize(sampleSize, cinfo); 645d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 646113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com SkScaledBitmapSampler sampler(cinfo.output_width, cinfo.output_height, sampleSize); 6475ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com // Assume an A8 bitmap is not opaque to avoid the check of each 6485ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com // individual pixel. It is very unlikely to be opaque, since 6495ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com // an opaque A8 bitmap would not be very interesting. 6505ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com // Otherwise, a jpeg image is opaque. 6516c22573edb234ad14df947278cfed010669a39a7reed bm->setInfo(SkImageInfo::Make(sampler.scaledWidth(), sampler.scaledHeight(), 6526c22573edb234ad14df947278cfed010669a39a7reed colorType, alphaType)); 653bc69ce982f8374742ca910587485f0d741350c2dscroggo@google.com if (SkImageDecoder::kDecodeBounds_Mode == mode) { 6542a1208017dd676f94a53bbb228197c3978dbdd8ascroggo return kSuccess; 655bc69ce982f8374742ca910587485f0d741350c2dscroggo@google.com } 656bc69ce982f8374742ca910587485f0d741350c2dscroggo@google.com if (!this->allocPixelRef(bm, NULL)) { 6572a1208017dd676f94a53bbb228197c3978dbdd8ascroggo return return_failure(cinfo, *bm, "allocPixelRef"); 658113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 659113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 660113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com SkAutoLockPixels alp(*bm); 661113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 662d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#ifdef ANDROID_RGB 663d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com /* short-circuit the SkScaledBitmapSampler when possible, as this gives 664d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com a significant performance boost. 665d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com */ 666d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com if (sampleSize == 1 && 6676c22573edb234ad14df947278cfed010669a39a7reed ((kN32_SkColorType == colorType && cinfo.out_color_space == JCS_RGBA_8888) || 6686c22573edb234ad14df947278cfed010669a39a7reed (kRGB_565_SkColorType == colorType && cinfo.out_color_space == JCS_RGB_565))) 669d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com { 670bc69ce982f8374742ca910587485f0d741350c2dscroggo@google.com JSAMPLE* rowptr = (JSAMPLE*)bm->getPixels(); 671d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com INT32 const bpr = bm->rowBytes(); 672d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com 673d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com while (cinfo.output_scanline < cinfo.output_height) { 674d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1); 675d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com if (0 == row_count) { 676fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com // if row_count == 0, then we didn't get a scanline, 677fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com // so return early. We will return a partial image. 678fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com fill_below_level(cinfo.output_scanline, bm); 679fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com cinfo.output_scanline = cinfo.output_height; 6802a1208017dd676f94a53bbb228197c3978dbdd8ascroggo jpeg_finish_decompress(&cinfo); 6812a1208017dd676f94a53bbb228197c3978dbdd8ascroggo return kPartialSuccess; 682d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 683d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com if (this->shouldCancelDecode()) { 6842a1208017dd676f94a53bbb228197c3978dbdd8ascroggo return return_failure(cinfo, *bm, "shouldCancelDecode"); 685d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 686d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com rowptr += bpr; 687d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 688d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com jpeg_finish_decompress(&cinfo); 6892a1208017dd676f94a53bbb228197c3978dbdd8ascroggo return kSuccess; 690d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 691d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#endif 6928570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com 693d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com // check for supported formats 694d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com SkScaledBitmapSampler::SrcConfig sc; 6955ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com int srcBytesPerPixel; 6965ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com 6975ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com if (!get_src_config(cinfo, &sc, &srcBytesPerPixel)) { 6982a1208017dd676f94a53bbb228197c3978dbdd8ascroggo return return_failure(cinfo, *bm, "jpeg colorspace"); 699d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 700d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 7018d2392487cd97e68c0a71da9fd5d2b42ecac5ec8scroggo@google.com if (!sampler.begin(bm, sc, *this)) { 7022a1208017dd676f94a53bbb228197c3978dbdd8ascroggo return return_failure(cinfo, *bm, "sampler.begin"); 703d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 704d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 7055ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com SkAutoMalloc srcStorage(cinfo.output_width * srcBytesPerPixel); 706113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com uint8_t* srcRow = (uint8_t*)srcStorage.get(); 707d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 708d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com // Possibly skip initial rows [sampler.srcY0] 709d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com if (!skip_src_rows(&cinfo, srcRow, sampler.srcY0())) { 7102a1208017dd676f94a53bbb228197c3978dbdd8ascroggo return return_failure(cinfo, *bm, "skip rows"); 711d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 712d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 713d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com // now loop through scanlines until y == bm->height() - 1 714d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com for (int y = 0;; y++) { 715d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com JSAMPLE* rowptr = (JSAMPLE*)srcRow; 716d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1); 717d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com if (0 == row_count) { 718fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com // if row_count == 0, then we didn't get a scanline, 719fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com // so return early. We will return a partial image. 720fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com fill_below_level(y, bm); 721fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com cinfo.output_scanline = cinfo.output_height; 7222a1208017dd676f94a53bbb228197c3978dbdd8ascroggo jpeg_finish_decompress(&cinfo); 723c6b8ffa0ac953f1c66016c5655e2c1057a31c5c3scroggo return kPartialSuccess; 724d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 725d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com if (this->shouldCancelDecode()) { 7262a1208017dd676f94a53bbb228197c3978dbdd8ascroggo return return_failure(cinfo, *bm, "shouldCancelDecode"); 727d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 7288570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com 7298570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com if (JCS_CMYK == cinfo.out_color_space) { 7308570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com convert_CMYK_to_RGB(srcRow, cinfo.output_width); 7318570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com } 7328570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com 733d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com sampler.next(srcRow); 734d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com if (bm->height() - 1 == y) { 735d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com // we're done 736d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com break; 737d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 738d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 739d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com if (!skip_src_rows(&cinfo, srcRow, sampler.srcDY() - 1)) { 7402a1208017dd676f94a53bbb228197c3978dbdd8ascroggo return return_failure(cinfo, *bm, "skip rows"); 741d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 742d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 743d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 744d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com // we formally skip the rest, so we don't get a complaint from libjpeg 745d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com if (!skip_src_rows(&cinfo, srcRow, 746d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com cinfo.output_height - cinfo.output_scanline)) { 7472a1208017dd676f94a53bbb228197c3978dbdd8ascroggo return return_failure(cinfo, *bm, "skip rows"); 748d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 749d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com jpeg_finish_decompress(&cinfo); 750d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 7512a1208017dd676f94a53bbb228197c3978dbdd8ascroggo return kSuccess; 752d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com} 753d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 7542a1208017dd676f94a53bbb228197c3978dbdd8ascroggo/////////////////////////////////////////////////////////////////////////////// 7552a1208017dd676f94a53bbb228197c3978dbdd8ascroggo 756b227e37eae36ccf630c4baef00b1354d42b40fd1sugoienum SizeType { 757b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi kSizeForMemoryAllocation_SizeType, 758b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi kActualSize_SizeType 759b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi}; 760b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 761b227e37eae36ccf630c4baef00b1354d42b40fd1sugoistatic SkISize compute_yuv_size(const jpeg_decompress_struct& info, int component, 762b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi SizeType sizeType) { 763b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi if (sizeType == kSizeForMemoryAllocation_SizeType) { 764b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi return SkISize::Make(info.cur_comp_info[component]->width_in_blocks * DCTSIZE, 765b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi info.cur_comp_info[component]->height_in_blocks * DCTSIZE); 766b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi } 767b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi return SkISize::Make(info.cur_comp_info[component]->downsampled_width, 768b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi info.cur_comp_info[component]->downsampled_height); 769b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi} 770b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 771b3e5e4d314301617d2d48b7589dfd426bd68a671mtkleinstatic bool appears_to_be_yuv(const jpeg_decompress_struct& info) { 772b3e5e4d314301617d2d48b7589dfd426bd68a671mtklein return (info.jpeg_color_space == JCS_YCbCr) 773b3e5e4d314301617d2d48b7589dfd426bd68a671mtklein && (DCTSIZE == 8) 774b3e5e4d314301617d2d48b7589dfd426bd68a671mtklein && (info.num_components == 3) 775b3e5e4d314301617d2d48b7589dfd426bd68a671mtklein && (info.comps_in_scan >= info.num_components) 776b3e5e4d314301617d2d48b7589dfd426bd68a671mtklein && (info.scale_denom <= 8) 777b3e5e4d314301617d2d48b7589dfd426bd68a671mtklein && (info.cur_comp_info[0]) 778b3e5e4d314301617d2d48b7589dfd426bd68a671mtklein && (info.cur_comp_info[1]) 779b3e5e4d314301617d2d48b7589dfd426bd68a671mtklein && (info.cur_comp_info[2]) 780b3e5e4d314301617d2d48b7589dfd426bd68a671mtklein && (info.cur_comp_info[1]->h_samp_factor == 1) 781b3e5e4d314301617d2d48b7589dfd426bd68a671mtklein && (info.cur_comp_info[1]->v_samp_factor == 1) 782b3e5e4d314301617d2d48b7589dfd426bd68a671mtklein && (info.cur_comp_info[2]->h_samp_factor == 1) 783b3e5e4d314301617d2d48b7589dfd426bd68a671mtklein && (info.cur_comp_info[2]->v_samp_factor == 1); 784b3e5e4d314301617d2d48b7589dfd426bd68a671mtklein} 785b3e5e4d314301617d2d48b7589dfd426bd68a671mtklein 786b227e37eae36ccf630c4baef00b1354d42b40fd1sugoistatic void update_components_sizes(const jpeg_decompress_struct& cinfo, SkISize componentSizes[3], 787b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi SizeType sizeType) { 788b3e5e4d314301617d2d48b7589dfd426bd68a671mtklein SkASSERT(appears_to_be_yuv(cinfo)); 789b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi for (int i = 0; i < 3; ++i) { 790b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi componentSizes[i] = compute_yuv_size(cinfo, i, sizeType); 791b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi } 792b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi} 793b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 794b227e37eae36ccf630c4baef00b1354d42b40fd1sugoistatic bool output_raw_data(jpeg_decompress_struct& cinfo, void* planes[3], size_t rowBytes[3]) { 795b3e5e4d314301617d2d48b7589dfd426bd68a671mtklein SkASSERT(appears_to_be_yuv(cinfo)); 796b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi // U size and V size have to be the same if we're calling output_raw_data() 797b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi SkISize uvSize = compute_yuv_size(cinfo, 1, kSizeForMemoryAllocation_SizeType); 798b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi SkASSERT(uvSize == compute_yuv_size(cinfo, 2, kSizeForMemoryAllocation_SizeType)); 799b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 800b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi JSAMPARRAY bufferraw[3]; 801b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi JSAMPROW bufferraw2[32]; 802b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi bufferraw[0] = &bufferraw2[0]; // Y channel rows (8 or 16) 803b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi bufferraw[1] = &bufferraw2[16]; // U channel rows (8) 804b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi bufferraw[2] = &bufferraw2[24]; // V channel rows (8) 805b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi int yWidth = cinfo.output_width; 806b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi int yHeight = cinfo.output_height; 807b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi int yMaxH = yHeight - 1; 808b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi int v = cinfo.cur_comp_info[0]->v_samp_factor; 809b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi int uvMaxH = uvSize.height() - 1; 810b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi JSAMPROW outputY = static_cast<JSAMPROW>(planes[0]); 811b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi JSAMPROW outputU = static_cast<JSAMPROW>(planes[1]); 812b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi JSAMPROW outputV = static_cast<JSAMPROW>(planes[2]); 813b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi size_t rowBytesY = rowBytes[0]; 814b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi size_t rowBytesU = rowBytes[1]; 815b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi size_t rowBytesV = rowBytes[2]; 816b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 817b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi int yScanlinesToRead = DCTSIZE * v; 818f421ec6cc9c8f32d717b9b1df71fd9e79817a16csugoi SkAutoMalloc lastRowStorage(rowBytesY * 4); 819b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi JSAMPROW yLastRow = (JSAMPROW)lastRowStorage.get(); 820f421ec6cc9c8f32d717b9b1df71fd9e79817a16csugoi JSAMPROW uLastRow = yLastRow + rowBytesY; 821f421ec6cc9c8f32d717b9b1df71fd9e79817a16csugoi JSAMPROW vLastRow = uLastRow + rowBytesY; 822f421ec6cc9c8f32d717b9b1df71fd9e79817a16csugoi JSAMPROW dummyRow = vLastRow + rowBytesY; 823b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 824b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi while (cinfo.output_scanline < cinfo.output_height) { 825b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi // Request 8 or 16 scanlines: returns 0 or more scanlines. 826b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi bool hasYLastRow(false), hasUVLastRow(false); 827b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi // Assign 8 or 16 rows of memory to read the Y channel. 828b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi for (int i = 0; i < yScanlinesToRead; ++i) { 829b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi int scanline = (cinfo.output_scanline + i); 830b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi if (scanline < yMaxH) { 831b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi bufferraw2[i] = &outputY[scanline * rowBytesY]; 832b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi } else if (scanline == yMaxH) { 833b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi bufferraw2[i] = yLastRow; 834b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi hasYLastRow = true; 835b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi } else { 836b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi bufferraw2[i] = dummyRow; 837b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi } 838b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi } 839b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi int scaledScanline = cinfo.output_scanline / v; 840b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi // Assign 8 rows of memory to read the U and V channels. 841b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi for (int i = 0; i < 8; ++i) { 842b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi int scanline = (scaledScanline + i); 843b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi if (scanline < uvMaxH) { 844b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi bufferraw2[16 + i] = &outputU[scanline * rowBytesU]; 845b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi bufferraw2[24 + i] = &outputV[scanline * rowBytesV]; 846b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi } else if (scanline == uvMaxH) { 847b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi bufferraw2[16 + i] = uLastRow; 848b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi bufferraw2[24 + i] = vLastRow; 849b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi hasUVLastRow = true; 850b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi } else { 851b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi bufferraw2[16 + i] = dummyRow; 852b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi bufferraw2[24 + i] = dummyRow; 853b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi } 854b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi } 855b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi JDIMENSION scanlinesRead = jpeg_read_raw_data(&cinfo, bufferraw, yScanlinesToRead); 856b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 8572a1208017dd676f94a53bbb228197c3978dbdd8ascroggo if (scanlinesRead == 0) { 858b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi return false; 8592a1208017dd676f94a53bbb228197c3978dbdd8ascroggo } 860b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 861b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi if (hasYLastRow) { 862b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi memcpy(&outputY[yMaxH * rowBytesY], yLastRow, yWidth); 863b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi } 864b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi if (hasUVLastRow) { 865b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi memcpy(&outputU[uvMaxH * rowBytesU], uLastRow, uvSize.width()); 866b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi memcpy(&outputV[uvMaxH * rowBytesV], vLastRow, uvSize.width()); 867b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi } 868b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi } 869b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 870b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi cinfo.output_scanline = SkMin32(cinfo.output_scanline, cinfo.output_height); 871b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 872b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi return true; 873b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi} 874b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 875b227e37eae36ccf630c4baef00b1354d42b40fd1sugoibool SkJPEGImageDecoder::onDecodeYUV8Planes(SkStream* stream, SkISize componentSizes[3], 876b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi void* planes[3], size_t rowBytes[3], 877b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi SkYUVColorSpace* colorSpace) { 878b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi#ifdef TIME_DECODE 879b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi SkAutoTime atm("JPEG YUV8 Decode"); 880b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi#endif 881b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi if (this->getSampleSize() != 1) { 882b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi return false; // Resizing not supported 883b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi } 884b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 885b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi JPEGAutoClean autoClean; 886b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 887b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi jpeg_decompress_struct cinfo; 888b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi skjpeg_source_mgr srcManager(stream, this); 889b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 890b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi skjpeg_error_mgr errorManager; 891b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi set_error_mgr(&cinfo, &errorManager); 892b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 893b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi // All objects need to be instantiated before this setjmp call so that 894b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi // they will be cleaned up properly if an error occurs. 895b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi if (setjmp(errorManager.fJmpBuf)) { 8962a1208017dd676f94a53bbb228197c3978dbdd8ascroggo return return_false(cinfo, "setjmp YUV8"); 897b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi } 898b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 899b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi initialize_info(&cinfo, &srcManager); 900b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi autoClean.set(&cinfo); 901b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 902b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi int status = jpeg_read_header(&cinfo, true); 903b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi if (status != JPEG_HEADER_OK) { 9042a1208017dd676f94a53bbb228197c3978dbdd8ascroggo return return_false(cinfo, "read_header YUV8"); 905b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi } 906b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 907b3e5e4d314301617d2d48b7589dfd426bd68a671mtklein if (!appears_to_be_yuv(cinfo)) { 908b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi // It's not an error to not be encoded in YUV, so no need to use return_false() 909b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi return false; 910b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi } 911b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 912b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi cinfo.out_color_space = JCS_YCbCr; 913b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi cinfo.raw_data_out = TRUE; 914b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 915b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi if (!planes || !planes[0] || !rowBytes || !rowBytes[0]) { // Compute size only 916b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi update_components_sizes(cinfo, componentSizes, kSizeForMemoryAllocation_SizeType); 917b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi return true; 918b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi } 919b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 920b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi set_dct_method(*this, &cinfo); 921b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 922b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi SkASSERT(1 == cinfo.scale_num); 923b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi cinfo.scale_denom = 1; 924b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 925b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi turn_off_visual_optimizations(&cinfo); 926b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 927b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi#ifdef ANDROID_RGB 928b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi cinfo.dither_mode = JDITHER_NONE; 929b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi#endif 930b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 931b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi /* image_width and image_height are the original dimensions, available 932b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi after jpeg_read_header(). To see the scaled dimensions, we have to call 933b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi jpeg_start_decompress(), and then read output_width and output_height. 934b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi */ 935b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi if (!jpeg_start_decompress(&cinfo)) { 9362a1208017dd676f94a53bbb228197c3978dbdd8ascroggo return return_false(cinfo, "start_decompress YUV8"); 937b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi } 938b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 939b3e5e4d314301617d2d48b7589dfd426bd68a671mtklein // Seems like jpeg_start_decompress is updating our opinion of whether cinfo represents YUV. 940b3e5e4d314301617d2d48b7589dfd426bd68a671mtklein // Again, not really an error. 941b3e5e4d314301617d2d48b7589dfd426bd68a671mtklein if (!appears_to_be_yuv(cinfo)) { 942b3e5e4d314301617d2d48b7589dfd426bd68a671mtklein return false; 943b3e5e4d314301617d2d48b7589dfd426bd68a671mtklein } 944b3e5e4d314301617d2d48b7589dfd426bd68a671mtklein 945b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi if (!output_raw_data(cinfo, planes, rowBytes)) { 9462a1208017dd676f94a53bbb228197c3978dbdd8ascroggo return return_false(cinfo, "output_raw_data"); 947b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi } 948b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 949b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi update_components_sizes(cinfo, componentSizes, kActualSize_SizeType); 950b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi jpeg_finish_decompress(&cinfo); 951b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 952b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi if (NULL != colorSpace) { 953b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi *colorSpace = kJPEG_SkYUVColorSpace; 954b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi } 955b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 956b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi return true; 957b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi} 958b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 9592a1208017dd676f94a53bbb228197c3978dbdd8ascroggo/////////////////////////////////////////////////////////////////////////////// 9602a1208017dd676f94a53bbb228197c3978dbdd8ascroggo 961d79277f67824392876b82cf5635cc11f819e64dfscroggo@google.com#ifdef SK_BUILD_FOR_ANDROID 962b5571b3324cf18629a255ec85e189447069c9b14scroggo@google.combool SkJPEGImageDecoder::onBuildTileIndex(SkStreamRewindable* stream, int *width, int *height) { 963113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 964a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com SkAutoTDelete<SkJPEGImageIndex> imageIndex(SkNEW_ARGS(SkJPEGImageIndex, (stream, this))); 965113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 966113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com skjpeg_error_mgr sk_err; 9676d7e47a8e0c8fd80ad33f659b01ec84f9e93a94bscroggo set_error_mgr(imageIndex->cinfo(), &sk_err); 968113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 969113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com // All objects need to be instantiated before this setjmp call so that 970113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com // they will be cleaned up properly if an error occurs. 971113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (setjmp(sk_err.fJmpBuf)) { 972113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return false; 973113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 974113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 975113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com // create the cinfo used to create/build the huffmanIndex 976a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com if (!imageIndex->initializeInfoAndReadHeader()) { 977113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return false; 978113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 979113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 980a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com if (!imageIndex->buildHuffmanIndex()) { 981113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return false; 982113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 983113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 984113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com // destroy the cinfo used to create/build the huffman index 985a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com imageIndex->destroyInfo(); 986113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 987113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com // Init decoder to image decode mode 988a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com if (!imageIndex->initializeInfoAndReadHeader()) { 989113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return false; 990113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 991113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 9926d7e47a8e0c8fd80ad33f659b01ec84f9e93a94bscroggo jpeg_decompress_struct* cinfo = imageIndex->cinfo(); 9936d7e47a8e0c8fd80ad33f659b01ec84f9e93a94bscroggo // We have a new cinfo, so set the error mgr again. 9946d7e47a8e0c8fd80ad33f659b01ec84f9e93a94bscroggo set_error_mgr(cinfo, &sk_err); 9956d7e47a8e0c8fd80ad33f659b01ec84f9e93a94bscroggo 996590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com // FIXME: This sets cinfo->out_color_space, which we may change later 997590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com // based on the config in onDecodeSubset. This should be fine, since 998590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com // jpeg_init_read_tile_scanline will check out_color_space again after 999590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com // that change (when it calls jinit_color_deconverter). 10006c22573edb234ad14df947278cfed010669a39a7reed (void) this->getBitmapColorType(cinfo); 1001590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com 1002590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com turn_off_visual_optimizations(cinfo); 1003113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 1004113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com // instead of jpeg_start_decompress() we start a tiled decompress 1005a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com if (!imageIndex->startTileDecompress()) { 1006a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com return false; 1007a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com } 1008113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 1009a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com SkASSERT(1 == cinfo->scale_num); 1010590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com fImageWidth = cinfo->output_width; 1011590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com fImageHeight = cinfo->output_height; 1012590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com 1013590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com if (width) { 1014590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com *width = fImageWidth; 1015590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com } 1016590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com if (height) { 1017590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com *height = fImageHeight; 1018590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com } 1019113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 1020113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com SkDELETE(fImageIndex); 1021a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com fImageIndex = imageIndex.detach(); 1022113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 1023113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return true; 1024113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com} 1025113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 10267e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.combool SkJPEGImageDecoder::onDecodeSubset(SkBitmap* bm, const SkIRect& region) { 1027113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (NULL == fImageIndex) { 1028113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return false; 1029113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 1030113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com jpeg_decompress_struct* cinfo = fImageIndex->cinfo(); 1031113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 1032113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com SkIRect rect = SkIRect::MakeWH(fImageWidth, fImageHeight); 1033113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (!rect.intersect(region)) { 1034113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com // If the requested region is entirely outside the image return false 1035113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return false; 1036113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 1037113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 1038113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 1039113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com skjpeg_error_mgr errorManager; 1040590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com set_error_mgr(cinfo, &errorManager); 1041590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com 1042113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (setjmp(errorManager.fJmpBuf)) { 1043113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return false; 1044113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 1045113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 1046113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com int requestedSampleSize = this->getSampleSize(); 1047113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com cinfo->scale_denom = requestedSampleSize; 1048113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 1049590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com set_dct_method(*this, cinfo); 1050113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 10516c22573edb234ad14df947278cfed010669a39a7reed const SkColorType colorType = this->getBitmapColorType(cinfo); 10526c22573edb234ad14df947278cfed010669a39a7reed adjust_out_color_space_and_dither(cinfo, colorType, *this); 1053113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 1054113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com int startX = rect.fLeft; 1055113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com int startY = rect.fTop; 1056113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com int width = rect.width(); 1057113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com int height = rect.height(); 1058113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 1059113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com jpeg_init_read_tile_scanline(cinfo, fImageIndex->huffmanIndex(), 1060113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com &startX, &startY, &width, &height); 1061113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com int skiaSampleSize = recompute_sampleSize(requestedSampleSize, *cinfo); 1062113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com int actualSampleSize = skiaSampleSize * (DCTSIZE / cinfo->min_DCT_scaled_size); 1063113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 1064113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com SkScaledBitmapSampler sampler(width, height, skiaSampleSize); 1065113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 1066113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com SkBitmap bitmap; 10675ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com // Assume an A8 bitmap is not opaque to avoid the check of each 10685ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com // individual pixel. It is very unlikely to be opaque, since 10695ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com // an opaque A8 bitmap would not be very interesting. 10705ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com // Otherwise, a jpeg image is opaque. 10716c22573edb234ad14df947278cfed010669a39a7reed bitmap.setInfo(SkImageInfo::Make(sampler.scaledWidth(), sampler.scaledHeight(), colorType, 10726c22573edb234ad14df947278cfed010669a39a7reed kAlpha_8_SkColorType == colorType ? 10736c22573edb234ad14df947278cfed010669a39a7reed kPremul_SkAlphaType : kOpaque_SkAlphaType)); 1074113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 1075113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com // Check ahead of time if the swap(dest, src) is possible or not. 1076113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com // If yes, then we will stick to AllocPixelRef since it's cheaper with the 1077113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com // swap happening. If no, then we will use alloc to allocate pixels to 1078113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com // prevent garbage collection. 1079113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com int w = rect.width() / actualSampleSize; 1080113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com int h = rect.height() / actualSampleSize; 1081113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com bool swapOnly = (rect == region) && bm->isNull() && 1082113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com (w == bitmap.width()) && (h == bitmap.height()) && 1083113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com ((startX - rect.x()) / actualSampleSize == 0) && 1084113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com ((startY - rect.y()) / actualSampleSize == 0); 1085113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (swapOnly) { 1086113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (!this->allocPixelRef(&bitmap, NULL)) { 1087113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return return_false(*cinfo, bitmap, "allocPixelRef"); 1088113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 1089113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } else { 1090848250415eddc54075f7eb8795e8db79e749c6abreed if (!bitmap.tryAllocPixels()) { 1091113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return return_false(*cinfo, bitmap, "allocPixels"); 1092113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 1093113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 1094113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 1095113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com SkAutoLockPixels alp(bitmap); 1096113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 1097113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#ifdef ANDROID_RGB 1098113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com /* short-circuit the SkScaledBitmapSampler when possible, as this gives 1099113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com a significant performance boost. 1100113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com */ 1101113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (skiaSampleSize == 1 && 11026c22573edb234ad14df947278cfed010669a39a7reed ((kN32_SkColorType == colorType && cinfo->out_color_space == JCS_RGBA_8888) || 11036c22573edb234ad14df947278cfed010669a39a7reed (kRGB_565_SkColorType == colorType && cinfo->out_color_space == JCS_RGB_565))) 1104113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com { 1105113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com JSAMPLE* rowptr = (JSAMPLE*)bitmap.getPixels(); 1106113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com INT32 const bpr = bitmap.rowBytes(); 1107113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com int rowTotalCount = 0; 1108113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 1109113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com while (rowTotalCount < height) { 1110113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com int rowCount = jpeg_read_tile_scanline(cinfo, 1111113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com fImageIndex->huffmanIndex(), 1112113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com &rowptr); 1113fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com // if rowCount == 0, then we didn't get a scanline, so abort. 1114fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com // onDecodeSubset() relies on onBuildTileIndex(), which 1115fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com // needs a complete image to succeed. 1116113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (0 == rowCount) { 1117113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return return_false(*cinfo, bitmap, "read_scanlines"); 1118113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 1119113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (this->shouldCancelDecode()) { 1120113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return return_false(*cinfo, bitmap, "shouldCancelDecode"); 1121113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 1122113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com rowTotalCount += rowCount; 1123113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com rowptr += bpr; 1124113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 1125113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 1126113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (swapOnly) { 1127113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com bm->swap(bitmap); 11287f00acbda6d35d2ba445a1e2909bb599b156cc5czoran.jovanovic return true; 1129113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 11307f00acbda6d35d2ba445a1e2909bb599b156cc5czoran.jovanovic 11317f00acbda6d35d2ba445a1e2909bb599b156cc5czoran.jovanovic return cropBitmap(bm, &bitmap, actualSampleSize, region.x(), region.y(), 11327f00acbda6d35d2ba445a1e2909bb599b156cc5czoran.jovanovic region.width(), region.height(), startX, startY); 1133113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 1134113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#endif 1135113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 1136113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com // check for supported formats 1137113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com SkScaledBitmapSampler::SrcConfig sc; 11385ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com int srcBytesPerPixel; 11395ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com 11405ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com if (!get_src_config(*cinfo, &sc, &srcBytesPerPixel)) { 1141113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return return_false(*cinfo, *bm, "jpeg colorspace"); 1142113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 1143113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 11448d2392487cd97e68c0a71da9fd5d2b42ecac5ec8scroggo@google.com if (!sampler.begin(&bitmap, sc, *this)) { 1145113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return return_false(*cinfo, bitmap, "sampler.begin"); 1146113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 1147113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 11485ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com SkAutoMalloc srcStorage(width * srcBytesPerPixel); 1149113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com uint8_t* srcRow = (uint8_t*)srcStorage.get(); 1150113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 1151113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com // Possibly skip initial rows [sampler.srcY0] 1152113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (!skip_src_rows_tile(cinfo, fImageIndex->huffmanIndex(), srcRow, sampler.srcY0())) { 1153113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return return_false(*cinfo, bitmap, "skip rows"); 1154113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 1155113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 1156113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com // now loop through scanlines until y == bitmap->height() - 1 1157113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com for (int y = 0;; y++) { 1158113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com JSAMPLE* rowptr = (JSAMPLE*)srcRow; 1159113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com int row_count = jpeg_read_tile_scanline(cinfo, fImageIndex->huffmanIndex(), &rowptr); 1160fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com // if row_count == 0, then we didn't get a scanline, so abort. 1161fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com // onDecodeSubset() relies on onBuildTileIndex(), which 1162fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com // needs a complete image to succeed. 1163113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (0 == row_count) { 1164113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return return_false(*cinfo, bitmap, "read_scanlines"); 1165113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 1166113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (this->shouldCancelDecode()) { 1167113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return return_false(*cinfo, bitmap, "shouldCancelDecode"); 1168113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 1169113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 1170113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (JCS_CMYK == cinfo->out_color_space) { 1171113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com convert_CMYK_to_RGB(srcRow, width); 1172113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 1173113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 1174113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com sampler.next(srcRow); 1175113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (bitmap.height() - 1 == y) { 1176113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com // we're done 1177113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com break; 1178113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 1179113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 1180113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (!skip_src_rows_tile(cinfo, fImageIndex->huffmanIndex(), srcRow, 1181113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com sampler.srcDY() - 1)) { 1182113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return return_false(*cinfo, bitmap, "skip rows"); 1183113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 1184113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 1185113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (swapOnly) { 1186113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com bm->swap(bitmap); 11877f00acbda6d35d2ba445a1e2909bb599b156cc5czoran.jovanovic return true; 1188113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 11897f00acbda6d35d2ba445a1e2909bb599b156cc5czoran.jovanovic return cropBitmap(bm, &bitmap, actualSampleSize, region.x(), region.y(), 11907f00acbda6d35d2ba445a1e2909bb599b156cc5czoran.jovanovic region.width(), region.height(), startX, startY); 1191113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com} 1192113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#endif 1193113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 1194d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com/////////////////////////////////////////////////////////////////////////////// 1195d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1196d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#include "SkColorPriv.h" 1197d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1198d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com// taken from jcolor.c in libjpeg 1199d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#if 0 // 16bit - precise but slow 1200d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #define CYR 19595 // 0.299 1201d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #define CYG 38470 // 0.587 1202d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #define CYB 7471 // 0.114 1203d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1204d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #define CUR -11059 // -0.16874 1205d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #define CUG -21709 // -0.33126 1206d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #define CUB 32768 // 0.5 1207d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1208d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #define CVR 32768 // 0.5 1209d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #define CVG -27439 // -0.41869 1210d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #define CVB -5329 // -0.08131 1211d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1212d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #define CSHIFT 16 1213d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#else // 8bit - fast, slightly less precise 1214d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #define CYR 77 // 0.299 1215d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #define CYG 150 // 0.587 1216d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #define CYB 29 // 0.114 1217d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1218d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #define CUR -43 // -0.16874 1219d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #define CUG -85 // -0.33126 1220d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #define CUB 128 // 0.5 1221d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1222d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #define CVR 128 // 0.5 1223d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #define CVG -107 // -0.41869 1224d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #define CVB -21 // -0.08131 1225d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1226d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #define CSHIFT 8 1227d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#endif 1228d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1229d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comstatic void rgb2yuv_32(uint8_t dst[], SkPMColor c) { 1230d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int r = SkGetPackedR32(c); 1231d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int g = SkGetPackedG32(c); 1232d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int b = SkGetPackedB32(c); 1233d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1234d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int y = ( CYR*r + CYG*g + CYB*b ) >> CSHIFT; 1235d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int u = ( CUR*r + CUG*g + CUB*b ) >> CSHIFT; 1236d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int v = ( CVR*r + CVG*g + CVB*b ) >> CSHIFT; 1237d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1238d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst[0] = SkToU8(y); 1239d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst[1] = SkToU8(u + 128); 1240d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst[2] = SkToU8(v + 128); 1241d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com} 1242d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1243d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comstatic void rgb2yuv_4444(uint8_t dst[], U16CPU c) { 1244d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int r = SkGetPackedR4444(c); 1245d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int g = SkGetPackedG4444(c); 1246d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int b = SkGetPackedB4444(c); 1247d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1248d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int y = ( CYR*r + CYG*g + CYB*b ) >> (CSHIFT - 4); 1249d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int u = ( CUR*r + CUG*g + CUB*b ) >> (CSHIFT - 4); 1250d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int v = ( CVR*r + CVG*g + CVB*b ) >> (CSHIFT - 4); 1251d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1252d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst[0] = SkToU8(y); 1253d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst[1] = SkToU8(u + 128); 1254d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst[2] = SkToU8(v + 128); 1255d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com} 1256d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1257d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comstatic void rgb2yuv_16(uint8_t dst[], U16CPU c) { 1258d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int r = SkGetPackedR16(c); 1259d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int g = SkGetPackedG16(c); 1260d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int b = SkGetPackedB16(c); 1261d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1262d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int y = ( 2*CYR*r + CYG*g + 2*CYB*b ) >> (CSHIFT - 2); 1263d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int u = ( 2*CUR*r + CUG*g + 2*CUB*b ) >> (CSHIFT - 2); 1264d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int v = ( 2*CVR*r + CVG*g + 2*CVB*b ) >> (CSHIFT - 2); 1265d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1266d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst[0] = SkToU8(y); 1267d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst[1] = SkToU8(u + 128); 1268d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst[2] = SkToU8(v + 128); 1269d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com} 1270d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1271d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com/////////////////////////////////////////////////////////////////////////////// 1272d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1273d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comtypedef void (*WriteScanline)(uint8_t* SK_RESTRICT dst, 1274d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com const void* SK_RESTRICT src, int width, 1275d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com const SkPMColor* SK_RESTRICT ctable); 1276d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1277d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comstatic void Write_32_YUV(uint8_t* SK_RESTRICT dst, 1278d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com const void* SK_RESTRICT srcRow, int width, 1279d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com const SkPMColor*) { 1280d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com const uint32_t* SK_RESTRICT src = (const uint32_t*)srcRow; 1281d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com while (--width >= 0) { 1282d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#ifdef WE_CONVERT_TO_YUV 1283d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com rgb2yuv_32(dst, *src++); 1284d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#else 1285d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com uint32_t c = *src++; 1286d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst[0] = SkGetPackedR32(c); 1287d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst[1] = SkGetPackedG32(c); 1288d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst[2] = SkGetPackedB32(c); 1289d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#endif 1290d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst += 3; 1291d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 1292d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com} 1293d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1294d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comstatic void Write_4444_YUV(uint8_t* SK_RESTRICT dst, 1295d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com const void* SK_RESTRICT srcRow, int width, 1296d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com const SkPMColor*) { 1297d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com const SkPMColor16* SK_RESTRICT src = (const SkPMColor16*)srcRow; 1298d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com while (--width >= 0) { 1299d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#ifdef WE_CONVERT_TO_YUV 1300d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com rgb2yuv_4444(dst, *src++); 1301d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#else 1302d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com SkPMColor16 c = *src++; 1303d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst[0] = SkPacked4444ToR32(c); 1304d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst[1] = SkPacked4444ToG32(c); 1305d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst[2] = SkPacked4444ToB32(c); 1306d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#endif 1307d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst += 3; 1308d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 1309d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com} 1310d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1311d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comstatic void Write_16_YUV(uint8_t* SK_RESTRICT dst, 1312d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com const void* SK_RESTRICT srcRow, int width, 1313d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com const SkPMColor*) { 1314d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com const uint16_t* SK_RESTRICT src = (const uint16_t*)srcRow; 1315d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com while (--width >= 0) { 1316d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#ifdef WE_CONVERT_TO_YUV 1317d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com rgb2yuv_16(dst, *src++); 1318d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#else 1319d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com uint16_t c = *src++; 1320d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst[0] = SkPacked16ToR32(c); 1321d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst[1] = SkPacked16ToG32(c); 1322d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst[2] = SkPacked16ToB32(c); 1323d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#endif 1324d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst += 3; 1325d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 1326d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com} 1327d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1328d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comstatic void Write_Index_YUV(uint8_t* SK_RESTRICT dst, 1329d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com const void* SK_RESTRICT srcRow, int width, 1330d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com const SkPMColor* SK_RESTRICT ctable) { 1331d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com const uint8_t* SK_RESTRICT src = (const uint8_t*)srcRow; 1332d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com while (--width >= 0) { 1333d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#ifdef WE_CONVERT_TO_YUV 1334d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com rgb2yuv_32(dst, ctable[*src++]); 1335d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#else 1336d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com uint32_t c = ctable[*src++]; 1337d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst[0] = SkGetPackedR32(c); 1338d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst[1] = SkGetPackedG32(c); 1339d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst[2] = SkGetPackedB32(c); 1340d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#endif 1341d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst += 3; 1342d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 1343d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com} 1344d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1345d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comstatic WriteScanline ChooseWriter(const SkBitmap& bm) { 13466c22573edb234ad14df947278cfed010669a39a7reed switch (bm.colorType()) { 13476c22573edb234ad14df947278cfed010669a39a7reed case kN32_SkColorType: 1348d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return Write_32_YUV; 13496c22573edb234ad14df947278cfed010669a39a7reed case kRGB_565_SkColorType: 1350d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return Write_16_YUV; 13516c22573edb234ad14df947278cfed010669a39a7reed case kARGB_4444_SkColorType: 1352d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return Write_4444_YUV; 13536c22573edb234ad14df947278cfed010669a39a7reed case kIndex_8_SkColorType: 1354d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return Write_Index_YUV; 1355d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com default: 1356d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return NULL; 1357d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 1358d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com} 1359d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1360d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comclass SkJPEGImageEncoder : public SkImageEncoder { 1361d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comprotected: 1362d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) { 1363d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#ifdef TIME_ENCODE 1364113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com SkAutoTime atm("JPEG Encode"); 1365d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#endif 1366d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1367d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com SkAutoLockPixels alp(bm); 1368d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com if (NULL == bm.getPixels()) { 1369d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return false; 1370d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 1371d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1372d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com jpeg_compress_struct cinfo; 1373d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com skjpeg_error_mgr sk_err; 1374d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com skjpeg_destination_mgr sk_wstream(stream); 1375d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1376d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com // allocate these before set call setjmp 1377d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com SkAutoMalloc oneRow; 1378d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1379d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com cinfo.err = jpeg_std_error(&sk_err); 1380d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com sk_err.error_exit = skjpeg_error_exit; 1381d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com if (setjmp(sk_err.fJmpBuf)) { 1382d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return false; 1383d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 1384d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 13858d725b25a6287e49e2b0cb2965871186e716ededmtklein@google.com // Keep after setjmp or mark volatile. 13868d725b25a6287e49e2b0cb2965871186e716ededmtklein@google.com const WriteScanline writer = ChooseWriter(bm); 13878d725b25a6287e49e2b0cb2965871186e716ededmtklein@google.com if (NULL == writer) { 13888d725b25a6287e49e2b0cb2965871186e716ededmtklein@google.com return false; 13898d725b25a6287e49e2b0cb2965871186e716ededmtklein@google.com } 13908d725b25a6287e49e2b0cb2965871186e716ededmtklein@google.com 13918d725b25a6287e49e2b0cb2965871186e716ededmtklein@google.com jpeg_create_compress(&cinfo); 1392d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com cinfo.dest = &sk_wstream; 1393d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com cinfo.image_width = bm.width(); 1394d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com cinfo.image_height = bm.height(); 1395d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com cinfo.input_components = 3; 1396d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#ifdef WE_CONVERT_TO_YUV 1397d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com cinfo.in_color_space = JCS_YCbCr; 1398d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#else 1399d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com cinfo.in_color_space = JCS_RGB; 1400d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#endif 1401d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com cinfo.input_gamma = 1; 1402d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1403d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com jpeg_set_defaults(&cinfo); 1404d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */); 1405b7decc539887069f3fb0f9fc80d543b437bdd624scroggo@google.com#ifdef DCT_IFAST_SUPPORTED 1406d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com cinfo.dct_method = JDCT_IFAST; 1407b7decc539887069f3fb0f9fc80d543b437bdd624scroggo@google.com#endif 1408d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1409d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com jpeg_start_compress(&cinfo, TRUE); 1410d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1411d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com const int width = bm.width(); 14128570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com uint8_t* oneRowP = (uint8_t*)oneRow.reset(width * 3); 1413d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1414775b8199a214af57c3ea7969e9d456f5f3eb137fmtklein const SkPMColor* colors = bm.getColorTable() ? bm.getColorTable()->readColors() : NULL; 1415d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com const void* srcRow = bm.getPixels(); 1416d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1417d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com while (cinfo.next_scanline < cinfo.image_height) { 1418d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ 1419d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1420d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com writer(oneRowP, srcRow, width, colors); 1421d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com row_pointer[0] = oneRowP; 1422d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); 1423d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com srcRow = (const void*)((const char*)srcRow + bm.rowBytes()); 1424d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 1425d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1426d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com jpeg_finish_compress(&cinfo); 1427d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com jpeg_destroy_compress(&cinfo); 1428d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1429d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return true; 1430d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 1431d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com}; 1432d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1433d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com/////////////////////////////////////////////////////////////////////////////// 1434ec51cb863409e238b40c5beef458669d9a824481robertphillips@google.comDEFINE_DECODER_CREATOR(JPEGImageDecoder); 1435ec51cb863409e238b40c5beef458669d9a824481robertphillips@google.comDEFINE_ENCODER_CREATOR(JPEGImageEncoder); 1436ec51cb863409e238b40c5beef458669d9a824481robertphillips@google.com/////////////////////////////////////////////////////////////////////////////// 1437d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1438b5571b3324cf18629a255ec85e189447069c9b14scroggo@google.comstatic bool is_jpeg(SkStreamRewindable* stream) { 1439ec51cb863409e238b40c5beef458669d9a824481robertphillips@google.com static const unsigned char gHeader[] = { 0xFF, 0xD8, 0xFF }; 1440d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com static const size_t HEADER_SIZE = sizeof(gHeader); 1441d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1442d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com char buffer[HEADER_SIZE]; 1443d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com size_t len = stream->read(buffer, HEADER_SIZE); 1444d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1445d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com if (len != HEADER_SIZE) { 144639edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com return false; // can't read enough 1447d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 1448d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com if (memcmp(buffer, gHeader, HEADER_SIZE)) { 144939edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com return false; 145039edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com } 145139edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com return true; 145239edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com} 145339edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com 1454b5571b3324cf18629a255ec85e189447069c9b14scroggo@google.com 1455b5571b3324cf18629a255ec85e189447069c9b14scroggo@google.comstatic SkImageDecoder* sk_libjpeg_dfactory(SkStreamRewindable* stream) { 145639edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com if (is_jpeg(stream)) { 145739edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com return SkNEW(SkJPEGImageDecoder); 145839edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com } 145939edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com return NULL; 146039edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com} 146139edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com 1462b5571b3324cf18629a255ec85e189447069c9b14scroggo@google.comstatic SkImageDecoder::Format get_format_jpeg(SkStreamRewindable* stream) { 146339edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com if (is_jpeg(stream)) { 146439edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com return SkImageDecoder::kJPEG_Format; 1465d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 146639edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com return SkImageDecoder::kUnknown_Format; 1467d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com} 1468d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 14698570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.comstatic SkImageEncoder* sk_libjpeg_efactory(SkImageEncoder::Type t) { 1470d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return (SkImageEncoder::kJPEG_Type == t) ? SkNEW(SkJPEGImageEncoder) : NULL; 1471d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com} 1472d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1473bd6343b1d60d2a85e930f33f4b06b4502b3e8caamtklein@google.comstatic SkImageDecoder_DecodeReg gDReg(sk_libjpeg_dfactory); 1474bd6343b1d60d2a85e930f33f4b06b4502b3e8caamtklein@google.comstatic SkImageDecoder_FormatReg gFormatReg(get_format_jpeg); 1475bd6343b1d60d2a85e930f33f4b06b4502b3e8caamtklein@google.comstatic SkImageEncoder_EncodeReg gEReg(sk_libjpeg_efactory); 1476