Chromium Code Reviews| Index: src/pdf/SkPDFBitmap.cpp |
| diff --git a/src/pdf/SkPDFBitmap.cpp b/src/pdf/SkPDFBitmap.cpp |
| index de43221630e5ed85e9db28bdf8738c3957c54ada..69a02bdca5e8659d88ece589cf895928ef96e483 100644 |
| --- a/src/pdf/SkPDFBitmap.cpp |
| +++ b/src/pdf/SkPDFBitmap.cpp |
| @@ -8,14 +8,23 @@ |
| #include "SkColorPriv.h" |
| #include "SkData.h" |
| #include "SkDeflate.h" |
| -#include "SkImageGenerator.h" |
| +#include "SkImage_Base.h" |
| #include "SkJpegInfo.h" |
| #include "SkPDFBitmap.h" |
| #include "SkPDFCanon.h" |
| -#include "SkPixelRef.h" |
| #include "SkStream.h" |
| #include "SkUnPreMultiply.h" |
| +void image_get_ro_pixels(const SkImage* image, SkBitmap* dst) { |
| + if(as_IB(image)->getROPixels(dst) |
| + && dst->dimensions() == image->dimensions()) { |
| + return; |
| + } |
| + // no pixels or wrong size: fill with zeros. |
| + SkAlphaType at = image->isOpaque() ? kOpaque_SkAlphaType : kPremul_SkAlphaType; |
| + dst->setInfo(SkImageInfo::MakeN32(image->width(), image->height(), at)); |
| +} |
| + |
| //////////////////////////////////////////////////////////////////////////////// |
| static void pdf_stream_begin(SkWStream* stream) { |
| @@ -245,34 +254,36 @@ namespace { |
| // This SkPDFObject only outputs the alpha layer of the given bitmap. |
| class PDFAlphaBitmap : public SkPDFObject { |
| public: |
| - PDFAlphaBitmap(const SkBitmap& bm) : fBitmap(bm) {} |
| + PDFAlphaBitmap(const SkImage* image) : fImage(SkRef(image)) {} |
| ~PDFAlphaBitmap() {} |
| void emitObject(SkWStream*, |
| const SkPDFObjNumMap&, |
| const SkPDFSubstituteMap&) const override; |
| private: |
| - const SkBitmap fBitmap; |
| + SkAutoTUnref<const SkImage> fImage; |
| }; |
| void PDFAlphaBitmap::emitObject(SkWStream* stream, |
| const SkPDFObjNumMap& objNumMap, |
| const SkPDFSubstituteMap& substitutes) const { |
| - SkAutoLockPixels autoLockPixels(fBitmap); |
| - SkASSERT(fBitmap.colorType() != kIndex_8_SkColorType || |
| - fBitmap.getColorTable()); |
| + SkBitmap bitmap; |
| + image_get_ro_pixels(fImage, &bitmap); |
| + SkAutoLockPixels autoLockPixels(bitmap); |
| + SkASSERT(bitmap.colorType() != kIndex_8_SkColorType || |
| + bitmap.getColorTable()); |
| // Write to a temporary buffer to get the compressed length. |
| SkDynamicMemoryWStream buffer; |
| SkDeflateWStream deflateWStream(&buffer); |
| - bitmap_alpha_to_a8(fBitmap, &deflateWStream); |
| + bitmap_alpha_to_a8(bitmap, &deflateWStream); |
| deflateWStream.finalize(); // call before detachAsStream(). |
| SkAutoTDelete<SkStreamAsset> asset(buffer.detachAsStream()); |
| SkPDFDict pdfDict("XObject"); |
| pdfDict.insertName("Subtype", "Image"); |
| - pdfDict.insertInt("Width", fBitmap.width()); |
| - pdfDict.insertInt("Height", fBitmap.height()); |
| + pdfDict.insertInt("Width", bitmap.width()); |
| + pdfDict.insertInt("Height", bitmap.height()); |
| pdfDict.insertName("ColorSpace", "DeviceGray"); |
| pdfDict.insertInt("BitsPerComponent", 8); |
| pdfDict.insertName("Filter", "FlateDecode"); |
| @@ -288,16 +299,19 @@ void PDFAlphaBitmap::emitObject(SkWStream* stream, |
| //////////////////////////////////////////////////////////////////////////////// |
| namespace { |
| -class PDFDefaultBitmap : public SkPDFBitmap { |
| +class PDFDefaultBitmap : public SkPDFObject { |
| public: |
| - const SkAutoTUnref<SkPDFObject> fSMask; |
| void emitObject(SkWStream*, |
| const SkPDFObjNumMap&, |
| const SkPDFSubstituteMap&) const override; |
| void addResources(SkPDFObjNumMap*, |
| const SkPDFSubstituteMap&) const override; |
| - PDFDefaultBitmap(const SkBitmap& bm, SkPDFObject* smask) |
| - : SkPDFBitmap(bm), fSMask(smask) {} |
| + PDFDefaultBitmap(const SkImage* image, SkPDFObject* smask) |
| + : fImage(SkRef(image)), fSMask(smask) {} |
| + |
| +private: |
| + SkAutoTUnref<const SkImage> fImage; |
| + const SkAutoTUnref<SkPDFObject> fSMask; |
| }; |
| } // namespace |
| @@ -346,26 +360,28 @@ static SkPDFArray* make_indexed_color_space(const SkColorTable* table) { |
| void PDFDefaultBitmap::emitObject(SkWStream* stream, |
|
tomhudson
2015/09/30 16:10:29
There's a lot of redundancy between this and PDFAl
hal.canary
2015/10/01 01:24:55
Done.
|
| const SkPDFObjNumMap& objNumMap, |
| const SkPDFSubstituteMap& substitutes) const { |
| - SkAutoLockPixels autoLockPixels(fBitmap); |
| - SkASSERT(fBitmap.colorType() != kIndex_8_SkColorType || |
| - fBitmap.getColorTable()); |
| + SkBitmap bitmap; |
| + image_get_ro_pixels(fImage, &bitmap); // TODO(halcanary): test |
|
tomhudson
2015/09/30 16:10:29
note TODO?
hal.canary
2015/10/01 01:24:55
Acknowledged.
|
| + SkAutoLockPixels autoLockPixels(bitmap); // with malformed images? |
| + SkASSERT(bitmap.colorType() != kIndex_8_SkColorType || |
| + bitmap.getColorTable()); |
| // Write to a temporary buffer to get the compressed length. |
| SkDynamicMemoryWStream buffer; |
| SkDeflateWStream deflateWStream(&buffer); |
| - bitmap_to_pdf_pixels(fBitmap, &deflateWStream); |
| + bitmap_to_pdf_pixels(bitmap, &deflateWStream); |
| deflateWStream.finalize(); // call before detachAsStream(). |
| SkAutoTDelete<SkStreamAsset> asset(buffer.detachAsStream()); |
| SkPDFDict pdfDict("XObject"); |
| pdfDict.insertName("Subtype", "Image"); |
| - pdfDict.insertInt("Width", fBitmap.width()); |
| - pdfDict.insertInt("Height", fBitmap.height()); |
| - if (fBitmap.colorType() == kIndex_8_SkColorType) { |
| - SkASSERT(1 == pdf_color_component_count(fBitmap.colorType())); |
| + pdfDict.insertInt("Width", bitmap.width()); |
| + pdfDict.insertInt("Height", bitmap.height()); |
| + if (bitmap.colorType() == kIndex_8_SkColorType) { |
| + SkASSERT(1 == pdf_color_component_count(bitmap.colorType())); |
| pdfDict.insertObject("ColorSpace", |
| - make_indexed_color_space(fBitmap.getColorTable())); |
| - } else if (1 == pdf_color_component_count(fBitmap.colorType())) { |
| + make_indexed_color_space(bitmap.getColorTable())); |
| + } else if (1 == pdf_color_component_count(bitmap.colorType())) { |
| pdfDict.insertName("ColorSpace", "DeviceGray"); |
| } else { |
| pdfDict.insertName("ColorSpace", "DeviceRGB"); |
| @@ -385,26 +401,19 @@ void PDFDefaultBitmap::emitObject(SkWStream* stream, |
| //////////////////////////////////////////////////////////////////////////////// |
| -static const SkBitmap& immutable_bitmap(const SkBitmap& bm, SkBitmap* copy) { |
| - if (bm.isImmutable()) { |
| - return bm; |
| - } |
| - bm.copyTo(copy); |
| - copy->setImmutable(); |
| - return *copy; |
| -} |
| - |
| namespace { |
| /** |
| - * This PDFObject assumes that its constructor was handed YUV JFIF |
| - * Jpeg-encoded data that can be directly embedded into a PDF. |
| + * This PDFObject assumes that its constructor was handed YUV or |
| + * Grayscale JFIF Jpeg-encoded data that can be directly embedded |
| + * into a PDF. |
| */ |
| -class PDFJpegBitmap : public SkPDFBitmap { |
| +class PDFJpegBitmap : public SkPDFObject { |
| public: |
| + SkISize fSize; |
| SkAutoTUnref<SkData> fData; |
| bool fIsYUV; |
| - PDFJpegBitmap(const SkBitmap& bm, SkData* data, bool isYUV) |
| - : SkPDFBitmap(bm), fData(SkRef(data)), fIsYUV(isYUV) {} |
| + PDFJpegBitmap(SkISize size, SkData* data, bool isYUV) |
| + : fSize(size), fData(SkRef(data)), fIsYUV(isYUV) {} |
| void emitObject(SkWStream*, |
| const SkPDFObjNumMap&, |
| const SkPDFSubstituteMap&) const override; |
| @@ -415,8 +424,8 @@ void PDFJpegBitmap::emitObject(SkWStream* stream, |
| const SkPDFSubstituteMap& substituteMap) const { |
| SkPDFDict pdfDict("XObject"); |
| pdfDict.insertName("Subtype", "Image"); |
| - pdfDict.insertInt("Width", fBitmap.width()); |
| - pdfDict.insertInt("Height", fBitmap.height()); |
| + pdfDict.insertInt("Width", fSize.width()); |
| + pdfDict.insertInt("Height", fSize.height()); |
| if (fIsYUV) { |
| pdfDict.insertName("ColorSpace", "DeviceRGB"); |
| } else { |
| @@ -435,39 +444,23 @@ void PDFJpegBitmap::emitObject(SkWStream* stream, |
| //////////////////////////////////////////////////////////////////////////////// |
| -SkPDFBitmap* SkPDFBitmap::Create(SkPDFCanon* canon, const SkBitmap& bitmap) { |
| - SkASSERT(canon); |
| - if (!SkColorTypeIsValid(bitmap.colorType()) || |
| - kUnknown_SkColorType == bitmap.colorType()) { |
| - return nullptr; |
| - } |
| - SkBitmap copy; |
| - const SkBitmap& bm = immutable_bitmap(bitmap, ©); |
| - if (bm.drawsNothing()) { |
| - return nullptr; |
| - } |
| - if (SkPDFBitmap* canonBitmap = canon->findBitmap(bm)) { |
| - return SkRef(canonBitmap); |
| - } |
| - |
| - if (bm.pixelRef() && bm.pixelRefOrigin().isZero() && |
| - bm.dimensions() == bm.pixelRef()->info().dimensions()) { |
| - // Requires the bitmap to be backed by lazy pixels. |
| - SkAutoTUnref<SkData> data(bm.pixelRef()->refEncodedData()); |
| - SkJFIFInfo info; |
| - if (data && SkIsJFIF(data, &info)) { |
| - bool yuv = info.fType == SkJFIFInfo::kYCbCr; |
| - SkPDFBitmap* pdfBitmap = new PDFJpegBitmap(bm, data, yuv); |
| - canon->addBitmap(pdfBitmap); |
| - return pdfBitmap; |
| +SkPDFObject* SkPDFCreateBitmapObject(const SkImage* image) { |
| + SkAutoTUnref<SkData> data(image->refEncoded()); |
| + SkJFIFInfo info; |
| + if (data && SkIsJFIF(data, &info)) { |
| + bool yuv = info.fType == SkJFIFInfo::kYCbCr; |
| + if (info.fSize == image->dimensions()) { // Sanity check. |
| + // hold on to data, not image. |
| + #ifdef SK_PDF_IMAGE_STATS |
| + gJpegImageObjects.fetch_add(1); |
| + #endif |
| + return new PDFJpegBitmap(info.fSize, data, yuv); |
| } |
| } |
| - |
| - SkPDFObject* smask = nullptr; |
| - if (!bm.isOpaque() && !SkBitmap::ComputeIsOpaque(bm)) { |
| - smask = new PDFAlphaBitmap(bm); |
| - } |
| - SkPDFBitmap* pdfBitmap = new PDFDefaultBitmap(bm, smask); |
| - canon->addBitmap(pdfBitmap); |
| - return pdfBitmap; |
| + SkPDFObject* smask = |
| + image->isOpaque() ? nullptr : new PDFAlphaBitmap(image); |
| + #ifdef SK_PDF_IMAGE_STATS |
| + gRegularImageObjects.fetch_add(1); |
| + #endif |
| + return new PDFDefaultBitmap(image, smask); |
| } |