| 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" |
| 11 #include "SkJpegUtility_codec.h" | 11 #include "SkJpegUtility_codec.h" |
| 12 #include "SkCodecPriv.h" | 12 #include "SkCodecPriv.h" |
| 13 #include "SkColorPriv.h" | 13 #include "SkColorPriv.h" |
| 14 #include "SkStream.h" | 14 #include "SkStream.h" |
| 15 #include "SkTemplates.h" | 15 #include "SkTemplates.h" |
| 16 #include "SkTypes.h" | 16 #include "SkTypes.h" |
| 17 | 17 |
| 18 // stdio is needed for libjpeg-turbo | 18 // stdio is needed for libjpeg-turbo |
| 19 #include <stdio.h> | 19 #include <stdio.h> |
| 20 | 20 |
| 21 extern "C" { | 21 extern "C" { |
| 22 #include "jerror.h" | 22 #include "jerror.h" |
| 23 #include "jpeglib.h" | 23 #include "jpeglib.h" |
| 24 } | 24 } |
| 25 | 25 |
| 26 /* | |
| 27 * Convert a row of CMYK samples to RGBA in place. | |
| 28 * Note that this method moves the row pointer. | |
| 29 * @param width the number of pixels in the row that is being converted | |
| 30 * CMYK is stored as four bytes per pixel | |
| 31 */ | |
| 32 static void convert_CMYK_to_RGBA(uint8_t* row, uint32_t width) { | |
| 33 // We will implement a crude conversion from CMYK -> RGB using formulas | |
| 34 // from easyrgb.com. | |
| 35 // | |
| 36 // CMYK -> CMY | |
| 37 // C = C * (1 - K) + K | |
| 38 // M = M * (1 - K) + K | |
| 39 // Y = Y * (1 - K) + K | |
| 40 // | |
| 41 // libjpeg actually gives us inverted CMYK, so we must subtract the | |
| 42 // original terms from 1. | |
| 43 // CMYK -> CMY | |
| 44 // C = (1 - C) * (1 - (1 - K)) + (1 - K) | |
| 45 // M = (1 - M) * (1 - (1 - K)) + (1 - K) | |
| 46 // Y = (1 - Y) * (1 - (1 - K)) + (1 - K) | |
| 47 // | |
| 48 // Simplifying the above expression. | |
| 49 // CMYK -> CMY | |
| 50 // C = 1 - CK | |
| 51 // M = 1 - MK | |
| 52 // Y = 1 - YK | |
| 53 // | |
| 54 // CMY -> RGB | |
| 55 // R = (1 - C) * 255 | |
| 56 // G = (1 - M) * 255 | |
| 57 // B = (1 - Y) * 255 | |
| 58 // | |
| 59 // Therefore the full conversion is below. This can be verified at | |
| 60 // www.rapidtables.com (assuming inverted CMYK). | |
| 61 // CMYK -> RGB | |
| 62 // R = C * K * 255 | |
| 63 // G = M * K * 255 | |
| 64 // B = Y * K * 255 | |
| 65 // | |
| 66 // As a final note, we have treated the CMYK values as if they were on | |
| 67 // a scale from 0-1, when in fact they are 8-bit ints scaling from 0-255. | |
| 68 // We must divide each CMYK component by 255 to obtain the true conversion | |
| 69 // we should perform. | |
| 70 // CMYK -> RGB | |
| 71 // R = C * K / 255 | |
| 72 // G = M * K / 255 | |
| 73 // B = Y * K / 255 | |
| 74 for (uint32_t x = 0; x < width; x++, row += 4) { | |
| 75 #if defined(SK_PMCOLOR_IS_RGBA) | |
| 76 row[0] = SkMulDiv255Round(row[0], row[3]); | |
| 77 row[1] = SkMulDiv255Round(row[1], row[3]); | |
| 78 row[2] = SkMulDiv255Round(row[2], row[3]); | |
| 79 #else | |
| 80 uint8_t tmp = row[0]; | |
| 81 row[0] = SkMulDiv255Round(row[2], row[3]); | |
| 82 row[1] = SkMulDiv255Round(row[1], row[3]); | |
| 83 row[2] = SkMulDiv255Round(tmp, row[3]); | |
| 84 #endif | |
| 85 row[3] = 0xFF; | |
| 86 } | |
| 87 } | |
| 88 | |
| 89 bool SkJpegCodec::IsJpeg(SkStream* stream) { | 26 bool SkJpegCodec::IsJpeg(SkStream* stream) { |
| 90 static const uint8_t jpegSig[] = { 0xFF, 0xD8, 0xFF }; | 27 static const uint8_t jpegSig[] = { 0xFF, 0xD8, 0xFF }; |
| 91 char buffer[sizeof(jpegSig)]; | 28 char buffer[sizeof(jpegSig)]; |
| 92 return stream->read(buffer, sizeof(jpegSig)) == sizeof(jpegSig) && | 29 return stream->read(buffer, sizeof(jpegSig)) == sizeof(jpegSig) && |
| 93 !memcmp(buffer, jpegSig, sizeof(jpegSig)); | 30 !memcmp(buffer, jpegSig, sizeof(jpegSig)); |
| 94 } | 31 } |
| 95 | 32 |
| 96 bool SkJpegCodec::ReadHeader(SkStream* stream, SkCodec** codecOut, | 33 bool SkJpegCodec::ReadHeader(SkStream* stream, SkCodec** codecOut, |
| 97 JpegDecoderMgr** decoderMgrOut) { | 34 JpegDecoderMgr** decoderMgrOut) { |
| 98 | 35 |
| (...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 256 #if defined(SK_PMCOLOR_IS_RGBA) | 193 #if defined(SK_PMCOLOR_IS_RGBA) |
| 257 fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA; | 194 fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA; |
| 258 #else | 195 #else |
| 259 fDecoderMgr->dinfo()->out_color_space = JCS_EXT_BGRA; | 196 fDecoderMgr->dinfo()->out_color_space = JCS_EXT_BGRA; |
| 260 #endif | 197 #endif |
| 261 #endif | 198 #endif |
| 262 } | 199 } |
| 263 return true; | 200 return true; |
| 264 case kRGB_565_SkColorType: | 201 case kRGB_565_SkColorType: |
| 265 if (isCMYK) { | 202 if (isCMYK) { |
| 266 // FIXME (msarett): We need to support 565 here. It's not hard
to do, considering | 203 fDecoderMgr->dinfo()->out_color_space = JCS_CMYK; |
| 267 // we already convert CMYK to RGBA, I just need to do it. I thi
nk it might be | |
| 268 // best to do this in SkSwizzler and also move convert_CMYK_to_R
GBA into SkSwizzler. | |
| 269 return false; | |
| 270 } else { | 204 } else { |
| 271 #if defined(GOOGLE3) | 205 #if defined(GOOGLE3) |
| 272 return false; | 206 return false; |
| 273 #else | 207 #else |
| 274 fDecoderMgr->dinfo()->dither_mode = JDITHER_NONE; | 208 fDecoderMgr->dinfo()->dither_mode = JDITHER_NONE; |
| 275 fDecoderMgr->dinfo()->out_color_space = JCS_RGB565; | 209 fDecoderMgr->dinfo()->out_color_space = JCS_RGB565; |
| 276 #endif | 210 #endif |
| 277 } | 211 } |
| 278 return true; | 212 return true; |
| 279 case kGray_8_SkColorType: | 213 case kGray_8_SkColorType: |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 358 | 292 |
| 359 // Now, given valid output dimensions, we can start the decompress | 293 // Now, given valid output dimensions, we can start the decompress |
| 360 if (!jpeg_start_decompress(dinfo)) { | 294 if (!jpeg_start_decompress(dinfo)) { |
| 361 return fDecoderMgr->returnFailure("startDecompress", kInvalidInput); | 295 return fDecoderMgr->returnFailure("startDecompress", kInvalidInput); |
| 362 } | 296 } |
| 363 | 297 |
| 364 // The recommended output buffer height should always be 1 in high quality m
odes. | 298 // The recommended output buffer height should always be 1 in high quality m
odes. |
| 365 // If it's not, we want to know because it means our strategy is not optimal
. | 299 // If it's not, we want to know because it means our strategy is not optimal
. |
| 366 SkASSERT(1 == dinfo->rec_outbuf_height); | 300 SkASSERT(1 == dinfo->rec_outbuf_height); |
| 367 | 301 |
| 302 if (JCS_CMYK == dinfo->out_color_space) { |
| 303 this->initializeSwizzler(dstInfo, options); |
| 304 } |
| 305 |
| 368 // Perform the decode a single row at a time | 306 // Perform the decode a single row at a time |
| 369 uint32_t dstHeight = dstInfo.height(); | 307 uint32_t dstHeight = dstInfo.height(); |
| 370 JSAMPLE* dstRow = (JSAMPLE*) dst; | 308 |
| 309 JSAMPLE* dstRow; |
| 310 if (fSwizzler) { |
| 311 // write data to storage row, then sample using swizzler |
| 312 dstRow = fSrcRow; |
| 313 } else { |
| 314 // write data directly to dst |
| 315 dstRow = (JSAMPLE*) dst; |
| 316 } |
| 317 |
| 371 for (uint32_t y = 0; y < dstHeight; y++) { | 318 for (uint32_t y = 0; y < dstHeight; y++) { |
| 372 // Read rows of the image | 319 // Read rows of the image |
| 373 uint32_t lines = jpeg_read_scanlines(dinfo, &dstRow, 1); | 320 uint32_t lines = jpeg_read_scanlines(dinfo, &dstRow, 1); |
| 374 | 321 |
| 375 // If we cannot read enough rows, assume the input is incomplete | 322 // If we cannot read enough rows, assume the input is incomplete |
| 376 if (lines != 1) { | 323 if (lines != 1) { |
| 377 *rowsDecoded = y; | 324 *rowsDecoded = y; |
| 378 | 325 |
| 379 return fDecoderMgr->returnFailure("Incomplete image data", kIncomple
teInput); | 326 return fDecoderMgr->returnFailure("Incomplete image data", kIncomple
teInput); |
| 380 } | 327 } |
| 381 | 328 |
| 382 // Convert to RGBA if necessary | 329 if (fSwizzler) { |
| 383 if (JCS_CMYK == dinfo->out_color_space) { | 330 // use swizzler to sample row |
| 384 convert_CMYK_to_RGBA(dstRow, dstInfo.width()); | 331 fSwizzler->swizzle(dst, dstRow); |
| 332 dst = SkTAddOffset<JSAMPLE>(dst, dstRowBytes); |
| 333 } else { |
| 334 dstRow = SkTAddOffset<JSAMPLE>(dstRow, dstRowBytes); |
| 385 } | 335 } |
| 386 | |
| 387 // Move to the next row | |
| 388 dstRow = SkTAddOffset<JSAMPLE>(dstRow, dstRowBytes); | |
| 389 } | 336 } |
| 390 | 337 |
| 391 return kSuccess; | 338 return kSuccess; |
| 392 } | 339 } |
| 393 | 340 |
| 394 void SkJpegCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options&
options) { | 341 void SkJpegCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options&
options) { |
| 395 SkSwizzler::SrcConfig srcConfig = SkSwizzler::kUnknown; | 342 SkSwizzler::SrcConfig srcConfig = SkSwizzler::kUnknown; |
| 396 switch (dstInfo.colorType()) { | 343 if (JCS_CMYK == fDecoderMgr->dinfo()->out_color_space) { |
| 397 case kGray_8_SkColorType: | 344 srcConfig = SkSwizzler::kCMYK; |
| 398 srcConfig = SkSwizzler::kGray; | 345 } else { |
| 399 break; | 346 switch (dstInfo.colorType()) { |
| 400 case kRGBA_8888_SkColorType: | 347 case kGray_8_SkColorType: |
| 401 srcConfig = SkSwizzler::kRGBX; | 348 srcConfig = SkSwizzler::kGray; |
| 402 break; | 349 break; |
| 403 case kBGRA_8888_SkColorType: | 350 case kRGBA_8888_SkColorType: |
| 404 srcConfig = SkSwizzler::kBGRX; | 351 srcConfig = SkSwizzler::kRGBX; |
| 405 break; | 352 break; |
| 406 case kRGB_565_SkColorType: | 353 case kBGRA_8888_SkColorType: |
| 407 srcConfig = SkSwizzler::kRGB_565; | 354 srcConfig = SkSwizzler::kBGRX; |
| 408 break; | 355 break; |
| 409 default: | 356 case kRGB_565_SkColorType: |
| 410 // This function should only be called if the colorType is supported
by jpeg | 357 srcConfig = SkSwizzler::kRGB_565; |
| 358 break; |
| 359 default: |
| 360 // This function should only be called if the colorType is suppo
rted by jpeg |
| 411 #if defined(GOOGLE3) | 361 #if defined(GOOGLE3) |
| 412 SK_CRASH(); | 362 SK_CRASH(); |
| 413 #else | 363 #else |
| 414 SkASSERT(false); | 364 SkASSERT(false); |
| 415 #endif | 365 #endif |
| 366 } |
| 416 } | 367 } |
| 417 | 368 |
| 418 fSwizzler.reset(SkSwizzler::CreateSwizzler(srcConfig, nullptr, dstInfo, opti
ons)); | 369 fSwizzler.reset(SkSwizzler::CreateSwizzler(srcConfig, nullptr, dstInfo, opti
ons)); |
| 419 fStorage.reset(get_row_bytes(fDecoderMgr->dinfo())); | 370 fStorage.reset(get_row_bytes(fDecoderMgr->dinfo())); |
| 420 fSrcRow = static_cast<uint8_t*>(fStorage.get()); | 371 fSrcRow = static_cast<uint8_t*>(fStorage.get()); |
| 421 } | 372 } |
| 422 | 373 |
| 423 SkSampler* SkJpegCodec::getSampler(bool createIfNecessary) { | 374 SkSampler* SkJpegCodec::getSampler(bool createIfNecessary) { |
| 424 if (!createIfNecessary || fSwizzler) { | 375 if (!createIfNecessary || fSwizzler) { |
| 425 SkASSERT(!fSwizzler || (fSrcRow && static_cast<uint8_t*>(fStorage.get())
== fSrcRow)); | 376 SkASSERT(!fSwizzler || (fSrcRow && static_cast<uint8_t*>(fStorage.get())
== fSrcRow)); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 447 fSwizzler.reset(nullptr); | 398 fSwizzler.reset(nullptr); |
| 448 fSrcRow = nullptr; | 399 fSrcRow = nullptr; |
| 449 fStorage.free(); | 400 fStorage.free(); |
| 450 | 401 |
| 451 // Now, given valid output dimensions, we can start the decompress | 402 // Now, given valid output dimensions, we can start the decompress |
| 452 if (!jpeg_start_decompress(fDecoderMgr->dinfo())) { | 403 if (!jpeg_start_decompress(fDecoderMgr->dinfo())) { |
| 453 SkCodecPrintf("start decompress failed\n"); | 404 SkCodecPrintf("start decompress failed\n"); |
| 454 return kInvalidInput; | 405 return kInvalidInput; |
| 455 } | 406 } |
| 456 | 407 |
| 457 // We will need a swizzler if we are performing a subset decode | 408 // We will need a swizzler if we are performing a subset decode or |
| 458 if (options.fSubset) { | 409 // converting from CMYK. |
| 410 if (options.fSubset || JCS_CMYK == fDecoderMgr->dinfo()->out_color_space) { |
| 459 this->initializeSwizzler(dstInfo, options); | 411 this->initializeSwizzler(dstInfo, options); |
| 460 } | 412 } |
| 461 | 413 |
| 462 return kSuccess; | 414 return kSuccess; |
| 463 } | 415 } |
| 464 | 416 |
| 465 int SkJpegCodec::onGetScanlines(void* dst, int count, size_t rowBytes) { | 417 int SkJpegCodec::onGetScanlines(void* dst, int count, size_t rowBytes) { |
| 466 // Set the jump location for libjpeg errors | 418 // Set the jump location for libjpeg errors |
| 467 if (setjmp(fDecoderMgr->getJmpBuf())) { | 419 if (setjmp(fDecoderMgr->getJmpBuf())) { |
| 468 return fDecoderMgr->returnFailure("setjmp", kInvalidInput); | 420 return fDecoderMgr->returnFailure("setjmp", kInvalidInput); |
| 469 } | 421 } |
| 470 // Read rows one at a time | 422 // Read rows one at a time |
| 471 JSAMPLE* dstRow; | 423 JSAMPLE* dstRow; |
| 472 if (fSwizzler) { | 424 if (fSwizzler) { |
| 473 // write data to storage row, then sample using swizzler | 425 // write data to storage row, then sample using swizzler |
| 474 dstRow = fSrcRow; | 426 dstRow = fSrcRow; |
| 475 } else { | 427 } else { |
| 476 // write data directly to dst | 428 // write data directly to dst |
| 477 dstRow = (JSAMPLE*) dst; | 429 dstRow = (JSAMPLE*) dst; |
| 478 } | 430 } |
| 479 | 431 |
| 480 for (int y = 0; y < count; y++) { | 432 for (int y = 0; y < count; y++) { |
| 481 // Read row of the image | 433 // Read row of the image |
| 482 uint32_t rowsDecoded = jpeg_read_scanlines(fDecoderMgr->dinfo(), &dstRow
, 1); | 434 uint32_t rowsDecoded = jpeg_read_scanlines(fDecoderMgr->dinfo(), &dstRow
, 1); |
| 483 if (rowsDecoded != 1) { | 435 if (rowsDecoded != 1) { |
| 484 fDecoderMgr->dinfo()->output_scanline = this->dstInfo().height(); | 436 fDecoderMgr->dinfo()->output_scanline = this->dstInfo().height(); |
| 485 return y; | 437 return y; |
| 486 } | 438 } |
| 487 | 439 |
| 488 // Convert to RGBA if necessary | 440 if (fSwizzler) { |
| 489 if (JCS_CMYK == fDecoderMgr->dinfo()->out_color_space) { | |
| 490 convert_CMYK_to_RGBA(dstRow, fDecoderMgr->dinfo()->output_width); | |
| 491 } | |
| 492 | |
| 493 if(fSwizzler) { | |
| 494 // use swizzler to sample row | 441 // use swizzler to sample row |
| 495 fSwizzler->swizzle(dst, dstRow); | 442 fSwizzler->swizzle(dst, dstRow); |
| 496 dst = SkTAddOffset<JSAMPLE>(dst, rowBytes); | 443 dst = SkTAddOffset<JSAMPLE>(dst, rowBytes); |
| 497 } else { | 444 } else { |
| 498 dstRow = SkTAddOffset<JSAMPLE>(dstRow, rowBytes); | 445 dstRow = SkTAddOffset<JSAMPLE>(dstRow, rowBytes); |
| 499 } | 446 } |
| 500 } | 447 } |
| 501 return count; | 448 return count; |
| 502 } | 449 } |
| 503 | 450 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 516 #endif | 463 #endif |
| 517 | 464 |
| 518 bool SkJpegCodec::onSkipScanlines(int count) { | 465 bool SkJpegCodec::onSkipScanlines(int count) { |
| 519 // Set the jump location for libjpeg errors | 466 // Set the jump location for libjpeg errors |
| 520 if (setjmp(fDecoderMgr->getJmpBuf())) { | 467 if (setjmp(fDecoderMgr->getJmpBuf())) { |
| 521 return fDecoderMgr->returnFalse("setjmp"); | 468 return fDecoderMgr->returnFalse("setjmp"); |
| 522 } | 469 } |
| 523 | 470 |
| 524 return (uint32_t) count == jpeg_skip_scanlines(fDecoderMgr->dinfo(), count); | 471 return (uint32_t) count == jpeg_skip_scanlines(fDecoderMgr->dinfo(), count); |
| 525 } | 472 } |
| OLD | NEW |