Index: src/pdf/SkPDFBitmap.cpp |
diff --git a/src/pdf/SkPDFBitmap.cpp b/src/pdf/SkPDFBitmap.cpp |
index 765016dcf2d0d06f05b25cca2747649513ad0ef5..42a5841b390eee67e84b6b02efe1e8bf0ec1ea77 100644 |
--- a/src/pdf/SkPDFBitmap.cpp |
+++ b/src/pdf/SkPDFBitmap.cpp |
@@ -6,10 +6,13 @@ |
*/ |
#include "SkColorPriv.h" |
+#include "SkData.h" |
#include "SkFlate.h" |
+#include "SkImageGenerator.h" |
#include "SkPDFBitmap.h" |
#include "SkPDFCanon.h" |
#include "SkPDFCatalog.h" |
+#include "SkPixelRef.h" |
#include "SkStream.h" |
#include "SkUnPreMultiply.h" |
@@ -248,7 +251,6 @@ public: |
private: |
const SkBitmap fBitmap; |
- void emitDict(SkWStream*, SkPDFCatalog*, size_t) const; |
}; |
void PDFAlphaBitmap::emitObject(SkWStream* stream, SkPDFCatalog* catalog) { |
@@ -263,15 +265,6 @@ void PDFAlphaBitmap::emitObject(SkWStream* stream, SkPDFCatalog* catalog) { |
deflateWStream.finalize(); // call before detachAsStream(). |
SkAutoTDelete<SkStreamAsset> asset(buffer.detachAsStream()); |
- this->emitDict(stream, catalog, asset->getLength()); |
- pdf_stream_begin(stream); |
- stream->writeStream(asset.get(), asset->getLength()); |
- pdf_stream_end(stream); |
-} |
- |
-void PDFAlphaBitmap::emitDict(SkWStream* stream, |
- SkPDFCatalog* catalog, |
- size_t length) const { |
SkPDFDict pdfDict("XObject"); |
pdfDict.insertName("Subtype", "Image"); |
pdfDict.insertInt("Width", fBitmap.width()); |
@@ -279,14 +272,29 @@ void PDFAlphaBitmap::emitDict(SkWStream* stream, |
pdfDict.insertName("ColorSpace", "DeviceGray"); |
pdfDict.insertInt("BitsPerComponent", 8); |
pdfDict.insertName("Filter", "FlateDecode"); |
- pdfDict.insertInt("Length", length); |
+ pdfDict.insertInt("Length", asset->getLength()); |
pdfDict.emitObject(stream, catalog); |
+ |
+ pdf_stream_begin(stream); |
+ stream->writeStream(asset.get(), asset->getLength()); |
+ pdf_stream_end(stream); |
} |
} // namespace |
//////////////////////////////////////////////////////////////////////////////// |
-void SkPDFBitmap::addResources(SkPDFCatalog* catalog) const { |
+namespace { |
+class PDFBitmap : public SkPDFBitmap { |
mtklein
2015/03/25 21:36:53
Oh come on.
hal.canary
2015/04/17 18:57:13
Done.
|
+public: |
+ const SkAutoTUnref<SkPDFObject> fSMask; |
+ void emitObject(SkWStream*, SkPDFCatalog*) SK_OVERRIDE; |
+ void addResources(SkPDFCatalog*) const SK_OVERRIDE; |
+ PDFBitmap(const SkBitmap& bm, SkPDFObject* smask) |
+ : SkPDFBitmap(bm), fSMask(smask) {} |
+}; |
+} // namespace |
+ |
+void PDFBitmap::addResources(SkPDFCatalog* catalog) const { |
if (fSMask.get()) { |
if (catalog->addObject(fSMask.get())) { |
fSMask->addResources(catalog); |
@@ -294,24 +302,6 @@ void SkPDFBitmap::addResources(SkPDFCatalog* catalog) const { |
} |
} |
-void SkPDFBitmap::emitObject(SkWStream* stream, SkPDFCatalog* catalog) { |
- SkAutoLockPixels autoLockPixels(fBitmap); |
- SkASSERT(fBitmap.colorType() != kIndex_8_SkColorType || |
- fBitmap.getColorTable()); |
- |
- // Write to a temporary buffer to get the compressed length. |
- SkDynamicMemoryWStream buffer; |
- SkDeflateWStream deflateWStream(&buffer); |
- bitmap_to_pdf_pixels(fBitmap, &deflateWStream); |
- deflateWStream.finalize(); // call before detachAsStream(). |
- SkAutoTDelete<SkStreamAsset> asset(buffer.detachAsStream()); |
- |
- this->emitDict(stream, catalog, asset->getLength()); |
- pdf_stream_begin(stream); |
- stream->writeStream(asset.get(), asset->getLength()); |
- pdf_stream_end(stream); |
-} |
- |
static SkPDFArray* make_indexed_color_space(const SkColorTable* table) { |
SkPDFArray* result = SkNEW(SkPDFArray); |
result->reserve(4); |
@@ -342,9 +332,18 @@ static SkPDFArray* make_indexed_color_space(const SkColorTable* table) { |
return result; |
} |
-void SkPDFBitmap::emitDict(SkWStream* stream, |
- SkPDFCatalog* catalog, |
- size_t length) const { |
+void PDFBitmap::emitObject(SkWStream* stream, SkPDFCatalog* catalog) { |
+ SkAutoLockPixels autoLockPixels(fBitmap); |
+ SkASSERT(fBitmap.colorType() != kIndex_8_SkColorType || |
+ fBitmap.getColorTable()); |
+ |
+ // Write to a temporary buffer to get the compressed length. |
+ SkDynamicMemoryWStream buffer; |
+ SkDeflateWStream deflateWStream(&buffer); |
+ bitmap_to_pdf_pixels(fBitmap, &deflateWStream); |
+ deflateWStream.finalize(); // call before detachAsStream(). |
+ SkAutoTDelete<SkStreamAsset> asset(buffer.detachAsStream()); |
+ |
SkPDFDict pdfDict("XObject"); |
pdfDict.insertName("Subtype", "Image"); |
pdfDict.insertInt("Width", fBitmap.width()); |
@@ -363,15 +362,13 @@ void SkPDFBitmap::emitDict(SkWStream* stream, |
pdfDict.insert("SMask", new SkPDFObjRef(fSMask))->unref(); |
} |
pdfDict.insertName("Filter", "FlateDecode"); |
- pdfDict.insertInt("Length", length); |
+ pdfDict.insertInt("Length", asset->getLength()); |
pdfDict.emitObject(stream, catalog); |
-} |
- |
-SkPDFBitmap::SkPDFBitmap(const SkBitmap& bm, |
- SkPDFObject* smask) |
- : fBitmap(bm), fSMask(smask) {} |
-SkPDFBitmap::~SkPDFBitmap() {} |
+ pdf_stream_begin(stream); |
+ stream->writeStream(asset.get(), asset->getLength()); |
+ pdf_stream_end(stream); |
+} |
//////////////////////////////////////////////////////////////////////////////// |
@@ -384,6 +381,55 @@ static const SkBitmap& immutable_bitmap(const SkBitmap& bm, SkBitmap* copy) { |
return *copy; |
} |
+namespace { |
+/** |
+ * This PDFObject assumes that its constructor was handed YUV JFIF |
+ * Jpeg-encoded data that can be directly embedded into a PDF. |
+ */ |
+class PDFJpegBitmap : public SkPDFBitmap { |
+public: |
+ SkAutoTUnref<SkData> fData; |
+ PDFJpegBitmap(const SkBitmap& bm, SkData* data) |
+ : SkPDFBitmap(bm), fData(SkRef(data)) {} |
+ void emitObject(SkWStream*, SkPDFCatalog*) SK_OVERRIDE; |
+}; |
+ |
+void PDFJpegBitmap::emitObject(SkWStream* stream, SkPDFCatalog* catalog) { |
+ SkPDFDict pdfDict("XObject"); |
+ pdfDict.insertName("Subtype", "Image"); |
+ pdfDict.insertInt("Width", fBitmap.width()); |
+ pdfDict.insertInt("Height", fBitmap.height()); |
+ pdfDict.insertName("ColorSpace", "DeviceRGB"); |
+ pdfDict.insertInt("BitsPerComponent", 8); |
+ pdfDict.insertName("Filter", "DCTDecode"); |
+ pdfDict.insertInt("ColorTransform", 0); |
+ pdfDict.insertInt("Length", SkToInt(fData->size())); |
+ pdfDict.emitObject(stream, catalog); |
+ pdf_stream_begin(stream); |
+ stream->write(fData->data(), fData->size()); |
+ pdf_stream_end(stream); |
+} |
+} // namespace |
+ |
+//////////////////////////////////////////////////////////////////////////////// |
+ |
+static bool is_jfif_yuv_jpeg(SkData* data) { |
+ const uint8_t bytesZeroToThree[] = {0xFF, 0xD8, 0xFF, 0xE0}; |
+ const uint8_t bytesSixToTen[] = {'J', 'F', 'I', 'F', 0}; |
+ // 0 1 2 3 4 5 6 7 8 9 10 |
+ // FF D8 FF E0 ?? ?? 'J' 'F' 'I' 'F' 00 ... |
+ if (data->size() < 11 || |
+ 0 != memcmp(data->bytes(), bytesZeroToThree, |
+ sizeof(bytesZeroToThree)) || |
+ 0 != memcmp(data->bytes() + 6, bytesSixToTen, sizeof(bytesSixToTen))) { |
+ return false; |
+ } |
+ SkAutoTDelete<SkImageGenerator> gen(SkImageGenerator::NewFromData(data)); |
+ SkISize sizes[3]; |
+ // Only YUV JPEG allows access to YUV planes. |
+ return gen && gen->getYUV8Planes(sizes, NULL, NULL, NULL); |
+} |
+ |
SkPDFBitmap* SkPDFBitmap::Create(SkPDFCanon* canon, const SkBitmap& bitmap) { |
SkASSERT(canon); |
if (!SkColorTypeIsValid(bitmap.colorType()) || |
@@ -398,11 +444,23 @@ SkPDFBitmap* SkPDFBitmap::Create(SkPDFCanon* canon, const SkBitmap& bitmap) { |
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()); |
+ if (data && is_jfif_yuv_jpeg(data)) { |
+ SkPDFBitmap* pdfBitmap = SkNEW_ARGS(PDFJpegBitmap, (bm, data)); |
+ canon->addBitmap(pdfBitmap); |
+ return pdfBitmap; |
+ } |
+ } |
+ |
SkPDFObject* smask = NULL; |
if (!bm.isOpaque() && !SkBitmap::ComputeIsOpaque(bm)) { |
smask = SkNEW_ARGS(PDFAlphaBitmap, (bm)); |
} |
- SkPDFBitmap* pdfBitmap = SkNEW_ARGS(SkPDFBitmap, (bm, smask)); |
+ SkPDFBitmap* pdfBitmap = SkNEW_ARGS(PDFBitmap, (bm, smask)); |
canon->addBitmap(pdfBitmap); |
return pdfBitmap; |
} |