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

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

Issue 2174493002: Add color space xform support to SkJpegCodec (includes F16!) (Closed) Base URL: https://skia.googlesource.com/skia.git@drop
Patch Set: Fix MSAN suppression Created 4 years, 4 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
« no previous file with comments | « src/codec/SkJpegCodec.h ('k') | src/core/SkColorSpaceXform.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 "SkMSAN.h" 9 #include "SkMSAN.h"
10 #include "SkJpegCodec.h" 10 #include "SkJpegCodec.h"
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after
189 } 189 }
190 190
191 bool SkJpegCodec::ReadHeader(SkStream* stream, SkCodec** codecOut, 191 bool SkJpegCodec::ReadHeader(SkStream* stream, SkCodec** codecOut,
192 JpegDecoderMgr** decoderMgrOut) { 192 JpegDecoderMgr** decoderMgrOut) {
193 193
194 // Create a JpegDecoderMgr to own all of the decompress information 194 // Create a JpegDecoderMgr to own all of the decompress information
195 SkAutoTDelete<JpegDecoderMgr> decoderMgr(new JpegDecoderMgr(stream)); 195 SkAutoTDelete<JpegDecoderMgr> decoderMgr(new JpegDecoderMgr(stream));
196 196
197 // libjpeg errors will be caught and reported here 197 // libjpeg errors will be caught and reported here
198 if (setjmp(decoderMgr->getJmpBuf())) { 198 if (setjmp(decoderMgr->getJmpBuf())) {
199 return decoderMgr->returnFalse("setjmp"); 199 return decoderMgr->returnFalse("ReadHeader");
200 } 200 }
201 201
202 // Initialize the decompress info and the source manager 202 // Initialize the decompress info and the source manager
203 decoderMgr->init(); 203 decoderMgr->init();
204 204
205 // Instruct jpeg library to save the markers that we care about. Since 205 // Instruct jpeg library to save the markers that we care about. Since
206 // the orientation and color profile will not change, we can skip this 206 // the orientation and color profile will not change, we can skip this
207 // step on rewinds. 207 // step on rewinds.
208 if (codecOut) { 208 if (codecOut) {
209 jpeg_save_markers(decoderMgr->dinfo(), kExifMarker, 0xFFFF); 209 jpeg_save_markers(decoderMgr->dinfo(), kExifMarker, 0xFFFF);
210 jpeg_save_markers(decoderMgr->dinfo(), kICCMarker, 0xFFFF); 210 jpeg_save_markers(decoderMgr->dinfo(), kICCMarker, 0xFFFF);
211 } 211 }
212 212
213 // Read the jpeg header 213 // Read the jpeg header
214 if (JPEG_HEADER_OK != jpeg_read_header(decoderMgr->dinfo(), true)) { 214 if (JPEG_HEADER_OK != jpeg_read_header(decoderMgr->dinfo(), true)) {
215 return decoderMgr->returnFalse("read_header"); 215 return decoderMgr->returnFalse("ReadHeader");
216 } 216 }
217 217
218 if (codecOut) { 218 if (codecOut) {
219 // Get the encoded color type 219 // Get the encoded color type
220 SkEncodedInfo::Color color; 220 SkEncodedInfo::Color color;
221 if (!decoderMgr->getEncodedColor(&color)) { 221 if (!decoderMgr->getEncodedColor(&color)) {
222 return false; 222 return false;
223 } 223 }
224 224
225 // Create image info object and the codec 225 // Create image info object and the codec
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
261 } 261 }
262 return nullptr; 262 return nullptr;
263 } 263 }
264 264
265 SkJpegCodec::SkJpegCodec(int width, int height, const SkEncodedInfo& info, SkStr eam* stream, 265 SkJpegCodec::SkJpegCodec(int width, int height, const SkEncodedInfo& info, SkStr eam* stream,
266 JpegDecoderMgr* decoderMgr, sk_sp<SkColorSpace> colorSpace, Origin origi n, 266 JpegDecoderMgr* decoderMgr, sk_sp<SkColorSpace> colorSpace, Origin origi n,
267 sk_sp<SkData> iccData) 267 sk_sp<SkData> iccData)
268 : INHERITED(width, height, info, stream, std::move(colorSpace), origin) 268 : INHERITED(width, height, info, stream, std::move(colorSpace), origin)
269 , fDecoderMgr(decoderMgr) 269 , fDecoderMgr(decoderMgr)
270 , fReadyState(decoderMgr->dinfo()->global_state) 270 , fReadyState(decoderMgr->dinfo()->global_state)
271 , fSrcRow(nullptr) 271 , fSwizzleSrcRow(nullptr)
272 , fColorXformSrcRow(nullptr)
272 , fSwizzlerSubset(SkIRect::MakeEmpty()) 273 , fSwizzlerSubset(SkIRect::MakeEmpty())
273 , fICCData(std::move(iccData)) 274 , fICCData(std::move(iccData))
274 {} 275 {}
275 276
276 /* 277 /*
277 * Return the row bytes of a particular image type and width 278 * Return the row bytes of a particular image type and width
278 */ 279 */
279 static size_t get_row_bytes(const j_decompress_ptr dinfo) { 280 static size_t get_row_bytes(const j_decompress_ptr dinfo) {
280 #ifdef TURBO_HAS_565 281 #ifdef TURBO_HAS_565
281 const size_t colorBytes = (dinfo->out_color_space == JCS_RGB565) ? 2 : 282 const size_t colorBytes = (dinfo->out_color_space == JCS_RGB565) ? 2 :
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
334 dinfo.global_state = fReadyState; 335 dinfo.global_state = fReadyState;
335 calc_output_dimensions(&dinfo, num, denom); 336 calc_output_dimensions(&dinfo, num, denom);
336 337
337 // Return the calculated output dimensions for the given scale 338 // Return the calculated output dimensions for the given scale
338 return SkISize::Make(dinfo.output_width, dinfo.output_height); 339 return SkISize::Make(dinfo.output_width, dinfo.output_height);
339 } 340 }
340 341
341 bool SkJpegCodec::onRewind() { 342 bool SkJpegCodec::onRewind() {
342 JpegDecoderMgr* decoderMgr = nullptr; 343 JpegDecoderMgr* decoderMgr = nullptr;
343 if (!ReadHeader(this->stream(), nullptr, &decoderMgr)) { 344 if (!ReadHeader(this->stream(), nullptr, &decoderMgr)) {
344 return fDecoderMgr->returnFalse("could not rewind"); 345 return fDecoderMgr->returnFalse("onRewind");
345 } 346 }
346 SkASSERT(nullptr != decoderMgr); 347 SkASSERT(nullptr != decoderMgr);
347 fDecoderMgr.reset(decoderMgr); 348 fDecoderMgr.reset(decoderMgr);
348 349
349 fSwizzler.reset(nullptr); 350 fSwizzler.reset(nullptr);
350 fSrcRow = nullptr; 351 fSwizzleSrcRow = nullptr;
352 fColorXformSrcRow = nullptr;
351 fStorage.reset(); 353 fStorage.reset();
354 fColorXform.reset(nullptr);
352 355
353 return true; 356 return true;
354 } 357 }
355 358
356 /* 359 /*
357 * Checks if the conversion between the input image and the requested output 360 * Checks if the conversion between the input image and the requested output
358 * image has been implemented 361 * image has been implemented
359 * Sets the output color space 362 * Sets the output color space
360 */ 363 */
361 bool SkJpegCodec::setOutputColorSpace(const SkImageInfo& dst) { 364 bool SkJpegCodec::setOutputColorSpace(const SkImageInfo& dstInfo, bool needsColo rXform) {
362 if (kUnknown_SkAlphaType == dst.alphaType()) { 365 if (kUnknown_SkAlphaType == dstInfo.alphaType()) {
363 return false; 366 return false;
364 } 367 }
365 368
366 if (kOpaque_SkAlphaType != dst.alphaType()) { 369 if (kOpaque_SkAlphaType != dstInfo.alphaType()) {
367 SkCodecPrintf("Warning: an opaque image should be decoded as opaque " 370 SkCodecPrintf("Warning: an opaque image should be decoded as opaque "
368 "- it is being decoded as non-opaque, which will draw slow er\n"); 371 "- it is being decoded as non-opaque, which will draw slow er\n");
369 } 372 }
370 373
371 // Check if we will decode to CMYK because a conversion to RGBA is not suppo rted 374 // Check if we will decode to CMYK. libjpeg-turbo does not convert CMYK to RGBA, so
372 J_COLOR_SPACE colorSpace = fDecoderMgr->dinfo()->jpeg_color_space; 375 // we must do it ourselves.
373 bool isCMYK = JCS_CMYK == colorSpace || JCS_YCCK == colorSpace; 376 J_COLOR_SPACE encodedColorType = fDecoderMgr->dinfo()->jpeg_color_space;
377 bool isCMYK = (JCS_CMYK == encodedColorType || JCS_YCCK == encodedColorType) ;
374 378
375 // Check for valid color types and set the output color space 379 // Check for valid color types and set the output color space
376 switch (dst.colorType()) { 380 switch (dstInfo.colorType()) {
377 case kRGBA_8888_SkColorType: 381 case kRGBA_8888_SkColorType:
378 if (isCMYK) { 382 if (isCMYK) {
379 fDecoderMgr->dinfo()->out_color_space = JCS_CMYK; 383 fDecoderMgr->dinfo()->out_color_space = JCS_CMYK;
380 } else { 384 } else {
381 fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA; 385 fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA;
382 } 386 }
383 return true; 387 return true;
384 case kBGRA_8888_SkColorType: 388 case kBGRA_8888_SkColorType:
385 if (isCMYK) { 389 if (isCMYK) {
386 fDecoderMgr->dinfo()->out_color_space = JCS_CMYK; 390 fDecoderMgr->dinfo()->out_color_space = JCS_CMYK;
391 } else if (needsColorXform) {
392 // Our color transformation code requires RGBA order inputs, but it'll swizzle
393 // to BGRA for us.
394 fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA;
387 } else { 395 } else {
388 fDecoderMgr->dinfo()->out_color_space = JCS_EXT_BGRA; 396 fDecoderMgr->dinfo()->out_color_space = JCS_EXT_BGRA;
389 } 397 }
390 return true; 398 return true;
391 case kRGB_565_SkColorType: 399 case kRGB_565_SkColorType:
400 if (needsColorXform) {
401 return false;
402 }
403
392 if (isCMYK) { 404 if (isCMYK) {
393 fDecoderMgr->dinfo()->out_color_space = JCS_CMYK; 405 fDecoderMgr->dinfo()->out_color_space = JCS_CMYK;
394 } else { 406 } else {
395 #ifdef TURBO_HAS_565 407 #ifdef TURBO_HAS_565
396 fDecoderMgr->dinfo()->dither_mode = JDITHER_NONE; 408 fDecoderMgr->dinfo()->dither_mode = JDITHER_NONE;
397 fDecoderMgr->dinfo()->out_color_space = JCS_RGB565; 409 fDecoderMgr->dinfo()->out_color_space = JCS_RGB565;
398 #else 410 #else
399 fDecoderMgr->dinfo()->out_color_space = JCS_RGB; 411 fDecoderMgr->dinfo()->out_color_space = JCS_RGB;
400 #endif 412 #endif
401 } 413 }
402 return true; 414 return true;
403 case kGray_8_SkColorType: 415 case kGray_8_SkColorType:
416 if (needsColorXform || JCS_GRAYSCALE != encodedColorType) {
417 return false;
418 }
419
420 fDecoderMgr->dinfo()->out_color_space = JCS_GRAYSCALE;
421 return true;
422 case kRGBA_F16_SkColorType:
423 SkASSERT(needsColorXform);
424
404 if (isCMYK) { 425 if (isCMYK) {
405 return false; 426 fDecoderMgr->dinfo()->out_color_space = JCS_CMYK;
406 } else { 427 } else {
407 // We will enable decodes to gray even if the image is color bec ause this is 428 fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA;
408 // much faster than decoding to color and then converting
409 fDecoderMgr->dinfo()->out_color_space = JCS_GRAYSCALE;
410 } 429 }
411 return true; 430 return true;
412 default: 431 default:
413 return false; 432 return false;
414 } 433 }
415 } 434 }
416 435
417 /* 436 /*
418 * Checks if we can natively scale to the requested dimensions and natively scal es the 437 * Checks if we can natively scale to the requested dimensions and natively scal es the
419 * dimensions if possible 438 * dimensions if possible
420 */ 439 */
421 bool SkJpegCodec::onDimensionsSupported(const SkISize& size) { 440 bool SkJpegCodec::onDimensionsSupported(const SkISize& size) {
422 if (setjmp(fDecoderMgr->getJmpBuf())) { 441 if (setjmp(fDecoderMgr->getJmpBuf())) {
423 return fDecoderMgr->returnFalse("onDimensionsSupported/setjmp"); 442 return fDecoderMgr->returnFalse("onDimensionsSupported");
424 } 443 }
425 444
426 const unsigned int dstWidth = size.width(); 445 const unsigned int dstWidth = size.width();
427 const unsigned int dstHeight = size.height(); 446 const unsigned int dstHeight = size.height();
428 447
429 // Set up a fake decompress struct in order to use libjpeg to calculate outp ut dimensions 448 // Set up a fake decompress struct in order to use libjpeg to calculate outp ut dimensions
430 // FIXME: Why is this necessary? 449 // FIXME: Why is this necessary?
431 jpeg_decompress_struct dinfo; 450 jpeg_decompress_struct dinfo;
432 sk_bzero(&dinfo, sizeof(dinfo)); 451 sk_bzero(&dinfo, sizeof(dinfo));
433 dinfo.image_width = this->getInfo().width(); 452 dinfo.image_width = this->getInfo().width();
(...skipping 14 matching lines...) Expand all
448 // Try the next scale 467 // Try the next scale
449 num -= 1; 468 num -= 1;
450 calc_output_dimensions(&dinfo, num, denom); 469 calc_output_dimensions(&dinfo, num, denom);
451 } 470 }
452 471
453 fDecoderMgr->dinfo()->scale_num = num; 472 fDecoderMgr->dinfo()->scale_num = num;
454 fDecoderMgr->dinfo()->scale_denom = denom; 473 fDecoderMgr->dinfo()->scale_denom = denom;
455 return true; 474 return true;
456 } 475 }
457 476
477 static bool needs_color_xform(const SkImageInfo& dstInfo, const SkImageInfo& src Info) {
478 // FIXME (msarett):
479 // Do a better check for color space equality.
480 return (kRGBA_F16_SkColorType == dstInfo.colorType()) ||
481 (dstInfo.colorSpace() && (dstInfo.colorSpace() != srcInfo.colorSpace( )));
482 }
483
484 int SkJpegCodec::readRows(const SkImageInfo& dstInfo, void* dst, size_t rowBytes , int count) {
485 // Set the jump location for libjpeg-turbo errors
486 if (setjmp(fDecoderMgr->getJmpBuf())) {
487 return 0;
488 }
489
490 // When fSwizzleSrcRow is non-null, it means that we need to swizzle. In th is case,
491 // we will always decode into fSwizzlerSrcRow before swizzling into the next buffer.
492 // We can never swizzle "in place" because the swizzler may perform sampling and/or
493 // subsetting.
494 // When fColorXformSrcRow is non-null, it means that we need to color xform and that
495 // we cannot color xform "in place" (many times we can, but not when the dst is F16).
496 // In this case, we will color xform from fColorXformSrc into the dst.
497 JSAMPLE* decodeDst = (JSAMPLE*) dst;
498 uint32_t* swizzleDst = (uint32_t*) dst;
499 size_t decodeDstRowBytes = rowBytes;
500 size_t swizzleDstRowBytes = rowBytes;
501 if (fSwizzleSrcRow && fColorXformSrcRow) {
502 decodeDst = (JSAMPLE*) fSwizzleSrcRow;
503 swizzleDst = fColorXformSrcRow;
504 decodeDstRowBytes = 0;
505 swizzleDstRowBytes = 0;
506 } else if (fColorXformSrcRow) {
507 decodeDst = (JSAMPLE*) fColorXformSrcRow;
508 swizzleDst = fColorXformSrcRow;
509 decodeDstRowBytes = 0;
510 swizzleDstRowBytes = 0;
511 } else if (fSwizzleSrcRow) {
512 decodeDst = (JSAMPLE*) fSwizzleSrcRow;
513 decodeDstRowBytes = 0;
514 }
515
516 for (int y = 0; y < count; y++) {
517 uint32_t lines = jpeg_read_scanlines(fDecoderMgr->dinfo(), &decodeDst, 1 );
518 size_t srcRowBytes = get_row_bytes(fDecoderMgr->dinfo());
519 sk_msan_mark_initialized(decodeDst, decodeDst + srcRowBytes, "skbug.com/ 4550");
520 if (0 == lines) {
521 return y;
522 }
523
524 if (fSwizzler) {
525 fSwizzler->swizzle(swizzleDst, decodeDst);
526 }
527
528 if (fColorXform) {
529 int width = dstInfo.width();
530 switch (dstInfo.colorType()) {
531 case kRGBA_8888_SkColorType:
532 fColorXform->applyToRGBA((uint32_t*) dst, swizzleDst, width) ;
533 break;
534 case kBGRA_8888_SkColorType:
535 fColorXform->applyToBGRA((uint32_t*) dst, swizzleDst, width) ;
536 break;
537 case kRGBA_F16_SkColorType:
538 fColorXform->applyToF16((uint64_t*) dst, swizzleDst, width);
539 break;
540 default:
541 SkASSERT(false);
542 break;
543 }
544
545 dst = SkTAddOffset<void>(dst, rowBytes);
546 }
547
548 decodeDst = SkTAddOffset<JSAMPLE>(decodeDst, decodeDstRowBytes);
549 swizzleDst = SkTAddOffset<uint32_t>(swizzleDst, swizzleDstRowBytes);
550 }
551
552 return count;
553 }
554
458 /* 555 /*
459 * Performs the jpeg decode 556 * Performs the jpeg decode
460 */ 557 */
461 SkCodec::Result SkJpegCodec::onGetPixels(const SkImageInfo& dstInfo, 558 SkCodec::Result SkJpegCodec::onGetPixels(const SkImageInfo& dstInfo,
462 void* dst, size_t dstRowBytes, 559 void* dst, size_t dstRowBytes,
463 const Options& options, SkPMColor*, int *, 560 const Options& options, SkPMColor*, int *,
464 int* rowsDecoded) { 561 int* rowsDecoded) {
465 if (options.fSubset) { 562 if (options.fSubset) {
466 // Subsets are not supported. 563 // Subsets are not supported.
467 return kUnimplemented; 564 return kUnimplemented;
468 } 565 }
469 566
470 // Get a pointer to the decompress info since we will use it quite frequentl y 567 // Get a pointer to the decompress info since we will use it quite frequentl y
471 jpeg_decompress_struct* dinfo = fDecoderMgr->dinfo(); 568 jpeg_decompress_struct* dinfo = fDecoderMgr->dinfo();
472 569
473 // Set the jump location for libjpeg errors 570 // Set the jump location for libjpeg errors
474 if (setjmp(fDecoderMgr->getJmpBuf())) { 571 if (setjmp(fDecoderMgr->getJmpBuf())) {
475 return fDecoderMgr->returnFailure("setjmp", kInvalidInput); 572 return fDecoderMgr->returnFailure("setjmp", kInvalidInput);
476 } 573 }
477 574
478 // Check if we can decode to the requested destination and set the output co lor space 575 // Check if we can decode to the requested destination and set the output co lor space
479 if (!this->setOutputColorSpace(dstInfo)) { 576 bool needsColorXform = needs_color_xform(dstInfo, this->getInfo());
480 return fDecoderMgr->returnFailure("conversion_possible", kInvalidConvers ion); 577 if (!this->setOutputColorSpace(dstInfo, needsColorXform)) {
578 return fDecoderMgr->returnFailure("setOutputColorSpace", kInvalidConvers ion);
481 } 579 }
482 580
483 // Now, given valid output dimensions, we can start the decompress 581 if (!this->initializeColorXform(dstInfo, needsColorXform)) {
582 return fDecoderMgr->returnFailure("initializeColorXform", kInvalidParame ters);
583 }
584
484 if (!jpeg_start_decompress(dinfo)) { 585 if (!jpeg_start_decompress(dinfo)) {
485 return fDecoderMgr->returnFailure("startDecompress", kInvalidInput); 586 return fDecoderMgr->returnFailure("startDecompress", kInvalidInput);
486 } 587 }
487 588
488 // The recommended output buffer height should always be 1 in high quality m odes. 589 // The recommended output buffer height should always be 1 in high quality m odes.
489 // If it's not, we want to know because it means our strategy is not optimal . 590 // If it's not, we want to know because it means our strategy is not optimal .
490 SkASSERT(1 == dinfo->rec_outbuf_height); 591 SkASSERT(1 == dinfo->rec_outbuf_height);
491 592
492 J_COLOR_SPACE colorSpace = dinfo->out_color_space; 593 J_COLOR_SPACE colorSpace = dinfo->out_color_space;
493 if (JCS_CMYK == colorSpace || JCS_RGB == colorSpace) { 594 if (JCS_CMYK == colorSpace || JCS_RGB == colorSpace) {
494 this->initializeSwizzler(dstInfo, options); 595 this->initializeSwizzler(dstInfo, options);
495 } 596 }
496 597
497 // Perform the decode a single row at a time 598 this->allocateStorage(dstInfo);
498 uint32_t dstHeight = dstInfo.height();
499 599
500 JSAMPLE* dstRow; 600 int rows = this->readRows(dstInfo, dst, dstRowBytes, dstInfo.height());
501 if (fSwizzler) { 601 if (rows < dstInfo.height()) {
502 // write data to storage row, then sample using swizzler 602 *rowsDecoded = rows;
503 dstRow = fSrcRow; 603 return fDecoderMgr->returnFailure("Incomplete image data", kIncompleteIn put);
504 } else {
505 // write data directly to dst
506 dstRow = (JSAMPLE*) dst;
507 }
508
509 for (uint32_t y = 0; y < dstHeight; y++) {
510 // Read rows of the image
511 uint32_t lines = jpeg_read_scanlines(dinfo, &dstRow, 1);
512 sk_msan_mark_initialized(dstRow, dstRow + dstRowBytes, "skbug.com/4550") ;
513
514 // If we cannot read enough rows, assume the input is incomplete
515 if (lines != 1) {
516 *rowsDecoded = y;
517 return fDecoderMgr->returnFailure("Incomplete image data", kIncomple teInput);
518 }
519
520 if (fSwizzler) {
521 // use swizzler to sample row
522 fSwizzler->swizzle(dst, dstRow);
523 dst = SkTAddOffset<JSAMPLE>(dst, dstRowBytes);
524 } else {
525 dstRow = SkTAddOffset<JSAMPLE>(dstRow, dstRowBytes);
526 }
527 } 604 }
528 605
529 return kSuccess; 606 return kSuccess;
530 } 607 }
531 608
609 void SkJpegCodec::allocateStorage(const SkImageInfo& dstInfo) {
610 size_t swizzleBytes = 0;
611 if (fSwizzler) {
612 swizzleBytes = get_row_bytes(fDecoderMgr->dinfo());
613 SkASSERT(!fColorXform || SkIsAlign4(swizzleBytes));
614 }
615
616 size_t xformBytes = 0;
617 if (kRGBA_F16_SkColorType == dstInfo.colorType()) {
618 SkASSERT(fColorXform);
619 xformBytes = dstInfo.width() * sizeof(SkColorSpaceXform::RGBA32);
620 }
621
622 size_t totalBytes = swizzleBytes + xformBytes;
623 if (totalBytes > 0) {
624 fStorage.reset(totalBytes);
625 fSwizzleSrcRow = (swizzleBytes > 0) ? fStorage.get() : nullptr;
626 fColorXformSrcRow = (xformBytes > 0) ?
627 SkTAddOffset<uint32_t>(fStorage.get(), swizzleBytes) : nullptr;
628 }
629 }
630
532 void SkJpegCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options& options) { 631 void SkJpegCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options& options) {
533 // libjpeg-turbo may have already performed color conversion. We must indic ate the 632 // libjpeg-turbo may have already performed color conversion. We must indic ate the
534 // appropriate format to the swizzler. 633 // appropriate format to the swizzler.
535 SkEncodedInfo swizzlerInfo = this->getEncodedInfo(); 634 SkEncodedInfo swizzlerInfo = this->getEncodedInfo();
536 bool preSwizzled = true; 635 bool preSwizzled = true;
537 switch (fDecoderMgr->dinfo()->out_color_space) { 636 switch (fDecoderMgr->dinfo()->out_color_space) {
538 case JCS_RGB: 637 case JCS_RGB:
539 preSwizzled = false; 638 preSwizzled = false;
540 swizzlerInfo = SkEncodedInfo::Make(SkEncodedInfo::kRGB_Color, 639 swizzlerInfo = SkEncodedInfo::Make(SkEncodedInfo::kRGB_Color,
541 swizzlerInfo.alpha(), 640 swizzlerInfo.alpha(),
542 swizzlerInfo.bitsPerComponent()); 641 swizzlerInfo.bitsPerComponent());
543 break; 642 break;
544 case JCS_CMYK: 643 case JCS_CMYK:
545 preSwizzled = false; 644 preSwizzled = false;
546 swizzlerInfo = SkEncodedInfo::Make( 645 swizzlerInfo = SkEncodedInfo::Make(SkEncodedInfo::kInvertedCMYK_Colo r,
547 SkEncodedInfo::kInvertedCMYK_Color, swizzlerInfo.alpha(), 646 swizzlerInfo.alpha(),
548 swizzlerInfo.bitsPerComponent()); 647 swizzlerInfo.bitsPerComponent());
549 break; 648 break;
550 default: 649 default:
551 break; 650 break;
552 } 651 }
553 652
554 Options swizzlerOptions = options; 653 Options swizzlerOptions = options;
555 if (options.fSubset) { 654 if (options.fSubset) {
556 // Use fSwizzlerSubset if this is a subset decode. This is necessary in the case 655 // Use fSwizzlerSubset if this is a subset decode. This is necessary in the case
557 // where libjpeg-turbo provides a subset and then we need to subset it f urther. 656 // where libjpeg-turbo provides a subset and then we need to subset it f urther.
558 // Also, verify that fSwizzlerSubset is initialized and valid. 657 // Also, verify that fSwizzlerSubset is initialized and valid.
559 SkASSERT(!fSwizzlerSubset.isEmpty() && fSwizzlerSubset.x() <= options.fS ubset->x() && 658 SkASSERT(!fSwizzlerSubset.isEmpty() && fSwizzlerSubset.x() <= options.fS ubset->x() &&
560 fSwizzlerSubset.width() == options.fSubset->width()); 659 fSwizzlerSubset.width() == options.fSubset->width());
561 swizzlerOptions.fSubset = &fSwizzlerSubset; 660 swizzlerOptions.fSubset = &fSwizzlerSubset;
562 } 661 }
563 fSwizzler.reset(SkSwizzler::CreateSwizzler(swizzlerInfo, nullptr, dstInfo, s wizzlerOptions, 662 fSwizzler.reset(SkSwizzler::CreateSwizzler(swizzlerInfo, nullptr, dstInfo, s wizzlerOptions,
564 nullptr, preSwizzled)); 663 nullptr, preSwizzled));
565 SkASSERT(fSwizzler); 664 SkASSERT(fSwizzler);
566 fStorage.reset(get_row_bytes(fDecoderMgr->dinfo())); 665 }
567 fSrcRow = fStorage.get(); 666
667 bool SkJpegCodec::initializeColorXform(const SkImageInfo& dstInfo, bool needsCol orXform) {
668 if (needsColorXform) {
669 fColorXform = SkColorSpaceXform::New(sk_ref_sp(this->getInfo().colorSpac e()),
670 sk_ref_sp(dstInfo.colorSpace()));
671 if (!fColorXform && kRGBA_F16_SkColorType == dstInfo.colorType()) {
672 return false;
673 }
674 }
675
676 return true;
568 } 677 }
569 678
570 SkSampler* SkJpegCodec::getSampler(bool createIfNecessary) { 679 SkSampler* SkJpegCodec::getSampler(bool createIfNecessary) {
571 if (!createIfNecessary || fSwizzler) { 680 if (!createIfNecessary || fSwizzler) {
572 SkASSERT(!fSwizzler || (fSrcRow && fStorage.get() == fSrcRow)); 681 SkASSERT(!fSwizzler || (fSwizzleSrcRow && fStorage.get() == fSwizzleSrcR ow));
573 return fSwizzler; 682 return fSwizzler;
574 } 683 }
575 684
576 this->initializeSwizzler(this->dstInfo(), this->options()); 685 this->initializeSwizzler(this->dstInfo(), this->options());
686 this->allocateStorage(this->dstInfo());
577 return fSwizzler; 687 return fSwizzler;
578 } 688 }
579 689
580 SkCodec::Result SkJpegCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, 690 SkCodec::Result SkJpegCodec::onStartScanlineDecode(const SkImageInfo& dstInfo,
581 const Options& options, SkPMColor ctable[], int* ctableCount) { 691 const Options& options, SkPMColor ctable[], int* ctableCount) {
582 // Set the jump location for libjpeg errors 692 // Set the jump location for libjpeg errors
583 if (setjmp(fDecoderMgr->getJmpBuf())) { 693 if (setjmp(fDecoderMgr->getJmpBuf())) {
584 SkCodecPrintf("setjmp: Error from libjpeg\n"); 694 SkCodecPrintf("setjmp: Error from libjpeg\n");
585 return kInvalidInput; 695 return kInvalidInput;
586 } 696 }
587 697
588 // Check if we can decode to the requested destination and set the output co lor space 698 // Check if we can decode to the requested destination and set the output co lor space
589 if (!this->setOutputColorSpace(dstInfo)) { 699 bool needsColorXform = needs_color_xform(dstInfo, this->getInfo());
700 if (!this->setOutputColorSpace(dstInfo, needsColorXform)) {
590 return kInvalidConversion; 701 return kInvalidConversion;
591 } 702 }
592 703
593 // Now, given valid output dimensions, we can start the decompress 704 if (!this->initializeColorXform(dstInfo, needsColorXform)) {
705 return fDecoderMgr->returnFailure("initializeColorXform", kInvalidParame ters);
706 }
707
594 if (!jpeg_start_decompress(fDecoderMgr->dinfo())) { 708 if (!jpeg_start_decompress(fDecoderMgr->dinfo())) {
595 SkCodecPrintf("start decompress failed\n"); 709 SkCodecPrintf("start decompress failed\n");
596 return kInvalidInput; 710 return kInvalidInput;
597 } 711 }
598 712
599 #ifdef TURBO_HAS_CROP 713 #ifdef TURBO_HAS_CROP
600 if (options.fSubset) { 714 if (options.fSubset) {
601 uint32_t startX = options.fSubset->x(); 715 uint32_t startX = options.fSubset->x();
602 uint32_t width = options.fSubset->width(); 716 uint32_t width = options.fSubset->width();
603 717
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
644 } 758 }
645 759
646 // We will need a swizzler if we are performing a subset decode or 760 // We will need a swizzler if we are performing a subset decode or
647 // converting from CMYK. 761 // converting from CMYK.
648 J_COLOR_SPACE colorSpace = fDecoderMgr->dinfo()->out_color_space; 762 J_COLOR_SPACE colorSpace = fDecoderMgr->dinfo()->out_color_space;
649 if (options.fSubset || JCS_CMYK == colorSpace || JCS_RGB == colorSpace) { 763 if (options.fSubset || JCS_CMYK == colorSpace || JCS_RGB == colorSpace) {
650 this->initializeSwizzler(dstInfo, options); 764 this->initializeSwizzler(dstInfo, options);
651 } 765 }
652 #endif 766 #endif
653 767
768 this->allocateStorage(dstInfo);
769
654 return kSuccess; 770 return kSuccess;
655 } 771 }
656 772
657 int SkJpegCodec::onGetScanlines(void* dst, int count, size_t dstRowBytes) { 773 int SkJpegCodec::onGetScanlines(void* dst, int count, size_t dstRowBytes) {
658 // Set the jump location for libjpeg errors 774 int rows = this->readRows(this->dstInfo(), dst, dstRowBytes, count);
659 if (setjmp(fDecoderMgr->getJmpBuf())) { 775 if (rows < count) {
660 return fDecoderMgr->returnFailure("setjmp", kInvalidInput); 776 // This allows us to skip calling jpeg_finish_decompress().
661 } 777 fDecoderMgr->dinfo()->output_scanline = this->dstInfo().height();
662 // Read rows one at a time
663 JSAMPLE* dstRow;
664 size_t srcRowBytes = get_row_bytes(fDecoderMgr->dinfo());
665 if (fSwizzler) {
666 // write data to storage row, then sample using swizzler
667 dstRow = fSrcRow;
668 } else {
669 // write data directly to dst
670 SkASSERT(count == 1 || dstRowBytes >= srcRowBytes);
671 dstRow = (JSAMPLE*) dst;
672 } 778 }
673 779
674 for (int y = 0; y < count; y++) { 780 return rows;
675 // Read row of the image
676 uint32_t rowsDecoded = jpeg_read_scanlines(fDecoderMgr->dinfo(), &dstRow , 1);
677 sk_msan_mark_initialized(dstRow, dstRow + srcRowBytes, "skbug.com/4550") ;
678 if (rowsDecoded != 1) {
679 fDecoderMgr->dinfo()->output_scanline = this->dstInfo().height();
680 return y;
681 }
682
683 if (fSwizzler) {
684 // use swizzler to sample row
685 fSwizzler->swizzle(dst, dstRow);
686 dst = SkTAddOffset<JSAMPLE>(dst, dstRowBytes);
687 } else {
688 dstRow = SkTAddOffset<JSAMPLE>(dstRow, dstRowBytes);
689 }
690 }
691 return count;
692 } 781 }
693 782
694 bool SkJpegCodec::onSkipScanlines(int count) { 783 bool SkJpegCodec::onSkipScanlines(int count) {
695 // Set the jump location for libjpeg errors 784 // Set the jump location for libjpeg errors
696 if (setjmp(fDecoderMgr->getJmpBuf())) { 785 if (setjmp(fDecoderMgr->getJmpBuf())) {
697 return fDecoderMgr->returnFalse("setjmp"); 786 return fDecoderMgr->returnFalse("onSkipScanlines");
698 } 787 }
699 788
700 #ifdef TURBO_HAS_SKIP 789 #ifdef TURBO_HAS_SKIP
701 return (uint32_t) count == jpeg_skip_scanlines(fDecoderMgr->dinfo(), count); 790 return (uint32_t) count == jpeg_skip_scanlines(fDecoderMgr->dinfo(), count);
702 #else 791 #else
703 if (!fSrcRow) { 792 if (!fSwizzleSrcRow) {
704 fStorage.reset(get_row_bytes(fDecoderMgr->dinfo())); 793 fStorage.reset(get_row_bytes(fDecoderMgr->dinfo()));
705 fSrcRow = fStorage.get(); 794 fSwizzleSrcRow = fStorage.get();
706 } 795 }
707 796
708 for (int y = 0; y < count; y++) { 797 for (int y = 0; y < count; y++) {
709 if (1 != jpeg_read_scanlines(fDecoderMgr->dinfo(), &fSrcRow, 1)) { 798 if (1 != jpeg_read_scanlines(fDecoderMgr->dinfo(), &fSwizzleSrcRow, 1)) {
710 return false; 799 return false;
711 } 800 }
712 } 801 }
713 return true; 802 return true;
714 #endif 803 #endif
715 } 804 }
716 805
717 static bool is_yuv_supported(jpeg_decompress_struct* dinfo) { 806 static bool is_yuv_supported(jpeg_decompress_struct* dinfo) {
718 // Scaling is not supported in raw data mode. 807 // Scaling is not supported in raw data mode.
719 SkASSERT(dinfo->scale_num == dinfo->scale_denom); 808 SkASSERT(dinfo->scale_num == dinfo->scale_denom);
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after
904 993
905 JDIMENSION linesRead = jpeg_read_raw_data(dinfo, yuv, numRowsPerBlock); 994 JDIMENSION linesRead = jpeg_read_raw_data(dinfo, yuv, numRowsPerBlock);
906 if (linesRead < remainingRows) { 995 if (linesRead < remainingRows) {
907 // FIXME: Handle incomplete YUV decodes without signalling an error. 996 // FIXME: Handle incomplete YUV decodes without signalling an error.
908 return kInvalidInput; 997 return kInvalidInput;
909 } 998 }
910 } 999 }
911 1000
912 return kSuccess; 1001 return kSuccess;
913 } 1002 }
OLDNEW
« no previous file with comments | « src/codec/SkJpegCodec.h ('k') | src/core/SkColorSpaceXform.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698