OLD | NEW |
---|---|
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 307 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
318 fDecoderMgr->dinfo()->scale_num = num; | 318 fDecoderMgr->dinfo()->scale_num = num; |
319 fDecoderMgr->dinfo()->scale_denom = denom; | 319 fDecoderMgr->dinfo()->scale_denom = denom; |
320 return true; | 320 return true; |
321 } | 321 } |
322 | 322 |
323 /* | 323 /* |
324 * Performs the jpeg decode | 324 * Performs the jpeg decode |
325 */ | 325 */ |
326 SkCodec::Result SkJpegCodec::onGetPixels(const SkImageInfo& dstInfo, | 326 SkCodec::Result SkJpegCodec::onGetPixels(const SkImageInfo& dstInfo, |
327 void* dst, size_t dstRowBytes, | 327 void* dst, size_t dstRowBytes, |
328 const Options& options, SkPMColor*, int *) { | 328 const Options& options, SkPMColor*, int *, |
329 int* rowsDecoded) { | |
329 if (options.fSubset) { | 330 if (options.fSubset) { |
330 // Subsets are not supported. | 331 // Subsets are not supported. |
331 return kUnimplemented; | 332 return kUnimplemented; |
332 } | 333 } |
333 | 334 |
334 // Get a pointer to the decompress info since we will use it quite frequentl y | 335 // Get a pointer to the decompress info since we will use it quite frequentl y |
335 jpeg_decompress_struct* dinfo = fDecoderMgr->dinfo(); | 336 jpeg_decompress_struct* dinfo = fDecoderMgr->dinfo(); |
336 | 337 |
337 // Set the jump location for libjpeg errors | 338 // Set the jump location for libjpeg errors |
338 if (setjmp(fDecoderMgr->getJmpBuf())) { | 339 if (setjmp(fDecoderMgr->getJmpBuf())) { |
339 return fDecoderMgr->returnFailure("setjmp", kInvalidInput); | 340 return fDecoderMgr->returnFailure("setjmp", kInvalidInput); |
340 } | 341 } |
341 | 342 |
342 // Check if we can decode to the requested destination and set the output co lor space | 343 // Check if we can decode to the requested destination and set the output co lor space |
343 if (!this->setOutputColorSpace(dstInfo)) { | 344 if (!this->setOutputColorSpace(dstInfo)) { |
344 return fDecoderMgr->returnFailure("conversion_possible", kInvalidConvers ion); | 345 return fDecoderMgr->returnFailure("conversion_possible", kInvalidConvers ion); |
345 } | 346 } |
347 fDstInfo = dstInfo; | |
346 | 348 |
347 // Now, given valid output dimensions, we can start the decompress | 349 // Now, given valid output dimensions, we can start the decompress |
348 if (!jpeg_start_decompress(dinfo)) { | 350 if (!jpeg_start_decompress(dinfo)) { |
349 return fDecoderMgr->returnFailure("startDecompress", kInvalidInput); | 351 return fDecoderMgr->returnFailure("startDecompress", kInvalidInput); |
350 } | 352 } |
351 | 353 |
352 // The recommended output buffer height should always be 1 in high quality m odes. | 354 // The recommended output buffer height should always be 1 in high quality m odes. |
353 // If it's not, we want to know because it means our strategy is not optimal . | 355 // If it's not, we want to know because it means our strategy is not optimal . |
354 SkASSERT(1 == dinfo->rec_outbuf_height); | 356 SkASSERT(1 == dinfo->rec_outbuf_height); |
355 | 357 |
356 // Perform the decode a single row at a time | 358 // Perform the decode a single row at a time |
357 uint32_t dstHeight = dstInfo.height(); | 359 uint32_t dstHeight = dstInfo.height(); |
358 JSAMPLE* dstRow = (JSAMPLE*) dst; | 360 JSAMPLE* dstRow = (JSAMPLE*) dst; |
359 for (uint32_t y = 0; y < dstHeight; y++) { | 361 for (uint32_t y = 0; y < dstHeight; y++) { |
360 // Read rows of the image | 362 // Read rows of the image |
361 uint32_t rowsDecoded = jpeg_read_scanlines(dinfo, &dstRow, 1); | 363 uint32_t lines = jpeg_read_scanlines(dinfo, &dstRow, 1); |
362 | 364 |
363 // If we cannot read enough rows, assume the input is incomplete | 365 // If we cannot read enough rows, assume the input is incomplete |
364 if (rowsDecoded != 1) { | 366 if (lines != 1) { |
365 // Fill the remainder of the image with black. This error handling | 367 *rowsDecoded = y; |
366 // behavior is unspecified but SkCodec consistently uses black as | |
367 // the fill color for opaque images. If the destination is kGray, | |
368 // the low 8 bits of SK_ColorBLACK will be used. Conveniently, | |
369 // these are zeros, which is the representation for black in kGray. | |
370 // If the destination is kRGB_565, the low 16 bits of SK_ColorBLACK | |
371 // will be used. Conveniently, these are zeros, which is the | |
372 // representation for black in kRGB_565. | |
373 SkSwizzler::Fill(dstRow, dstInfo, dstRowBytes, dstHeight - y, | |
374 SK_ColorBLACK, nullptr, options.fZeroInitialized); | |
375 | 368 |
376 return fDecoderMgr->returnFailure("Incomplete image data", kIncomple teInput); | 369 return fDecoderMgr->returnFailure("Incomplete image data", kIncomple teInput); |
377 } | 370 } |
378 | 371 |
379 // Convert to RGBA if necessary | 372 // Convert to RGBA if necessary |
380 if (JCS_CMYK == dinfo->out_color_space) { | 373 if (JCS_CMYK == dinfo->out_color_space) { |
381 convert_CMYK_to_RGBA(dstRow, dstInfo.width()); | 374 convert_CMYK_to_RGBA(dstRow, dstInfo.width()); |
382 } | 375 } |
383 | 376 |
384 // Move to the next row | 377 // Move to the next row |
385 dstRow = SkTAddOffset<JSAMPLE>(dstRow, dstRowBytes); | 378 dstRow = SkTAddOffset<JSAMPLE>(dstRow, dstRowBytes); |
386 } | 379 } |
387 | 380 |
388 return kSuccess; | 381 return kSuccess; |
389 } | 382 } |
390 | 383 |
391 SkSampler* SkJpegCodec::getSampler() { | 384 SkSampler* SkJpegCodec::getSampler() { |
392 if (fSwizzler) { | 385 if (fSwizzler) { |
393 SkASSERT(fSrcRow && static_cast<uint8_t*>(fStorage.get()) == fSrcRow); | 386 SkASSERT(fSrcRow && static_cast<uint8_t*>(fStorage.get()) == fSrcRow); |
394 return fSwizzler; | 387 return fSwizzler; |
395 } | 388 } |
396 | 389 |
397 const SkImageInfo& info = this->dstInfo(); | |
398 SkSwizzler::SrcConfig srcConfig; | 390 SkSwizzler::SrcConfig srcConfig; |
399 switch (info.colorType()) { | 391 switch (fDstInfo.colorType()) { |
400 case kGray_8_SkColorType: | 392 case kGray_8_SkColorType: |
401 srcConfig = SkSwizzler::kGray; | 393 srcConfig = SkSwizzler::kGray; |
402 break; | 394 break; |
403 case kRGBA_8888_SkColorType: | 395 case kRGBA_8888_SkColorType: |
404 srcConfig = SkSwizzler::kRGBX; | 396 srcConfig = SkSwizzler::kRGBX; |
405 break; | 397 break; |
406 case kBGRA_8888_SkColorType: | 398 case kBGRA_8888_SkColorType: |
407 srcConfig = SkSwizzler::kBGRX; | 399 srcConfig = SkSwizzler::kBGRX; |
408 break; | 400 break; |
409 case kRGB_565_SkColorType: | 401 case kRGB_565_SkColorType: |
410 srcConfig = SkSwizzler::kRGB_565; | 402 srcConfig = SkSwizzler::kRGB_565; |
411 break; | 403 break; |
412 default: | 404 default: |
413 // This function should only be called if the colorType is supported by jpeg | 405 // This function should only be called if the colorType is supported by jpeg |
414 SkASSERT(false); | 406 SkASSERT(false); |
415 } | 407 } |
416 | 408 |
417 fSwizzler.reset(SkSwizzler::CreateSwizzler(srcConfig, nullptr, info, | 409 fSwizzler.reset(SkSwizzler::CreateSwizzler(srcConfig, nullptr, fDstInfo, |
scroggo
2015/10/07 16:04:24
After SkScaledCodec calls this, it will modify the
msarett
2015/10/07 17:40:41
That's correct.
The point of fDstInfo was to ensu
| |
418 this->options().fZeroInitialized) ); | 410 this->options().fZeroInitialized) ); |
419 if (!fSwizzler) { | 411 if (!fSwizzler) { |
420 return nullptr; | 412 return nullptr; |
421 } | 413 } |
422 | 414 |
423 fStorage.reset(get_row_bytes(fDecoderMgr->dinfo())); | 415 fStorage.reset(get_row_bytes(fDecoderMgr->dinfo())); |
424 fSrcRow = static_cast<uint8_t*>(fStorage.get()); | 416 fSrcRow = static_cast<uint8_t*>(fStorage.get()); |
425 return fSwizzler; | 417 return fSwizzler; |
426 } | 418 } |
427 | 419 |
428 SkCodec::Result SkJpegCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, | 420 SkCodec::Result SkJpegCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, |
429 const Options& options, SkPMColor ctable[], int* ctableCount) { | 421 const Options& options, SkPMColor ctable[], int* ctableCount) { |
430 // Set the jump location for libjpeg errors | 422 // Set the jump location for libjpeg errors |
431 if (setjmp(fDecoderMgr->getJmpBuf())) { | 423 if (setjmp(fDecoderMgr->getJmpBuf())) { |
432 SkCodecPrintf("setjmp: Error from libjpeg\n"); | 424 SkCodecPrintf("setjmp: Error from libjpeg\n"); |
433 return kInvalidInput; | 425 return kInvalidInput; |
434 } | 426 } |
435 | 427 |
436 // Check if we can decode to the requested destination and set the output co lor space | 428 // Check if we can decode to the requested destination and set the output co lor space |
437 if (!this->setOutputColorSpace(dstInfo)) { | 429 if (!this->setOutputColorSpace(dstInfo)) { |
438 return kInvalidConversion; | 430 return kInvalidConversion; |
439 } | 431 } |
440 | 432 |
441 // Remove objects used for sampling. | 433 // Remove objects used for sampling. |
442 fSwizzler.reset(nullptr); | 434 fSwizzler.reset(nullptr); |
443 fSrcRow = nullptr; | 435 fSrcRow = nullptr; |
444 fStorage.free(); | 436 fStorage.free(); |
437 fDstInfo = dstInfo; | |
445 | 438 |
446 // Now, given valid output dimensions, we can start the decompress | 439 // Now, given valid output dimensions, we can start the decompress |
447 if (!jpeg_start_decompress(fDecoderMgr->dinfo())) { | 440 if (!jpeg_start_decompress(fDecoderMgr->dinfo())) { |
448 SkCodecPrintf("start decompress failed\n"); | 441 SkCodecPrintf("start decompress failed\n"); |
449 return kInvalidInput; | 442 return kInvalidInput; |
450 } | 443 } |
451 | 444 |
452 return kSuccess; | 445 return kSuccess; |
453 } | 446 } |
454 | 447 |
455 SkCodec::Result SkJpegCodec::onGetScanlines(void* dst, int count, size_t rowByte s) { | 448 int SkJpegCodec::onGetScanlines(void* dst, int count, size_t rowBytes) { |
456 // Set the jump location for libjpeg errors | 449 // Set the jump location for libjpeg errors |
457 if (setjmp(fDecoderMgr->getJmpBuf())) { | 450 if (setjmp(fDecoderMgr->getJmpBuf())) { |
458 return fDecoderMgr->returnFailure("setjmp", kInvalidInput); | 451 return fDecoderMgr->returnFailure("setjmp", kInvalidInput); |
459 } | 452 } |
460 // Read rows one at a time | 453 // Read rows one at a time |
461 JSAMPLE* dstRow; | 454 JSAMPLE* dstRow; |
462 if (fSwizzler) { | 455 if (fSwizzler) { |
463 // write data to storage row, then sample using swizzler | 456 // write data to storage row, then sample using swizzler |
464 dstRow = fSrcRow; | 457 dstRow = fSrcRow; |
465 } else { | 458 } else { |
466 // write data directly to dst | 459 // write data directly to dst |
467 dstRow = (JSAMPLE*) dst; | 460 dstRow = (JSAMPLE*) dst; |
468 } | 461 } |
469 | 462 |
470 for (int y = 0; y < count; y++) { | 463 for (int y = 0; y < count; y++) { |
471 // Read row of the image | 464 // Read row of the image |
472 uint32_t rowsDecoded = jpeg_read_scanlines(fDecoderMgr->dinfo(), &dstRow , 1); | 465 uint32_t rowsDecoded = jpeg_read_scanlines(fDecoderMgr->dinfo(), &dstRow , 1); |
473 if (rowsDecoded != 1) { | 466 if (rowsDecoded != 1) { |
474 SkSwizzler::Fill(dstRow, this->dstInfo(), rowBytes, count - y, | |
475 SK_ColorBLACK, nullptr, this->options().fZeroInitialized ); | |
476 fDecoderMgr->dinfo()->output_scanline = this->dstInfo().height(); | 467 fDecoderMgr->dinfo()->output_scanline = this->dstInfo().height(); |
477 return kIncompleteInput; | 468 return y; |
478 } | 469 } |
479 | 470 |
480 // Convert to RGBA if necessary | 471 // Convert to RGBA if necessary |
481 if (JCS_CMYK == fDecoderMgr->dinfo()->out_color_space) { | 472 if (JCS_CMYK == fDecoderMgr->dinfo()->out_color_space) { |
482 convert_CMYK_to_RGBA(dstRow, fDecoderMgr->dinfo()->output_width); | 473 convert_CMYK_to_RGBA(dstRow, fDecoderMgr->dinfo()->output_width); |
483 } | 474 } |
484 | 475 |
485 if(fSwizzler) { | 476 if(fSwizzler) { |
486 // use swizzler to sample row | 477 // use swizzler to sample row |
487 fSwizzler->swizzle(dst, dstRow); | 478 fSwizzler->swizzle(dst, dstRow); |
488 dst = SkTAddOffset<JSAMPLE>(dst, rowBytes); | 479 dst = SkTAddOffset<JSAMPLE>(dst, rowBytes); |
489 } else { | 480 } else { |
490 dstRow = SkTAddOffset<JSAMPLE>(dstRow, rowBytes); | 481 dstRow = SkTAddOffset<JSAMPLE>(dstRow, rowBytes); |
491 } | 482 } |
492 } | 483 } |
493 return kSuccess; | 484 return count; |
494 } | 485 } |
495 | 486 |
496 #ifndef TURBO_HAS_SKIP | 487 #ifndef TURBO_HAS_SKIP |
497 // TODO (msarett): Make this a member function and avoid reallocating the | 488 // TODO (msarett): Make this a member function and avoid reallocating the |
498 // memory buffer on each call to skip. | 489 // memory buffer on each call to skip. |
499 #define jpeg_skip_scanlines(dinfo, count) \ | 490 #define jpeg_skip_scanlines(dinfo, count) \ |
500 SkAutoMalloc storage(get_row_bytes(dinfo)); \ | 491 SkAutoMalloc storage(get_row_bytes(dinfo)); \ |
501 uint8_t* storagePtr = static_cast<uint8_t*>(storage.get()); \ | 492 uint8_t* storagePtr = static_cast<uint8_t*>(storage.get()); \ |
502 for (int y = 0; y < count; y++) { \ | 493 for (int y = 0; y < count; y++) { \ |
503 jpeg_read_scanlines(dinfo, &storagePtr, 1); \ | 494 jpeg_read_scanlines(dinfo, &storagePtr, 1); \ |
504 } | 495 } |
505 #endif | 496 #endif |
506 | 497 |
507 SkCodec::Result SkJpegCodec::onSkipScanlines(int count) { | 498 bool SkJpegCodec::onSkipScanlines(int count) { |
508 // Set the jump location for libjpeg errors | 499 // Set the jump location for libjpeg errors |
509 if (setjmp(fDecoderMgr->getJmpBuf())) { | 500 if (setjmp(fDecoderMgr->getJmpBuf())) { |
510 return fDecoderMgr->returnFailure("setjmp", kInvalidInput); | 501 return fDecoderMgr->returnFailure("setjmp", kInvalidInput); |
511 } | 502 } |
512 | 503 |
513 jpeg_skip_scanlines(fDecoderMgr->dinfo(), count); | 504 return count == jpeg_skip_scanlines(fDecoderMgr->dinfo(), count); |
514 | |
515 return kSuccess; | |
516 } | 505 } |
517 | |
OLD | NEW |