blob: 6ea13b7639dd560d9e06d5b490f26be267616e46 [file] [log] [blame]
msarette16b04a2015-04-15 07:32:19 -07001/*
2 * Copyright 2015 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "SkCodec.h"
9#include "SkJpegCodec.h"
10#include "SkJpegDecoderMgr.h"
mtklein525e90a2015-06-18 09:58:57 -070011#include "SkJpegUtility_codec.h"
msarette16b04a2015-04-15 07:32:19 -070012#include "SkCodecPriv.h"
13#include "SkColorPriv.h"
14#include "SkStream.h"
15#include "SkTemplates.h"
16#include "SkTypes.h"
17
msarett1c8a5872015-07-07 08:50:01 -070018// stdio is needed for libjpeg-turbo
msarette16b04a2015-04-15 07:32:19 -070019#include <stdio.h>
20
21extern "C" {
22 #include "jerror.h"
msarette16b04a2015-04-15 07:32:19 -070023 #include "jpeglib.h"
24}
25
scroggodb30be22015-12-08 18:54:13 -080026bool SkJpegCodec::IsJpeg(const void* buffer, size_t bytesRead) {
msarette16b04a2015-04-15 07:32:19 -070027 static const uint8_t jpegSig[] = { 0xFF, 0xD8, 0xFF };
scroggodb30be22015-12-08 18:54:13 -080028 return bytesRead >= 3 && !memcmp(buffer, jpegSig, sizeof(jpegSig));
msarette16b04a2015-04-15 07:32:19 -070029}
30
31bool SkJpegCodec::ReadHeader(SkStream* stream, SkCodec** codecOut,
32 JpegDecoderMgr** decoderMgrOut) {
33
34 // Create a JpegDecoderMgr to own all of the decompress information
halcanary385fe4d2015-08-26 13:07:48 -070035 SkAutoTDelete<JpegDecoderMgr> decoderMgr(new JpegDecoderMgr(stream));
msarette16b04a2015-04-15 07:32:19 -070036
37 // libjpeg errors will be caught and reported here
38 if (setjmp(decoderMgr->getJmpBuf())) {
39 return decoderMgr->returnFalse("setjmp");
40 }
41
42 // Initialize the decompress info and the source manager
43 decoderMgr->init();
44
45 // Read the jpeg header
msarettfbccb592015-09-01 06:43:41 -070046 if (JPEG_HEADER_OK != jpeg_read_header(decoderMgr->dinfo(), true)) {
msarette16b04a2015-04-15 07:32:19 -070047 return decoderMgr->returnFalse("read_header");
48 }
49
halcanary96fcdcc2015-08-27 07:41:13 -070050 if (nullptr != codecOut) {
msarette16b04a2015-04-15 07:32:19 -070051 // Recommend the color type to decode to
52 const SkColorType colorType = decoderMgr->getColorType();
53
54 // Create image info object and the codec
55 const SkImageInfo& imageInfo = SkImageInfo::Make(decoderMgr->dinfo()->image_width,
56 decoderMgr->dinfo()->image_height, colorType, kOpaque_SkAlphaType);
halcanary385fe4d2015-08-26 13:07:48 -070057 *codecOut = new SkJpegCodec(imageInfo, stream, decoderMgr.detach());
msarette16b04a2015-04-15 07:32:19 -070058 } else {
halcanary96fcdcc2015-08-27 07:41:13 -070059 SkASSERT(nullptr != decoderMgrOut);
msarette16b04a2015-04-15 07:32:19 -070060 *decoderMgrOut = decoderMgr.detach();
61 }
62 return true;
63}
64
65SkCodec* SkJpegCodec::NewFromStream(SkStream* stream) {
66 SkAutoTDelete<SkStream> streamDeleter(stream);
halcanary96fcdcc2015-08-27 07:41:13 -070067 SkCodec* codec = nullptr;
68 if (ReadHeader(stream, &codec, nullptr)) {
msarette16b04a2015-04-15 07:32:19 -070069 // Codec has taken ownership of the stream, we do not need to delete it
70 SkASSERT(codec);
71 streamDeleter.detach();
72 return codec;
73 }
halcanary96fcdcc2015-08-27 07:41:13 -070074 return nullptr;
msarette16b04a2015-04-15 07:32:19 -070075}
76
77SkJpegCodec::SkJpegCodec(const SkImageInfo& srcInfo, SkStream* stream,
78 JpegDecoderMgr* decoderMgr)
79 : INHERITED(srcInfo, stream)
80 , fDecoderMgr(decoderMgr)
msarettfbccb592015-09-01 06:43:41 -070081 , fReadyState(decoderMgr->dinfo()->global_state)
msarette16b04a2015-04-15 07:32:19 -070082{}
83
84/*
emmaleer8f4ba762015-08-14 07:44:46 -070085 * Return the row bytes of a particular image type and width
86 */
87static int get_row_bytes(const j_decompress_ptr dinfo) {
88 int colorBytes = (dinfo->out_color_space == JCS_RGB565) ? 2 : dinfo->out_color_components;
89 return dinfo->output_width * colorBytes;
90
91}
scroggoe7fc14b2015-10-02 13:14:46 -070092
93/*
94 * Calculate output dimensions based on the provided factors.
95 *
96 * Not to be used on the actual jpeg_decompress_struct used for decoding, since it will
97 * incorrectly modify num_components.
98 */
99void calc_output_dimensions(jpeg_decompress_struct* dinfo, unsigned int num, unsigned int denom) {
100 dinfo->num_components = 0;
101 dinfo->scale_num = num;
102 dinfo->scale_denom = denom;
103 jpeg_calc_output_dimensions(dinfo);
104}
105
emmaleer8f4ba762015-08-14 07:44:46 -0700106/*
msarette16b04a2015-04-15 07:32:19 -0700107 * Return a valid set of output dimensions for this decoder, given an input scale
108 */
109SkISize SkJpegCodec::onGetScaledDimensions(float desiredScale) const {
msarett1c8a5872015-07-07 08:50:01 -0700110 // libjpeg-turbo supports scaling by 1/8, 1/4, 3/8, 1/2, 5/8, 3/4, 7/8, and 1/1, so we will
111 // support these as well
scroggoe7fc14b2015-10-02 13:14:46 -0700112 unsigned int num;
113 unsigned int denom = 8;
msarettfdb47572015-10-13 12:50:14 -0700114 if (desiredScale >= 0.9375) {
msarett1c8a5872015-07-07 08:50:01 -0700115 num = 8;
msarettfdb47572015-10-13 12:50:14 -0700116 } else if (desiredScale >= 0.8125) {
msarett1c8a5872015-07-07 08:50:01 -0700117 num = 7;
msarettfdb47572015-10-13 12:50:14 -0700118 } else if (desiredScale >= 0.6875f) {
msarett1c8a5872015-07-07 08:50:01 -0700119 num = 6;
msarettfdb47572015-10-13 12:50:14 -0700120 } else if (desiredScale >= 0.5625f) {
msarett1c8a5872015-07-07 08:50:01 -0700121 num = 5;
msarettfdb47572015-10-13 12:50:14 -0700122 } else if (desiredScale >= 0.4375f) {
msarett1c8a5872015-07-07 08:50:01 -0700123 num = 4;
msarettfdb47572015-10-13 12:50:14 -0700124 } else if (desiredScale >= 0.3125f) {
msarett1c8a5872015-07-07 08:50:01 -0700125 num = 3;
msarettfdb47572015-10-13 12:50:14 -0700126 } else if (desiredScale >= 0.1875f) {
msarett1c8a5872015-07-07 08:50:01 -0700127 num = 2;
msarette16b04a2015-04-15 07:32:19 -0700128 } else {
msarett1c8a5872015-07-07 08:50:01 -0700129 num = 1;
msarette16b04a2015-04-15 07:32:19 -0700130 }
131
132 // Set up a fake decompress struct in order to use libjpeg to calculate output dimensions
133 jpeg_decompress_struct dinfo;
mtkleinf7aaadb2015-04-16 06:09:27 -0700134 sk_bzero(&dinfo, sizeof(dinfo));
msarette16b04a2015-04-15 07:32:19 -0700135 dinfo.image_width = this->getInfo().width();
136 dinfo.image_height = this->getInfo().height();
msarettfbccb592015-09-01 06:43:41 -0700137 dinfo.global_state = fReadyState;
scroggoe7fc14b2015-10-02 13:14:46 -0700138 calc_output_dimensions(&dinfo, num, denom);
msarette16b04a2015-04-15 07:32:19 -0700139
140 // Return the calculated output dimensions for the given scale
141 return SkISize::Make(dinfo.output_width, dinfo.output_height);
142}
143
scroggob427db12015-08-12 07:24:13 -0700144bool SkJpegCodec::onRewind() {
halcanary96fcdcc2015-08-27 07:41:13 -0700145 JpegDecoderMgr* decoderMgr = nullptr;
146 if (!ReadHeader(this->stream(), nullptr, &decoderMgr)) {
scroggob427db12015-08-12 07:24:13 -0700147 return fDecoderMgr->returnFalse("could not rewind");
msarett97fdea62015-04-29 08:17:15 -0700148 }
halcanary96fcdcc2015-08-27 07:41:13 -0700149 SkASSERT(nullptr != decoderMgr);
scroggob427db12015-08-12 07:24:13 -0700150 fDecoderMgr.reset(decoderMgr);
151 return true;
msarett97fdea62015-04-29 08:17:15 -0700152}
153
154/*
msarett1c8a5872015-07-07 08:50:01 -0700155 * Checks if the conversion between the input image and the requested output
156 * image has been implemented
157 * Sets the output color space
158 */
159bool SkJpegCodec::setOutputColorSpace(const SkImageInfo& dst) {
160 const SkImageInfo& src = this->getInfo();
161
162 // Ensure that the profile type is unchanged
163 if (dst.profileType() != src.profileType()) {
164 return false;
165 }
166
167 // Ensure that the alpha type is opaque
168 if (kOpaque_SkAlphaType != dst.alphaType()) {
169 return false;
170 }
171
172 // Check if we will decode to CMYK because a conversion to RGBA is not supported
173 J_COLOR_SPACE colorSpace = fDecoderMgr->dinfo()->jpeg_color_space;
174 bool isCMYK = JCS_CMYK == colorSpace || JCS_YCCK == colorSpace;
175
176 // Check for valid color types and set the output color space
177 switch (dst.colorType()) {
178 case kN32_SkColorType:
179 if (isCMYK) {
180 fDecoderMgr->dinfo()->out_color_space = JCS_CMYK;
181 } else {
182 // Check the byte ordering of the RGBA color space for the
183 // current platform
benjaminwagneraada3e82015-10-27 09:14:29 -0700184#if defined(SK_PMCOLOR_IS_RGBA)
benjaminwagner6f6bef82015-10-15 08:09:44 -0700185 fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA;
benjaminwagneraada3e82015-10-27 09:14:29 -0700186#else
msarett1c8a5872015-07-07 08:50:01 -0700187 fDecoderMgr->dinfo()->out_color_space = JCS_EXT_BGRA;
188#endif
189 }
190 return true;
191 case kRGB_565_SkColorType:
192 if (isCMYK) {
scroggoef27d892015-10-23 09:29:22 -0700193 fDecoderMgr->dinfo()->out_color_space = JCS_CMYK;
msarett1c8a5872015-07-07 08:50:01 -0700194 } else {
msarett8ff6ca62015-09-18 12:06:04 -0700195 fDecoderMgr->dinfo()->dither_mode = JDITHER_NONE;
msarett1c8a5872015-07-07 08:50:01 -0700196 fDecoderMgr->dinfo()->out_color_space = JCS_RGB565;
197 }
198 return true;
199 case kGray_8_SkColorType:
200 if (isCMYK) {
201 return false;
202 } else {
203 // We will enable decodes to gray even if the image is color because this is
204 // much faster than decoding to color and then converting
205 fDecoderMgr->dinfo()->out_color_space = JCS_GRAYSCALE;
206 }
207 return true;
208 default:
209 return false;
210 }
211}
212
213/*
emmaleer8f4ba762015-08-14 07:44:46 -0700214 * Checks if we can natively scale to the requested dimensions and natively scales the
215 * dimensions if possible
msarett97fdea62015-04-29 08:17:15 -0700216 */
scroggoe7fc14b2015-10-02 13:14:46 -0700217bool SkJpegCodec::onDimensionsSupported(const SkISize& size) {
218 if (setjmp(fDecoderMgr->getJmpBuf())) {
219 return fDecoderMgr->returnFalse("onDimensionsSupported/setjmp");
220 }
221
222 const unsigned int dstWidth = size.width();
223 const unsigned int dstHeight = size.height();
224
225 // Set up a fake decompress struct in order to use libjpeg to calculate output dimensions
226 // FIXME: Why is this necessary?
227 jpeg_decompress_struct dinfo;
228 sk_bzero(&dinfo, sizeof(dinfo));
229 dinfo.image_width = this->getInfo().width();
230 dinfo.image_height = this->getInfo().height();
231 dinfo.global_state = fReadyState;
232
msarett1c8a5872015-07-07 08:50:01 -0700233 // libjpeg-turbo can scale to 1/8, 1/4, 3/8, 1/2, 5/8, 3/4, 7/8, and 1/1
scroggoe7fc14b2015-10-02 13:14:46 -0700234 unsigned int num = 8;
235 const unsigned int denom = 8;
236 calc_output_dimensions(&dinfo, num, denom);
237 while (dinfo.output_width != dstWidth || dinfo.output_height != dstHeight) {
msarett97fdea62015-04-29 08:17:15 -0700238
239 // Return a failure if we have tried all of the possible scales
scroggoe7fc14b2015-10-02 13:14:46 -0700240 if (1 == num || dstWidth > dinfo.output_width || dstHeight > dinfo.output_height) {
emmaleer8f4ba762015-08-14 07:44:46 -0700241 return false;
msarett97fdea62015-04-29 08:17:15 -0700242 }
243
244 // Try the next scale
scroggoe7fc14b2015-10-02 13:14:46 -0700245 num -= 1;
246 calc_output_dimensions(&dinfo, num, denom);
msarett97fdea62015-04-29 08:17:15 -0700247 }
scroggoe7fc14b2015-10-02 13:14:46 -0700248
249 fDecoderMgr->dinfo()->scale_num = num;
250 fDecoderMgr->dinfo()->scale_denom = denom;
msarett97fdea62015-04-29 08:17:15 -0700251 return true;
252}
253
254/*
msarette16b04a2015-04-15 07:32:19 -0700255 * Performs the jpeg decode
256 */
257SkCodec::Result SkJpegCodec::onGetPixels(const SkImageInfo& dstInfo,
258 void* dst, size_t dstRowBytes,
msarette6dd0042015-10-09 11:07:34 -0700259 const Options& options, SkPMColor*, int*,
260 int* rowsDecoded) {
scroggob636b452015-07-22 07:16:20 -0700261 if (options.fSubset) {
262 // Subsets are not supported.
263 return kUnimplemented;
264 }
265
msarette16b04a2015-04-15 07:32:19 -0700266 // Get a pointer to the decompress info since we will use it quite frequently
267 jpeg_decompress_struct* dinfo = fDecoderMgr->dinfo();
268
269 // Set the jump location for libjpeg errors
270 if (setjmp(fDecoderMgr->getJmpBuf())) {
271 return fDecoderMgr->returnFailure("setjmp", kInvalidInput);
272 }
273
msarett1c8a5872015-07-07 08:50:01 -0700274 // Check if we can decode to the requested destination and set the output color space
275 if (!this->setOutputColorSpace(dstInfo)) {
msarette16b04a2015-04-15 07:32:19 -0700276 return fDecoderMgr->returnFailure("conversion_possible", kInvalidConversion);
277 }
msarette16b04a2015-04-15 07:32:19 -0700278
msarette16b04a2015-04-15 07:32:19 -0700279 // Now, given valid output dimensions, we can start the decompress
msarettfbccb592015-09-01 06:43:41 -0700280 if (!jpeg_start_decompress(dinfo)) {
msarette16b04a2015-04-15 07:32:19 -0700281 return fDecoderMgr->returnFailure("startDecompress", kInvalidInput);
282 }
283
msarett1c8a5872015-07-07 08:50:01 -0700284 // The recommended output buffer height should always be 1 in high quality modes.
285 // If it's not, we want to know because it means our strategy is not optimal.
286 SkASSERT(1 == dinfo->rec_outbuf_height);
msarette16b04a2015-04-15 07:32:19 -0700287
scroggoef27d892015-10-23 09:29:22 -0700288 if (JCS_CMYK == dinfo->out_color_space) {
289 this->initializeSwizzler(dstInfo, options);
290 }
291
msarett1c8a5872015-07-07 08:50:01 -0700292 // Perform the decode a single row at a time
msarett97fdea62015-04-29 08:17:15 -0700293 uint32_t dstHeight = dstInfo.height();
scroggoef27d892015-10-23 09:29:22 -0700294
295 JSAMPLE* dstRow;
296 if (fSwizzler) {
297 // write data to storage row, then sample using swizzler
298 dstRow = fSrcRow;
299 } else {
300 // write data directly to dst
301 dstRow = (JSAMPLE*) dst;
302 }
303
msarett1c8a5872015-07-07 08:50:01 -0700304 for (uint32_t y = 0; y < dstHeight; y++) {
msarette16b04a2015-04-15 07:32:19 -0700305 // Read rows of the image
msarette6dd0042015-10-09 11:07:34 -0700306 uint32_t lines = jpeg_read_scanlines(dinfo, &dstRow, 1);
msarette16b04a2015-04-15 07:32:19 -0700307
308 // If we cannot read enough rows, assume the input is incomplete
msarette6dd0042015-10-09 11:07:34 -0700309 if (lines != 1) {
310 *rowsDecoded = y;
msarette16b04a2015-04-15 07:32:19 -0700311
msarette16b04a2015-04-15 07:32:19 -0700312 return fDecoderMgr->returnFailure("Incomplete image data", kIncompleteInput);
313 }
msarett1c8a5872015-07-07 08:50:01 -0700314
scroggoef27d892015-10-23 09:29:22 -0700315 if (fSwizzler) {
316 // use swizzler to sample row
317 fSwizzler->swizzle(dst, dstRow);
318 dst = SkTAddOffset<JSAMPLE>(dst, dstRowBytes);
319 } else {
320 dstRow = SkTAddOffset<JSAMPLE>(dstRow, dstRowBytes);
msarett1c8a5872015-07-07 08:50:01 -0700321 }
msarette16b04a2015-04-15 07:32:19 -0700322 }
msarette16b04a2015-04-15 07:32:19 -0700323
324 return kSuccess;
325}
msarett97fdea62015-04-29 08:17:15 -0700326
msarettfdb47572015-10-13 12:50:14 -0700327void SkJpegCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options& options) {
msarettf724b992015-10-15 06:41:06 -0700328 SkSwizzler::SrcConfig srcConfig = SkSwizzler::kUnknown;
scroggoef27d892015-10-23 09:29:22 -0700329 if (JCS_CMYK == fDecoderMgr->dinfo()->out_color_space) {
330 srcConfig = SkSwizzler::kCMYK;
331 } else {
332 switch (dstInfo.colorType()) {
333 case kGray_8_SkColorType:
334 srcConfig = SkSwizzler::kGray;
335 break;
336 case kRGBA_8888_SkColorType:
337 srcConfig = SkSwizzler::kRGBX;
338 break;
339 case kBGRA_8888_SkColorType:
340 srcConfig = SkSwizzler::kBGRX;
341 break;
342 case kRGB_565_SkColorType:
343 srcConfig = SkSwizzler::kRGB_565;
344 break;
345 default:
346 // This function should only be called if the colorType is supported by jpeg
scroggoef27d892015-10-23 09:29:22 -0700347 SkASSERT(false);
scroggoef27d892015-10-23 09:29:22 -0700348 }
emmaleer8f4ba762015-08-14 07:44:46 -0700349 }
350
msarettfdb47572015-10-13 12:50:14 -0700351 fSwizzler.reset(SkSwizzler::CreateSwizzler(srcConfig, nullptr, dstInfo, options));
scroggoe7fc14b2015-10-02 13:14:46 -0700352 fStorage.reset(get_row_bytes(fDecoderMgr->dinfo()));
353 fSrcRow = static_cast<uint8_t*>(fStorage.get());
msarettfdb47572015-10-13 12:50:14 -0700354}
355
356SkSampler* SkJpegCodec::getSampler(bool createIfNecessary) {
357 if (!createIfNecessary || fSwizzler) {
358 SkASSERT(!fSwizzler || (fSrcRow && static_cast<uint8_t*>(fStorage.get()) == fSrcRow));
359 return fSwizzler;
360 }
361
362 this->initializeSwizzler(this->dstInfo(), this->options());
scroggoe7fc14b2015-10-02 13:14:46 -0700363 return fSwizzler;
scroggo46c57472015-09-30 08:57:13 -0700364}
scroggo1c005e42015-08-04 09:24:45 -0700365
scroggo46c57472015-09-30 08:57:13 -0700366SkCodec::Result SkJpegCodec::onStartScanlineDecode(const SkImageInfo& dstInfo,
367 const Options& options, SkPMColor ctable[], int* ctableCount) {
scroggo46c57472015-09-30 08:57:13 -0700368 // Set the jump location for libjpeg errors
369 if (setjmp(fDecoderMgr->getJmpBuf())) {
370 SkCodecPrintf("setjmp: Error from libjpeg\n");
371 return kInvalidInput;
372 }
373
374 // Check if we can decode to the requested destination and set the output color space
375 if (!this->setOutputColorSpace(dstInfo)) {
376 return kInvalidConversion;
377 }
378
scroggoe7fc14b2015-10-02 13:14:46 -0700379 // Remove objects used for sampling.
380 fSwizzler.reset(nullptr);
381 fSrcRow = nullptr;
382 fStorage.free();
scroggo46c57472015-09-30 08:57:13 -0700383
384 // Now, given valid output dimensions, we can start the decompress
385 if (!jpeg_start_decompress(fDecoderMgr->dinfo())) {
386 SkCodecPrintf("start decompress failed\n");
387 return kInvalidInput;
388 }
389
scroggoef27d892015-10-23 09:29:22 -0700390 // We will need a swizzler if we are performing a subset decode or
391 // converting from CMYK.
392 if (options.fSubset || JCS_CMYK == fDecoderMgr->dinfo()->out_color_space) {
msarettfdb47572015-10-13 12:50:14 -0700393 this->initializeSwizzler(dstInfo, options);
394 }
395
scroggo46c57472015-09-30 08:57:13 -0700396 return kSuccess;
397}
398
msarette6dd0042015-10-09 11:07:34 -0700399int SkJpegCodec::onGetScanlines(void* dst, int count, size_t rowBytes) {
scroggo46c57472015-09-30 08:57:13 -0700400 // Set the jump location for libjpeg errors
401 if (setjmp(fDecoderMgr->getJmpBuf())) {
402 return fDecoderMgr->returnFailure("setjmp", kInvalidInput);
403 }
404 // Read rows one at a time
405 JSAMPLE* dstRow;
406 if (fSwizzler) {
msarettfdb47572015-10-13 12:50:14 -0700407 // write data to storage row, then sample using swizzler
scroggo46c57472015-09-30 08:57:13 -0700408 dstRow = fSrcRow;
409 } else {
410 // write data directly to dst
411 dstRow = (JSAMPLE*) dst;
412 }
413
414 for (int y = 0; y < count; y++) {
415 // Read row of the image
416 uint32_t rowsDecoded = jpeg_read_scanlines(fDecoderMgr->dinfo(), &dstRow, 1);
417 if (rowsDecoded != 1) {
scroggo46c57472015-09-30 08:57:13 -0700418 fDecoderMgr->dinfo()->output_scanline = this->dstInfo().height();
msarette6dd0042015-10-09 11:07:34 -0700419 return y;
scroggo1c005e42015-08-04 09:24:45 -0700420 }
421
scroggoef27d892015-10-23 09:29:22 -0700422 if (fSwizzler) {
scroggo46c57472015-09-30 08:57:13 -0700423 // use swizzler to sample row
424 fSwizzler->swizzle(dst, dstRow);
425 dst = SkTAddOffset<JSAMPLE>(dst, rowBytes);
emmaleer8f4ba762015-08-14 07:44:46 -0700426 } else {
scroggo46c57472015-09-30 08:57:13 -0700427 dstRow = SkTAddOffset<JSAMPLE>(dstRow, rowBytes);
scroggo1c005e42015-08-04 09:24:45 -0700428 }
scroggo1c005e42015-08-04 09:24:45 -0700429 }
msarette6dd0042015-10-09 11:07:34 -0700430 return count;
scroggo46c57472015-09-30 08:57:13 -0700431}
msarett97fdea62015-04-29 08:17:15 -0700432
msarett1c8a5872015-07-07 08:50:01 -0700433#ifndef TURBO_HAS_SKIP
msarettf724b992015-10-15 06:41:06 -0700434// TODO (msarett): Avoid reallocating the memory buffer on each call to skip.
benjaminwagner6f6bef82015-10-15 08:09:44 -0700435static uint32_t jpeg_skip_scanlines(jpeg_decompress_struct* dinfo, int count) {
msarettf724b992015-10-15 06:41:06 -0700436 SkAutoMalloc storage(get_row_bytes(dinfo));
437 uint8_t* storagePtr = static_cast<uint8_t*>(storage.get());
438 for (int y = 0; y < count; y++) {
439 if (1 != jpeg_read_scanlines(dinfo, &storagePtr, 1)) {
440 return y;
441 }
msarett1c8a5872015-07-07 08:50:01 -0700442 }
msarettf724b992015-10-15 06:41:06 -0700443 return count;
444}
msarett1c8a5872015-07-07 08:50:01 -0700445#endif
446
msarette6dd0042015-10-09 11:07:34 -0700447bool SkJpegCodec::onSkipScanlines(int count) {
scroggo46c57472015-09-30 08:57:13 -0700448 // Set the jump location for libjpeg errors
449 if (setjmp(fDecoderMgr->getJmpBuf())) {
msarette6dd0042015-10-09 11:07:34 -0700450 return fDecoderMgr->returnFalse("setjmp");
msarett97fdea62015-04-29 08:17:15 -0700451 }
452
msarettf724b992015-10-15 06:41:06 -0700453 return (uint32_t) count == jpeg_skip_scanlines(fDecoderMgr->dinfo(), count);
msarett97fdea62015-04-29 08:17:15 -0700454}