Index: src/pdf/SkPDFImage.cpp |
diff --git a/src/pdf/SkPDFImage.cpp b/src/pdf/SkPDFImage.cpp |
index 715fb4859dc9bb256cd6f0196927f131e32ace87..49460510d9b6f4ef8eb140c3b4c147c0470779d1 100644 |
--- a/src/pdf/SkPDFImage.cpp |
+++ b/src/pdf/SkPDFImage.cpp |
@@ -13,6 +13,7 @@ |
#include "SkData.h" |
#include "SkFlate.h" |
#include "SkPDFCatalog.h" |
+#include "SkPixelRef.h" |
#include "SkRect.h" |
#include "SkStream.h" |
#include "SkString.h" |
@@ -628,3 +629,91 @@ bool SkPDFImage::populate(SkPDFCatalog* catalog) { |
} |
return true; |
} |
+ |
+namespace { |
+/** |
+ * This PDFObject assumes that its constructor was handed |
+ * Jpeg-encoded data that can be directly embedded into a PDF. |
+ */ |
+class PDFJPEGImage : public SkPDFObject { |
+ SkAutoTUnref<SkData> fData; |
+ int fWidth; |
+ int fHeight; |
+public: |
+ PDFJPEGImage(SkData* data, int width, int height) |
+ : fData(SkRef(data)), fWidth(width), fHeight(height) {} |
+ virtual void getResources(const SkTSet<SkPDFObject*>&, |
+ SkTSet<SkPDFObject*>*) SK_OVERRIDE {} |
+ virtual void emitObject( |
+ SkWStream* stream, |
+ SkPDFCatalog* catalog, bool indirect) SK_OVERRIDE { |
+ if (indirect) { |
+ this->emitIndirectObject(stream, catalog); |
+ return; |
+ } |
+ SkASSERT(fData.get()); |
+ const char kPrefaceFormat[] = |
+ "<<" |
+ "/Type /XObject\n" |
+ "/Subtype /Image\n" |
+ "/Width %d\n" |
+ "/Height %d\n" |
+ "/ColorSpace /DeviceRGB\n" |
+ "/BitsPerComponent 8\n" |
+ "/Filter /DCTDecode\n" |
+ "/ColorTransform 0\n" |
+ "/Length " SK_SIZE_T_SPECIFIER "\n" |
+ ">> stream\n"; |
+ SkString preface( |
+ SkStringPrintf(kPrefaceFormat, fWidth, fHeight, fData->size())); |
+ const char kPostface[] = "\nendstream"; |
+ stream->write(preface.c_str(), preface.size()); |
+ stream->write(fData->data(), fData->size()); |
+ stream->write(kPostface, sizeof(kPostface)); |
+ } |
+}; |
+ |
+/** |
+ * If the bitmap is not subsetted, return its encoded data, if |
+ * availible. |
+ */ |
+static inline SkData* ref_encoded_data(const SkBitmap& bm) { |
+ if ((NULL == bm.pixelRef()) |
+ || !bm.pixelRefOrigin().isZero() |
+ || (bm.info().dimensions() != bm.pixelRef()->info().dimensions())) { |
+ return NULL; |
+ } |
+ return bm.pixelRef()->refEncodedData(); |
+} |
+ |
+/* |
+ * This functions may give false negatives but no false positives. |
+ */ |
+static bool is_jfif_jpeg(SkData* data) { |
+ if (!data || (data->size() < 11)) { |
+ return false; |
+ } |
+ 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 ... |
+ return ((0 == memcmp(data->bytes(), bytesZeroToThree, |
+ sizeof(bytesZeroToThree))) |
+ && (0 == memcmp(data->bytes() + 6, bytesSixToTen, |
+ sizeof(bytesSixToTen)))); |
+} |
+} // namespace |
+ |
+SkPDFObject* SkPDFCreateImageObject( |
+ const SkBitmap& bitmap, |
+ const SkIRect& subset, |
+ SkPicture::EncodeBitmap encoder) { |
+ if (SkIRect::MakeWH(bitmap.width(), bitmap.height()) == subset) { |
+ SkAutoTUnref<SkData> encodedData(ref_encoded_data(bitmap)); |
+ if (is_jfif_jpeg(encodedData)) { |
+ return SkNEW_ARGS(PDFJPEGImage, |
+ (encodedData, bitmap.width(), bitmap.height())); |
+ } |
+ } |
+ return SkPDFImage::CreateImage(bitmap, subset, encoder); |
+} |