Chromium Code Reviews| 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 |