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

Side by Side Diff: src/codec/SkJpegCodec.cpp

Issue 1092303003: Scanline decoding for jpeg (Closed) Base URL: https://skia.googlesource.com/skia.git@index-scanline
Patch Set: Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright 2015 Google Inc. 2 * Copyright 2015 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "SkCodec.h" 8 #include "SkCodec.h"
9 #include "SkJpegCodec.h" 9 #include "SkJpegCodec.h"
10 #include "SkJpegDecoderMgr.h" 10 #include "SkJpegDecoderMgr.h"
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
54 } 54 }
55 return SkSwizzler::kUnknown; 55 return SkSwizzler::kUnknown;
56 } 56 }
57 57
58 /* 58 /*
59 * Convert a row of CMYK samples to RGBX in place. 59 * Convert a row of CMYK samples to RGBX in place.
60 * Note that this method moves the row pointer. 60 * Note that this method moves the row pointer.
61 * @param width the number of pixels in the row that is being converted 61 * @param width the number of pixels in the row that is being converted
62 * CMYK is stored as four bytes per pixel 62 * CMYK is stored as four bytes per pixel
63 */ 63 */
64 static void convert_CMYK_to_RGB(uint8_t* row, uint32_t width) { 64 static void convert_CMYK_to_RGB(uint8_t* row, size_t rowBytes) {
scroggo 2015/04/24 13:14:28 It seems very weird to me to pass rowBytes here. W
msarett 2015/04/24 15:08:44 Yeah you are absolutely right. I made the change
65 // We will implement a crude conversion from CMYK -> RGB using formulas 65 // We will implement a crude conversion from CMYK -> RGB using formulas
66 // from easyrgb.com. 66 // from easyrgb.com.
67 // 67 //
68 // CMYK -> CMY 68 // CMYK -> CMY
69 // C = C * (1 - K) + K 69 // C = C * (1 - K) + K
70 // M = M * (1 - K) + K 70 // M = M * (1 - K) + K
71 // Y = Y * (1 - K) + K 71 // Y = Y * (1 - K) + K
72 // 72 //
73 // libjpeg actually gives us inverted CMYK, so we must subtract the 73 // libjpeg actually gives us inverted CMYK, so we must subtract the
74 // original terms from 1. 74 // original terms from 1.
(...skipping 21 matching lines...) Expand all
96 // B = Y * K * 255 96 // B = Y * K * 255
97 // 97 //
98 // As a final note, we have treated the CMYK values as if they were on 98 // As a final note, we have treated the CMYK values as if they were on
99 // a scale from 0-1, when in fact they are 8-bit ints scaling from 0-255. 99 // a scale from 0-1, when in fact they are 8-bit ints scaling from 0-255.
100 // We must divide each CMYK component by 255 to obtain the true conversion 100 // We must divide each CMYK component by 255 to obtain the true conversion
101 // we should perform. 101 // we should perform.
102 // CMYK -> RGB 102 // CMYK -> RGB
103 // R = C * K / 255 103 // R = C * K / 255
104 // G = M * K / 255 104 // G = M * K / 255
105 // B = Y * K / 255 105 // B = Y * K / 255
106 uint32_t width = rowBytes / 4;
106 for (uint32_t x = 0; x < width; x++, row += 4) { 107 for (uint32_t x = 0; x < width; x++, row += 4) {
107 row[0] = SkMulDiv255Round(row[0], row[3]); 108 row[0] = SkMulDiv255Round(row[0], row[3]);
108 row[1] = SkMulDiv255Round(row[1], row[3]); 109 row[1] = SkMulDiv255Round(row[1], row[3]);
109 row[2] = SkMulDiv255Round(row[2], row[3]); 110 row[2] = SkMulDiv255Round(row[2], row[3]);
110 row[3] = 0xFF; 111 row[3] = 0xFF;
111 } 112 }
112 } 113 }
113 114
114 bool SkJpegCodec::IsJpeg(SkStream* stream) { 115 bool SkJpegCodec::IsJpeg(SkStream* stream) {
115 static const uint8_t jpegSig[] = { 0xFF, 0xD8, 0xFF }; 116 static const uint8_t jpegSig[] = { 0xFF, 0xD8, 0xFF };
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
161 streamDeleter.detach(); 162 streamDeleter.detach();
162 return codec; 163 return codec;
163 } 164 }
164 return NULL; 165 return NULL;
165 } 166 }
166 167
167 SkJpegCodec::SkJpegCodec(const SkImageInfo& srcInfo, SkStream* stream, 168 SkJpegCodec::SkJpegCodec(const SkImageInfo& srcInfo, SkStream* stream,
168 JpegDecoderMgr* decoderMgr) 169 JpegDecoderMgr* decoderMgr)
169 : INHERITED(srcInfo, stream) 170 : INHERITED(srcInfo, stream)
170 , fDecoderMgr(decoderMgr) 171 , fDecoderMgr(decoderMgr)
172 , fSwizzler(NULL)
173 , fSrcRowBytes(0)
171 {} 174 {}
172 175
173 /* 176 /*
174 * Return a valid set of output dimensions for this decoder, given an input scal e 177 * Return a valid set of output dimensions for this decoder, given an input scal e
175 */ 178 */
176 SkISize SkJpegCodec::onGetScaledDimensions(float desiredScale) const { 179 SkISize SkJpegCodec::onGetScaledDimensions(float desiredScale) const {
177 // libjpeg supports scaling by 1/1, 1/2, 1/4, and 1/8, so we will support th ese as well 180 // libjpeg supports scaling by 1/1, 1/2, 1/4, and 1/8, so we will support th ese as well
178 long scale; 181 long scale;
179 if (desiredScale > 0.75f) { 182 if (desiredScale > 0.75f) {
180 scale = 1; 183 scale = 1;
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
220 // Always allow kN32 as the color type 223 // Always allow kN32 as the color type
221 if (kN32_SkColorType == dst.colorType()) { 224 if (kN32_SkColorType == dst.colorType()) {
222 return true; 225 return true;
223 } 226 }
224 227
225 // Otherwise require that the destination color type match our recommendatio n 228 // Otherwise require that the destination color type match our recommendatio n
226 return dst.colorType() == src.colorType(); 229 return dst.colorType() == src.colorType();
227 } 230 }
228 231
229 /* 232 /*
233 * Handles rewinding the input stream if it is necessary
234 */
235 bool SkJpegCodec::handleRewind() {
236 SkCodec::RewindState rewindState = this->rewindIfNeeded();
237 if (rewindState == kCouldNotRewind_RewindState) {
238 return fDecoderMgr->returnFalse("could not rewind");
239 } else if (rewindState == kRewound_RewindState) {
240 JpegDecoderMgr* decoderMgr = NULL;
241 if (!ReadHeader(this->stream(), NULL, &decoderMgr)) {
242 return fDecoderMgr->returnFalse("could not rewind");
243 }
244 SkASSERT(NULL != decoderMgr);
245 fDecoderMgr.reset(decoderMgr);
246 }
247 return true;
scroggo 2015/04/24 13:14:28 nit: I think this should go inside the else statem
msarett 2015/04/24 15:08:44 Hmmm I'm not quite sure I understand, but let me k
scroggo 2015/04/24 15:23:13 Oh no, I was confused. I like it better the first
msarett 2015/04/24 15:40:13 Done.
248 }
249
250 /*
251 * Checks if we can scale to the requested dimensions and performs the scaling
252 */
253 bool SkJpegCodec::handleScaling(const SkImageInfo& dstInfo) {
scroggo 2015/04/24 13:14:28 You only need width and height here. Why not pass
msarett 2015/04/24 15:08:44 Agreed.
254 // libjpeg can scale to 1/1, 1/2, 1/4, and 1/8
255 SkASSERT(1 == fDecoderMgr->dinfo()->scale_num);
256 SkASSERT(1 == fDecoderMgr->dinfo()->scale_denom);
257 jpeg_calc_output_dimensions(fDecoderMgr->dinfo());
258 const uint32_t dstWidth = dstInfo.width();
259 const uint32_t dstHeight = dstInfo.height();
260 while (fDecoderMgr->dinfo()->output_width != dstWidth ||
261 fDecoderMgr->dinfo()->output_height != dstHeight) {
262
263 // Return a failure if we have tried all of the possible scales
264 if (8 == fDecoderMgr->dinfo()->scale_denom ||
265 dstWidth > fDecoderMgr->dinfo()->output_width ||
266 dstHeight > fDecoderMgr->dinfo()->output_height) {
267 return fDecoderMgr->returnFalse("could not scale to requested dimens ions");
268 }
269
270 // Try the next scale
271 fDecoderMgr->dinfo()->scale_denom *= 2;
272 jpeg_calc_output_dimensions(fDecoderMgr->dinfo());
273 }
274 return true;
275 }
276
277 /*
278 * Create the swizzler based on the encoded format
279 */
280 void SkJpegCodec::initializeSwizzler(const SkImageInfo& dstInfo,
281 void* dst, size_t dstRowBytes,
282 const Options& options) {
283 SkSwizzler::SrcConfig srcConfig = get_src_config(*fDecoderMgr->dinfo());
284 fSwizzler.reset(SkSwizzler::CreateSwizzler(srcConfig, NULL, dstInfo, dst, ds tRowBytes,
285 options.fZeroInitialized));
286 fSrcRowBytes = SkSwizzler::BytesPerPixel(srcConfig) * dstInfo.width();
287 }
288
289 /*
230 * Performs the jpeg decode 290 * Performs the jpeg decode
231 */ 291 */
232 SkCodec::Result SkJpegCodec::onGetPixels(const SkImageInfo& dstInfo, 292 SkCodec::Result SkJpegCodec::onGetPixels(const SkImageInfo& dstInfo,
233 void* dst, size_t dstRowBytes, 293 void* dst, size_t dstRowBytes,
234 const Options& options, SkPMColor*, int *) { 294 const Options& options, SkPMColor*, int *) {
295
235 // Rewind the stream if needed 296 // Rewind the stream if needed
236 SkCodec::RewindState rewindState = this->rewindIfNeeded(); 297 if (!this->handleRewind()) {
237 if (rewindState == kCouldNotRewind_RewindState) { 298 fDecoderMgr->returnFailure("could not rewind stream", kCouldNotRewind);
238 return kCouldNotRewind;
239 } else if (rewindState == kRewound_RewindState) {
240 JpegDecoderMgr* decoderMgr = NULL;
241 if (!ReadHeader(this->stream(), NULL, &decoderMgr)) {
242 return kCouldNotRewind;
243 }
244 SkASSERT(NULL != decoderMgr);
245 fDecoderMgr.reset(decoderMgr);
246 } 299 }
247 300
248 // Get a pointer to the decompress info since we will use it quite frequentl y 301 // Get a pointer to the decompress info since we will use it quite frequentl y
249 jpeg_decompress_struct* dinfo = fDecoderMgr->dinfo(); 302 jpeg_decompress_struct* dinfo = fDecoderMgr->dinfo();
250 303
251 // Set the jump location for libjpeg errors 304 // Set the jump location for libjpeg errors
252 if (setjmp(fDecoderMgr->getJmpBuf())) { 305 if (setjmp(fDecoderMgr->getJmpBuf())) {
253 return fDecoderMgr->returnFailure("setjmp", kInvalidInput); 306 return fDecoderMgr->returnFailure("setjmp", kInvalidInput);
254 } 307 }
255 308
256 // Check if we can decode to the requested destination 309 // Check if we can decode to the requested destination
257 if (!conversion_possible(dstInfo, this->getInfo())) { 310 if (!conversion_possible(dstInfo, this->getInfo())) {
258 return fDecoderMgr->returnFailure("conversion_possible", kInvalidConvers ion); 311 return fDecoderMgr->returnFailure("conversion_possible", kInvalidConvers ion);
259 } 312 }
260 // Check if we can scale to the requested dimensions
261 // libjpeg can scale to 1/1, 1/2, 1/4, and 1/8
262 SkASSERT(1 == dinfo->scale_num);
263 SkASSERT(1 == dinfo->scale_denom);
264 jpeg_calc_output_dimensions(dinfo);
265 const uint32_t dstWidth = dstInfo.width();
266 const uint32_t dstHeight = dstInfo.height();
267 while (dinfo->output_width != dstWidth || dinfo->output_height != dstHeight) {
268 313
269 // Return a failure if we have tried all of the possible scales 314 // Perform the necessary scaling
270 if (8 == dinfo->scale_denom || 315 if (!this->handleScaling(dstInfo)) {
271 dstWidth > dinfo->output_width || 316 fDecoderMgr->returnFailure("cannot scale to requested dims", kInvalidSca le);
272 dstHeight > dinfo->output_height) {
273 return fDecoderMgr->returnFailure("cannot scale to requested dims", kInvalidScale);
274 }
275
276 // Try the next scale
277 dinfo->scale_denom *= 2;
278 jpeg_calc_output_dimensions(dinfo);
279 } 317 }
280 318
281 // Now, given valid output dimensions, we can start the decompress 319 // Now, given valid output dimensions, we can start the decompress
282 if (!jpeg_start_decompress(dinfo)) { 320 if (!jpeg_start_decompress(dinfo)) {
283 return fDecoderMgr->returnFailure("startDecompress", kInvalidInput); 321 return fDecoderMgr->returnFailure("startDecompress", kInvalidInput);
284 } 322 }
285 323
286 // Create the swizzler 324 // Create the swizzler
287 SkSwizzler::SrcConfig srcConfig = get_src_config(*dinfo); 325 this->initializeSwizzler(dstInfo, dst, dstRowBytes, options);
288 SkAutoTDelete<SkSwizzler> swizzler(SkSwizzler::CreateSwizzler(srcConfig, NUL L, dstInfo, dst, 326 if (NULL == fSwizzler) {
289 dstRowBytes, options.fZeroInitialized));
290 if (NULL == swizzler) {
291 return fDecoderMgr->returnFailure("getSwizzler", kInvalidInput); 327 return fDecoderMgr->returnFailure("getSwizzler", kInvalidInput);
scroggo 2015/04/24 13:14:28 This is not new to this change, but I think kInval
msarett 2015/04/24 15:08:44 I think kUnimplemented sounds like the right choic
292 } 328 }
293 const uint32_t srcBytesPerPixel = SkSwizzler::BytesPerPixel(srcConfig);
294 329
295 // This is usually 1, but can also be 2 or 4. 330 // This is usually 1, but can also be 2 or 4.
296 // If we wanted to always read one row at a time, we could, but we will save space and time 331 // If we wanted to always read one row at a time, we could, but we will save space and time
297 // by using the recommendation from libjpeg. 332 // by using the recommendation from libjpeg.
298 const uint32_t rowsPerDecode = dinfo->rec_outbuf_height; 333 const uint32_t rowsPerDecode = dinfo->rec_outbuf_height;
299 SkASSERT(rowsPerDecode <= 4); 334 SkASSERT(rowsPerDecode <= 4);
300 335
301 // Create a buffer to contain decoded rows (libjpeg requires a 2D array) 336 // Create a buffer to contain decoded rows (libjpeg requires a 2D array)
302 const uint32_t srcRowBytes = srcBytesPerPixel * dstWidth; 337 SkAutoTDeleteArray<uint8_t> srcBuffer(SkNEW_ARRAY(uint8_t, fSrcRowBytes * ro wsPerDecode));
scroggo 2015/04/24 13:14:28 Maybe SkASSERT(fSrcRowBytes != 0)
msarett 2015/04/24 15:08:44 Done.
303 SkAutoTDeleteArray<uint8_t> srcBuffer(SkNEW_ARRAY(uint8_t, srcRowBytes * row sPerDecode));
304 JSAMPLE* srcRows[4]; 338 JSAMPLE* srcRows[4];
305 uint8_t* srcPtr = srcBuffer.get(); 339 uint8_t* srcPtr = srcBuffer.get();
306 for (uint8_t i = 0; i < rowsPerDecode; i++) { 340 for (uint8_t i = 0; i < rowsPerDecode; i++) {
307 srcRows[i] = (JSAMPLE*) srcPtr; 341 srcRows[i] = (JSAMPLE*) srcPtr;
308 srcPtr += srcRowBytes; 342 srcPtr += fSrcRowBytes;
309 } 343 }
310 344
311 // Ensure that we loop enough times to decode all of the rows 345 // Ensure that we loop enough times to decode all of the rows
312 // libjpeg will prevent us from reading past the bottom of the image 346 // libjpeg will prevent us from reading past the bottom of the image
347 uint32_t dstHeight = dstInfo.height();
313 for (uint32_t y = 0; y < dstHeight + rowsPerDecode - 1; y += rowsPerDecode) { 348 for (uint32_t y = 0; y < dstHeight + rowsPerDecode - 1; y += rowsPerDecode) {
314 // Read rows of the image 349 // Read rows of the image
315 uint32_t rowsDecoded = jpeg_read_scanlines(dinfo, srcRows, rowsPerDecode ); 350 uint32_t rowsDecoded = jpeg_read_scanlines(dinfo, srcRows, rowsPerDecode );
316 351
317 // Convert to RGB if necessary 352 // Convert to RGB if necessary
318 if (JCS_CMYK == dinfo->out_color_space) { 353 if (JCS_CMYK == dinfo->out_color_space) {
319 convert_CMYK_to_RGB(srcRows[0], dstWidth * rowsDecoded); 354 convert_CMYK_to_RGB(srcRows[0], fSrcRowBytes * rowsDecoded);
320 } 355 }
321 356
322 // Swizzle to output destination 357 // Swizzle to output destination
323 for (uint32_t i = 0; i < rowsDecoded; i++) { 358 for (uint32_t i = 0; i < rowsDecoded; i++) {
324 swizzler->next(srcRows[i]); 359 fSwizzler->next(srcRows[i]);
325 } 360 }
326 361
327 // If we cannot read enough rows, assume the input is incomplete 362 // If we cannot read enough rows, assume the input is incomplete
328 if (rowsDecoded < rowsPerDecode && y + rowsDecoded < dstHeight) { 363 if (rowsDecoded < rowsPerDecode && y + rowsDecoded < dstHeight) {
329 // Fill the remainder of the image with black. This error handling 364 // Fill the remainder of the image with black. This error handling
330 // behavior is unspecified but SkCodec consistently uses black as 365 // behavior is unspecified but SkCodec consistently uses black as
331 // the fill color for opaque images. If the destination is kGray, 366 // the fill color for opaque images. If the destination is kGray,
332 // the low 8 bits of SK_ColorBLACK will be used. Conveniently, 367 // the low 8 bits of SK_ColorBLACK will be used. Conveniently,
333 // these are zeros, which is the representation for black in kGray. 368 // these are zeros, which is the representation for black in kGray.
334 SkSwizzler::Fill(swizzler->getDstRow(), dstInfo, dstRowBytes, 369 SkSwizzler::Fill(fSwizzler->getDstRow(), dstInfo, dstRowBytes,
335 dstHeight - y - rowsDecoded, SK_ColorBLACK, NULL); 370 dstHeight - y - rowsDecoded, SK_ColorBLACK, NULL);
336 371
337 // Prevent libjpeg from failing on incomplete decode 372 // Prevent libjpeg from failing on incomplete decode
338 dinfo->output_scanline = dstHeight; 373 dinfo->output_scanline = dstHeight;
339 374
340 // Finish the decode and indicate that the input was incomplete. 375 // Finish the decode and indicate that the input was incomplete.
341 jpeg_finish_decompress(dinfo); 376 jpeg_finish_decompress(dinfo);
342 return fDecoderMgr->returnFailure("Incomplete image data", kIncomple teInput); 377 return fDecoderMgr->returnFailure("Incomplete image data", kIncomple teInput);
343 } 378 }
344 } 379 }
345 jpeg_finish_decompress(dinfo); 380 jpeg_finish_decompress(dinfo);
346 381
347 return kSuccess; 382 return kSuccess;
348 } 383 }
384
385 /*
386 * Enable scanline decoding for jpegs
387 */
388 class SkJpegScanlineDecoder : public SkScanlineDecoder {
389 public:
390 SkJpegScanlineDecoder(const SkImageInfo& dstInfo, SkJpegCodec* codec)
391 : INHERITED(dstInfo)
392 , fCodec(codec)
393 {
394 fStorage.reset(fCodec->fSrcRowBytes);
395 fSrcRow = static_cast<uint8_t*>(fStorage.get());
396 }
397
398 SkImageGenerator::Result onGetScanlines(void* dst, int count, size_t rowByte s) override {
399 // Set the jump location for libjpeg errors
400 if (setjmp(fCodec->fDecoderMgr->getJmpBuf())) {
401 return fCodec->fDecoderMgr->returnFailure("setjmp", SkImageGenerator ::kInvalidInput);
402 }
403
404 // Read rows one at a time
405 for (int y = 0; y < count; y++) {
406 // Read row of the image
407 uint32_t rowsDecoded = jpeg_read_scanlines(fCodec->fDecoderMgr->dinf o(), &fSrcRow, 1);
msarett 2015/04/22 19:52:21 Here we intentionally decode rows one at a time.
408 if (rowsDecoded != 1) {
409 SkSwizzler::Fill(dst, this->dstInfo(), rowBytes, count - y, SK_C olorBLACK, NULL);
410 return SkImageGenerator::kIncompleteInput;
411 }
412
413 // Convert to RGB if necessary
414 if (JCS_CMYK == fCodec->fDecoderMgr->dinfo()->out_color_space) {
415 convert_CMYK_to_RGB(fSrcRow, fCodec->fSrcRowBytes);
416 }
417
418 // Swizzle to output destination
419 fCodec->fSwizzler->setDstRow(dst);
420 fCodec->fSwizzler->next(fSrcRow);
421 dst = SkTAddOffset<void>(dst, rowBytes);
422 }
423
424 return SkImageGenerator::kSuccess;
425 }
426
427 SkImageGenerator::Result onSkipScanlines(int count) override {
428 // Set the jump location for libjpeg errors
429 if (setjmp(fCodec->fDecoderMgr->getJmpBuf())) {
430 return fCodec->fDecoderMgr->returnFailure("setjmp", SkImageGenerator ::kInvalidInput);
431 }
432
433 // Read rows but ignore the output
434 for (int y = 0; y < count; y++) {
435 jpeg_read_scanlines(fCodec->fDecoderMgr->dinfo(), &fSrcRow, 1);
msarett 2015/04/22 19:52:21 AFAICT there is not a skip function in libjpeg. W
scroggo 2015/04/24 13:14:28 This seems fine to me, until/unless we discover it
436 }
437
438 return SkImageGenerator::kSuccess;
439 }
440
441 void onFinish() override {
442 if (setjmp(fCodec->fDecoderMgr->getJmpBuf())) {
443 SkCodecPrintf("setjmp: Error in libjpeg finish_decompress\n");
444 return;
445 }
446
447 jpeg_finish_decompress(fCodec->fDecoderMgr->dinfo());
448 }
449
450 private:
451 SkJpegCodec* fCodec; // unowned
452 SkAutoMalloc fStorage;
453 uint8_t* fSrcRow;
scroggo 2015/04/24 13:14:28 // pointer into fStorage
msarett 2015/04/24 15:08:44 Done.
454
455 typedef SkScanlineDecoder INHERITED;
456 };
457
458 SkScanlineDecoder* SkJpegCodec::onGetScanlineDecoder(const SkImageInfo& dstInfo,
459 const Options& options, SkPMColor ctable[], int* ctableCount) {
460
461 // Rewind the stream if needed
462 if (!this->handleRewind()) {
463 SkCodecPrintf("Could not rewind\n");
464 return NULL;
465 }
466
467 // Set the jump location for libjpeg errors
468 if (setjmp(fDecoderMgr->getJmpBuf())) {
469 SkCodecPrintf("setjmp: Error from libjpeg\n");
470 return NULL;
471 }
472
473 // Check if we can decode to the requested destination
474 if (!conversion_possible(dstInfo, this->getInfo())) {
475 SkCodecPrintf("Cannot convert to output type\n");
476 return NULL;
477 }
478
479 // Perform the necessary scaling
480 if (!this->handleScaling(dstInfo)) {
481 SkCodecPrintf("Cannot scale ot output dimensions\n");
482 return NULL;
483 }
484
485 // Now, given valid output dimensions, we can start the decompress
486 if (!jpeg_start_decompress(fDecoderMgr->dinfo())) {
487 SkCodecPrintf("start decompress failed\n");
488 return NULL;
489 }
490
491 // Create the swizzler
492 this->initializeSwizzler(dstInfo, NULL, dstInfo.minRowBytes(), options);
493 if (NULL == fSwizzler) {
494 SkCodecPrintf("Could not create swizzler\n");
495 return NULL;
496 }
497
498 // Return the new scanline decoder
499 return SkNEW_ARGS(SkJpegScanlineDecoder, (dstInfo, this));
500 }
OLDNEW
« src/codec/SkJpegCodec.h ('K') | « src/codec/SkJpegCodec.h ('k') | tests/CodexTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698