aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar halcanary <halcanary@google.com>2014-08-27 13:00:54 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2014-08-27 13:00:54 -0700
commitdaefa5b340d7aa36fe31865a3646f6fce321bb38 (patch)
treef8e39a0d39dc50cf150a5160bada38602cb90c8a /src
parent9694d63cf042779bdac027f8d69fc0cdd413c5e6 (diff)
JPEG(JFIF only) directly embedded into PDF
R=reed@google.com, djsollen@google.com, mtklein@google.com Author: halcanary@google.com Review URL: https://codereview.chromium.org/515493003
Diffstat (limited to 'src')
-rw-r--r--src/pdf/SkPDFDevice.cpp4
-rw-r--r--src/pdf/SkPDFImage.cpp89
-rw-r--r--src/pdf/SkPDFImage.h11
3 files changed, 102 insertions, 2 deletions
diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp
index 5946b9ae6f..ec07a8ff0e 100644
--- a/src/pdf/SkPDFDevice.cpp
+++ b/src/pdf/SkPDFDevice.cpp
@@ -2182,8 +2182,8 @@ void SkPDFDevice::internalDrawBitmap(const SkMatrix& origMatrix,
return;
}
- SkAutoTUnref<SkPDFImage> image(
- SkPDFImage::CreateImage(*bitmap, subset, fEncoder));
+ SkAutoTUnref<SkPDFObject> image(
+ SkPDFCreateImageObject(*bitmap, subset, fEncoder));
if (!image) {
return;
}
diff --git a/src/pdf/SkPDFImage.cpp b/src/pdf/SkPDFImage.cpp
index 715fb4859d..49460510d9 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);
+}
diff --git a/src/pdf/SkPDFImage.h b/src/pdf/SkPDFImage.h
index 10f8be6270..5c026dac9a 100644
--- a/src/pdf/SkPDFImage.h
+++ b/src/pdf/SkPDFImage.h
@@ -17,9 +17,20 @@
#include "SkRefCnt.h"
class SkBitmap;
+class SkData;
class SkPDFCatalog;
struct SkIRect;
+/**
+ * Return the mose efficient availible encoding of the given bitmap.
+ *
+ * If the bitmap has encoded JPEG data and that data can be embedded
+ * into the PDF output stream directly, use that. Otherwise, fall
+ * back on SkPDFImage::CreateImage.
+ */
+SkPDFObject* SkPDFCreateImageObject(
+ const SkBitmap&, const SkIRect& subset, SkPicture::EncodeBitmap);
+
/** \class SkPDFImage
An image XObject.