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 |
26 bool SkJpegCodec::IsJpeg(SkStream* stream) { | 89 bool SkJpegCodec::IsJpeg(SkStream* stream) { |
27 static const uint8_t jpegSig[] = { 0xFF, 0xD8, 0xFF }; | 90 static const uint8_t jpegSig[] = { 0xFF, 0xD8, 0xFF }; |
28 char buffer[sizeof(jpegSig)]; | 91 char buffer[sizeof(jpegSig)]; |
29 return stream->read(buffer, sizeof(jpegSig)) == sizeof(jpegSig) && | 92 return stream->read(buffer, sizeof(jpegSig)) == sizeof(jpegSig) && |
30 !memcmp(buffer, jpegSig, sizeof(jpegSig)); | 93 !memcmp(buffer, jpegSig, sizeof(jpegSig)); |
31 } | 94 } |
32 | 95 |
33 bool SkJpegCodec::ReadHeader(SkStream* stream, SkCodec** codecOut, | 96 bool SkJpegCodec::ReadHeader(SkStream* stream, SkCodec** codecOut, |
34 JpegDecoderMgr** decoderMgrOut) { | 97 JpegDecoderMgr** decoderMgrOut) { |
35 | 98 |
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
193 #if defined(SK_PMCOLOR_IS_RGBA) | 256 #if defined(SK_PMCOLOR_IS_RGBA) |
194 fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA; | 257 fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA; |
195 #else | 258 #else |
196 fDecoderMgr->dinfo()->out_color_space = JCS_EXT_BGRA; | 259 fDecoderMgr->dinfo()->out_color_space = JCS_EXT_BGRA; |
197 #endif | 260 #endif |
198 #endif | 261 #endif |
199 } | 262 } |
200 return true; | 263 return true; |
201 case kRGB_565_SkColorType: | 264 case kRGB_565_SkColorType: |
202 if (isCMYK) { | 265 if (isCMYK) { |
203 fDecoderMgr->dinfo()->out_color_space = JCS_CMYK; | 266 // FIXME (msarett): We need to support 565 here. It's not hard
to do, considering |
| 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; |
204 } else { | 270 } else { |
205 #if defined(GOOGLE3) | 271 #if defined(GOOGLE3) |
206 return false; | 272 return false; |
207 #else | 273 #else |
208 fDecoderMgr->dinfo()->dither_mode = JDITHER_NONE; | 274 fDecoderMgr->dinfo()->dither_mode = JDITHER_NONE; |
209 fDecoderMgr->dinfo()->out_color_space = JCS_RGB565; | 275 fDecoderMgr->dinfo()->out_color_space = JCS_RGB565; |
210 #endif | 276 #endif |
211 } | 277 } |
212 return true; | 278 return true; |
213 case kGray_8_SkColorType: | 279 case kGray_8_SkColorType: |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
292 | 358 |
293 // Now, given valid output dimensions, we can start the decompress | 359 // Now, given valid output dimensions, we can start the decompress |
294 if (!jpeg_start_decompress(dinfo)) { | 360 if (!jpeg_start_decompress(dinfo)) { |
295 return fDecoderMgr->returnFailure("startDecompress", kInvalidInput); | 361 return fDecoderMgr->returnFailure("startDecompress", kInvalidInput); |
296 } | 362 } |
297 | 363 |
298 // The recommended output buffer height should always be 1 in high quality m
odes. | 364 // The recommended output buffer height should always be 1 in high quality m
odes. |
299 // If it's not, we want to know because it means our strategy is not optimal
. | 365 // If it's not, we want to know because it means our strategy is not optimal
. |
300 SkASSERT(1 == dinfo->rec_outbuf_height); | 366 SkASSERT(1 == dinfo->rec_outbuf_height); |
301 | 367 |
302 if (JCS_CMYK == dinfo->out_color_space) { | |
303 this->initializeSwizzler(dstInfo, options); | |
304 } | |
305 | |
306 // Perform the decode a single row at a time | 368 // Perform the decode a single row at a time |
307 uint32_t dstHeight = dstInfo.height(); | 369 uint32_t dstHeight = dstInfo.height(); |
308 | 370 JSAMPLE* dstRow = (JSAMPLE*) dst; |
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 | |
318 for (uint32_t y = 0; y < dstHeight; y++) { | 371 for (uint32_t y = 0; y < dstHeight; y++) { |
319 // Read rows of the image | 372 // Read rows of the image |
320 uint32_t lines = jpeg_read_scanlines(dinfo, &dstRow, 1); | 373 uint32_t lines = jpeg_read_scanlines(dinfo, &dstRow, 1); |
321 | 374 |
322 // If we cannot read enough rows, assume the input is incomplete | 375 // If we cannot read enough rows, assume the input is incomplete |
323 if (lines != 1) { | 376 if (lines != 1) { |
324 *rowsDecoded = y; | 377 *rowsDecoded = y; |
325 | 378 |
326 return fDecoderMgr->returnFailure("Incomplete image data", kIncomple
teInput); | 379 return fDecoderMgr->returnFailure("Incomplete image data", kIncomple
teInput); |
327 } | 380 } |
328 | 381 |
329 if (fSwizzler) { | 382 // Convert to RGBA if necessary |
330 // use swizzler to sample row | 383 if (JCS_CMYK == dinfo->out_color_space) { |
331 fSwizzler->swizzle(dst, dstRow); | 384 convert_CMYK_to_RGBA(dstRow, dstInfo.width()); |
332 dst = SkTAddOffset<JSAMPLE>(dst, dstRowBytes); | |
333 } else { | |
334 dstRow = SkTAddOffset<JSAMPLE>(dstRow, dstRowBytes); | |
335 } | 385 } |
| 386 |
| 387 // Move to the next row |
| 388 dstRow = SkTAddOffset<JSAMPLE>(dstRow, dstRowBytes); |
336 } | 389 } |
337 | 390 |
338 return kSuccess; | 391 return kSuccess; |
339 } | 392 } |
340 | 393 |
341 void SkJpegCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options&
options) { | 394 void SkJpegCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options&
options) { |
342 SkSwizzler::SrcConfig srcConfig = SkSwizzler::kUnknown; | 395 SkSwizzler::SrcConfig srcConfig = SkSwizzler::kUnknown; |
343 if (JCS_CMYK == fDecoderMgr->dinfo()->out_color_space) { | 396 switch (dstInfo.colorType()) { |
344 srcConfig = SkSwizzler::kCMYK; | 397 case kGray_8_SkColorType: |
345 } else { | 398 srcConfig = SkSwizzler::kGray; |
346 switch (dstInfo.colorType()) { | 399 break; |
347 case kGray_8_SkColorType: | 400 case kRGBA_8888_SkColorType: |
348 srcConfig = SkSwizzler::kGray; | 401 srcConfig = SkSwizzler::kRGBX; |
349 break; | 402 break; |
350 case kRGBA_8888_SkColorType: | 403 case kBGRA_8888_SkColorType: |
351 srcConfig = SkSwizzler::kRGBX; | 404 srcConfig = SkSwizzler::kBGRX; |
352 break; | 405 break; |
353 case kBGRA_8888_SkColorType: | 406 case kRGB_565_SkColorType: |
354 srcConfig = SkSwizzler::kBGRX; | 407 srcConfig = SkSwizzler::kRGB_565; |
355 break; | 408 break; |
356 case kRGB_565_SkColorType: | 409 default: |
357 srcConfig = SkSwizzler::kRGB_565; | 410 // This function should only be called if the colorType is supported
by jpeg |
358 break; | |
359 default: | |
360 // This function should only be called if the colorType is suppo
rted by jpeg | |
361 #if defined(GOOGLE3) | 411 #if defined(GOOGLE3) |
362 SK_CRASH(); | 412 SK_CRASH(); |
363 #else | 413 #else |
364 SkASSERT(false); | 414 SkASSERT(false); |
365 #endif | 415 #endif |
366 } | |
367 } | 416 } |
368 | 417 |
369 fSwizzler.reset(SkSwizzler::CreateSwizzler(srcConfig, nullptr, dstInfo, opti
ons)); | 418 fSwizzler.reset(SkSwizzler::CreateSwizzler(srcConfig, nullptr, dstInfo, opti
ons)); |
370 fStorage.reset(get_row_bytes(fDecoderMgr->dinfo())); | 419 fStorage.reset(get_row_bytes(fDecoderMgr->dinfo())); |
371 fSrcRow = static_cast<uint8_t*>(fStorage.get()); | 420 fSrcRow = static_cast<uint8_t*>(fStorage.get()); |
372 } | 421 } |
373 | 422 |
374 SkSampler* SkJpegCodec::getSampler(bool createIfNecessary) { | 423 SkSampler* SkJpegCodec::getSampler(bool createIfNecessary) { |
375 if (!createIfNecessary || fSwizzler) { | 424 if (!createIfNecessary || fSwizzler) { |
376 SkASSERT(!fSwizzler || (fSrcRow && static_cast<uint8_t*>(fStorage.get())
== fSrcRow)); | 425 SkASSERT(!fSwizzler || (fSrcRow && static_cast<uint8_t*>(fStorage.get())
== fSrcRow)); |
(...skipping 21 matching lines...) Expand all Loading... |
398 fSwizzler.reset(nullptr); | 447 fSwizzler.reset(nullptr); |
399 fSrcRow = nullptr; | 448 fSrcRow = nullptr; |
400 fStorage.free(); | 449 fStorage.free(); |
401 | 450 |
402 // Now, given valid output dimensions, we can start the decompress | 451 // Now, given valid output dimensions, we can start the decompress |
403 if (!jpeg_start_decompress(fDecoderMgr->dinfo())) { | 452 if (!jpeg_start_decompress(fDecoderMgr->dinfo())) { |
404 SkCodecPrintf("start decompress failed\n"); | 453 SkCodecPrintf("start decompress failed\n"); |
405 return kInvalidInput; | 454 return kInvalidInput; |
406 } | 455 } |
407 | 456 |
408 // We will need a swizzler if we are performing a subset decode or | 457 // We will need a swizzler if we are performing a subset decode |
409 // converting from CMYK. | 458 if (options.fSubset) { |
410 if (options.fSubset || JCS_CMYK == fDecoderMgr->dinfo()->out_color_space) { | |
411 this->initializeSwizzler(dstInfo, options); | 459 this->initializeSwizzler(dstInfo, options); |
412 } | 460 } |
413 | 461 |
414 return kSuccess; | 462 return kSuccess; |
415 } | 463 } |
416 | 464 |
417 int SkJpegCodec::onGetScanlines(void* dst, int count, size_t rowBytes) { | 465 int SkJpegCodec::onGetScanlines(void* dst, int count, size_t rowBytes) { |
418 // Set the jump location for libjpeg errors | 466 // Set the jump location for libjpeg errors |
419 if (setjmp(fDecoderMgr->getJmpBuf())) { | 467 if (setjmp(fDecoderMgr->getJmpBuf())) { |
420 return fDecoderMgr->returnFailure("setjmp", kInvalidInput); | 468 return fDecoderMgr->returnFailure("setjmp", kInvalidInput); |
421 } | 469 } |
422 // Read rows one at a time | 470 // Read rows one at a time |
423 JSAMPLE* dstRow; | 471 JSAMPLE* dstRow; |
424 if (fSwizzler) { | 472 if (fSwizzler) { |
425 // write data to storage row, then sample using swizzler | 473 // write data to storage row, then sample using swizzler |
426 dstRow = fSrcRow; | 474 dstRow = fSrcRow; |
427 } else { | 475 } else { |
428 // write data directly to dst | 476 // write data directly to dst |
429 dstRow = (JSAMPLE*) dst; | 477 dstRow = (JSAMPLE*) dst; |
430 } | 478 } |
431 | 479 |
432 for (int y = 0; y < count; y++) { | 480 for (int y = 0; y < count; y++) { |
433 // Read row of the image | 481 // Read row of the image |
434 uint32_t rowsDecoded = jpeg_read_scanlines(fDecoderMgr->dinfo(), &dstRow
, 1); | 482 uint32_t rowsDecoded = jpeg_read_scanlines(fDecoderMgr->dinfo(), &dstRow
, 1); |
435 if (rowsDecoded != 1) { | 483 if (rowsDecoded != 1) { |
436 fDecoderMgr->dinfo()->output_scanline = this->dstInfo().height(); | 484 fDecoderMgr->dinfo()->output_scanline = this->dstInfo().height(); |
437 return y; | 485 return y; |
438 } | 486 } |
439 | 487 |
440 if (fSwizzler) { | 488 // Convert to RGBA if necessary |
| 489 if (JCS_CMYK == fDecoderMgr->dinfo()->out_color_space) { |
| 490 convert_CMYK_to_RGBA(dstRow, fDecoderMgr->dinfo()->output_width); |
| 491 } |
| 492 |
| 493 if(fSwizzler) { |
441 // use swizzler to sample row | 494 // use swizzler to sample row |
442 fSwizzler->swizzle(dst, dstRow); | 495 fSwizzler->swizzle(dst, dstRow); |
443 dst = SkTAddOffset<JSAMPLE>(dst, rowBytes); | 496 dst = SkTAddOffset<JSAMPLE>(dst, rowBytes); |
444 } else { | 497 } else { |
445 dstRow = SkTAddOffset<JSAMPLE>(dstRow, rowBytes); | 498 dstRow = SkTAddOffset<JSAMPLE>(dstRow, rowBytes); |
446 } | 499 } |
447 } | 500 } |
448 return count; | 501 return count; |
449 } | 502 } |
450 | 503 |
(...skipping 12 matching lines...) Expand all Loading... |
463 #endif | 516 #endif |
464 | 517 |
465 bool SkJpegCodec::onSkipScanlines(int count) { | 518 bool SkJpegCodec::onSkipScanlines(int count) { |
466 // Set the jump location for libjpeg errors | 519 // Set the jump location for libjpeg errors |
467 if (setjmp(fDecoderMgr->getJmpBuf())) { | 520 if (setjmp(fDecoderMgr->getJmpBuf())) { |
468 return fDecoderMgr->returnFalse("setjmp"); | 521 return fDecoderMgr->returnFalse("setjmp"); |
469 } | 522 } |
470 | 523 |
471 return (uint32_t) count == jpeg_skip_scanlines(fDecoderMgr->dinfo(), count); | 524 return (uint32_t) count == jpeg_skip_scanlines(fDecoderMgr->dinfo(), count); |
472 } | 525 } |
OLD | NEW |