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 "SkPixelRef.h" |
16 #include "SkRect.h" | 17 #include "SkRect.h" |
17 #include "SkStream.h" | 18 #include "SkStream.h" |
18 #include "SkString.h" | 19 #include "SkString.h" |
19 #include "SkUnPreMultiply.h" | 20 #include "SkUnPreMultiply.h" |
20 | 21 |
21 static const int kNoColorTransform = 0; | 22 static const int kNoColorTransform = 0; |
22 | 23 |
23 static bool skip_compression(SkPDFCatalog* catalog) { | 24 static bool skip_compression(SkPDFCatalog* catalog) { |
24 return SkToBool(catalog->getDocumentFlags() & | 25 return SkToBool(catalog->getDocumentFlags() & |
25 SkPDFDocument::kFavorSpeedOverSize_Flags); | 26 SkPDFDocument::kFavorSpeedOverSize_Flags); |
(...skipping 595 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
621 // but the new catalog wants it compressed. | 622 // but the new catalog wants it compressed. |
622 if (!getSubstitute()) { | 623 if (!getSubstitute()) { |
623 SkPDFStream* substitute = SkNEW_ARGS(SkPDFImage, (*this)); | 624 SkPDFStream* substitute = SkNEW_ARGS(SkPDFImage, (*this)); |
624 setSubstitute(substitute); | 625 setSubstitute(substitute); |
625 catalog->setSubstitute(this, substitute); | 626 catalog->setSubstitute(this, substitute); |
626 } | 627 } |
627 return false; | 628 return false; |
628 } | 629 } |
629 return true; | 630 return true; |
630 } | 631 } |
| 632 |
| 633 namespace { |
| 634 /** |
| 635 * This PDFObject assumes that its constructor was handed |
| 636 * Jpeg-encoded data that can be directly embedded into a PDF. |
| 637 */ |
| 638 class PDFJPEGImage : public SkPDFObject { |
| 639 SkAutoTUnref<SkData> fData; |
| 640 int fWidth; |
| 641 int fHeight; |
| 642 public: |
| 643 PDFJPEGImage(SkData* data, int width, int height) |
| 644 : fData(SkRef(data)), fWidth(width), fHeight(height) {} |
| 645 virtual void getResources(const SkTSet<SkPDFObject*>&, |
| 646 SkTSet<SkPDFObject*>*) SK_OVERRIDE {} |
| 647 virtual void emitObject( |
| 648 SkWStream* stream, |
| 649 SkPDFCatalog* catalog, bool indirect) SK_OVERRIDE { |
| 650 if (indirect) { |
| 651 this->emitIndirectObject(stream, catalog); |
| 652 return; |
| 653 } |
| 654 SkASSERT(fData.get()); |
| 655 const char kPrefaceFormat[] = |
| 656 "<<" |
| 657 "/Type /XObject\n" |
| 658 "/Subtype /Image\n" |
| 659 "/Width %d\n" |
| 660 "/Height %d\n" |
| 661 "/ColorSpace /DeviceRGB\n" |
| 662 "/BitsPerComponent 8\n" |
| 663 "/Filter /DCTDecode\n" |
| 664 "/ColorTransform 0\n" |
| 665 "/Length " SK_SIZE_T_SPECIFIER "\n" |
| 666 ">> stream\n"; |
| 667 SkString preface( |
| 668 SkStringPrintf(kPrefaceFormat, fWidth, fHeight, fData->size())); |
| 669 const char kPostface[] = "\nendstream"; |
| 670 stream->write(preface.c_str(), preface.size()); |
| 671 stream->write(fData->data(), fData->size()); |
| 672 stream->write(kPostface, sizeof(kPostface)); |
| 673 } |
| 674 }; |
| 675 |
| 676 /** |
| 677 * If the bitmap is not subsetted, return its encoded data, if |
| 678 * availible. |
| 679 */ |
| 680 static inline SkData* ref_encoded_data(const SkBitmap& bm) { |
| 681 if ((NULL == bm.pixelRef()) |
| 682 || !bm.pixelRefOrigin().isZero() |
| 683 || (bm.info().dimensions() != bm.pixelRef()->info().dimensions())) { |
| 684 return NULL; |
| 685 } |
| 686 return bm.pixelRef()->refEncodedData(); |
| 687 } |
| 688 |
| 689 /* |
| 690 * This functions may give false negatives but no false positives. |
| 691 */ |
| 692 static bool is_jfif_jpeg(SkData* data) { |
| 693 if (!data || (data->size() < 11)) { |
| 694 return false; |
| 695 } |
| 696 const uint8_t bytesZeroToThree[] = {0xFF, 0xD8, 0xFF, 0xE0}; |
| 697 const uint8_t bytesSixToTen[] = {'J', 'F', 'I', 'F', 0}; |
| 698 // 0 1 2 3 4 5 6 7 8 9 10 |
| 699 // FF D8 FF E0 ?? ?? 'J' 'F' 'I' 'F' 00 ... |
| 700 return ((0 == memcmp(data->bytes(), bytesZeroToThree, |
| 701 sizeof(bytesZeroToThree))) |
| 702 && (0 == memcmp(data->bytes() + 6, bytesSixToTen, |
| 703 sizeof(bytesSixToTen)))); |
| 704 } |
| 705 } // namespace |
| 706 |
| 707 SkPDFObject* SkPDFCreateImageObject( |
| 708 const SkBitmap& bitmap, |
| 709 const SkIRect& subset, |
| 710 SkPicture::EncodeBitmap encoder) { |
| 711 if (SkIRect::MakeWH(bitmap.width(), bitmap.height()) == subset) { |
| 712 SkAutoTUnref<SkData> encodedData(ref_encoded_data(bitmap)); |
| 713 if (is_jfif_jpeg(encodedData)) { |
| 714 return SkNEW_ARGS(PDFJPEGImage, |
| 715 (encodedData, bitmap.width(), bitmap.height())); |
| 716 } |
| 717 } |
| 718 return SkPDFImage::CreateImage(bitmap, subset, encoder); |
| 719 } |
OLD | NEW |