SkDocument::setDCTEncoder() for old versions of webkit
authorhalcanary <halcanary@google.com>
Thu, 10 Dec 2015 16:59:43 +0000 (08:59 -0800)
committerCommit bot <commit-bot@chromium.org>
Thu, 10 Dec 2015 16:59:43 +0000 (08:59 -0800)
Review URL: https://codereview.chromium.org/1505763003

include/core/SkDocument.h
src/doc/SkDocument_PDF.cpp
src/pdf/SkPDFBitmap.cpp
src/pdf/SkPDFBitmap.h
src/pdf/SkPDFCanon.h
src/pdf/SkPDFDevice.cpp
tests/PDFDocumentTest.cpp

index 316d15a253429ea07c7b40e102a8e22f36e8e6d8..6ee96b9ce3afed5e69eb1e0fcf20d9a72ac71951 100644 (file)
@@ -16,6 +16,7 @@
 #include "SkTime.h"
 
 class SkCanvas;
+class SkPixelSerializer;
 class SkWStream;
 
 /** SK_ScalarDefaultDPI is 72 DPI.
@@ -57,6 +58,24 @@ public:
     static SkDocument* CreatePDF(SkWStream*,
                                  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.
      */
index ff7a038b6bf268c9a9b85ba2dbd1da38eb1b5035..fb560ea1e36c8347364747058e0697269b3eaa0c 100644 (file)
@@ -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);
 }
index 0c53da69743c622249aa9a2cfb361c030a050862..4e49db518d802896ed069a75fe4f3f66d9bd0bb2 100644 (file)
@@ -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
index d93133143118a66fa13f34799e782764d18b8257..b0254c1f551fbb97b7b6bc4b7c6a2d88feabf42f 100644 (file)
@@ -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
index 3d2ba6a77d1b4b2ea36023814c11080553e33e65..9ecb3a02d999c16dc853a4c3e7163a9d07e10108 100644 (file)
@@ -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;
index 1c5b4da07065c7a7afc0963fd713f7bd3a47091a..012caf6d7de7b07759148bb67643ecf1596e3a29 100644 (file)
@@ -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;
         }
index 04c3ede6aa4c595ae7ea6799c23e9d26b1f5d90a..c3a5f0e04165846749a4203861ad250396f94dd1 100644 (file)
@@ -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));
+    }
+}