SkImageDecoder_libjpeg.cpp revision b227e37eae36ccf630c4baef00b1354d42b40fd1
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: 108b5571b3324cf18629a255ec85e189447069c9b14scroggo@google.com SkJPEGImageIndex(SkStreamRewindable* stream, SkImageDecoder* decoder) 109a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com : fSrcMgr(stream, decoder) 110a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com , fInfoInitialized(false) 111a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com , fHuffmanCreated(false) 112a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com , fDecompressStarted(false) 113a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com { 114a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com SkDEBUGCODE(fReadHeaderSucceeded = false;) 115a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com } 116113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 117113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com ~SkJPEGImageIndex() { 118a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com if (fHuffmanCreated) { 119590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com // Set to false before calling the libjpeg function, in case 120590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com // the libjpeg function calls longjmp. Our setjmp handler may 121590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com // attempt to delete this SkJPEGImageIndex, thus entering this 122590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com // destructor again. Setting fHuffmanCreated to false first 123590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com // prevents an infinite loop. 124a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com fHuffmanCreated = false; 125a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com jpeg_destroy_huffman_index(&fHuffmanIndex); 126a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com } 127a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com if (fDecompressStarted) { 128590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com // Like fHuffmanCreated, set to false before calling libjpeg 129590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com // function to prevent potential infinite loop. 130a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com fDecompressStarted = false; 131a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com jpeg_finish_decompress(&fCInfo); 132a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com } 133a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com if (fInfoInitialized) { 134a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com this->destroyInfo(); 135a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com } 136a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com } 137a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com 138a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com /** 139a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com * Destroy the cinfo struct. 140a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com * After this call, if a huffman index was already built, it 141a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com * can be used after calling initializeInfoAndReadHeader 142a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com * again. Must not be called after startTileDecompress except 143a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com * in the destructor. 144a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com */ 145a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com void destroyInfo() { 146a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com SkASSERT(fInfoInitialized); 147a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com SkASSERT(!fDecompressStarted); 148590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com // Like fHuffmanCreated, set to false before calling libjpeg 149590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com // function to prevent potential infinite loop. 150a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com fInfoInitialized = false; 151113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com jpeg_destroy_decompress(&fCInfo); 152a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com SkDEBUGCODE(fReadHeaderSucceeded = false;) 153d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 154d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 155113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com /** 156a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com * Initialize the cinfo struct. 157a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com * Calls jpeg_create_decompress, makes customizations, and 158a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com * finally calls jpeg_read_header. Returns true if jpeg_read_header 159a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com * returns JPEG_HEADER_OK. 160a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com * If cinfo was already initialized, destroyInfo must be called to 161a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com * destroy the old one. Must not be called after startTileDecompress. 162113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com */ 163a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com bool initializeInfoAndReadHeader() { 164a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com SkASSERT(!fInfoInitialized && !fDecompressStarted); 165590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com initialize_info(&fCInfo, &fSrcMgr); 166a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com fInfoInitialized = true; 167a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com const bool success = (JPEG_HEADER_OK == jpeg_read_header(&fCInfo, true)); 168a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com SkDEBUGCODE(fReadHeaderSucceeded = success;) 169a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com return success; 170113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 171d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 172113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com jpeg_decompress_struct* cinfo() { return &fCInfo; } 173d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 174113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com huffman_index* huffmanIndex() { return &fHuffmanIndex; } 175a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com 176a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com /** 177a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com * Build the index to be used for tile based decoding. 178a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com * Must only be called after a successful call to 179a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com * initializeInfoAndReadHeader and must not be called more 180a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com * than once. 181a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com */ 182a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com bool buildHuffmanIndex() { 183a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com SkASSERT(fReadHeaderSucceeded); 184a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com SkASSERT(!fHuffmanCreated); 185a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com jpeg_create_huffman_index(&fCInfo, &fHuffmanIndex); 186a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com SkASSERT(1 == fCInfo.scale_num && 1 == fCInfo.scale_denom); 18757a529877e65687de1fa4d19d52746427c6896dcscroggo@google.com fHuffmanCreated = jpeg_build_huffman_index(&fCInfo, &fHuffmanIndex); 18857a529877e65687de1fa4d19d52746427c6896dcscroggo@google.com return fHuffmanCreated; 189a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com } 190a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com 191a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com /** 192a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com * Start tile based decoding. Must only be called after a 193a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com * successful call to buildHuffmanIndex, and must only be 194a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com * called once. 195a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com */ 196a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com bool startTileDecompress() { 197a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com SkASSERT(fHuffmanCreated); 198a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com SkASSERT(fReadHeaderSucceeded); 199a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com SkASSERT(!fDecompressStarted); 200a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com if (jpeg_start_tile_decompress(&fCInfo)) { 201a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com fDecompressStarted = true; 202a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com return true; 203a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com } 204a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com return false; 205a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com } 206113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 207113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.comprivate: 208113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com skjpeg_source_mgr fSrcMgr; 209113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com jpeg_decompress_struct fCInfo; 210113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com huffman_index fHuffmanIndex; 211a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com bool fInfoInitialized; 212a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com bool fHuffmanCreated; 213a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com bool fDecompressStarted; 214a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com SkDEBUGCODE(bool fReadHeaderSucceeded;) 215113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com}; 216a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com#endif 217d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 218113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.comclass SkJPEGImageDecoder : public SkImageDecoder { 219d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.compublic: 220a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com#ifdef SK_BUILD_FOR_ANDROID 221113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com SkJPEGImageDecoder() { 222113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com fImageIndex = NULL; 223113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com fImageWidth = 0; 224113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com fImageHeight = 0; 225d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 226113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 227113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com virtual ~SkJPEGImageDecoder() { 228113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com SkDELETE(fImageIndex); 229d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 230a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com#endif 231113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 232113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com virtual Format getFormat() const { 233113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return kJPEG_Format; 234113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 235113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 236113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.comprotected: 237d79277f67824392876b82cf5635cc11f819e64dfscroggo@google.com#ifdef SK_BUILD_FOR_ANDROID 238b5571b3324cf18629a255ec85e189447069c9b14scroggo@google.com virtual bool onBuildTileIndex(SkStreamRewindable *stream, int *width, int *height) SK_OVERRIDE; 2397e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com virtual bool onDecodeSubset(SkBitmap* bitmap, const SkIRect& rect) SK_OVERRIDE; 240113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#endif 241113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE; 242b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi virtual bool onDecodeYUV8Planes(SkStream* stream, SkISize componentSizes[3], 243b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi void* planes[3], size_t rowBytes[3], 244b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi SkYUVColorSpace* colorSpace) SK_OVERRIDE; 245113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 246d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comprivate: 247a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com#ifdef SK_BUILD_FOR_ANDROID 248113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com SkJPEGImageIndex* fImageIndex; 249113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com int fImageWidth; 250113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com int fImageHeight; 251a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com#endif 252113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 253590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com /** 2546c22573edb234ad14df947278cfed010669a39a7reed * Determine the appropriate bitmap colortype and out_color_space based on 255590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com * both the preference of the caller and the jpeg_color_space on the 256590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com * jpeg_decompress_struct passed in. 257590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com * Must be called after jpeg_read_header. 258590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com */ 2596c22573edb234ad14df947278cfed010669a39a7reed SkColorType getBitmapColorType(jpeg_decompress_struct*); 260590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com 261113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com typedef SkImageDecoder INHERITED; 262d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com}; 263d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 264113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com////////////////////////////////////////////////////////////////////////// 265113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 266d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com/* Automatically clean up after throwing an exception */ 267d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comclass JPEGAutoClean { 268d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.compublic: 269d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com JPEGAutoClean(): cinfo_ptr(NULL) {} 270d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com ~JPEGAutoClean() { 271d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com if (cinfo_ptr) { 272d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com jpeg_destroy_decompress(cinfo_ptr); 273d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 274d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 275d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com void set(jpeg_decompress_struct* info) { 276d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com cinfo_ptr = info; 277d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 278d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comprivate: 279d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com jpeg_decompress_struct* cinfo_ptr; 280d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com}; 281d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 282d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com/////////////////////////////////////////////////////////////////////////////// 283d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 284d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com/* If we need to better match the request, we might examine the image and 285d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com output dimensions, and determine if the downsampling jpeg provided is 286d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com not sufficient. If so, we can recompute a modified sampleSize value to 287d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com make up the difference. 288d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 289d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com To skip this additional scaling, just set sampleSize = 1; below. 290d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com */ 291d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comstatic int recompute_sampleSize(int sampleSize, 292d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com const jpeg_decompress_struct& cinfo) { 293d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return sampleSize * cinfo.output_width / cinfo.image_width; 294d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com} 295d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 296d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comstatic bool valid_output_dimensions(const jpeg_decompress_struct& cinfo) { 297d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com /* These are initialized to 0, so if they have non-zero values, we assume 298d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com they are "valid" (i.e. have been computed by libjpeg) 299d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com */ 300113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return 0 != cinfo.output_width && 0 != cinfo.output_height; 301d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com} 302d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 303113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.comstatic bool skip_src_rows(jpeg_decompress_struct* cinfo, void* buffer, int count) { 304d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com for (int i = 0; i < count; i++) { 305d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com JSAMPLE* rowptr = (JSAMPLE*)buffer; 306d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int row_count = jpeg_read_scanlines(cinfo, &rowptr, 1); 307113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (1 != row_count) { 308d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return false; 309d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 310d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 311d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return true; 312d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com} 313d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 314d79277f67824392876b82cf5635cc11f819e64dfscroggo@google.com#ifdef SK_BUILD_FOR_ANDROID 315113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.comstatic bool skip_src_rows_tile(jpeg_decompress_struct* cinfo, 316113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com huffman_index *index, void* buffer, int count) { 317113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com for (int i = 0; i < count; i++) { 318113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com JSAMPLE* rowptr = (JSAMPLE*)buffer; 319113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com int row_count = jpeg_read_tile_scanline(cinfo, index, &rowptr); 320113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (1 != row_count) { 321113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return false; 322113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 323113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 324113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return true; 325113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com} 326113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#endif 327113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 328d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com// This guy exists just to aid in debugging, as it allows debuggers to just 329d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com// set a break-point in one place to see all error exists. 330d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comstatic bool return_false(const jpeg_decompress_struct& cinfo, 331b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi int width, int height, const char caller[]) { 33204b57f87ab6789f7fc302eda8a993d88d4feea8fhalcanary@google.com if (!(c_suppressJPEGImageDecoderErrors)) { 33304b57f87ab6789f7fc302eda8a993d88d4feea8fhalcanary@google.com char buffer[JMSG_LENGTH_MAX]; 33404b57f87ab6789f7fc302eda8a993d88d4feea8fhalcanary@google.com cinfo.err->format_message((const j_common_ptr)&cinfo, buffer); 33504b57f87ab6789f7fc302eda8a993d88d4feea8fhalcanary@google.com SkDebugf("libjpeg error %d <%s> from %s [%d %d]\n", 336b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi cinfo.err->msg_code, buffer, caller, width, height); 33704b57f87ab6789f7fc302eda8a993d88d4feea8fhalcanary@google.com } 338d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return false; // must always return false 339d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com} 340d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 341b227e37eae36ccf630c4baef00b1354d42b40fd1sugoistatic bool return_false(const jpeg_decompress_struct& cinfo, 342b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi const SkBitmap& bm, const char caller[]) { 343b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi return return_false(cinfo, bm.width(), bm.height(), caller); 344b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi} 345b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 3468570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com// Convert a scanline of CMYK samples to RGBX in place. Note that this 3478570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com// method moves the "scanline" pointer in its processing 3488570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.comstatic void convert_CMYK_to_RGB(uint8_t* scanline, unsigned int width) { 3498570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com // At this point we've received CMYK pixels from libjpeg. We 350d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com // perform a crude conversion to RGB (based on the formulae 3518570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com // from easyrgb.com): 3528570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com // CMYK -> CMY 3538570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com // C = ( C * (1 - K) + K ) // for each CMY component 3548570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com // CMY -> RGB 3558570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com // R = ( 1 - C ) * 255 // for each RGB component 3568570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com // Unfortunately we are seeing inverted CMYK so all the original terms 3578570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com // are 1-. This yields: 3588570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com // CMYK -> CMY 3598570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com // C = ( (1-C) * (1 - (1-K) + (1-K) ) -> C = 1 - C*K 3608570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com // The conversion from CMY->RGB remains the same 3618570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com for (unsigned int x = 0; x < width; ++x, scanline += 4) { 3628570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com scanline[0] = SkMulDiv255Round(scanline[0], scanline[3]); 3638570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com scanline[1] = SkMulDiv255Round(scanline[1], scanline[3]); 3648570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com scanline[2] = SkMulDiv255Round(scanline[2], scanline[3]); 3658570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com scanline[3] = 255; 3668570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com } 3678570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com} 3688570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com 369590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com/** 370590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com * Common code for setting the error manager. 371590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com */ 372590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.comstatic void set_error_mgr(jpeg_decompress_struct* cinfo, skjpeg_error_mgr* errorManager) { 373590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com SkASSERT(cinfo != NULL); 374590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com SkASSERT(errorManager != NULL); 375590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com cinfo->err = jpeg_std_error(errorManager); 376590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com errorManager->error_exit = skjpeg_error_exit; 377590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com} 378590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com 379590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com/** 380590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com * Common code for turning off upsampling and smoothing. Turning these 381590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com * off helps performance without showing noticable differences in the 382590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com * resulting bitmap. 383590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com */ 384590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.comstatic void turn_off_visual_optimizations(jpeg_decompress_struct* cinfo) { 385590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com SkASSERT(cinfo != NULL); 386590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com /* this gives about 30% performance improvement. In theory it may 387590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com reduce the visual quality, in practice I'm not seeing a difference 388590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com */ 389590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com cinfo->do_fancy_upsampling = 0; 390590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com 391590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com /* this gives another few percents */ 392590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com cinfo->do_block_smoothing = 0; 393590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com} 394590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com 395590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com/** 396590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com * Common code for setting the dct method. 397590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com */ 398590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.comstatic void set_dct_method(const SkImageDecoder& decoder, jpeg_decompress_struct* cinfo) { 399590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com SkASSERT(cinfo != NULL); 400590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com#ifdef DCT_IFAST_SUPPORTED 401590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com if (decoder.getPreferQualityOverSpeed()) { 402590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com cinfo->dct_method = JDCT_ISLOW; 403590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com } else { 404590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com cinfo->dct_method = JDCT_IFAST; 405590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com } 406590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com#else 407590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com cinfo->dct_method = JDCT_ISLOW; 408590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com#endif 409590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com} 410590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com 4116c22573edb234ad14df947278cfed010669a39a7reedSkColorType SkJPEGImageDecoder::getBitmapColorType(jpeg_decompress_struct* cinfo) { 412590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com SkASSERT(cinfo != NULL); 413590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com 414590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com SrcDepth srcDepth = k32Bit_SrcDepth; 415590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com if (JCS_GRAYSCALE == cinfo->jpeg_color_space) { 416590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com srcDepth = k8BitGray_SrcDepth; 417590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com } 418590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com 4196c22573edb234ad14df947278cfed010669a39a7reed SkColorType colorType = this->getPrefColorType(srcDepth, /*hasAlpha*/ false); 4206c22573edb234ad14df947278cfed010669a39a7reed switch (colorType) { 4216c22573edb234ad14df947278cfed010669a39a7reed case kAlpha_8_SkColorType: 4226c22573edb234ad14df947278cfed010669a39a7reed // Only respect A8 colortype if the original is grayscale, 423590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com // in which case we will treat the grayscale as alpha 424590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com // values. 425590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com if (cinfo->jpeg_color_space != JCS_GRAYSCALE) { 4266c22573edb234ad14df947278cfed010669a39a7reed colorType = kN32_SkColorType; 427590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com } 428590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com break; 4296c22573edb234ad14df947278cfed010669a39a7reed case kN32_SkColorType: 430590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com // Fall through. 4316c22573edb234ad14df947278cfed010669a39a7reed case kARGB_4444_SkColorType: 432590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com // Fall through. 4336c22573edb234ad14df947278cfed010669a39a7reed case kRGB_565_SkColorType: 4346c22573edb234ad14df947278cfed010669a39a7reed // These are acceptable destination colortypes. 435590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com break; 436590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com default: 4376c22573edb234ad14df947278cfed010669a39a7reed // Force all other colortypes to 8888. 4386c22573edb234ad14df947278cfed010669a39a7reed colorType = kN32_SkColorType; 439590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com break; 440590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com } 441590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com 442590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com switch (cinfo->jpeg_color_space) { 443590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com case JCS_CMYK: 444590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com // Fall through. 445590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com case JCS_YCCK: 446590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com // libjpeg cannot convert from CMYK or YCCK to RGB - here we set up 447590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com // so libjpeg will give us CMYK samples back and we will later 448590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com // manually convert them to RGB 449590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com cinfo->out_color_space = JCS_CMYK; 450590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com break; 451590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com case JCS_GRAYSCALE: 4526c22573edb234ad14df947278cfed010669a39a7reed if (kAlpha_8_SkColorType == colorType) { 453590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com cinfo->out_color_space = JCS_GRAYSCALE; 454590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com break; 455590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com } 456590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com // The data is JCS_GRAYSCALE, but the caller wants some sort of RGB 4576c22573edb234ad14df947278cfed010669a39a7reed // colortype. Fall through to set to the default. 458590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com default: 459590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com cinfo->out_color_space = JCS_RGB; 460590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com break; 461590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com } 4626c22573edb234ad14df947278cfed010669a39a7reed return colorType; 463590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com} 464590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com 465590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com/** 4666c22573edb234ad14df947278cfed010669a39a7reed * Based on the colortype and dither mode, adjust out_color_space and 4676c22573edb234ad14df947278cfed010669a39a7reed * dither_mode of cinfo. Only does work in ANDROID_RGB 468590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com */ 469590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.comstatic void adjust_out_color_space_and_dither(jpeg_decompress_struct* cinfo, 4706c22573edb234ad14df947278cfed010669a39a7reed SkColorType colorType, 471590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com const SkImageDecoder& decoder) { 472590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com SkASSERT(cinfo != NULL); 4736c22573edb234ad14df947278cfed010669a39a7reed#ifdef ANDROID_RGB 474590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com cinfo->dither_mode = JDITHER_NONE; 475590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com if (JCS_CMYK == cinfo->out_color_space) { 476590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com return; 477590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com } 4786c22573edb234ad14df947278cfed010669a39a7reed switch (colorType) { 4796c22573edb234ad14df947278cfed010669a39a7reed case kN32_SkColorType: 480590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com cinfo->out_color_space = JCS_RGBA_8888; 481590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com break; 4826c22573edb234ad14df947278cfed010669a39a7reed case kRGB_565_SkColorType: 483590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com cinfo->out_color_space = JCS_RGB_565; 484590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com if (decoder.getDitherImage()) { 485590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com cinfo->dither_mode = JDITHER_ORDERED; 486590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com } 487590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com break; 488590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com default: 489590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com break; 490590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com } 491590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com#endif 4926c22573edb234ad14df947278cfed010669a39a7reed} 493590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com 494fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com 495fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com/** 496fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com Sets all pixels in given bitmap to SK_ColorWHITE for all rows >= y. 497fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com Used when decoding fails partway through reading scanlines to fill 498fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com remaining lines. */ 499fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.comstatic void fill_below_level(int y, SkBitmap* bitmap) { 5002dcf36e25186bb0396eaa692bda402993252b88ahalcanary@google.com SkIRect rect = SkIRect::MakeLTRB(0, y, bitmap->width(), bitmap->height()); 501fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com SkCanvas canvas(*bitmap); 5022dcf36e25186bb0396eaa692bda402993252b88ahalcanary@google.com canvas.clipRect(SkRect::Make(rect)); 503fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com canvas.drawColor(SK_ColorWHITE); 504fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com} 505fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com 5065ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com/** 5075ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com * Get the config and bytes per pixel of the source data. Return 5085ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com * whether the data is supported. 5095ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com */ 5105ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.comstatic bool get_src_config(const jpeg_decompress_struct& cinfo, 5115ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com SkScaledBitmapSampler::SrcConfig* sc, 5125ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com int* srcBytesPerPixel) { 5135ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com SkASSERT(sc != NULL && srcBytesPerPixel != NULL); 5145ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com if (JCS_CMYK == cinfo.out_color_space) { 5155ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com // In this case we will manually convert the CMYK values to RGB 5165ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com *sc = SkScaledBitmapSampler::kRGBX; 5175ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com // The CMYK work-around relies on 4 components per pixel here 5185ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com *srcBytesPerPixel = 4; 5195ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com } else if (3 == cinfo.out_color_components && JCS_RGB == cinfo.out_color_space) { 5205ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com *sc = SkScaledBitmapSampler::kRGB; 5215ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com *srcBytesPerPixel = 3; 5225ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com#ifdef ANDROID_RGB 5235ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com } else if (JCS_RGBA_8888 == cinfo.out_color_space) { 5245ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com *sc = SkScaledBitmapSampler::kRGBX; 5255ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com *srcBytesPerPixel = 4; 5265ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com } else if (JCS_RGB_565 == cinfo.out_color_space) { 5275ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com *sc = SkScaledBitmapSampler::kRGB_565; 5285ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com *srcBytesPerPixel = 2; 5295ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com#endif 5305ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com } else if (1 == cinfo.out_color_components && 5315ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com JCS_GRAYSCALE == cinfo.out_color_space) { 5325ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com *sc = SkScaledBitmapSampler::kGray; 5335ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com *srcBytesPerPixel = 1; 5345ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com } else { 5355ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com return false; 5365ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com } 5375ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com return true; 5385ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com} 539fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com 540d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.combool SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { 541d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#ifdef TIME_DECODE 542113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com SkAutoTime atm("JPEG Decode"); 543d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#endif 544d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 545d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com JPEGAutoClean autoClean; 546d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 547d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com jpeg_decompress_struct cinfo; 548d4c3565aac5c83ff0008453abed4c6d6009bb394scroggo@google.com skjpeg_source_mgr srcManager(stream, this); 549d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 550590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com skjpeg_error_mgr errorManager; 551590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com set_error_mgr(&cinfo, &errorManager); 552d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 553d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com // All objects need to be instantiated before this setjmp call so that 554d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com // they will be cleaned up properly if an error occurs. 555113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (setjmp(errorManager.fJmpBuf)) { 556d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return return_false(cinfo, *bm, "setjmp"); 557d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 558d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 559590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com initialize_info(&cinfo, &srcManager); 560d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com autoClean.set(&cinfo); 561d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 562d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int status = jpeg_read_header(&cinfo, true); 563d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com if (status != JPEG_HEADER_OK) { 564d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return return_false(cinfo, *bm, "read_header"); 565d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 566d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 567d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com /* Try to fulfill the requested sampleSize. Since jpeg can do it (when it 568d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com can) much faster that we, just use their num/denom api to approximate 569d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com the size. 570d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com */ 571d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int sampleSize = this->getSampleSize(); 572d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 573590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com set_dct_method(*this, &cinfo); 574113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 575590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com SkASSERT(1 == cinfo.scale_num); 576d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com cinfo.scale_denom = sampleSize; 577d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 578590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com turn_off_visual_optimizations(&cinfo); 579d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 5806c22573edb234ad14df947278cfed010669a39a7reed const SkColorType colorType = this->getBitmapColorType(&cinfo); 5816c22573edb234ad14df947278cfed010669a39a7reed const SkAlphaType alphaType = kAlpha_8_SkColorType == colorType ? 5826c22573edb234ad14df947278cfed010669a39a7reed kPremul_SkAlphaType : kOpaque_SkAlphaType; 583d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 5846c22573edb234ad14df947278cfed010669a39a7reed adjust_out_color_space_and_dither(&cinfo, colorType, *this); 585d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 586113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (1 == sampleSize && SkImageDecoder::kDecodeBounds_Mode == mode) { 5875ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com // Assume an A8 bitmap is not opaque to avoid the check of each 5885ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com // individual pixel. It is very unlikely to be opaque, since 5895ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com // an opaque A8 bitmap would not be very interesting. 5905ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com // Otherwise, a jpeg image is opaque. 5916c22573edb234ad14df947278cfed010669a39a7reed return bm->setInfo(SkImageInfo::Make(cinfo.image_width, cinfo.image_height, 5926c22573edb234ad14df947278cfed010669a39a7reed colorType, alphaType)); 593d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 594d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 595d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com /* image_width and image_height are the original dimensions, available 596d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com after jpeg_read_header(). To see the scaled dimensions, we have to call 597d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com jpeg_start_decompress(), and then read output_width and output_height. 598d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com */ 599d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com if (!jpeg_start_decompress(&cinfo)) { 600d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com /* If we failed here, we may still have enough information to return 601d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com to the caller if they just wanted (subsampled bounds). If sampleSize 602d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com was 1, then we would have already returned. Thus we just check if 603d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com we're in kDecodeBounds_Mode, and that we have valid output sizes. 604d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 605d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com One reason to fail here is that we have insufficient stream data 606d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com to complete the setup. However, output dimensions seem to get 607d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com computed very early, which is why this special check can pay off. 608d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com */ 609113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (SkImageDecoder::kDecodeBounds_Mode == mode && valid_output_dimensions(cinfo)) { 610d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com SkScaledBitmapSampler smpl(cinfo.output_width, cinfo.output_height, 611d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com recompute_sampleSize(sampleSize, cinfo)); 6125ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com // Assume an A8 bitmap is not opaque to avoid the check of each 6135ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com // individual pixel. It is very unlikely to be opaque, since 6145ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com // an opaque A8 bitmap would not be very interesting. 6155ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com // Otherwise, a jpeg image is opaque. 6166c22573edb234ad14df947278cfed010669a39a7reed return bm->setInfo(SkImageInfo::Make(smpl.scaledWidth(), smpl.scaledHeight(), 6176c22573edb234ad14df947278cfed010669a39a7reed colorType, alphaType)); 618d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } else { 619d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return return_false(cinfo, *bm, "start_decompress"); 620d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 621d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 622d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com sampleSize = recompute_sampleSize(sampleSize, cinfo); 623d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 6245926b86b90c68bffefbdc8639e41b5bc9102cec6reed#ifdef SK_SUPPORT_LEGACY_IMAGEDECODER_CHOOSER 6256c22573edb234ad14df947278cfed010669a39a7reed // should we allow the Chooser (if present) to pick a colortype for us??? 6266c22573edb234ad14df947278cfed010669a39a7reed if (!this->chooseFromOneChoice(colorType, cinfo.output_width, cinfo.output_height)) { 627d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return return_false(cinfo, *bm, "chooseFromOneChoice"); 628d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 6295926b86b90c68bffefbdc8639e41b5bc9102cec6reed#endif 630d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 631113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com SkScaledBitmapSampler sampler(cinfo.output_width, cinfo.output_height, sampleSize); 6325ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com // Assume an A8 bitmap is not opaque to avoid the check of each 6335ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com // individual pixel. It is very unlikely to be opaque, since 6345ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com // an opaque A8 bitmap would not be very interesting. 6355ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com // Otherwise, a jpeg image is opaque. 6366c22573edb234ad14df947278cfed010669a39a7reed bm->setInfo(SkImageInfo::Make(sampler.scaledWidth(), sampler.scaledHeight(), 6376c22573edb234ad14df947278cfed010669a39a7reed colorType, alphaType)); 638bc69ce982f8374742ca910587485f0d741350c2dscroggo@google.com if (SkImageDecoder::kDecodeBounds_Mode == mode) { 639bc69ce982f8374742ca910587485f0d741350c2dscroggo@google.com return true; 640bc69ce982f8374742ca910587485f0d741350c2dscroggo@google.com } 641bc69ce982f8374742ca910587485f0d741350c2dscroggo@google.com if (!this->allocPixelRef(bm, NULL)) { 642bc69ce982f8374742ca910587485f0d741350c2dscroggo@google.com return return_false(cinfo, *bm, "allocPixelRef"); 643113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 644113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 645113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com SkAutoLockPixels alp(*bm); 646113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 647d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#ifdef ANDROID_RGB 648d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com /* short-circuit the SkScaledBitmapSampler when possible, as this gives 649d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com a significant performance boost. 650d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com */ 651d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com if (sampleSize == 1 && 6526c22573edb234ad14df947278cfed010669a39a7reed ((kN32_SkColorType == colorType && cinfo.out_color_space == JCS_RGBA_8888) || 6536c22573edb234ad14df947278cfed010669a39a7reed (kRGB_565_SkColorType == colorType && cinfo.out_color_space == JCS_RGB_565))) 654d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com { 655bc69ce982f8374742ca910587485f0d741350c2dscroggo@google.com JSAMPLE* rowptr = (JSAMPLE*)bm->getPixels(); 656d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com INT32 const bpr = bm->rowBytes(); 657d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com 658d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com while (cinfo.output_scanline < cinfo.output_height) { 659d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1); 660d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com if (0 == row_count) { 661fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com // if row_count == 0, then we didn't get a scanline, 662fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com // so return early. We will return a partial image. 663fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com fill_below_level(cinfo.output_scanline, bm); 664fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com cinfo.output_scanline = cinfo.output_height; 665fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com break; // Skip to jpeg_finish_decompress() 666d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 667d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com if (this->shouldCancelDecode()) { 668d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return return_false(cinfo, *bm, "shouldCancelDecode"); 669d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 670d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com rowptr += bpr; 671d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 672d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com jpeg_finish_decompress(&cinfo); 673d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return true; 674d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 675d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#endif 6768570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com 677d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com // check for supported formats 678d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com SkScaledBitmapSampler::SrcConfig sc; 6795ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com int srcBytesPerPixel; 6805ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com 6815ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com if (!get_src_config(cinfo, &sc, &srcBytesPerPixel)) { 682d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return return_false(cinfo, *bm, "jpeg colorspace"); 683d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 684d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 6858d2392487cd97e68c0a71da9fd5d2b42ecac5ec8scroggo@google.com if (!sampler.begin(bm, sc, *this)) { 686d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return return_false(cinfo, *bm, "sampler.begin"); 687d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 688d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 6895ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com SkAutoMalloc srcStorage(cinfo.output_width * srcBytesPerPixel); 690113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com uint8_t* srcRow = (uint8_t*)srcStorage.get(); 691d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 692d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com // Possibly skip initial rows [sampler.srcY0] 693d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com if (!skip_src_rows(&cinfo, srcRow, sampler.srcY0())) { 694d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return return_false(cinfo, *bm, "skip rows"); 695d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 696d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 697d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com // now loop through scanlines until y == bm->height() - 1 698d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com for (int y = 0;; y++) { 699d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com JSAMPLE* rowptr = (JSAMPLE*)srcRow; 700d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1); 701d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com if (0 == row_count) { 702fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com // if row_count == 0, then we didn't get a scanline, 703fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com // so return early. We will return a partial image. 704fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com fill_below_level(y, bm); 705fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com cinfo.output_scanline = cinfo.output_height; 706fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com break; // Skip to jpeg_finish_decompress() 707d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 708d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com if (this->shouldCancelDecode()) { 709d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return return_false(cinfo, *bm, "shouldCancelDecode"); 710d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 7118570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com 7128570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com if (JCS_CMYK == cinfo.out_color_space) { 7138570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com convert_CMYK_to_RGB(srcRow, cinfo.output_width); 7148570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com } 7158570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com 716d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com sampler.next(srcRow); 717d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com if (bm->height() - 1 == y) { 718d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com // we're done 719d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com break; 720d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 721d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 722d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com if (!skip_src_rows(&cinfo, srcRow, sampler.srcDY() - 1)) { 723d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return return_false(cinfo, *bm, "skip rows"); 724d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 725d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 726d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 727d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com // we formally skip the rest, so we don't get a complaint from libjpeg 728d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com if (!skip_src_rows(&cinfo, srcRow, 729d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com cinfo.output_height - cinfo.output_scanline)) { 730d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return return_false(cinfo, *bm, "skip rows"); 731d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 732d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com jpeg_finish_decompress(&cinfo); 733d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 734d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return true; 735d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com} 736d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 737b227e37eae36ccf630c4baef00b1354d42b40fd1sugoienum SizeType { 738b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi kSizeForMemoryAllocation_SizeType, 739b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi kActualSize_SizeType 740b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi}; 741b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 742b227e37eae36ccf630c4baef00b1354d42b40fd1sugoistatic SkISize compute_yuv_size(const jpeg_decompress_struct& info, int component, 743b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi SizeType sizeType) { 744b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi if (sizeType == kSizeForMemoryAllocation_SizeType) { 745b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi return SkISize::Make(info.cur_comp_info[component]->width_in_blocks * DCTSIZE, 746b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi info.cur_comp_info[component]->height_in_blocks * DCTSIZE); 747b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi } 748b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi return SkISize::Make(info.cur_comp_info[component]->downsampled_width, 749b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi info.cur_comp_info[component]->downsampled_height); 750b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi} 751b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 752b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi// Enum for YUV decoding 753b227e37eae36ccf630c4baef00b1354d42b40fd1sugoienum YUVSubsampling { 754b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi kUNKNOWN_YUVSubsampling, 755b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi k410_YUVSubsampling, 756b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi k411_YUVSubsampling, 757b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi k420_YUVSubsampling, 758b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi k422_YUVSubsampling, 759b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi k440_YUVSubsampling, 760b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi k444_YUVSubsampling 761b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi}; 762b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 763b227e37eae36ccf630c4baef00b1354d42b40fd1sugoistatic YUVSubsampling yuv_subsampling(const jpeg_decompress_struct& info) { 764b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi if ((DCTSIZE == 8) 765b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi && (info.num_components == 3) 766b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi && (info.comps_in_scan >= info.num_components) 767b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi && (info.scale_denom <= 8) 768b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi && (info.cur_comp_info[0]) 769b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi && (info.cur_comp_info[1]) 770b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi && (info.cur_comp_info[2]) 771b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi && (info.cur_comp_info[1]->h_samp_factor == 1) 772b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi && (info.cur_comp_info[1]->v_samp_factor == 1) 773b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi && (info.cur_comp_info[2]->h_samp_factor == 1) 774b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi && (info.cur_comp_info[2]->v_samp_factor == 1)) 775b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi { 776b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi int h = info.cur_comp_info[0]->h_samp_factor; 777b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi int v = info.cur_comp_info[0]->v_samp_factor; 778b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi // 4:4:4 : (h == 1) && (v == 1) 779b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi // 4:4:0 : (h == 1) && (v == 2) 780b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi // 4:2:2 : (h == 2) && (v == 1) 781b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi // 4:2:0 : (h == 2) && (v == 2) 782b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi // 4:1:1 : (h == 4) && (v == 1) 783b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi // 4:1:0 : (h == 4) && (v == 2) 784b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi if (v == 1) { 785b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi switch (h) { 786b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi case 1: 787b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi return k444_YUVSubsampling; 788b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi case 2: 789b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi return k422_YUVSubsampling; 790b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi case 4: 791b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi return k411_YUVSubsampling; 792b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi default: 793b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi break; 794b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi } 795b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi } else if (v == 2) { 796b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi switch (h) { 797b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi case 1: 798b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi return k440_YUVSubsampling; 799b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi case 2: 800b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi return k420_YUVSubsampling; 801b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi case 4: 802b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi return k410_YUVSubsampling; 803b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi default: 804b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi break; 805b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi } 806b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi } 807b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi } 808b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 809b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi return kUNKNOWN_YUVSubsampling; 810b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi} 811b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 812b227e37eae36ccf630c4baef00b1354d42b40fd1sugoistatic void update_components_sizes(const jpeg_decompress_struct& cinfo, SkISize componentSizes[3], 813b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi SizeType sizeType) { 814b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi for (int i = 0; i < 3; ++i) { 815b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi componentSizes[i] = compute_yuv_size(cinfo, i, sizeType); 816b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi } 817b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi} 818b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 819b227e37eae36ccf630c4baef00b1354d42b40fd1sugoistatic bool output_raw_data(jpeg_decompress_struct& cinfo, void* planes[3], size_t rowBytes[3]) { 820b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi // U size and V size have to be the same if we're calling output_raw_data() 821b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi SkISize uvSize = compute_yuv_size(cinfo, 1, kSizeForMemoryAllocation_SizeType); 822b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi SkASSERT(uvSize == compute_yuv_size(cinfo, 2, kSizeForMemoryAllocation_SizeType)); 823b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 824b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi JSAMPARRAY bufferraw[3]; 825b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi JSAMPROW bufferraw2[32]; 826b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi bufferraw[0] = &bufferraw2[0]; // Y channel rows (8 or 16) 827b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi bufferraw[1] = &bufferraw2[16]; // U channel rows (8) 828b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi bufferraw[2] = &bufferraw2[24]; // V channel rows (8) 829b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi int yWidth = cinfo.output_width; 830b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi int yHeight = cinfo.output_height; 831b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi int yMaxH = yHeight - 1; 832b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi int v = cinfo.cur_comp_info[0]->v_samp_factor; 833b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi int uvMaxH = uvSize.height() - 1; 834b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi JSAMPROW outputY = static_cast<JSAMPROW>(planes[0]); 835b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi JSAMPROW outputU = static_cast<JSAMPROW>(planes[1]); 836b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi JSAMPROW outputV = static_cast<JSAMPROW>(planes[2]); 837b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi size_t rowBytesY = rowBytes[0]; 838b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi size_t rowBytesU = rowBytes[1]; 839b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi size_t rowBytesV = rowBytes[2]; 840b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 841b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi int yScanlinesToRead = DCTSIZE * v; 842b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi SkAutoMalloc lastRowStorage(yWidth * 8); 843b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi JSAMPROW yLastRow = (JSAMPROW)lastRowStorage.get(); 844b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi JSAMPROW uLastRow = yLastRow + 2 * yWidth; 845b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi JSAMPROW vLastRow = uLastRow + 2 * yWidth; 846b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi JSAMPROW dummyRow = vLastRow + 2 * yWidth; 847b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 848b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi while (cinfo.output_scanline < cinfo.output_height) { 849b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi // Request 8 or 16 scanlines: returns 0 or more scanlines. 850b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi bool hasYLastRow(false), hasUVLastRow(false); 851b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi // Assign 8 or 16 rows of memory to read the Y channel. 852b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi for (int i = 0; i < yScanlinesToRead; ++i) { 853b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi int scanline = (cinfo.output_scanline + i); 854b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi if (scanline < yMaxH) { 855b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi bufferraw2[i] = &outputY[scanline * rowBytesY]; 856b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi } else if (scanline == yMaxH) { 857b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi bufferraw2[i] = yLastRow; 858b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi hasYLastRow = true; 859b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi } else { 860b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi bufferraw2[i] = dummyRow; 861b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi } 862b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi } 863b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi int scaledScanline = cinfo.output_scanline / v; 864b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi // Assign 8 rows of memory to read the U and V channels. 865b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi for (int i = 0; i < 8; ++i) { 866b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi int scanline = (scaledScanline + i); 867b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi if (scanline < uvMaxH) { 868b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi bufferraw2[16 + i] = &outputU[scanline * rowBytesU]; 869b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi bufferraw2[24 + i] = &outputV[scanline * rowBytesV]; 870b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi } else if (scanline == uvMaxH) { 871b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi bufferraw2[16 + i] = uLastRow; 872b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi bufferraw2[24 + i] = vLastRow; 873b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi hasUVLastRow = true; 874b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi } else { 875b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi bufferraw2[16 + i] = dummyRow; 876b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi bufferraw2[24 + i] = dummyRow; 877b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi } 878b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi } 879b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi JDIMENSION scanlinesRead = jpeg_read_raw_data(&cinfo, bufferraw, yScanlinesToRead); 880b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 881b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi if (scanlinesRead == 0) 882b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi return false; 883b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 884b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi if (hasYLastRow) { 885b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi memcpy(&outputY[yMaxH * rowBytesY], yLastRow, yWidth); 886b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi } 887b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi if (hasUVLastRow) { 888b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi memcpy(&outputU[uvMaxH * rowBytesU], uLastRow, uvSize.width()); 889b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi memcpy(&outputV[uvMaxH * rowBytesV], vLastRow, uvSize.width()); 890b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi } 891b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi } 892b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 893b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi cinfo.output_scanline = SkMin32(cinfo.output_scanline, cinfo.output_height); 894b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 895b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi return true; 896b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi} 897b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 898b227e37eae36ccf630c4baef00b1354d42b40fd1sugoibool SkJPEGImageDecoder::onDecodeYUV8Planes(SkStream* stream, SkISize componentSizes[3], 899b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi void* planes[3], size_t rowBytes[3], 900b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi SkYUVColorSpace* colorSpace) { 901b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi#ifdef TIME_DECODE 902b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi SkAutoTime atm("JPEG YUV8 Decode"); 903b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi#endif 904b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 905b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi if (this->getSampleSize() != 1) { 906b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi return false; // Resizing not supported 907b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi } 908b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 909b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi JPEGAutoClean autoClean; 910b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 911b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi jpeg_decompress_struct cinfo; 912b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi skjpeg_source_mgr srcManager(stream, this); 913b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 914b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi skjpeg_error_mgr errorManager; 915b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi set_error_mgr(&cinfo, &errorManager); 916b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 917b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi // All objects need to be instantiated before this setjmp call so that 918b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi // they will be cleaned up properly if an error occurs. 919b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi if (setjmp(errorManager.fJmpBuf)) { 920b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi return return_false(cinfo, 0, 0, "setjmp YUV8"); 921b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi } 922b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 923b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi initialize_info(&cinfo, &srcManager); 924b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi autoClean.set(&cinfo); 925b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 926b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi int status = jpeg_read_header(&cinfo, true); 927b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi if (status != JPEG_HEADER_OK) { 928b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi return return_false(cinfo, 0, 0, "read_header YUV8"); 929b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi } 930b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 931b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi if (cinfo.jpeg_color_space != JCS_YCbCr) { 932b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi // It's not an error to not be encoded in YUV, so no need to use return_false() 933b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi return false; 934b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi } 935b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 936b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi cinfo.out_color_space = JCS_YCbCr; 937b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi cinfo.raw_data_out = TRUE; 938b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 939b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi if (!planes || !planes[0] || !rowBytes || !rowBytes[0]) { // Compute size only 940b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi update_components_sizes(cinfo, componentSizes, kSizeForMemoryAllocation_SizeType); 941b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi return true; 942b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi } 943b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 944b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi set_dct_method(*this, &cinfo); 945b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 946b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi SkASSERT(1 == cinfo.scale_num); 947b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi cinfo.scale_denom = 1; 948b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 949b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi turn_off_visual_optimizations(&cinfo); 950b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 951b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi#ifdef ANDROID_RGB 952b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi cinfo.dither_mode = JDITHER_NONE; 953b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi#endif 954b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 955b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi /* image_width and image_height are the original dimensions, available 956b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi after jpeg_read_header(). To see the scaled dimensions, we have to call 957b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi jpeg_start_decompress(), and then read output_width and output_height. 958b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi */ 959b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi if (!jpeg_start_decompress(&cinfo)) { 960b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi return return_false(cinfo, 0, 0, "start_decompress YUV8"); 961b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi } 962b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 963b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi if (!output_raw_data(cinfo, planes, rowBytes)) { 964b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi return return_false(cinfo, 0, 0, "output_raw_data"); 965b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi } 966b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 967b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi update_components_sizes(cinfo, componentSizes, kActualSize_SizeType); 968b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi jpeg_finish_decompress(&cinfo); 969b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 970b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi if (NULL != colorSpace) { 971b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi *colorSpace = kJPEG_SkYUVColorSpace; 972b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi } 973b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 974b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi return true; 975b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi} 976b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi 977d79277f67824392876b82cf5635cc11f819e64dfscroggo@google.com#ifdef SK_BUILD_FOR_ANDROID 978b5571b3324cf18629a255ec85e189447069c9b14scroggo@google.combool SkJPEGImageDecoder::onBuildTileIndex(SkStreamRewindable* stream, int *width, int *height) { 979113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 980a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com SkAutoTDelete<SkJPEGImageIndex> imageIndex(SkNEW_ARGS(SkJPEGImageIndex, (stream, this))); 981113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com jpeg_decompress_struct* cinfo = imageIndex->cinfo(); 982113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 983113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com skjpeg_error_mgr sk_err; 984590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com set_error_mgr(cinfo, &sk_err); 985113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 986113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com // All objects need to be instantiated before this setjmp call so that 987113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com // they will be cleaned up properly if an error occurs. 988113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (setjmp(sk_err.fJmpBuf)) { 989113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return false; 990113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 991113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 992113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com // create the cinfo used to create/build the huffmanIndex 993a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com if (!imageIndex->initializeInfoAndReadHeader()) { 994113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return false; 995113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 996113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 997a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com if (!imageIndex->buildHuffmanIndex()) { 998113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return false; 999113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 1000113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 1001113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com // destroy the cinfo used to create/build the huffman index 1002a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com imageIndex->destroyInfo(); 1003113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 1004113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com // Init decoder to image decode mode 1005a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com if (!imageIndex->initializeInfoAndReadHeader()) { 1006113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return false; 1007113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 1008113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 1009590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com // FIXME: This sets cinfo->out_color_space, which we may change later 1010590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com // based on the config in onDecodeSubset. This should be fine, since 1011590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com // jpeg_init_read_tile_scanline will check out_color_space again after 1012590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com // that change (when it calls jinit_color_deconverter). 10136c22573edb234ad14df947278cfed010669a39a7reed (void) this->getBitmapColorType(cinfo); 1014590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com 1015590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com turn_off_visual_optimizations(cinfo); 1016113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 1017113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com // instead of jpeg_start_decompress() we start a tiled decompress 1018a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com if (!imageIndex->startTileDecompress()) { 1019a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com return false; 1020a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com } 1021113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 1022a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com SkASSERT(1 == cinfo->scale_num); 1023590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com fImageWidth = cinfo->output_width; 1024590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com fImageHeight = cinfo->output_height; 1025590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com 1026590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com if (width) { 1027590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com *width = fImageWidth; 1028590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com } 1029590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com if (height) { 1030590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com *height = fImageHeight; 1031590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com } 1032113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 1033113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com SkDELETE(fImageIndex); 1034a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com fImageIndex = imageIndex.detach(); 1035113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 1036113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return true; 1037113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com} 1038113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 10397e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.combool SkJPEGImageDecoder::onDecodeSubset(SkBitmap* bm, const SkIRect& region) { 1040113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (NULL == fImageIndex) { 1041113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return false; 1042113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 1043113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com jpeg_decompress_struct* cinfo = fImageIndex->cinfo(); 1044113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 1045113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com SkIRect rect = SkIRect::MakeWH(fImageWidth, fImageHeight); 1046113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (!rect.intersect(region)) { 1047113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com // If the requested region is entirely outside the image return false 1048113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return false; 1049113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 1050113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 1051113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 1052113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com skjpeg_error_mgr errorManager; 1053590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com set_error_mgr(cinfo, &errorManager); 1054590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com 1055113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (setjmp(errorManager.fJmpBuf)) { 1056113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return false; 1057113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 1058113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 1059113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com int requestedSampleSize = this->getSampleSize(); 1060113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com cinfo->scale_denom = requestedSampleSize; 1061113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 1062590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com set_dct_method(*this, cinfo); 1063113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 10646c22573edb234ad14df947278cfed010669a39a7reed const SkColorType colorType = this->getBitmapColorType(cinfo); 10656c22573edb234ad14df947278cfed010669a39a7reed adjust_out_color_space_and_dither(cinfo, colorType, *this); 1066113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 1067113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com int startX = rect.fLeft; 1068113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com int startY = rect.fTop; 1069113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com int width = rect.width(); 1070113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com int height = rect.height(); 1071113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 1072113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com jpeg_init_read_tile_scanline(cinfo, fImageIndex->huffmanIndex(), 1073113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com &startX, &startY, &width, &height); 1074113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com int skiaSampleSize = recompute_sampleSize(requestedSampleSize, *cinfo); 1075113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com int actualSampleSize = skiaSampleSize * (DCTSIZE / cinfo->min_DCT_scaled_size); 1076113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 1077113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com SkScaledBitmapSampler sampler(width, height, skiaSampleSize); 1078113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 1079113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com SkBitmap bitmap; 10805ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com // Assume an A8 bitmap is not opaque to avoid the check of each 10815ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com // individual pixel. It is very unlikely to be opaque, since 10825ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com // an opaque A8 bitmap would not be very interesting. 10835ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com // Otherwise, a jpeg image is opaque. 10846c22573edb234ad14df947278cfed010669a39a7reed bitmap.setInfo(SkImageInfo::Make(sampler.scaledWidth(), sampler.scaledHeight(), colorType, 10856c22573edb234ad14df947278cfed010669a39a7reed kAlpha_8_SkColorType == colorType ? 10866c22573edb234ad14df947278cfed010669a39a7reed kPremul_SkAlphaType : kOpaque_SkAlphaType)); 1087113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 1088113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com // Check ahead of time if the swap(dest, src) is possible or not. 1089113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com // If yes, then we will stick to AllocPixelRef since it's cheaper with the 1090113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com // swap happening. If no, then we will use alloc to allocate pixels to 1091113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com // prevent garbage collection. 1092113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com int w = rect.width() / actualSampleSize; 1093113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com int h = rect.height() / actualSampleSize; 1094113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com bool swapOnly = (rect == region) && bm->isNull() && 1095113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com (w == bitmap.width()) && (h == bitmap.height()) && 1096113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com ((startX - rect.x()) / actualSampleSize == 0) && 1097113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com ((startY - rect.y()) / actualSampleSize == 0); 1098113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (swapOnly) { 1099113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (!this->allocPixelRef(&bitmap, NULL)) { 1100113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return return_false(*cinfo, bitmap, "allocPixelRef"); 1101113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 1102113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } else { 1103848250415eddc54075f7eb8795e8db79e749c6abreed if (!bitmap.tryAllocPixels()) { 1104113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return return_false(*cinfo, bitmap, "allocPixels"); 1105113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 1106113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 1107113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 1108113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com SkAutoLockPixels alp(bitmap); 1109113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 1110113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#ifdef ANDROID_RGB 1111113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com /* short-circuit the SkScaledBitmapSampler when possible, as this gives 1112113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com a significant performance boost. 1113113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com */ 1114113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (skiaSampleSize == 1 && 11156c22573edb234ad14df947278cfed010669a39a7reed ((kN32_SkColorType == colorType && cinfo->out_color_space == JCS_RGBA_8888) || 11166c22573edb234ad14df947278cfed010669a39a7reed (kRGB_565_SkColorType == colorType && cinfo->out_color_space == JCS_RGB_565))) 1117113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com { 1118113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com JSAMPLE* rowptr = (JSAMPLE*)bitmap.getPixels(); 1119113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com INT32 const bpr = bitmap.rowBytes(); 1120113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com int rowTotalCount = 0; 1121113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 1122113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com while (rowTotalCount < height) { 1123113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com int rowCount = jpeg_read_tile_scanline(cinfo, 1124113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com fImageIndex->huffmanIndex(), 1125113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com &rowptr); 1126fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com // if rowCount == 0, then we didn't get a scanline, so abort. 1127fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com // onDecodeSubset() relies on onBuildTileIndex(), which 1128fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com // needs a complete image to succeed. 1129113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (0 == rowCount) { 1130113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return return_false(*cinfo, bitmap, "read_scanlines"); 1131113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 1132113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (this->shouldCancelDecode()) { 1133113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return return_false(*cinfo, bitmap, "shouldCancelDecode"); 1134113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 1135113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com rowTotalCount += rowCount; 1136113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com rowptr += bpr; 1137113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 1138113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 1139113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (swapOnly) { 1140113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com bm->swap(bitmap); 1141113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } else { 1142113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com cropBitmap(bm, &bitmap, actualSampleSize, region.x(), region.y(), 1143113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com region.width(), region.height(), startX, startY); 1144113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 1145113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return true; 1146113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 1147113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#endif 1148113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 1149113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com // check for supported formats 1150113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com SkScaledBitmapSampler::SrcConfig sc; 11515ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com int srcBytesPerPixel; 11525ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com 11535ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com if (!get_src_config(*cinfo, &sc, &srcBytesPerPixel)) { 1154113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return return_false(*cinfo, *bm, "jpeg colorspace"); 1155113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 1156113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 11578d2392487cd97e68c0a71da9fd5d2b42ecac5ec8scroggo@google.com if (!sampler.begin(&bitmap, sc, *this)) { 1158113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return return_false(*cinfo, bitmap, "sampler.begin"); 1159113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 1160113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 11615ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com SkAutoMalloc srcStorage(width * srcBytesPerPixel); 1162113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com uint8_t* srcRow = (uint8_t*)srcStorage.get(); 1163113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 1164113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com // Possibly skip initial rows [sampler.srcY0] 1165113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (!skip_src_rows_tile(cinfo, fImageIndex->huffmanIndex(), srcRow, sampler.srcY0())) { 1166113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return return_false(*cinfo, bitmap, "skip rows"); 1167113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 1168113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 1169113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com // now loop through scanlines until y == bitmap->height() - 1 1170113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com for (int y = 0;; y++) { 1171113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com JSAMPLE* rowptr = (JSAMPLE*)srcRow; 1172113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com int row_count = jpeg_read_tile_scanline(cinfo, fImageIndex->huffmanIndex(), &rowptr); 1173fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com // if row_count == 0, then we didn't get a scanline, so abort. 1174fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com // onDecodeSubset() relies on onBuildTileIndex(), which 1175fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com // needs a complete image to succeed. 1176113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (0 == row_count) { 1177113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return return_false(*cinfo, bitmap, "read_scanlines"); 1178113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 1179113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (this->shouldCancelDecode()) { 1180113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return return_false(*cinfo, bitmap, "shouldCancelDecode"); 1181113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 1182113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 1183113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (JCS_CMYK == cinfo->out_color_space) { 1184113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com convert_CMYK_to_RGB(srcRow, width); 1185113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 1186113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 1187113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com sampler.next(srcRow); 1188113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (bitmap.height() - 1 == y) { 1189113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com // we're done 1190113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com break; 1191113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 1192113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 1193113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (!skip_src_rows_tile(cinfo, fImageIndex->huffmanIndex(), srcRow, 1194113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com sampler.srcDY() - 1)) { 1195113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return return_false(*cinfo, bitmap, "skip rows"); 1196113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 1197113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 1198113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com if (swapOnly) { 1199113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com bm->swap(bitmap); 1200113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } else { 1201113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com cropBitmap(bm, &bitmap, actualSampleSize, region.x(), region.y(), 1202113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com region.width(), region.height(), startX, startY); 1203113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com } 1204113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com return true; 1205113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com} 1206113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#endif 1207113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com 1208d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com/////////////////////////////////////////////////////////////////////////////// 1209d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1210d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#include "SkColorPriv.h" 1211d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1212d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com// taken from jcolor.c in libjpeg 1213d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#if 0 // 16bit - precise but slow 1214d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #define CYR 19595 // 0.299 1215d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #define CYG 38470 // 0.587 1216d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #define CYB 7471 // 0.114 1217d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1218d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #define CUR -11059 // -0.16874 1219d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #define CUG -21709 // -0.33126 1220d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #define CUB 32768 // 0.5 1221d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1222d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #define CVR 32768 // 0.5 1223d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #define CVG -27439 // -0.41869 1224d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #define CVB -5329 // -0.08131 1225d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1226d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #define CSHIFT 16 1227d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#else // 8bit - fast, slightly less precise 1228d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #define CYR 77 // 0.299 1229d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #define CYG 150 // 0.587 1230d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #define CYB 29 // 0.114 1231d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1232d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #define CUR -43 // -0.16874 1233d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #define CUG -85 // -0.33126 1234d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #define CUB 128 // 0.5 1235d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1236d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #define CVR 128 // 0.5 1237d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #define CVG -107 // -0.41869 1238d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #define CVB -21 // -0.08131 1239d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1240d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com #define CSHIFT 8 1241d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#endif 1242d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1243d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comstatic void rgb2yuv_32(uint8_t dst[], SkPMColor c) { 1244d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int r = SkGetPackedR32(c); 1245d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int g = SkGetPackedG32(c); 1246d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int b = SkGetPackedB32(c); 1247d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1248d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int y = ( CYR*r + CYG*g + CYB*b ) >> CSHIFT; 1249d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int u = ( CUR*r + CUG*g + CUB*b ) >> CSHIFT; 1250d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int v = ( CVR*r + CVG*g + CVB*b ) >> CSHIFT; 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_4444(uint8_t dst[], U16CPU c) { 1258d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int r = SkGetPackedR4444(c); 1259d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int g = SkGetPackedG4444(c); 1260d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int b = SkGetPackedB4444(c); 1261d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1262d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int y = ( CYR*r + CYG*g + CYB*b ) >> (CSHIFT - 4); 1263d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int u = ( CUR*r + CUG*g + CUB*b ) >> (CSHIFT - 4); 1264d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int v = ( CVR*r + CVG*g + CVB*b ) >> (CSHIFT - 4); 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.comstatic void rgb2yuv_16(uint8_t dst[], U16CPU c) { 1272d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int r = SkGetPackedR16(c); 1273d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int g = SkGetPackedG16(c); 1274d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int b = SkGetPackedB16(c); 1275d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1276d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int y = ( 2*CYR*r + CYG*g + 2*CYB*b ) >> (CSHIFT - 2); 1277d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int u = ( 2*CUR*r + CUG*g + 2*CUB*b ) >> (CSHIFT - 2); 1278d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com int v = ( 2*CVR*r + CVG*g + 2*CVB*b ) >> (CSHIFT - 2); 1279d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1280d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst[0] = SkToU8(y); 1281d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst[1] = SkToU8(u + 128); 1282d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst[2] = SkToU8(v + 128); 1283d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com} 1284d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1285d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com/////////////////////////////////////////////////////////////////////////////// 1286d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1287d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comtypedef void (*WriteScanline)(uint8_t* SK_RESTRICT dst, 1288d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com const void* SK_RESTRICT src, int width, 1289d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com const SkPMColor* SK_RESTRICT ctable); 1290d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1291d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comstatic void Write_32_YUV(uint8_t* SK_RESTRICT dst, 1292d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com const void* SK_RESTRICT srcRow, int width, 1293d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com const SkPMColor*) { 1294d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com const uint32_t* SK_RESTRICT src = (const uint32_t*)srcRow; 1295d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com while (--width >= 0) { 1296d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#ifdef WE_CONVERT_TO_YUV 1297d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com rgb2yuv_32(dst, *src++); 1298d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#else 1299d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com uint32_t c = *src++; 1300d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst[0] = SkGetPackedR32(c); 1301d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst[1] = SkGetPackedG32(c); 1302d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst[2] = SkGetPackedB32(c); 1303d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#endif 1304d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst += 3; 1305d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 1306d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com} 1307d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1308d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comstatic void Write_4444_YUV(uint8_t* SK_RESTRICT dst, 1309d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com const void* SK_RESTRICT srcRow, int width, 1310d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com const SkPMColor*) { 1311d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com const SkPMColor16* SK_RESTRICT src = (const SkPMColor16*)srcRow; 1312d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com while (--width >= 0) { 1313d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#ifdef WE_CONVERT_TO_YUV 1314d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com rgb2yuv_4444(dst, *src++); 1315d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#else 1316d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com SkPMColor16 c = *src++; 1317d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst[0] = SkPacked4444ToR32(c); 1318d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst[1] = SkPacked4444ToG32(c); 1319d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst[2] = SkPacked4444ToB32(c); 1320d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#endif 1321d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst += 3; 1322d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 1323d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com} 1324d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1325d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comstatic void Write_16_YUV(uint8_t* SK_RESTRICT dst, 1326d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com const void* SK_RESTRICT srcRow, int width, 1327d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com const SkPMColor*) { 1328d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com const uint16_t* SK_RESTRICT src = (const uint16_t*)srcRow; 1329d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com while (--width >= 0) { 1330d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#ifdef WE_CONVERT_TO_YUV 1331d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com rgb2yuv_16(dst, *src++); 1332d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#else 1333d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com uint16_t c = *src++; 1334d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst[0] = SkPacked16ToR32(c); 1335d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst[1] = SkPacked16ToG32(c); 1336d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst[2] = SkPacked16ToB32(c); 1337d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#endif 1338d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst += 3; 1339d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 1340d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com} 1341d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1342d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comstatic void Write_Index_YUV(uint8_t* SK_RESTRICT dst, 1343d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com const void* SK_RESTRICT srcRow, int width, 1344d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com const SkPMColor* SK_RESTRICT ctable) { 1345d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com const uint8_t* SK_RESTRICT src = (const uint8_t*)srcRow; 1346d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com while (--width >= 0) { 1347d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#ifdef WE_CONVERT_TO_YUV 1348d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com rgb2yuv_32(dst, ctable[*src++]); 1349d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#else 1350d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com uint32_t c = ctable[*src++]; 1351d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst[0] = SkGetPackedR32(c); 1352d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst[1] = SkGetPackedG32(c); 1353d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst[2] = SkGetPackedB32(c); 1354d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#endif 1355d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com dst += 3; 1356d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 1357d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com} 1358d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1359d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comstatic WriteScanline ChooseWriter(const SkBitmap& bm) { 13606c22573edb234ad14df947278cfed010669a39a7reed switch (bm.colorType()) { 13616c22573edb234ad14df947278cfed010669a39a7reed case kN32_SkColorType: 1362d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return Write_32_YUV; 13636c22573edb234ad14df947278cfed010669a39a7reed case kRGB_565_SkColorType: 1364d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return Write_16_YUV; 13656c22573edb234ad14df947278cfed010669a39a7reed case kARGB_4444_SkColorType: 1366d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return Write_4444_YUV; 13676c22573edb234ad14df947278cfed010669a39a7reed case kIndex_8_SkColorType: 1368d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return Write_Index_YUV; 1369d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com default: 1370d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return NULL; 1371d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 1372d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com} 1373d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1374d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comclass SkJPEGImageEncoder : public SkImageEncoder { 1375d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comprotected: 1376d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) { 1377d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#ifdef TIME_ENCODE 1378113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com SkAutoTime atm("JPEG Encode"); 1379d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#endif 1380d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1381d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com SkAutoLockPixels alp(bm); 1382d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com if (NULL == bm.getPixels()) { 1383d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return false; 1384d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 1385d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1386d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com jpeg_compress_struct cinfo; 1387d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com skjpeg_error_mgr sk_err; 1388d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com skjpeg_destination_mgr sk_wstream(stream); 1389d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1390d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com // allocate these before set call setjmp 1391d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com SkAutoMalloc oneRow; 1392d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com SkAutoLockColors ctLocker; 1393d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1394d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com cinfo.err = jpeg_std_error(&sk_err); 1395d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com sk_err.error_exit = skjpeg_error_exit; 1396d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com if (setjmp(sk_err.fJmpBuf)) { 1397d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return false; 1398d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 1399d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 14008d725b25a6287e49e2b0cb2965871186e716ededmtklein@google.com // Keep after setjmp or mark volatile. 14018d725b25a6287e49e2b0cb2965871186e716ededmtklein@google.com const WriteScanline writer = ChooseWriter(bm); 14028d725b25a6287e49e2b0cb2965871186e716ededmtklein@google.com if (NULL == writer) { 14038d725b25a6287e49e2b0cb2965871186e716ededmtklein@google.com return false; 14048d725b25a6287e49e2b0cb2965871186e716ededmtklein@google.com } 14058d725b25a6287e49e2b0cb2965871186e716ededmtklein@google.com 14068d725b25a6287e49e2b0cb2965871186e716ededmtklein@google.com jpeg_create_compress(&cinfo); 1407d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com cinfo.dest = &sk_wstream; 1408d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com cinfo.image_width = bm.width(); 1409d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com cinfo.image_height = bm.height(); 1410d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com cinfo.input_components = 3; 1411d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#ifdef WE_CONVERT_TO_YUV 1412d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com cinfo.in_color_space = JCS_YCbCr; 1413d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#else 1414d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com cinfo.in_color_space = JCS_RGB; 1415d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#endif 1416d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com cinfo.input_gamma = 1; 1417d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1418d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com jpeg_set_defaults(&cinfo); 1419d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */); 1420b7decc539887069f3fb0f9fc80d543b437bdd624scroggo@google.com#ifdef DCT_IFAST_SUPPORTED 1421d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com cinfo.dct_method = JDCT_IFAST; 1422b7decc539887069f3fb0f9fc80d543b437bdd624scroggo@google.com#endif 1423d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1424d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com jpeg_start_compress(&cinfo, TRUE); 1425d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1426d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com const int width = bm.width(); 14278570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com uint8_t* oneRowP = (uint8_t*)oneRow.reset(width * 3); 1428d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1429d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com const SkPMColor* colors = ctLocker.lockColors(bm); 1430d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com const void* srcRow = bm.getPixels(); 1431d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1432d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com while (cinfo.next_scanline < cinfo.image_height) { 1433d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ 1434d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1435d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com writer(oneRowP, srcRow, width, colors); 1436d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com row_pointer[0] = oneRowP; 1437d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); 1438d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com srcRow = (const void*)((const char*)srcRow + bm.rowBytes()); 1439d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 1440d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1441d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com jpeg_finish_compress(&cinfo); 1442d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com jpeg_destroy_compress(&cinfo); 1443d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1444d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return true; 1445d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 1446d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com}; 1447d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1448d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com/////////////////////////////////////////////////////////////////////////////// 1449ec51cb863409e238b40c5beef458669d9a824481robertphillips@google.comDEFINE_DECODER_CREATOR(JPEGImageDecoder); 1450ec51cb863409e238b40c5beef458669d9a824481robertphillips@google.comDEFINE_ENCODER_CREATOR(JPEGImageEncoder); 1451ec51cb863409e238b40c5beef458669d9a824481robertphillips@google.com/////////////////////////////////////////////////////////////////////////////// 1452d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1453b5571b3324cf18629a255ec85e189447069c9b14scroggo@google.comstatic bool is_jpeg(SkStreamRewindable* stream) { 1454ec51cb863409e238b40c5beef458669d9a824481robertphillips@google.com static const unsigned char gHeader[] = { 0xFF, 0xD8, 0xFF }; 1455d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com static const size_t HEADER_SIZE = sizeof(gHeader); 1456d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1457d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com char buffer[HEADER_SIZE]; 1458d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com size_t len = stream->read(buffer, HEADER_SIZE); 1459d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1460d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com if (len != HEADER_SIZE) { 146139edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com return false; // can't read enough 1462d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 1463d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com if (memcmp(buffer, gHeader, HEADER_SIZE)) { 146439edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com return false; 146539edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com } 146639edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com return true; 146739edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com} 146839edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com 1469b5571b3324cf18629a255ec85e189447069c9b14scroggo@google.com 1470b5571b3324cf18629a255ec85e189447069c9b14scroggo@google.comstatic SkImageDecoder* sk_libjpeg_dfactory(SkStreamRewindable* stream) { 147139edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com if (is_jpeg(stream)) { 147239edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com return SkNEW(SkJPEGImageDecoder); 147339edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com } 147439edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com return NULL; 147539edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com} 147639edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com 1477b5571b3324cf18629a255ec85e189447069c9b14scroggo@google.comstatic SkImageDecoder::Format get_format_jpeg(SkStreamRewindable* stream) { 147839edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com if (is_jpeg(stream)) { 147939edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com return SkImageDecoder::kJPEG_Format; 1480d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com } 148139edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com return SkImageDecoder::kUnknown_Format; 1482d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com} 1483d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 14848570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.comstatic SkImageEncoder* sk_libjpeg_efactory(SkImageEncoder::Type t) { 1485d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com return (SkImageEncoder::kJPEG_Type == t) ? SkNEW(SkJPEGImageEncoder) : NULL; 1486d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com} 1487d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com 1488bd6343b1d60d2a85e930f33f4b06b4502b3e8caamtklein@google.comstatic SkImageDecoder_DecodeReg gDReg(sk_libjpeg_dfactory); 1489bd6343b1d60d2a85e930f33f4b06b4502b3e8caamtklein@google.comstatic SkImageDecoder_FormatReg gFormatReg(get_format_jpeg); 1490bd6343b1d60d2a85e930f33f4b06b4502b3e8caamtklein@google.comstatic SkImageEncoder_EncodeReg gEReg(sk_libjpeg_efactory); 1491