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 318 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
329 SkColor color = SkUnPreMultiply::PMColorToColor((*table)[i]); | 329 SkColor color = SkUnPreMultiply::PMColorToColor((*table)[i]); |
330 buf[0] = SkGetPackedR32(color); | 330 buf[0] = SkGetPackedR32(color); |
331 buf[1] = SkGetPackedG32(color); | 331 buf[1] = SkGetPackedG32(color); |
332 buf[2] = SkGetPackedB32(color); | 332 buf[2] = SkGetPackedB32(color); |
333 index.append(buf, 3); | 333 index.append(buf, 3); |
334 } | 334 } |
335 result->append(new SkPDFString(index))->unref(); | 335 result->append(new SkPDFString(index))->unref(); |
336 return result; | 336 return result; |
337 } | 337 } |
338 | 338 |
339 /** | |
340 * Removes the alpha component of an ARGB color (including unpremultiply) while | |
341 * keeping the output in the same format as the input. | |
342 */ | |
343 static uint32_t remove_alpha_argb8888(uint32_t pmColor) { | |
344 SkColor color = SkUnPreMultiply::PMColorToColor(pmColor); | |
345 return SkPackARGB32NoCheck(SK_AlphaOPAQUE, | |
346 SkColorGetR(color), | |
347 SkColorGetG(color), | |
348 SkColorGetB(color)); | |
349 } | |
350 | |
351 static uint16_t remove_alpha_argb4444(uint16_t pmColor) { | |
352 return SkPixel32ToPixel4444( | |
353 remove_alpha_argb8888(SkPixel4444ToPixel32(pmColor))); | |
354 } | |
355 | |
356 static uint32_t get_argb8888_neighbor_avg_color(const SkBitmap& bitmap, | |
357 int xOrig, int yOrig) { | |
358 uint8_t count = 0; | |
359 uint16_t r = 0; | |
360 uint16_t g = 0; | |
361 uint16_t b = 0; | |
362 | |
363 for (int y = yOrig - 1; y <= yOrig + 1; y++) { | |
364 if (y < 0 || y >= bitmap.height()) { | |
365 continue; | |
366 } | |
367 uint32_t* src = bitmap.getAddr32(0, y); | |
368 for (int x = xOrig - 1; x <= xOrig + 1; x++) { | |
369 if (x < 0 || x >= bitmap.width()) { | |
370 continue; | |
371 } | |
372 if (SkGetPackedA32(src[x]) != SK_AlphaTRANSPARENT) { | |
373 uint32_t color = remove_alpha_argb8888(src[x]); | |
374 r += SkGetPackedR32(color); | |
375 g += SkGetPackedG32(color); | |
376 b += SkGetPackedB32(color); | |
377 count++; | |
378 } | |
379 } | |
380 } | |
381 | |
382 if (count == 0) { | |
383 return SkPackARGB32NoCheck(SK_AlphaOPAQUE, 0, 0, 0); | |
384 } else { | |
385 return SkPackARGB32NoCheck(SK_AlphaOPAQUE, | |
386 r / count, g / count, b / count); | |
387 } | |
388 } | |
389 | |
390 static uint16_t get_argb4444_neighbor_avg_color(const SkBitmap& bitmap, | |
391 int xOrig, int yOrig) { | |
392 uint8_t count = 0; | |
393 uint8_t r = 0; | |
394 uint8_t g = 0; | |
395 uint8_t b = 0; | |
396 | |
397 for (int y = yOrig - 1; y <= yOrig + 1; y++) { | |
398 if (y < 0 || y >= bitmap.height()) { | |
399 continue; | |
400 } | |
401 uint16_t* src = bitmap.getAddr16(0, y); | |
402 for (int x = xOrig - 1; x <= xOrig + 1; x++) { | |
403 if (x < 0 || x >= bitmap.width()) { | |
404 continue; | |
405 } | |
406 if ((SkGetPackedA4444(src[x]) & 0x0F) != SK_AlphaTRANSPARENT) { | |
407 uint16_t color = remove_alpha_argb4444(src[x]); | |
408 r += SkGetPackedR4444(color); | |
409 g += SkGetPackedG4444(color); | |
410 b += SkGetPackedB4444(color); | |
411 count++; | |
412 } | |
413 } | |
414 } | |
415 | |
416 if (count == 0) { | |
417 return SkPackARGB4444(SK_AlphaOPAQUE & 0x0F, 0, 0, 0); | |
418 } else { | |
419 return SkPackARGB4444(SK_AlphaOPAQUE & 0x0F, | |
420 r / count, g / count, b / count); | |
421 } | |
422 } | |
423 | |
424 static SkBitmap unpremultiply_bitmap(const SkBitmap& bitmap, | |
425 const SkIRect& srcRect) { | |
426 SkBitmap outBitmap; | |
427 outBitmap.setConfig(bitmap.config(), srcRect.width(), srcRect.height()); | |
428 SkASSERT(outBitmap.allocPixels()); | |
429 size_t dstRow = 0; | |
430 | |
431 outBitmap.lockPixels(); | |
432 bitmap.lockPixels(); | |
433 switch (bitmap.config()) { | |
434 case SkBitmap::kARGB_4444_Config: { | |
435 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) { | |
436 uint16_t* dst = outBitmap.getAddr16(0, dstRow); | |
437 uint16_t* src = bitmap.getAddr16(0, y); | |
438 for (int x = srcRect.fLeft; x < srcRect.fRight; x++) { | |
439 uint8_t a = SkGetPackedA4444(src[x]); | |
440 // It is necessary to average the color component of | |
441 // transparent pixels with their surrounding neighbors | |
442 // since the PDF renderer may separately re-sample the | |
443 // alpha and color channels when the image is not | |
444 // displayed at its native resolution. Since an alpha of | |
445 // zero gives no information about the color component, | |
446 // the pathological case is a white image with sharp | |
447 // transparency bounds - the color channel goes to black, | |
448 // and the should-be-transparent pixels are rendered | |
449 // as grey because of the separate soft mask and color | |
450 // resizing. | |
451 if (a == (SK_AlphaTRANSPARENT & 0x0F)) { | |
452 *dst = get_argb4444_neighbor_avg_color(bitmap, x, y); | |
453 } else { | |
454 *dst = remove_alpha_argb4444(src[x]); | |
455 } | |
456 dst++; | |
457 } | |
458 dstRow++; | |
459 } | |
460 break; | |
461 } | |
462 case SkBitmap::kARGB_8888_Config: { | |
463 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) { | |
464 uint32_t* dst = outBitmap.getAddr32(0, dstRow); | |
465 uint32_t* src = bitmap.getAddr32(0, y); | |
466 for (int x = srcRect.fLeft; x < srcRect.fRight; x++) { | |
467 uint8_t a = SkGetPackedA32(src[x]); | |
468 if (a == SK_AlphaTRANSPARENT) { | |
469 *dst = get_argb8888_neighbor_avg_color(bitmap, x, y); | |
470 } else { | |
471 *dst = remove_alpha_argb8888(src[x]); | |
472 } | |
473 dst++; | |
474 } | |
475 dstRow++; | |
476 } | |
477 break; | |
478 } | |
479 default: | |
480 SkASSERT(false); | |
481 } | |
482 bitmap.unlockPixels(); | |
483 outBitmap.unlockPixels(); | |
484 | |
485 outBitmap.setImmutable(); | |
486 | |
487 return outBitmap; | |
488 } | |
489 | |
490 // static | 339 // static |
491 SkPDFImage* SkPDFImage::CreateImage(const SkBitmap& bitmap, | 340 SkPDFImage* SkPDFImage::CreateImage(const SkBitmap& bitmap, |
492 const SkIRect& srcRect, | 341 const SkIRect& srcRect, |
493 SkPicture::EncodeBitmap encoder) { | 342 SkPicture::EncodeBitmap encoder) { |
494 if (bitmap.getConfig() == SkBitmap::kNo_Config) { | 343 if (bitmap.getConfig() == SkBitmap::kNo_Config) { |
495 return NULL; | 344 return NULL; |
496 } | 345 } |
497 | 346 |
498 bool isTransparent = false; | 347 bool isTransparent = false; |
499 SkAutoTUnref<SkStream> alphaData; | 348 SkAutoTUnref<SkStream> alphaData; |
500 if (!bitmap.isOpaque()) { | 349 if (!bitmap.isOpaque()) { |
501 // Note that isOpaque is not guaranteed to return false for bitmaps | 350 // Note that isOpaque is not guaranteed to return false for bitmaps |
502 // with alpha support but a completely opaque alpha channel, | 351 // with alpha support but a completely opaque alpha channel, |
503 // so alphaData may still be NULL if we have a completely opaque | 352 // so alphaData may still be NULL if we have a completely opaque |
504 // (or transparent) bitmap. | 353 // (or transparent) bitmap. |
505 alphaData.reset( | 354 alphaData.reset( |
506 extract_image_data(bitmap, srcRect, true, &isTransparent)); | 355 extract_image_data(bitmap, srcRect, true, &isTransparent)); |
507 } | 356 } |
508 if (isTransparent) { | 357 if (isTransparent) { |
509 return NULL; | 358 return NULL; |
510 } | 359 } |
511 | 360 |
512 SkPDFImage* image; | 361 SkPDFImage* image = SkNEW_ARGS(SkPDFImage, (NULL, bitmap, |
513 SkBitmap::Config config = bitmap.config(); | 362 false, srcRect, encoder)); |
514 if (alphaData.get() != NULL && (config == SkBitmap::kARGB_8888_Config || | |
515 config == SkBitmap::kARGB_4444_Config)) { | |
516 SkBitmap unpremulBitmap = unpremultiply_bitmap(bitmap, srcRect); | |
517 image = SkNEW_ARGS(SkPDFImage, (NULL, unpremulBitmap, false, | |
518 SkIRect::MakeWH(srcRect.width(), srcRect.height()), | |
519 encoder)); | |
520 } else { | |
521 image = SkNEW_ARGS(SkPDFImage, (NULL, bitmap, false, srcRect, encoder)); | |
522 } | |
523 if (alphaData.get() != NULL) { | 363 if (alphaData.get() != NULL) { |
524 SkAutoTUnref<SkPDFImage> mask( | 364 SkAutoTUnref<SkPDFImage> mask( |
525 SkNEW_ARGS(SkPDFImage, (alphaData.get(), bitmap, | 365 SkNEW_ARGS(SkPDFImage, (alphaData.get(), bitmap, |
526 true, srcRect, NULL))); | 366 true, srcRect, NULL))); |
527 image->addSMask(mask); | 367 image->addSMask(mask); |
528 } | 368 } |
529 | 369 |
530 return image; | 370 return image; |
531 } | 371 } |
532 | 372 |
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
680 // but the new catalog wants it compressed. | 520 // but the new catalog wants it compressed. |
681 if (!getSubstitute()) { | 521 if (!getSubstitute()) { |
682 SkPDFStream* substitute = SkNEW_ARGS(SkPDFImage, (*this)); | 522 SkPDFStream* substitute = SkNEW_ARGS(SkPDFImage, (*this)); |
683 setSubstitute(substitute); | 523 setSubstitute(substitute); |
684 catalog->setSubstitute(this, substitute); | 524 catalog->setSubstitute(this, substitute); |
685 } | 525 } |
686 return false; | 526 return false; |
687 } | 527 } |
688 return true; | 528 return true; |
689 } | 529 } |
OLD | NEW |