Chromium Code Reviews| 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 |