aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--include/core/SkDocument.h19
-rw-r--r--src/doc/SkDocument_PDF.cpp19
-rw-r--r--src/pdf/SkPDFBitmap.cpp18
-rw-r--r--src/pdf/SkPDFBitmap.h2
-rw-r--r--src/pdf/SkPDFCanon.h3
-rw-r--r--src/pdf/SkPDFDevice.cpp3
-rw-r--r--tests/PDFDocumentTest.cpp44
7 files changed, 101 insertions, 7 deletions
diff --git a/include/core/SkDocument.h b/include/core/SkDocument.h
index 316d15a253..6ee96b9ce3 100644
--- a/include/core/SkDocument.h
+++ b/include/core/SkDocument.h
@@ -16,6 +16,7 @@
#include "SkTime.h"
class SkCanvas;
+class SkPixelSerializer;
class SkWStream;
/** SK_ScalarDefaultDPI is 72 DPI.
@@ -58,6 +59,24 @@ public:
SkScalar dpi = SK_ScalarDefaultRasterDPI);
/**
+ * @param jpegEncoder For PDF documents, if a jpegEncoder is set,
+ * use it to encode SkImages and SkBitmaps as [JFIF]JPEGs.
+ * This feature is deprecated and is only supplied for
+ * backwards compatability.
+ *
+ * The prefered method to create PDFs with JPEG images is
+ * to use SkImage::NewFromEncoded() and not jpegEncoder.
+ * Chromium uses NewFromEncoded.
+ *
+ * If the encoder is unset, or if jpegEncoder->onEncode()
+ * returns NULL, fall back on encoding images losslessly
+ * with Deflate.
+ */
+ static SkDocument* CreatePDF(SkWStream*,
+ SkScalar dpi,
+ SkPixelSerializer* jpegEncoder);
+
+ /**
* Create a PDF-backed document, writing the results into a file.
*/
static SkDocument* CreatePDF(const char outputFilePath[],
diff --git a/src/doc/SkDocument_PDF.cpp b/src/doc/SkDocument_PDF.cpp
index ff7a038b6b..fb560ea1e3 100644
--- a/src/doc/SkDocument_PDF.cpp
+++ b/src/doc/SkDocument_PDF.cpp
@@ -322,9 +322,12 @@ class SkDocument_PDF : public SkDocument {
public:
SkDocument_PDF(SkWStream* stream,
void (*doneProc)(SkWStream*, bool),
- SkScalar rasterDpi)
+ SkScalar rasterDpi,
+ SkPixelSerializer* jpegEncoder)
: SkDocument(stream, doneProc)
- , fRasterDpi(rasterDpi) {}
+ , fRasterDpi(rasterDpi) {
+ fCanon.fPixelSerializer.reset(SkSafeRef(jpegEncoder));
+ }
virtual ~SkDocument_PDF() {
// subclasses must call close() in their destructors
@@ -386,7 +389,15 @@ private:
///////////////////////////////////////////////////////////////////////////////
SkDocument* SkDocument::CreatePDF(SkWStream* stream, SkScalar dpi) {
- return stream ? new SkDocument_PDF(stream, nullptr, dpi) : nullptr;
+ return stream ? new SkDocument_PDF(stream, nullptr, dpi, nullptr) : nullptr;
+}
+
+SkDocument* SkDocument::CreatePDF(SkWStream* stream,
+ SkScalar dpi,
+ SkPixelSerializer* jpegEncoder) {
+ return stream
+ ? new SkDocument_PDF(stream, nullptr, dpi, jpegEncoder)
+ : nullptr;
}
SkDocument* SkDocument::CreatePDF(const char path[], SkScalar dpi) {
@@ -396,5 +407,5 @@ SkDocument* SkDocument::CreatePDF(const char path[], SkScalar dpi) {
return nullptr;
}
auto delete_wstream = [](SkWStream* stream, bool) { delete stream; };
- return new SkDocument_PDF(stream, delete_wstream, dpi);
+ return new SkDocument_PDF(stream, delete_wstream, dpi, nullptr);
}
diff --git a/src/pdf/SkPDFBitmap.cpp b/src/pdf/SkPDFBitmap.cpp
index 0c53da6974..4e49db518d 100644
--- a/src/pdf/SkPDFBitmap.cpp
+++ b/src/pdf/SkPDFBitmap.cpp
@@ -468,7 +468,8 @@ void PDFJpegBitmap::emitObject(SkWStream* stream,
////////////////////////////////////////////////////////////////////////////////
-SkPDFObject* SkPDFCreateBitmapObject(const SkImage* image) {
+SkPDFObject* SkPDFCreateBitmapObject(const SkImage* image,
+ SkPixelSerializer* pixelSerializer) {
SkAutoTUnref<SkData> data(image->refEncoded());
SkJFIFInfo info;
if (data && SkIsJFIF(data, &info)) {
@@ -481,6 +482,21 @@ SkPDFObject* SkPDFCreateBitmapObject(const SkImage* image) {
return new PDFJpegBitmap(info.fSize, data, yuv);
}
}
+
+ if (pixelSerializer) {
+ SkBitmap bm;
+ SkAutoPixmapUnlock apu;
+ if (as_IB(image)->getROPixels(&bm) && bm.requestLock(&apu)) {
+ data.reset(pixelSerializer->encode(apu.pixmap()));
+ if (data && SkIsJFIF(data, &info)) {
+ bool yuv = info.fType == SkJFIFInfo::kYCbCr;
+ if (info.fSize == image->dimensions()) { // Sanity check.
+ return new PDFJpegBitmap(info.fSize, data, yuv);
+ }
+ }
+ }
+ }
+
SkPDFObject* smask =
image_compute_is_opaque(image) ? nullptr : new PDFAlphaBitmap(image);
#ifdef SK_PDF_IMAGE_STATS
diff --git a/src/pdf/SkPDFBitmap.h b/src/pdf/SkPDFBitmap.h
index d931331431..b0254c1f55 100644
--- a/src/pdf/SkPDFBitmap.h
+++ b/src/pdf/SkPDFBitmap.h
@@ -16,6 +16,6 @@ class SkImage;
* It is designed to use a minimal amout of memory, aside from refing
* the image, and its emitObject() does not cache any data.
*/
-SkPDFObject* SkPDFCreateBitmapObject(const SkImage*);
+SkPDFObject* SkPDFCreateBitmapObject(const SkImage*, SkPixelSerializer*);
#endif // SkPDFBitmap_DEFINED
diff --git a/src/pdf/SkPDFCanon.h b/src/pdf/SkPDFCanon.h
index 3d2ba6a77d..9ecb3a02d9 100644
--- a/src/pdf/SkPDFCanon.h
+++ b/src/pdf/SkPDFCanon.h
@@ -10,6 +10,7 @@
#include "SkBitmap.h"
#include "SkPDFGraphicState.h"
#include "SkPDFShader.h"
+#include "SkPixelSerializer.h"
#include "SkTDArray.h"
#include "SkTHash.h"
@@ -80,6 +81,8 @@ public:
SkTHashMap<uint32_t, bool> fCanEmbedTypeface;
+ SkAutoTUnref<SkPixelSerializer> fPixelSerializer;
+
private:
struct FontRec {
SkPDFFont* fFont;
diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp
index 1c5b4da070..012caf6d7d 100644
--- a/src/pdf/SkPDFDevice.cpp
+++ b/src/pdf/SkPDFDevice.cpp
@@ -2433,7 +2433,8 @@ void SkPDFDevice::internalDrawImage(const SkMatrix& origMatrix,
}
SkAutoTUnref<SkPDFObject> pdfimage(SkSafeRef(fCanon->findPDFBitmap(image)));
if (!pdfimage) {
- pdfimage.reset(SkPDFCreateBitmapObject(image));
+ pdfimage.reset(SkPDFCreateBitmapObject(
+ image, fCanon->fPixelSerializer));
if (!pdfimage) {
return;
}
diff --git a/tests/PDFDocumentTest.cpp b/tests/PDFDocumentTest.cpp
index 04c3ede6aa..c3a5f0e041 100644
--- a/tests/PDFDocumentTest.cpp
+++ b/tests/PDFDocumentTest.cpp
@@ -6,10 +6,12 @@
*/
#include "Test.h"
+#include "Resources.h"
#include "SkCanvas.h"
#include "SkDocument.h"
#include "SkOSFile.h"
#include "SkStream.h"
+#include "SkPixelSerializer.h"
static void test_empty(skiatest::Reporter* reporter) {
SkDynamicMemoryWStream stream;
@@ -110,3 +112,45 @@ DEF_TEST(document_tests, reporter) {
test_file(reporter);
test_close(reporter);
}
+
+namespace {
+class JPEGSerializer final : public SkPixelSerializer {
+ bool onUseEncodedData(const void*, size_t) override { return true; }
+ SkData* onEncode(const SkPixmap& pixmap) override {
+ SkBitmap bm;
+ return bm.installPixels(pixmap.info(),
+ pixmap.writable_addr(),
+ pixmap.rowBytes(),
+ pixmap.ctable(),
+ nullptr, nullptr)
+ ? SkImageEncoder::EncodeData(bm, SkImageEncoder::kJPEG_Type, 85)
+ : nullptr;
+ }
+};
+} // namespace
+
+size_t count_bytes(const SkBitmap& bm, bool useDCT) {
+ SkDynamicMemoryWStream stream;
+ SkAutoTUnref<SkDocument> doc;
+ if (useDCT) {
+ SkAutoTUnref<SkPixelSerializer> serializer(new JPEGSerializer);
+ doc.reset(SkDocument::CreatePDF(
+ &stream, SK_ScalarDefaultRasterDPI, serializer));
+ } else {
+ doc.reset(SkDocument::CreatePDF(&stream));
+ }
+ SkCanvas* canvas = doc->beginPage(64, 64);
+ canvas->drawBitmap(bm, 0, 0);
+ doc->endPage();
+ doc->close();
+ return stream.bytesWritten();
+}
+
+DEF_TEST(document_dct_encoder, r) {
+ REQUIRE_PDF_DOCUMENT(document_dct_encoder, r);
+ SkBitmap bm;
+ if (GetResourceAsBitmap("mandrill_64.png", &bm)) {
+ // Lossy encoding works better on photographs.
+ REPORTER_ASSERT(r, count_bytes(bm, true) < count_bytes(bm, false));
+ }
+}