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 |