OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright 2010 The Android Open Source Project | 2 * Copyright 2010 The Android Open Source Project |
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 "SkPDFImage.h" | 8 #include "SkPDFImage.h" |
9 | 9 |
10 #include "SkBitmap.h" | 10 #include "SkBitmap.h" |
(...skipping 349 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
360 SkColor color = SkUnPreMultiply::PMColorToColor((*table)[i]); | 360 SkColor color = SkUnPreMultiply::PMColorToColor((*table)[i]); |
361 buf[0] = SkGetPackedR32(color); | 361 buf[0] = SkGetPackedR32(color); |
362 buf[1] = SkGetPackedG32(color); | 362 buf[1] = SkGetPackedG32(color); |
363 buf[2] = SkGetPackedB32(color); | 363 buf[2] = SkGetPackedB32(color); |
364 index.append(buf, 3); | 364 index.append(buf, 3); |
365 } | 365 } |
366 result->append(new SkPDFString(index))->unref(); | 366 result->append(new SkPDFString(index))->unref(); |
367 return result; | 367 return result; |
368 } | 368 } |
369 | 369 |
370 /** | |
371 * Unpremultiply an ARGB color, keeping the output in the same format | |
372 * as the input. | |
373 */ | |
374 static uint32_t unpremultiply_argb8888(uint32_t src) { | |
vandebo (ex-Chrome)
2013/08/23 06:16:11
nit: src -> pm_color
ducky
2013/08/23 08:06:11
Done.
| |
375 uint8_t a = SkGetPackedA32(src); | |
376 SkUnPreMultiply::Scale scale = SkUnPreMultiply::GetScale(a); | |
377 return SkPackARGB32NoCheck( | |
378 SK_AlphaOPAQUE, | |
379 SkUnPreMultiply::ApplyScale(scale, SkGetPackedR32(src)), | |
vandebo (ex-Chrome)
2013/08/23 06:16:11
I think it's nicer to hide the scale stuff, so on
ducky
2013/08/23 08:06:11
Done.
| |
380 SkUnPreMultiply::ApplyScale(scale, SkGetPackedG32(src)), | |
381 SkUnPreMultiply::ApplyScale(scale, SkGetPackedB32(src))); | |
382 } | |
383 | |
384 static uint16_t unpremultiply_argb4444(uint16_t src) { | |
385 // Unpack and transform the alpha values from 4 bits to 8 bits. | |
386 // This is necessary since the unpremultiply functions expect to work in | |
387 // 8-bit space, but we are passing in 4-bit values. Since we scale up | |
388 // the alpha, we scale down the amount the value is increased by, so that | |
389 // the results are correct for 4-bit color components. | |
390 uint8_t alpha = SkGetPackedA4444(src); | |
vandebo (ex-Chrome)
2013/08/23 06:16:11
While it might be a bit wasteful, the simplest thi
ducky
2013/08/23 08:06:11
Ehhhhhh - it would make more sense if the code had
vandebo (ex-Chrome)
2013/08/23 16:09:17
Just because it's already written is not a good re
ducky
2013/08/23 18:49:17
Done.
Though for performance overhead, it could al
| |
391 alpha = (alpha << 4) | alpha; | |
392 SkUnPreMultiply::Scale scale = SkUnPreMultiply::GetScale(alpha); | |
393 return SkPackARGB4444(SK_AlphaOPAQUE & 0x0F, | |
394 SkUnPreMultiply::ApplyScale(scale, SkGetPackedR4444(src)), | |
395 SkUnPreMultiply::ApplyScale(scale, SkGetPackedG4444(src)), | |
396 SkUnPreMultiply::ApplyScale(scale, SkGetPackedB4444(src))); | |
397 } | |
398 | |
399 static void argb8888_pixel_sum(uint32_t pixel, uint8_t* count, | |
vandebo (ex-Chrome)
2013/08/23 06:16:11
Since this is only used in one place, I think it'l
ducky
2013/08/23 08:06:11
Ok. Though the nested loops doesn't that look nice
| |
400 uint16_t* r, uint16_t* g, uint16_t* b) { | |
401 if (SkGetPackedA32(pixel) != SK_AlphaTRANSPARENT) { | |
402 uint32_t color = unpremultiply_argb8888(pixel); | |
403 *r += SkGetPackedR32(color); | |
404 *g += SkGetPackedG32(color); | |
405 *b += SkGetPackedB32(color); | |
406 (*count)++; | |
407 } | |
408 } | |
409 | |
410 static void argb4444_pixel_sum(uint16_t pixel, uint8_t* count, | |
411 uint8_t* r, uint8_t* g, uint8_t* b) { | |
412 if ((SkGetPackedA4444(pixel) & 0x0F) != SK_AlphaTRANSPARENT) { | |
413 uint16_t color = unpremultiply_argb4444(pixel); | |
414 *r += SkGetPackedR4444(color); | |
415 *g += SkGetPackedG4444(color); | |
416 *b += SkGetPackedB4444(color); | |
417 (*count)++; | |
418 } | |
419 } | |
420 | |
421 static uint32_t get_argb8888_neighbor_color(const SkBitmap& bitmap, | |
422 int xOrig, int yOrig) { | |
423 uint8_t count = 0; | |
424 uint16_t r = 0; | |
425 uint16_t g = 0; | |
426 uint16_t b = 0; | |
427 | |
428 for (int y = yOrig - 1; y <= yOrig + 1; y++) { | |
429 if (y < 0 || y >= bitmap.height()) { | |
430 continue; | |
431 } | |
432 uint32_t* src = bitmap.getAddr32(0, y); | |
433 for (int x = xOrig - 1; x <= xOrig + 1; x++) { | |
434 if (x < 0 || x >= bitmap.width()) { | |
435 continue; | |
436 } | |
437 argb8888_pixel_sum(src[x], &count, &r, &g, &b); | |
438 } | |
439 } | |
440 | |
441 if (count == 0) { | |
442 return SkPackARGB32NoCheck(SK_AlphaOPAQUE, 0, 0, 0); | |
vandebo (ex-Chrome)
2013/08/23 06:16:11
return SK_ColorBLACK
ducky
2013/08/23 08:06:11
SkColor packing doesn't necessarily match ARGB8888
| |
443 } else { | |
444 return SkPackARGB32NoCheck(SK_AlphaOPAQUE, | |
445 r / count, g / count, b / count); | |
446 } | |
447 } | |
448 | |
449 static uint16_t get_argb4444_neighbor_color(const SkBitmap& bitmap, | |
vandebo (ex-Chrome)
2013/08/23 06:16:11
nit: ...neighbor_color_avg
ducky
2013/08/23 08:06:11
Done.
| |
450 int xOrig, int yOrig) { | |
451 uint8_t count = 0; | |
452 uint8_t r = 0; | |
453 uint8_t g = 0; | |
454 uint8_t b = 0; | |
455 | |
456 for (int y = yOrig - 1; y <= yOrig + 1; y++) { | |
457 if (y < 0 || y >= bitmap.height()) { | |
458 continue; | |
459 } | |
460 uint16_t* src = bitmap.getAddr16(0, y); | |
461 for (int x = xOrig - 1; x <= xOrig + 1; x++) { | |
462 if (x < 0 || x >= bitmap.width()) { | |
463 continue; | |
464 } | |
465 argb4444_pixel_sum(src[x], &count, &r, &g, &b); | |
466 } | |
467 } | |
468 | |
469 if (count == 0) { | |
470 return SkPackARGB4444(SK_AlphaOPAQUE & 0x0F, 0, 0, 0); | |
471 } else { | |
472 return SkPackARGB4444(SK_AlphaOPAQUE & 0x0F, | |
473 r / count, g / count, b / count); | |
474 } | |
475 } | |
476 | |
477 static SkBitmap unpremultiply_bitmap(const SkBitmap& bitmap, | |
478 const SkIRect& srcRect) { | |
479 SkBitmap outBitmap; | |
480 outBitmap.setConfig(bitmap.config(), srcRect.width(), srcRect.height()); | |
481 SkASSERT(outBitmap.allocPixels()); | |
482 size_t dstRow = 0; | |
483 | |
484 outBitmap.lockPixels(); | |
485 bitmap.lockPixels(); | |
486 switch (bitmap.config()) { | |
487 case SkBitmap::kARGB_4444_Config: { | |
488 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) { | |
vandebo (ex-Chrome)
2013/08/23 06:16:11
y++, dstRow++ ?
ducky
2013/08/23 08:06:11
It's kind of nice to keep the loop self-contained
| |
489 uint16_t* dst = outBitmap.getAddr16(0, dstRow); | |
490 uint16_t* src = bitmap.getAddr16(0, y); | |
491 for (int x = srcRect.fLeft; x < srcRect.fRight; x++) { | |
vandebo (ex-Chrome)
2013/08/23 06:16:11
x++, dst++
ducky
2013/08/23 08:06:11
Same as above.
| |
492 uint8_t a = SkGetPackedA4444(src[x]); | |
493 if ((a & 0x0F) == SK_AlphaTRANSPARENT) { | |
vandebo (ex-Chrome)
2013/08/23 06:16:11
if (a == (SK_AlphaTRANSPARENT & 0x0F))
vandebo (ex-Chrome)
2013/08/23 06:16:11
A big comment here about why we need to do this wo
ducky
2013/08/23 08:06:11
Done.
ducky
2013/08/23 08:06:11
Done.
vandebo (ex-Chrome)
2013/08/23 16:09:17
Sorry, I didn't mean a comment about masking the b
ducky
2013/08/23 18:49:17
Done.
| |
494 *dst = get_argb4444_neighbor_color(bitmap, x, y); | |
495 } else { | |
496 *dst = unpremultiply_argb4444(src[x]); | |
497 } | |
498 dst++; | |
499 } | |
500 dstRow++; | |
501 } | |
502 } break; | |
vandebo (ex-Chrome)
2013/08/23 06:16:11
Put the break inside the braces.
ducky
2013/08/23 08:06:11
Done.
| |
503 case SkBitmap::kARGB_8888_Config: { | |
504 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) { | |
505 uint32_t* dst = outBitmap.getAddr32(0, dstRow); | |
506 uint32_t* src = bitmap.getAddr32(0, y); | |
507 for (int x = srcRect.fLeft; x < srcRect.fRight; x++) { | |
508 uint8_t a = SkGetPackedA32(src[x]); | |
509 if (a == SK_AlphaTRANSPARENT) { | |
510 *dst = get_argb8888_neighbor_color(bitmap, x, y); | |
511 } else { | |
512 *dst = unpremultiply_argb8888(src[x]); | |
513 } | |
514 dst++; | |
515 } | |
516 dstRow++; | |
517 } | |
518 } break; | |
519 default: | |
520 SkASSERT(false); | |
521 } | |
522 bitmap.unlockPixels(); | |
523 outBitmap.unlockPixels(); | |
524 | |
525 outBitmap.setImmutable(); | |
526 | |
527 return outBitmap; | |
528 } | |
529 | |
370 // static | 530 // static |
371 SkPDFImage* SkPDFImage::CreateImage(const SkBitmap& bitmap, | 531 SkPDFImage* SkPDFImage::CreateImage(const SkBitmap& bitmap, |
372 const SkIRect& srcRect, | 532 const SkIRect& srcRect, |
373 EncodeToDCTStream encoder) { | 533 EncodeToDCTStream encoder) { |
374 if (bitmap.getConfig() == SkBitmap::kNo_Config) { | 534 if (bitmap.getConfig() == SkBitmap::kNo_Config) { |
375 return NULL; | 535 return NULL; |
376 } | 536 } |
377 | 537 |
378 bool isTransparent; | 538 bool isTransparent; |
379 SkAutoTUnref<SkStream> alphaData( | 539 SkAutoTUnref<SkStream> alphaData( |
380 extract_image_data(bitmap, srcRect, true, &isTransparent)); | 540 extract_image_data(bitmap, srcRect, true, &isTransparent)); |
381 if (isTransparent) { | 541 if (isTransparent) { |
382 return NULL; | 542 return NULL; |
383 } | 543 } |
384 | 544 |
385 SkPDFImage* image = SkNEW_ARGS(SkPDFImage, (bitmap, srcRect, encoder)); | 545 SkPDFImage* image; |
546 SkBitmap::Config config = bitmap.config(); | |
547 if (alphaData.get() != NULL && (config == SkBitmap::kARGB_8888_Config || | |
548 config == SkBitmap::kARGB_4444_Config)) { | |
549 SkBitmap unpremulBitmap = unpremultiply_bitmap(bitmap, srcRect); | |
550 SkIRect newSrcRect = srcRect; | |
551 newSrcRect.offset(-srcRect.left(), -srcRect.top()); | |
552 image = SkNEW_ARGS(SkPDFImage, (unpremulBitmap, srcRect, encoder)); | |
vandebo (ex-Chrome)
2013/08/23 06:16:11
You need to use newSrcRect here.
ducky
2013/08/23 08:06:11
Done.
| |
553 } else { | |
554 image = SkNEW_ARGS(SkPDFImage, (bitmap, srcRect, encoder)); | |
555 } | |
386 if (alphaData.get() != NULL) { | 556 if (alphaData.get() != NULL) { |
387 SkAutoTUnref<SkPDFImage> mask( | 557 SkAutoTUnref<SkPDFImage> mask( |
388 SkNEW_ARGS(SkPDFImage, (alphaData.get(), bitmap, srcRect))); | 558 SkNEW_ARGS(SkPDFImage, (alphaData.get(), bitmap, srcRect))); |
389 image->addSMask(mask); | 559 image->addSMask(mask); |
390 } | 560 } |
391 | 561 |
392 return image; | 562 return image; |
393 } | 563 } |
394 | 564 |
395 SkPDFImage::~SkPDFImage() { | 565 SkPDFImage::~SkPDFImage() { |
396 fResources.unrefAll(); | 566 fResources.unrefAll(); |
397 } | 567 } |
398 | 568 |
399 SkPDFImage* SkPDFImage::addSMask(SkPDFImage* mask) { | 569 SkPDFImage* SkPDFImage::addSMask(SkPDFImage* mask) { |
400 fResources.push(mask); | 570 fResources.push(mask); |
401 mask->ref(); | 571 mask->ref(); |
402 insert("SMask", new SkPDFObjRef(mask))->unref(); | 572 insert("SMask", new SkPDFObjRef(mask))->unref(); |
403 return mask; | 573 return mask; |
404 } | 574 } |
405 | 575 |
406 void SkPDFImage::getResources(const SkTSet<SkPDFObject*>& knownResourceObjects, | 576 void SkPDFImage::getResources(const SkTSet<SkPDFObject*>& knownResourceObjects, |
407 SkTSet<SkPDFObject*>* newResourceObjects) { | 577 SkTSet<SkPDFObject*>* newResourceObjects) { |
408 GetResourcesHelper(&fResources, knownResourceObjects, newResourceObjects); | 578 GetResourcesHelper(&fResources, knownResourceObjects, newResourceObjects); |
409 } | 579 } |
410 | 580 |
411 SkPDFImage::SkPDFImage(const SkBitmap& bitmap, | 581 SkPDFImage::SkPDFImage(const SkBitmap& bitmap, |
412 const SkIRect& srcRect, | 582 const SkIRect& srcRect, |
413 EncodeToDCTStream encoder) | 583 EncodeToDCTStream encoder) |
414 : fBitmap(bitmap), | 584 : fSrcRect(srcRect), |
415 fSrcRect(srcRect), | |
416 fEncoder(encoder), | 585 fEncoder(encoder), |
417 fStreamValid(false) { | 586 fStreamValid(false) { |
587 initBitmap(bitmap); | |
418 initImageParams(false); | 588 initImageParams(false); |
419 } | 589 } |
420 | 590 |
421 SkPDFImage::SkPDFImage(SkStream* stream, const SkBitmap& bitmap, | 591 SkPDFImage::SkPDFImage(SkStream* stream, const SkBitmap& bitmap, |
422 const SkIRect& srcRect) | 592 const SkIRect& srcRect) |
423 : fBitmap(bitmap), | 593 : fSrcRect(srcRect), |
424 fSrcRect(srcRect), | |
425 fEncoder(NULL), | 594 fEncoder(NULL), |
426 fStreamValid(true) { | 595 fStreamValid(true) { |
427 setData(stream); | 596 setData(stream); |
597 initBitmap(bitmap); | |
428 initImageParams(true); | 598 initImageParams(true); |
429 } | 599 } |
430 | 600 |
431 SkPDFImage::SkPDFImage(SkPDFImage& pdfImage) | 601 SkPDFImage::SkPDFImage(SkPDFImage& pdfImage) |
432 : SkPDFStream(pdfImage), | 602 : SkPDFStream(pdfImage), |
433 fBitmap(pdfImage.fBitmap), | 603 fBitmap(pdfImage.fBitmap), |
434 fSrcRect(pdfImage.fSrcRect), | 604 fSrcRect(pdfImage.fSrcRect), |
435 fEncoder(pdfImage.fEncoder), | 605 fEncoder(pdfImage.fEncoder), |
436 fStreamValid(pdfImage.fStreamValid) { | 606 fStreamValid(pdfImage.fStreamValid) { |
437 // Nothing to do here - the image params are already copied in SkPDFStream's | 607 // Nothing to do here - the image params are already copied in SkPDFStream's |
438 // constructor, and the bitmap will be regenerated and re-encoded in | 608 // constructor, and the bitmap will be regenerated and re-encoded in |
439 // populate. | 609 // populate. It is assumed that the source bitmap is immutable. |
610 } | |
611 | |
612 void SkPDFImage::initBitmap(const SkBitmap& bitmap) { | |
613 if (bitmap.isImmutable()) { | |
614 fBitmap = bitmap; | |
615 } else { | |
616 bitmap.deepCopyTo(&fBitmap, bitmap.config()); | |
617 fBitmap.setImmutable(); | |
618 } | |
440 } | 619 } |
441 | 620 |
442 void SkPDFImage::initImageParams(bool isAlpha) { | 621 void SkPDFImage::initImageParams(bool isAlpha) { |
443 SkBitmap::Config config = fBitmap.getConfig(); | 622 SkBitmap::Config config = fBitmap.getConfig(); |
444 | 623 |
445 insertName("Type", "XObject"); | 624 insertName("Type", "XObject"); |
446 insertName("Subtype", "Image"); | 625 insertName("Subtype", "Image"); |
447 | 626 |
448 bool alphaOnly = (config == SkBitmap::kA1_Config || | 627 bool alphaOnly = (config == SkBitmap::kA1_Config || |
449 config == SkBitmap::kA8_Config); | 628 config == SkBitmap::kA8_Config); |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
531 // but the new catalog wants it compressed. | 710 // but the new catalog wants it compressed. |
532 if (!getSubstitute()) { | 711 if (!getSubstitute()) { |
533 SkPDFStream* substitute = SkNEW_ARGS(SkPDFImage, (*this)); | 712 SkPDFStream* substitute = SkNEW_ARGS(SkPDFImage, (*this)); |
534 setSubstitute(substitute); | 713 setSubstitute(substitute); |
535 catalog->setSubstitute(this, substitute); | 714 catalog->setSubstitute(this, substitute); |
536 } | 715 } |
537 return false; | 716 return false; |
538 } | 717 } |
539 return true; | 718 return true; |
540 } | 719 } |
OLD | NEW |