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" |
11 #include "SkColor.h" | 11 #include "SkColor.h" |
12 #include "SkColorPriv.h" | 12 #include "SkColorPriv.h" |
13 #include "SkData.h" | 13 #include "SkData.h" |
14 #include "SkFlate.h" | 14 #include "SkFlate.h" |
15 #include "SkPDFCatalog.h" | 15 #include "SkPDFCatalog.h" |
16 #include "SkRect.h" | 16 #include "SkRect.h" |
17 #include "SkStream.h" | 17 #include "SkStream.h" |
18 #include "SkString.h" | 18 #include "SkString.h" |
19 #include "SkUnPreMultiply.h" | 19 #include "SkUnPreMultiply.h" |
20 | 20 |
21 static const int kNoColorTransform = 0; | 21 static const int kNoColorTransform = 0; |
22 | 22 |
23 static bool skip_compression(SkPDFCatalog* catalog) { | 23 static bool skip_compression(SkPDFCatalog* catalog) { |
24 return SkToBool(catalog->getDocumentFlags() & | 24 return SkToBool(catalog->getDocumentFlags() & |
25 SkPDFDocument::kFavorSpeedOverSize_Flags); | 25 SkPDFDocument::kFavorSpeedOverSize_Flags); |
26 } | 26 } |
27 | 27 |
28 static size_t get_uncompressed_size(const SkBitmap& bitmap, | 28 static size_t get_uncompressed_size(const SkBitmap& bitmap, |
29 const SkIRect& srcRect) { | 29 const SkIRect& srcRect) { |
30 switch (bitmap.config()) { | 30 switch (bitmap.colorType()) { |
31 case SkBitmap::kIndex8_Config: | 31 case kIndex_8_SkColorType: |
32 return srcRect.width() * srcRect.height(); | 32 return srcRect.width() * srcRect.height(); |
33 case SkBitmap::kARGB_4444_Config: | 33 case kARGB_4444_SkColorType: |
34 return ((srcRect.width() * 3 + 1) / 2) * srcRect.height(); | 34 return ((srcRect.width() * 3 + 1) / 2) * srcRect.height(); |
35 case SkBitmap::kRGB_565_Config: | 35 case kRGB_565_SkColorType: |
36 return srcRect.width() * 3 * srcRect.height(); | 36 return srcRect.width() * 3 * srcRect.height(); |
37 case SkBitmap::kARGB_8888_Config: | 37 case kRGBA_8888_SkColorType: |
| 38 case kBGRA_8888_SkColorType: |
38 return srcRect.width() * 3 * srcRect.height(); | 39 return srcRect.width() * 3 * srcRect.height(); |
39 case SkBitmap::kA8_Config: | 40 case kAlpha_8_SkColorType: |
40 return 1; | 41 return 1; |
41 default: | 42 default: |
42 SkASSERT(false); | 43 SkASSERT(false); |
43 return 0; | 44 return 0; |
44 } | 45 } |
45 } | 46 } |
46 | 47 |
47 static SkStream* extract_index8_image(const SkBitmap& bitmap, | 48 static SkStream* extract_index8_image(const SkBitmap& bitmap, |
48 const SkIRect& srcRect) { | 49 const SkIRect& srcRect) { |
49 const int rowBytes = srcRect.width(); | 50 const int rowBytes = srcRect.width(); |
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
201 * @param isTransparent Pointer to a bool to output whether the alpha is | 202 * @param isTransparent Pointer to a bool to output whether the alpha is |
202 * completely transparent. May be NULL. Only valid when | 203 * completely transparent. May be NULL. Only valid when |
203 * extractAlpha == true. | 204 * extractAlpha == true. |
204 * @return Unencoded image data, or NULL if either data was not | 205 * @return Unencoded image data, or NULL if either data was not |
205 * available or alpha data was requested but the image was | 206 * available or alpha data was requested but the image was |
206 * entirely transparent or opaque. | 207 * entirely transparent or opaque. |
207 */ | 208 */ |
208 static SkStream* extract_image_data(const SkBitmap& bitmap, | 209 static SkStream* extract_image_data(const SkBitmap& bitmap, |
209 const SkIRect& srcRect, | 210 const SkIRect& srcRect, |
210 bool extractAlpha, bool* isTransparent) { | 211 bool extractAlpha, bool* isTransparent) { |
211 SkBitmap::Config config = bitmap.config(); | 212 SkColorType colorType = bitmap.colorType(); |
212 if (extractAlpha && (config == SkBitmap::kIndex8_Config || | 213 if (extractAlpha && (kIndex_8_SkColorType == colorType || |
213 config == SkBitmap::kRGB_565_Config)) { | 214 kRGB_565_SkColorType == colorType)) { |
214 if (isTransparent != NULL) { | 215 if (isTransparent != NULL) { |
215 *isTransparent = false; | 216 *isTransparent = false; |
216 } | 217 } |
217 return NULL; | 218 return NULL; |
218 } | 219 } |
219 bool isOpaque = true; | 220 bool isOpaque = true; |
220 bool transparent = extractAlpha; | 221 bool transparent = extractAlpha; |
221 SkStream* stream = NULL; | 222 SkStream* stream = NULL; |
222 | 223 |
223 bitmap.lockPixels(); | 224 bitmap.lockPixels(); |
224 switch (config) { | 225 switch (colorType) { |
225 case SkBitmap::kIndex8_Config: | 226 case kIndex_8_SkColorType: |
226 if (!extractAlpha) { | 227 if (!extractAlpha) { |
227 stream = extract_index8_image(bitmap, srcRect); | 228 stream = extract_index8_image(bitmap, srcRect); |
228 } | 229 } |
229 break; | 230 break; |
230 case SkBitmap::kARGB_4444_Config: | 231 case kARGB_4444_SkColorType: |
231 stream = extract_argb4444_data(bitmap, srcRect, extractAlpha, | 232 stream = extract_argb4444_data(bitmap, srcRect, extractAlpha, |
232 &isOpaque, &transparent); | 233 &isOpaque, &transparent); |
233 break; | 234 break; |
234 case SkBitmap::kRGB_565_Config: | 235 case kRGB_565_SkColorType: |
235 if (!extractAlpha) { | 236 if (!extractAlpha) { |
236 stream = extract_rgb565_image(bitmap, srcRect); | 237 stream = extract_rgb565_image(bitmap, srcRect); |
237 } | 238 } |
238 break; | 239 break; |
239 case SkBitmap::kARGB_8888_Config: | 240 case kN32_SkColorType: |
240 stream = extract_argb8888_data(bitmap, srcRect, extractAlpha, | 241 stream = extract_argb8888_data(bitmap, srcRect, extractAlpha, |
241 &isOpaque, &transparent); | 242 &isOpaque, &transparent); |
242 break; | 243 break; |
243 case SkBitmap::kA8_Config: | 244 case kAlpha_8_SkColorType: |
244 if (!extractAlpha) { | 245 if (!extractAlpha) { |
245 stream = create_black_image(); | 246 stream = create_black_image(); |
246 } else { | 247 } else { |
247 stream = extract_a8_alpha(bitmap, srcRect, | 248 stream = extract_a8_alpha(bitmap, srcRect, |
248 &isOpaque, &transparent); | 249 &isOpaque, &transparent); |
249 } | 250 } |
250 break; | 251 break; |
251 default: | 252 default: |
252 SkASSERT(false); | 253 SkASSERT(false); |
253 } | 254 } |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
366 return SkPackARGB4444(SK_AlphaOPAQUE & 0x0F, 0, 0, 0); | 367 return SkPackARGB4444(SK_AlphaOPAQUE & 0x0F, 0, 0, 0); |
367 } else { | 368 } else { |
368 return SkPackARGB4444(SK_AlphaOPAQUE & 0x0F, | 369 return SkPackARGB4444(SK_AlphaOPAQUE & 0x0F, |
369 r / count, g / count, b / count); | 370 r / count, g / count, b / count); |
370 } | 371 } |
371 } | 372 } |
372 | 373 |
373 static SkBitmap unpremultiply_bitmap(const SkBitmap& bitmap, | 374 static SkBitmap unpremultiply_bitmap(const SkBitmap& bitmap, |
374 const SkIRect& srcRect) { | 375 const SkIRect& srcRect) { |
375 SkBitmap outBitmap; | 376 SkBitmap outBitmap; |
376 outBitmap.setConfig(bitmap.config(), srcRect.width(), srcRect.height()); | 377 outBitmap.allocPixels(bitmap.info().makeWH(srcRect.width(), srcRect.height()
)); |
377 outBitmap.allocPixels(); | |
378 int dstRow = 0; | 378 int dstRow = 0; |
379 | 379 |
380 outBitmap.lockPixels(); | 380 outBitmap.lockPixels(); |
381 bitmap.lockPixels(); | 381 bitmap.lockPixels(); |
382 switch (bitmap.config()) { | 382 switch (bitmap.colorType()) { |
383 case SkBitmap::kARGB_4444_Config: { | 383 case kARGB_4444_SkColorType: { |
384 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) { | 384 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) { |
385 uint16_t* dst = outBitmap.getAddr16(0, dstRow); | 385 uint16_t* dst = outBitmap.getAddr16(0, dstRow); |
386 uint16_t* src = bitmap.getAddr16(0, y); | 386 uint16_t* src = bitmap.getAddr16(0, y); |
387 for (int x = srcRect.fLeft; x < srcRect.fRight; x++) { | 387 for (int x = srcRect.fLeft; x < srcRect.fRight; x++) { |
388 uint8_t a = SkGetPackedA4444(src[x]); | 388 uint8_t a = SkGetPackedA4444(src[x]); |
389 // It is necessary to average the color component of | 389 // It is necessary to average the color component of |
390 // transparent pixels with their surrounding neighbors | 390 // transparent pixels with their surrounding neighbors |
391 // since the PDF renderer may separately re-sample the | 391 // since the PDF renderer may separately re-sample the |
392 // alpha and color channels when the image is not | 392 // alpha and color channels when the image is not |
393 // displayed at its native resolution. Since an alpha of | 393 // displayed at its native resolution. Since an alpha of |
394 // zero gives no information about the color component, | 394 // zero gives no information about the color component, |
395 // the pathological case is a white image with sharp | 395 // the pathological case is a white image with sharp |
396 // transparency bounds - the color channel goes to black, | 396 // transparency bounds - the color channel goes to black, |
397 // and the should-be-transparent pixels are rendered | 397 // and the should-be-transparent pixels are rendered |
398 // as grey because of the separate soft mask and color | 398 // as grey because of the separate soft mask and color |
399 // resizing. | 399 // resizing. |
400 if (a == (SK_AlphaTRANSPARENT & 0x0F)) { | 400 if (a == (SK_AlphaTRANSPARENT & 0x0F)) { |
401 *dst = get_argb4444_neighbor_avg_color(bitmap, x, y); | 401 *dst = get_argb4444_neighbor_avg_color(bitmap, x, y); |
402 } else { | 402 } else { |
403 *dst = remove_alpha_argb4444(src[x]); | 403 *dst = remove_alpha_argb4444(src[x]); |
404 } | 404 } |
405 dst++; | 405 dst++; |
406 } | 406 } |
407 dstRow++; | 407 dstRow++; |
408 } | 408 } |
409 break; | 409 break; |
410 } | 410 } |
411 case SkBitmap::kARGB_8888_Config: { | 411 case kN32_SkColorType: { |
412 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) { | 412 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) { |
413 uint32_t* dst = outBitmap.getAddr32(0, dstRow); | 413 uint32_t* dst = outBitmap.getAddr32(0, dstRow); |
414 uint32_t* src = bitmap.getAddr32(0, y); | 414 uint32_t* src = bitmap.getAddr32(0, y); |
415 for (int x = srcRect.fLeft; x < srcRect.fRight; x++) { | 415 for (int x = srcRect.fLeft; x < srcRect.fRight; x++) { |
416 uint8_t a = SkGetPackedA32(src[x]); | 416 uint8_t a = SkGetPackedA32(src[x]); |
417 if (a == SK_AlphaTRANSPARENT) { | 417 if (a == SK_AlphaTRANSPARENT) { |
418 *dst = get_argb8888_neighbor_avg_color(bitmap, x, y); | 418 *dst = get_argb8888_neighbor_avg_color(bitmap, x, y); |
419 } else { | 419 } else { |
420 *dst = remove_alpha_argb8888(src[x]); | 420 *dst = remove_alpha_argb8888(src[x]); |
421 } | 421 } |
(...skipping 11 matching lines...) Expand all Loading... |
433 | 433 |
434 outBitmap.setImmutable(); | 434 outBitmap.setImmutable(); |
435 | 435 |
436 return outBitmap; | 436 return outBitmap; |
437 } | 437 } |
438 | 438 |
439 // static | 439 // static |
440 SkPDFImage* SkPDFImage::CreateImage(const SkBitmap& bitmap, | 440 SkPDFImage* SkPDFImage::CreateImage(const SkBitmap& bitmap, |
441 const SkIRect& srcRect, | 441 const SkIRect& srcRect, |
442 SkPicture::EncodeBitmap encoder) { | 442 SkPicture::EncodeBitmap encoder) { |
443 if (bitmap.config() == SkBitmap::kNo_Config) { | 443 if (bitmap.colorType() == kUnknown_SkColorType) { |
444 return NULL; | 444 return NULL; |
445 } | 445 } |
446 | 446 |
447 bool isTransparent = false; | 447 bool isTransparent = false; |
448 SkAutoTUnref<SkStream> alphaData; | 448 SkAutoTUnref<SkStream> alphaData; |
449 if (!bitmap.isOpaque()) { | 449 if (!bitmap.isOpaque()) { |
450 // Note that isOpaque is not guaranteed to return false for bitmaps | 450 // Note that isOpaque is not guaranteed to return false for bitmaps |
451 // with alpha support but a completely opaque alpha channel, | 451 // with alpha support but a completely opaque alpha channel, |
452 // so alphaData may still be NULL if we have a completely opaque | 452 // so alphaData may still be NULL if we have a completely opaque |
453 // (or transparent) bitmap. | 453 // (or transparent) bitmap. |
454 alphaData.reset( | 454 alphaData.reset( |
455 extract_image_data(bitmap, srcRect, true, &isTransparent)); | 455 extract_image_data(bitmap, srcRect, true, &isTransparent)); |
456 } | 456 } |
457 if (isTransparent) { | 457 if (isTransparent) { |
458 return NULL; | 458 return NULL; |
459 } | 459 } |
460 | 460 |
461 SkPDFImage* image; | 461 SkPDFImage* image; |
462 SkBitmap::Config config = bitmap.config(); | 462 SkColorType colorType = bitmap.colorType(); |
463 if (alphaData.get() != NULL && (config == SkBitmap::kARGB_8888_Config || | 463 if (alphaData.get() != NULL && (kN32_SkColorType == colorType || |
464 config == SkBitmap::kARGB_4444_Config)) { | 464 kARGB_4444_SkColorType == colorType)) { |
465 SkBitmap unpremulBitmap = unpremultiply_bitmap(bitmap, srcRect); | 465 SkBitmap unpremulBitmap = unpremultiply_bitmap(bitmap, srcRect); |
466 image = SkNEW_ARGS(SkPDFImage, (NULL, unpremulBitmap, false, | 466 image = SkNEW_ARGS(SkPDFImage, (NULL, unpremulBitmap, false, |
467 SkIRect::MakeWH(srcRect.width(), srcRect.height()), | 467 SkIRect::MakeWH(srcRect.width(), srcRect.height()), |
468 encoder)); | 468 encoder)); |
469 } else { | 469 } else { |
470 image = SkNEW_ARGS(SkPDFImage, (NULL, bitmap, false, srcRect, encoder)); | 470 image = SkNEW_ARGS(SkPDFImage, (NULL, bitmap, false, srcRect, encoder)); |
471 } | 471 } |
472 if (alphaData.get() != NULL) { | 472 if (alphaData.get() != NULL) { |
473 SkAutoTUnref<SkPDFImage> mask( | 473 SkAutoTUnref<SkPDFImage> mask( |
474 SkNEW_ARGS(SkPDFImage, (alphaData.get(), bitmap, | 474 SkNEW_ARGS(SkPDFImage, (alphaData.get(), bitmap, |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
511 fBitmap.setImmutable(); | 511 fBitmap.setImmutable(); |
512 } | 512 } |
513 | 513 |
514 if (stream != NULL) { | 514 if (stream != NULL) { |
515 setData(stream); | 515 setData(stream); |
516 fStreamValid = true; | 516 fStreamValid = true; |
517 } else { | 517 } else { |
518 fStreamValid = false; | 518 fStreamValid = false; |
519 } | 519 } |
520 | 520 |
521 SkBitmap::Config config = fBitmap.config(); | 521 SkColorType colorType = fBitmap.colorType(); |
522 | 522 |
523 insertName("Type", "XObject"); | 523 insertName("Type", "XObject"); |
524 insertName("Subtype", "Image"); | 524 insertName("Subtype", "Image"); |
525 | 525 |
526 bool alphaOnly = (config == SkBitmap::kA8_Config); | 526 bool alphaOnly = (kAlpha_8_SkColorType == colorType); |
527 | 527 |
528 if (!isAlpha && alphaOnly) { | 528 if (!isAlpha && alphaOnly) { |
529 // For alpha only images, we stretch a single pixel of black for | 529 // For alpha only images, we stretch a single pixel of black for |
530 // the color/shape part. | 530 // the color/shape part. |
531 SkAutoTUnref<SkPDFInt> one(new SkPDFInt(1)); | 531 SkAutoTUnref<SkPDFInt> one(new SkPDFInt(1)); |
532 insert("Width", one.get()); | 532 insert("Width", one.get()); |
533 insert("Height", one.get()); | 533 insert("Height", one.get()); |
534 } else { | 534 } else { |
535 insertInt("Width", fSrcRect.width()); | 535 insertInt("Width", fSrcRect.width()); |
536 insertInt("Height", fSrcRect.height()); | 536 insertInt("Height", fSrcRect.height()); |
537 } | 537 } |
538 | 538 |
539 if (isAlpha || alphaOnly) { | 539 if (isAlpha || alphaOnly) { |
540 insertName("ColorSpace", "DeviceGray"); | 540 insertName("ColorSpace", "DeviceGray"); |
541 } else if (config == SkBitmap::kIndex8_Config) { | 541 } else if (kIndex_8_SkColorType == colorType) { |
542 SkAutoLockPixels alp(fBitmap); | 542 SkAutoLockPixels alp(fBitmap); |
543 insert("ColorSpace", | 543 insert("ColorSpace", |
544 make_indexed_color_space(fBitmap.getColorTable()))->unref(); | 544 make_indexed_color_space(fBitmap.getColorTable()))->unref(); |
545 } else { | 545 } else { |
546 insertName("ColorSpace", "DeviceRGB"); | 546 insertName("ColorSpace", "DeviceRGB"); |
547 } | 547 } |
548 | 548 |
549 int bitsPerComp = 8; | 549 int bitsPerComp = 8; |
550 if (config == SkBitmap::kARGB_4444_Config) { | 550 if (kARGB_4444_SkColorType == colorType) { |
551 bitsPerComp = 4; | 551 bitsPerComp = 4; |
552 } | 552 } |
553 insertInt("BitsPerComponent", bitsPerComp); | 553 insertInt("BitsPerComponent", bitsPerComp); |
554 | 554 |
555 if (config == SkBitmap::kRGB_565_Config) { | 555 if (kRGB_565_SkColorType == colorType) { |
556 SkASSERT(!isAlpha); | 556 SkASSERT(!isAlpha); |
557 SkAutoTUnref<SkPDFInt> zeroVal(new SkPDFInt(0)); | 557 SkAutoTUnref<SkPDFInt> zeroVal(new SkPDFInt(0)); |
558 SkAutoTUnref<SkPDFScalar> scale5Val( | 558 SkAutoTUnref<SkPDFScalar> scale5Val( |
559 new SkPDFScalar(8.2258f)); // 255/2^5-1 | 559 new SkPDFScalar(8.2258f)); // 255/2^5-1 |
560 SkAutoTUnref<SkPDFScalar> scale6Val( | 560 SkAutoTUnref<SkPDFScalar> scale6Val( |
561 new SkPDFScalar(4.0476f)); // 255/2^6-1 | 561 new SkPDFScalar(4.0476f)); // 255/2^6-1 |
562 SkAutoTUnref<SkPDFArray> decodeValue(new SkPDFArray()); | 562 SkAutoTUnref<SkPDFArray> decodeValue(new SkPDFArray()); |
563 decodeValue->reserve(6); | 563 decodeValue->reserve(6); |
564 decodeValue->append(zeroVal.get()); | 564 decodeValue->append(zeroVal.get()); |
565 decodeValue->append(scale5Val.get()); | 565 decodeValue->append(scale5Val.get()); |
(...skipping 19 matching lines...) Expand all Loading... |
585 | 585 |
586 bool SkPDFImage::populate(SkPDFCatalog* catalog) { | 586 bool SkPDFImage::populate(SkPDFCatalog* catalog) { |
587 if (getState() == kUnused_State) { | 587 if (getState() == kUnused_State) { |
588 // Initializing image data for the first time. | 588 // Initializing image data for the first time. |
589 SkDynamicMemoryWStream dctCompressedWStream; | 589 SkDynamicMemoryWStream dctCompressedWStream; |
590 if (!skip_compression(catalog) && fEncoder && | 590 if (!skip_compression(catalog) && fEncoder && |
591 get_uncompressed_size(fBitmap, fSrcRect) > 1) { | 591 get_uncompressed_size(fBitmap, fSrcRect) > 1) { |
592 SkBitmap subset; | 592 SkBitmap subset; |
593 // Extract subset | 593 // Extract subset |
594 if (!fBitmap.extractSubset(&subset, fSrcRect)) { | 594 if (!fBitmap.extractSubset(&subset, fSrcRect)) { |
595 // TODO(edisonn) It fails only for kA1_Config, if that is a | |
596 // major concern we will fix it later, so far it is NYI. | |
597 return false; | 595 return false; |
598 } | 596 } |
599 size_t pixelRefOffset = 0; | 597 size_t pixelRefOffset = 0; |
600 SkAutoTUnref<SkData> data(fEncoder(&pixelRefOffset, subset)); | 598 SkAutoTUnref<SkData> data(fEncoder(&pixelRefOffset, subset)); |
601 if (data.get() && data->size() < get_uncompressed_size(fBitmap, | 599 if (data.get() && data->size() < get_uncompressed_size(fBitmap, |
602 fSrcRect)) { | 600 fSrcRect)) { |
603 SkAutoTUnref<SkStream> stream(SkNEW_ARGS(SkMemoryStream, | 601 SkAutoTUnref<SkStream> stream(SkNEW_ARGS(SkMemoryStream, |
604 (data))); | 602 (data))); |
605 setData(stream.get()); | 603 setData(stream.get()); |
606 | 604 |
(...skipping 19 matching lines...) Expand all Loading... |
626 // but the new catalog wants it compressed. | 624 // but the new catalog wants it compressed. |
627 if (!getSubstitute()) { | 625 if (!getSubstitute()) { |
628 SkPDFStream* substitute = SkNEW_ARGS(SkPDFImage, (*this)); | 626 SkPDFStream* substitute = SkNEW_ARGS(SkPDFImage, (*this)); |
629 setSubstitute(substitute); | 627 setSubstitute(substitute); |
630 catalog->setSubstitute(this, substitute); | 628 catalog->setSubstitute(this, substitute); |
631 } | 629 } |
632 return false; | 630 return false; |
633 } | 631 } |
634 return true; | 632 return true; |
635 } | 633 } |
OLD | NEW |