PDF: remove last use of SkPDFImage

Add a GM.

BUG=skia:255

Review URL: https://codereview.chromium.org/950633003
diff --git a/src/pdf/SkPDFBitmap.cpp b/src/pdf/SkPDFBitmap.cpp
index 668f7de..486dac4 100644
--- a/src/pdf/SkPDFBitmap.cpp
+++ b/src/pdf/SkPDFBitmap.cpp
@@ -25,114 +25,214 @@
     stream->write(streamEnd, strlen(streamEnd));
 }
 
-static size_t pixel_count(const SkBitmap& bm) {
-    return SkToSizeT(bm.width()) * SkToSizeT(bm.height());
-}
+////////////////////////////////////////////////////////////////////////////////
 
 // write a single byte to a stream n times.
 static void fill_stream(SkWStream* out, char value, size_t n) {
     char buffer[4096];
     memset(buffer, value, sizeof(buffer));
-    while (n) {
-        size_t k = SkTMin(n, sizeof(buffer));
-        out->write(buffer, k);
-        n -= k;
+    for (size_t i = 0; i < n / sizeof(buffer); ++i) {
+        out->write(buffer, sizeof(buffer));
     }
+    out->write(buffer, n % sizeof(buffer));
 }
 
-static SkPMColor get_pmcolor_neighbor_avg_color(const SkBitmap& bitmap,
-                                                int xOrig,
-                                                int yOrig) {
-    SkASSERT(kN32_SkColorType == bitmap.colorType());
-    SkASSERT(bitmap.getPixels());
-    uint8_t count = 0;
-    unsigned r = 0;
-    unsigned g = 0;
-    unsigned b = 0;
-    for (int y = yOrig - 1; y <= yOrig + 1; ++y) {
-        if (y < 0 || y >= bitmap.height()) {
-            continue;
-        }
-        uint32_t* src = bitmap.getAddr32(0, y);
-        for (int x = xOrig - 1; x <= xOrig + 1; ++x) {
-            if (x < 0 || x >= bitmap.width()) {
-                continue;
-            }
-            SkPMColor pmColor = src[x];
-            U8CPU alpha = SkGetPackedA32(pmColor);
-            if (alpha != SK_AlphaTRANSPARENT) {
-                uint32_t s = SkUnPreMultiply::GetScale(alpha);
-                r += SkUnPreMultiply::ApplyScale(s, SkGetPackedR32(pmColor));
-                g += SkUnPreMultiply::ApplyScale(s, SkGetPackedG32(pmColor));
-                b += SkUnPreMultiply::ApplyScale(s, SkGetPackedB32(pmColor));
-                ++count;
-            }
+// unpremultiply and extract R, G, B components.
+static void pmcolor_to_rgb24(SkPMColor pmColor, uint8_t* rgb) {
+    uint32_t s = SkUnPreMultiply::GetScale(SkGetPackedA32(pmColor));
+    rgb[0] = SkUnPreMultiply::ApplyScale(s, SkGetPackedR32(pmColor));
+    rgb[1] = SkUnPreMultiply::ApplyScale(s, SkGetPackedG32(pmColor));
+    rgb[2] = SkUnPreMultiply::ApplyScale(s, SkGetPackedB32(pmColor));
+}
+
+/* It is necessary to average the color component of transparent
+   pixels with their surrounding neighbors since the PDF renderer may
+   separately re-sample the alpha and color channels when the image is
+   not displayed at its native resolution. Since an alpha of zero
+   gives no information about the color component, the pathological
+   case is a white image with sharp transparency bounds - the color
+   channel goes to black, and the should-be-transparent pixels are
+   rendered as grey because of the separate soft mask and color
+   resizing. e.g.: gm/bitmappremul.cpp */
+static void get_neighbor_avg_color(const SkBitmap& bm,
+                                   int xOrig,
+                                   int yOrig,
+                                   uint8_t rgb[3]) {
+    SkASSERT(kN32_SkColorType == bm.colorType());
+    unsigned a = 0, r = 0, g = 0, b = 0;
+    // Clamp the range to the edge of the bitmap.
+    int ymin = SkTMax(0, yOrig - 1);
+    int ymax = SkTMin(yOrig + 1, bm.height() - 1);
+    int xmin = SkTMax(0, xOrig - 1);
+    int xmax = SkTMin(xOrig + 1, bm.width() - 1);
+    for (int y = ymin; y <= ymax; ++y) {
+        SkPMColor* scanline = bm.getAddr32(0, y);
+        for (int x = xmin; x <= xmax; ++x) {
+            SkPMColor pmColor = scanline[x];
+            a += SkGetPackedA32(pmColor);
+            r += SkGetPackedR32(pmColor);
+            g += SkGetPackedG32(pmColor);
+            b += SkGetPackedB32(pmColor);
         }
     }
-    if (count == 0) {
-        return SkPackARGB32NoCheck(SK_AlphaOPAQUE, 0, 0, 0);
+    if (a > 0) {
+        rgb[0] = SkToU8(255 * r / a);
+        rgb[1] = SkToU8(255 * g / a);
+        rgb[2] = SkToU8(255 * b / a);
     } else {
-        return SkPackARGB32NoCheck(
-                SK_AlphaOPAQUE, r / count, g / count, b / count);
+        rgb[0] = rgb[1] = rgb[2] = 0;
     }
 }
 
-static void pmcolor_to_rgb24(const SkBitmap& bm, SkWStream* out) {
-    SkASSERT(kN32_SkColorType == bm.colorType());
-    if (!bm.getPixels()) {
-        fill_stream(out, '\xFF', 3 * pixel_count(bm));
+static size_t pixel_count(const SkBitmap& bm) {
+    return SkToSizeT(bm.width()) * SkToSizeT(bm.height());
+}
+
+static const SkBitmap& not4444(const SkBitmap& input, SkBitmap* copy) {
+    if (input.colorType() != kARGB_4444_SkColorType) {
+        return input;
+    }
+    // ARGB_4444 is rarely used, so we can do a wasteful tmp copy.
+    SkAssertResult(input.copyTo(copy, kN32_SkColorType));
+    copy->setImmutable();
+    return *copy;
+}
+
+static size_t pdf_color_component_count(SkColorType ct) {
+    switch (ct) {
+        case kN32_SkColorType:
+        case kRGB_565_SkColorType:
+        case kARGB_4444_SkColorType:
+            return 3;
+        case kAlpha_8_SkColorType:
+        case kIndex_8_SkColorType:
+        case kGray_8_SkColorType:
+            return 1;
+        case kUnknown_SkColorType:
+        default:
+            SkDEBUGFAIL("unexpected color type");
+            return 0;
+    }
+}
+
+static void bitmap_to_pdf_pixels(const SkBitmap& bitmap, SkWStream* out) {
+    if (!bitmap.getPixels()) {
+        size_t size = pixel_count(bitmap) *
+                      pdf_color_component_count(bitmap.colorType());
+        fill_stream(out, '\x00', size);
         return;
     }
-    size_t scanlineLength = 3 * bm.width();
-    SkAutoTMalloc<uint8_t> scanline(scanlineLength);
-    for (int y = 0; y < bm.height(); ++y) {
-        uint8_t* dst = scanline.get();
-        const SkPMColor* src = bm.getAddr32(0, y);
-        for (int x = 0; x < bm.width(); ++x) {
-            SkPMColor color = *src++;
-            U8CPU alpha = SkGetPackedA32(color);
-            if (alpha != SK_AlphaTRANSPARENT) {
-                uint32_t s = SkUnPreMultiply::GetScale(alpha);
-                *dst++ = SkUnPreMultiply::ApplyScale(s, SkGetPackedR32(color));
-                *dst++ = SkUnPreMultiply::ApplyScale(s, SkGetPackedG32(color));
-                *dst++ = SkUnPreMultiply::ApplyScale(s, SkGetPackedB32(color));
-            } else {
-                /* It is necessary to average the color component of
-                   transparent pixels with their surrounding neighbors
-                   since the PDF renderer may separately re-sample the
-                   alpha and color channels when the image is not
-                   displayed at its native resolution. Since an alpha
-                   of zero gives no information about the color
-                   component, the pathological case is a white image
-                   with sharp transparency bounds - the color channel
-                   goes to black, and the should-be-transparent pixels
-                   are rendered as grey because of the separate soft
-                   mask and color resizing. e.g.: gm/bitmappremul.cpp */
-                color = get_pmcolor_neighbor_avg_color(bm, x, y);
-                *dst++ = SkGetPackedR32(color);
-                *dst++ = SkGetPackedG32(color);
-                *dst++ = SkGetPackedB32(color);
+    SkBitmap copy;
+    const SkBitmap& bm = not4444(bitmap, &copy);
+    SkAutoLockPixels autoLockPixels(bm);
+    switch (bm.colorType()) {
+        case kN32_SkColorType: {
+            SkASSERT(3 == pdf_color_component_count(bitmap.colorType()));
+            SkAutoTMalloc<uint8_t> scanline(3 * bm.width());
+            for (int y = 0; y < bm.height(); ++y) {
+                const SkPMColor* src = bm.getAddr32(0, y);
+                uint8_t* dst = scanline.get();
+                for (int x = 0; x < bm.width(); ++x) {
+                    SkPMColor color = *src++;
+                    U8CPU alpha = SkGetPackedA32(color);
+                    if (alpha != SK_AlphaTRANSPARENT) {
+                        pmcolor_to_rgb24(color, dst);
+                    } else {
+                        get_neighbor_avg_color(bm, x, y, dst);
+                    }
+                    dst += 3;
+                }
+                out->write(scanline.get(), 3 * bm.width());
             }
+            return;
         }
-        out->write(scanline.get(), scanlineLength);
+        case kRGB_565_SkColorType: {
+            SkASSERT(3 == pdf_color_component_count(bitmap.colorType()));
+            SkAutoTMalloc<uint8_t> scanline(3 * bm.width());
+            for (int y = 0; y < bm.height(); ++y) {
+                const uint16_t* src = bm.getAddr16(0, y);
+                uint8_t* dst = scanline.get();
+                for (int x = 0; x < bm.width(); ++x) {
+                    U16CPU color565 = *src++;
+                    *dst++ = SkPacked16ToR32(color565);
+                    *dst++ = SkPacked16ToG32(color565);
+                    *dst++ = SkPacked16ToB32(color565);
+                }
+                out->write(scanline.get(), 3 * bm.width());
+            }
+            return;
+        }
+        case kAlpha_8_SkColorType:
+            SkASSERT(1 == pdf_color_component_count(bitmap.colorType()));
+            fill_stream(out, '\x00', pixel_count(bm));
+            return;
+        case kGray_8_SkColorType:
+        case kIndex_8_SkColorType:
+            SkASSERT(1 == pdf_color_component_count(bitmap.colorType()));
+            // these two formats need no transformation to serialize.
+            for (int y = 0; y < bm.height(); ++y) {
+                out->write(bm.getAddr8(0, y), bm.width());
+            }
+            return;
+        case kUnknown_SkColorType:
+        case kARGB_4444_SkColorType:
+        default:
+            SkDEBUGFAIL("unexpected color type");
     }
 }
 
-static void pmcolor_alpha_to_a8(const SkBitmap& bm, SkWStream* out) {
-    SkASSERT(kN32_SkColorType == bm.colorType());
-    if (!bm.getPixels()) {
-        fill_stream(out, '\xFF', pixel_count(bm));
+////////////////////////////////////////////////////////////////////////////////
+
+static void bitmap_alpha_to_a8(const SkBitmap& bitmap, SkWStream* out) {
+    if (!bitmap.getPixels()) {
+        fill_stream(out, '\xFF', pixel_count(bitmap));
         return;
     }
-    size_t scanlineLength = bm.width();
-    SkAutoTMalloc<uint8_t> scanline(scanlineLength);
-    for (int y = 0; y < bm.height(); ++y) {
-        uint8_t* dst = scanline.get();
-        const SkPMColor* src = bm.getAddr32(0, y);
-        for (int x = 0; x < bm.width(); ++x) {
-            *dst++ = SkGetPackedA32(*src++);
+    SkBitmap copy;
+    const SkBitmap& bm = not4444(bitmap, &copy);
+    SkAutoLockPixels autoLockPixels(bm);
+    switch (bm.colorType()) {
+        case kN32_SkColorType: {
+            SkAutoTMalloc<uint8_t> scanline(bm.width());
+            for (int y = 0; y < bm.height(); ++y) {
+                uint8_t* dst = scanline.get();
+                const SkPMColor* src = bm.getAddr32(0, y);
+                for (int x = 0; x < bm.width(); ++x) {
+                    *dst++ = SkGetPackedA32(*src++);
+                }
+                out->write(scanline.get(), bm.width());
+            }
+            return;
         }
-        out->write(scanline.get(), scanlineLength);
+        case kAlpha_8_SkColorType:
+            for (int y = 0; y < bm.height(); ++y) {
+                out->write(bm.getAddr8(0, y), bm.width());
+            }
+            return;
+        case kIndex_8_SkColorType: {
+            SkColorTable* ct = bm.getColorTable();
+            SkASSERT(ct);
+            SkAutoTMalloc<uint8_t> scanline(bm.width());
+            for (int y = 0; y < bm.height(); ++y) {
+                uint8_t* dst = scanline.get();
+                const uint8_t* src = bm.getAddr8(0, y);
+                for (int x = 0; x < bm.width(); ++x) {
+                    *dst++ = SkGetPackedA32((*ct)[*src++]);
+                }
+                out->write(scanline.get(), bm.width());
+            }
+            return;
+        }
+        case kRGB_565_SkColorType:
+        case kGray_8_SkColorType:
+            SkDEBUGFAIL("color type has no alpha");
+            return;
+        case kARGB_4444_SkColorType:
+            SkDEBUGFAIL("4444 color type should have been converted to N32");
+            return;
+        case kUnknown_SkColorType:
+        default:
+            SkDEBUGFAIL("unexpected color type");
     }
 }
 
@@ -145,49 +245,40 @@
     PDFAlphaBitmap(const SkBitmap& bm) : fBitmap(bm) {}
     ~PDFAlphaBitmap() {}
     void emitObject(SkWStream*, SkPDFCatalog*) SK_OVERRIDE;
-    void addResources(SkTSet<SkPDFObject*>*, SkPDFCatalog*) const SK_OVERRIDE {}
 
 private:
     const SkBitmap fBitmap;
-    void emitDict(SkWStream*, SkPDFCatalog*, size_t, bool) const;
+    void emitDict(SkWStream*, SkPDFCatalog*, size_t) const;
 };
 
 void PDFAlphaBitmap::emitObject(SkWStream* stream, SkPDFCatalog* catalog) {
     SkAutoLockPixels autoLockPixels(fBitmap);
+    SkASSERT(fBitmap.colorType() != kIndex_8_SkColorType ||
+             fBitmap.getColorTable());
 
-#ifndef SK_NO_FLATE
     // Write to a temporary buffer to get the compressed length.
     SkDynamicMemoryWStream buffer;
     SkDeflateWStream deflateWStream(&buffer);
-    pmcolor_alpha_to_a8(fBitmap, &deflateWStream);
+    bitmap_alpha_to_a8(fBitmap, &deflateWStream);
     deflateWStream.finalize();  // call before detachAsStream().
     SkAutoTDelete<SkStreamAsset> asset(buffer.detachAsStream());
 
-    this->emitDict(stream, catalog, asset->getLength(), /*deflate=*/true);
+    this->emitDict(stream, catalog, asset->getLength());
     pdf_stream_begin(stream);
     stream->writeStream(asset.get(), asset->getLength());
     pdf_stream_end(stream);
-#else
-    this->emitDict(stream, catalog, pixel_count(fBitmap), /*deflate=*/false);
-    pdf_stream_begin(stream);
-    pmcolor_alpha_to_a8(fBitmap, stream);
-    pdf_stream_end(stream);
-#endif  // SK_NO_FLATE
 }
 
 void PDFAlphaBitmap::emitDict(SkWStream* stream,
                               SkPDFCatalog* catalog,
-                              size_t length,
-                              bool deflate) const {
+                              size_t length) const {
     SkPDFDict pdfDict("XObject");
     pdfDict.insertName("Subtype", "Image");
     pdfDict.insertInt("Width", fBitmap.width());
     pdfDict.insertInt("Height", fBitmap.height());
     pdfDict.insertName("ColorSpace", "DeviceGray");
     pdfDict.insertInt("BitsPerComponent", 8);
-    if (deflate) {
-        pdfDict.insertName("Filter", "FlateDecode");
-    }
+    pdfDict.insertName("Filter", "FlateDecode");
     pdfDict.insertInt("Length", length);
     pdfDict.emitObject(stream, catalog);
 }
@@ -198,50 +289,81 @@
 void SkPDFBitmap::addResources(SkTSet<SkPDFObject*>* resourceSet,
                                SkPDFCatalog* catalog) const {
     if (fSMask.get()) {
-        resourceSet->add(fSMask.get());
+        if (resourceSet->add(fSMask.get())) {
+            fSMask->addResources(resourceSet, catalog);
+        }
     }
 }
 
 void SkPDFBitmap::emitObject(SkWStream* stream, SkPDFCatalog* catalog) {
     SkAutoLockPixels autoLockPixels(fBitmap);
+    SkASSERT(fBitmap.colorType() != kIndex_8_SkColorType ||
+             fBitmap.getColorTable());
 
-#ifndef SK_NO_FLATE
     // Write to a temporary buffer to get the compressed length.
     SkDynamicMemoryWStream buffer;
     SkDeflateWStream deflateWStream(&buffer);
-    pmcolor_to_rgb24(fBitmap, &deflateWStream);
+    bitmap_to_pdf_pixels(fBitmap, &deflateWStream);
     deflateWStream.finalize();  // call before detachAsStream().
     SkAutoTDelete<SkStreamAsset> asset(buffer.detachAsStream());
 
-    this->emitDict(stream, catalog, asset->getLength(), /*deflate=*/true);
+    this->emitDict(stream, catalog, asset->getLength());
     pdf_stream_begin(stream);
     stream->writeStream(asset.get(), asset->getLength());
     pdf_stream_end(stream);
-#else
-    this->emitDict(stream, catalog, 3 * pixel_count(fBitmap), /*deflate=*/false);
-    pdf_stream_begin(stream);
-    pmcolor_to_rgb24(fBitmap, stream);
-    pdf_stream_end(stream);
-    return;
-#endif  // SK_NO_FLATE
+}
+
+static SkPDFArray* make_indexed_color_space(const SkColorTable* table) {
+    SkPDFArray* result = SkNEW(SkPDFArray);
+    result->reserve(4);
+    result->appendName("Indexed");
+    result->appendName("DeviceRGB");
+    SkASSERT(table);
+    if (table->count() < 1) {
+        result->appendInt(0);
+        char shortTableArray[3] = {0, 0, 0};
+        SkString tableString(shortTableArray, SK_ARRAY_COUNT(shortTableArray));
+        result->append(new SkPDFString(tableString))->unref();
+        return result;
+    }
+    result->appendInt(table->count() - 1);  // maximum color index.
+
+    // Potentially, this could be represented in fewer bytes with a stream.
+    // Max size as a string is 1.5k.
+    char tableArray[256 * 3];
+    SkASSERT(3u * table->count() <= SK_ARRAY_COUNT(tableArray));
+    uint8_t* tablePtr = reinterpret_cast<uint8_t*>(tableArray);
+    const SkPMColor* colors = table->readColors();
+    for (int i = 0; i < table->count(); i++) {
+        pmcolor_to_rgb24(colors[i], tablePtr);
+        tablePtr += 3;
+    }
+    SkString tableString(tableArray, 3 * table->count());
+    result->append(new SkPDFString(tableString))->unref();
+    return result;
 }
 
 void SkPDFBitmap::emitDict(SkWStream* stream,
                            SkPDFCatalog* catalog,
-                           size_t length,
-                           bool deflate) const {
+                           size_t length) const {
     SkPDFDict pdfDict("XObject");
     pdfDict.insertName("Subtype", "Image");
     pdfDict.insertInt("Width", fBitmap.width());
     pdfDict.insertInt("Height", fBitmap.height());
-    pdfDict.insertName("ColorSpace", "DeviceRGB");
+    if (fBitmap.colorType() == kIndex_8_SkColorType) {
+        SkASSERT(1 == pdf_color_component_count(fBitmap.colorType()));
+        pdfDict.insert("ColorSpace", make_indexed_color_space(
+                                             fBitmap.getColorTable()))->unref();
+    } else if (1 == pdf_color_component_count(fBitmap.colorType())) {
+        pdfDict.insertName("ColorSpace", "DeviceGray");
+    } else {
+        pdfDict.insertName("ColorSpace", "DeviceRGB");
+    }
     pdfDict.insertInt("BitsPerComponent", 8);
     if (fSMask) {
         pdfDict.insert("SMask", new SkPDFObjRef(fSMask))->unref();
     }
-    if (deflate) {
-        pdfDict.insertName("Filter", "FlateDecode");
-    }
+    pdfDict.insertName("Filter", "FlateDecode");
     pdfDict.insertInt("Length", length);
     pdfDict.emitObject(stream, catalog);
 }
@@ -253,64 +375,35 @@
 SkPDFBitmap::~SkPDFBitmap() {}
 
 ////////////////////////////////////////////////////////////////////////////////
-static bool is_transparent(const SkBitmap& bm) {
-    SkAutoLockPixels autoLockPixels(bm);
-    if (NULL == bm.getPixels()) {
-        return true;
+
+static const SkBitmap& immutable_bitmap(const SkBitmap& bm, SkBitmap* copy) {
+    if (bm.isImmutable()) {
+        return bm;
     }
-    SkASSERT(kN32_SkColorType == bm.colorType());
-    for (int y = 0; y < bm.height(); ++y) {
-        U8CPU alpha = 0;
-        const SkPMColor* src = bm.getAddr32(0, y);
-        for (int x = 0; x < bm.width(); ++x) {
-            alpha |= SkGetPackedA32(*src++);
-        }
-        if (alpha) {
-            return false;
-        }
-    }
-    return true;
+    bm.copyTo(copy);
+    copy->setImmutable();
+    return *copy;
 }
 
-SkPDFBitmap* SkPDFBitmap::Create(SkPDFCanon* canon,
-                                 const SkBitmap& bitmap,
-                                 const SkIRect& subset) {
+SkPDFBitmap* SkPDFBitmap::Create(SkPDFCanon* canon, const SkBitmap& bitmap) {
     SkASSERT(canon);
-    if (kN32_SkColorType != bitmap.colorType()) {
-        // TODO(halcanary): support other colortypes.
+    if (!SkColorTypeIsValid(bitmap.colorType()) ||
+        kUnknown_SkColorType == bitmap.colorType()) {
         return NULL;
     }
-    SkBitmap bm;
-    // Should extractSubset be done by the SkPDFDevice?
-    if (!bitmap.extractSubset(&bm, subset)) {
-        return NULL;
-    }
+    SkBitmap copy;
+    const SkBitmap& bm = immutable_bitmap(bitmap, &copy);
     if (bm.drawsNothing()) {
         return NULL;
     }
-    if (!bm.isImmutable()) {
-        SkBitmap copy;
-        if (!bm.copyTo(&copy)) {
-            return NULL;
-        }
-        copy.setImmutable();
-        bm = copy;
-    }
-
-    SkPDFBitmap* pdfBitmap = canon->findBitmap(bm);
-    if (pdfBitmap) {
-        return SkRef(pdfBitmap);
+    if (SkPDFBitmap* canonBitmap = canon->findBitmap(bm)) {
+        return SkRef(canonBitmap);
     }
     SkPDFObject* smask = NULL;
     if (!bm.isOpaque() && !SkBitmap::ComputeIsOpaque(bm)) {
-        if (is_transparent(bm)) {
-            return NULL;
-        }
-        // PDFAlphaBitmaps do not get directly canonicalized (they
-        // are refed by the SkPDFBitmap).
         smask = SkNEW_ARGS(PDFAlphaBitmap, (bm));
     }
-    pdfBitmap = SkNEW_ARGS(SkPDFBitmap, (bm, smask));
+    SkPDFBitmap* pdfBitmap = SkNEW_ARGS(SkPDFBitmap, (bm, smask));
     canon->addBitmap(pdfBitmap);
     return pdfBitmap;
 }
diff --git a/src/pdf/SkPDFBitmap.h b/src/pdf/SkPDFBitmap.h
index 45a8aa6..02a79df 100644
--- a/src/pdf/SkPDFBitmap.h
+++ b/src/pdf/SkPDFBitmap.h
@@ -17,18 +17,15 @@
  * It is designed to use a minimal amout of memory, aside from refing
  * the bitmap's pixels, and its emitObject() does not cache any data.
  *
- * As of now, it only supports 8888 bitmaps (the most common case).
+ * If !bitmap.isImmutable(), then a copy of the bitmap must be made;
+ * there is no way around this.
  *
  * The SkPDFBitmap::Create function will check the canon for duplicates.
  */
 class SkPDFBitmap : public SkPDFObject {
 public:
     // Returns NULL on unsupported bitmap;
-    // TODO(halcanary): support other bitmap colortypes and replace
-    // SkPDFImage.
-    static SkPDFBitmap* Create(SkPDFCanon*,
-                               const SkBitmap&,
-                               const SkIRect& subset);
+    static SkPDFBitmap* Create(SkPDFCanon*, const SkBitmap&);
     ~SkPDFBitmap();
     void emitObject(SkWStream*, SkPDFCatalog*) SK_OVERRIDE;
     void addResources(SkTSet<SkPDFObject*>* resourceSet,
@@ -43,7 +40,7 @@
     const SkBitmap fBitmap;
     const SkAutoTUnref<SkPDFObject> fSMask;
     SkPDFBitmap(const SkBitmap&, SkPDFObject*);
-    void emitDict(SkWStream*, SkPDFCatalog*, size_t, bool) const;
+    void emitDict(SkWStream*, SkPDFCatalog*, size_t) const;
 };
 
 #endif  // SkPDFBitmap_DEFINED
diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp
index 273b958..a0ad134 100644
--- a/src/pdf/SkPDFDevice.cpp
+++ b/src/pdf/SkPDFDevice.cpp
@@ -17,10 +17,10 @@
 #include "SkPaint.h"
 #include "SkPath.h"
 #include "SkPathOps.h"
+#include "SkPDFBitmap.h"
 #include "SkPDFFont.h"
 #include "SkPDFFormXObject.h"
 #include "SkPDFGraphicState.h"
-#include "SkPDFImage.h"
 #include "SkPDFResourceDict.h"
 #include "SkPDFShader.h"
 #include "SkPDFStream.h"
@@ -2126,7 +2126,7 @@
     if (content.needShape()) {
         SkPath shape;
         shape.addRect(SkRect::MakeWH(SkIntToScalar(subset.width()),
-                                     SkIntToScalar( subset.height())));
+                                     SkIntToScalar(subset.height())));
         shape.transform(matrix);
         content.setShape(shape);
     }
@@ -2134,8 +2134,12 @@
         return;
     }
 
-    SkAutoTUnref<SkPDFObject> image(
-            SkPDFCreateImageObject(fCanon, *bitmap, subset));
+    SkBitmap subsetBitmap;
+    // Should extractSubset be done by the SkPDFDevice?
+    if (!bitmap->extractSubset(&subsetBitmap, subset)) {
+        return;
+    }
+    SkAutoTUnref<SkPDFObject> image(SkPDFBitmap::Create(fCanon, subsetBitmap));
     if (!image) {
         return;
     }
diff --git a/src/pdf/SkPDFImage.cpp b/src/pdf/SkPDFImage.cpp
deleted file mode 100644
index e3971aa..0000000
--- a/src/pdf/SkPDFImage.cpp
+++ /dev/null
@@ -1,727 +0,0 @@
-/*
- * Copyright 2010 The Android Open Source Project
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "SkPDFImage.h"
-
-#include "SkBitmap.h"
-#include "SkColor.h"
-#include "SkColorPriv.h"
-#include "SkData.h"
-#include "SkFlate.h"
-#include "SkPDFBitmap.h"
-#include "SkPDFCatalog.h"
-#include "SkPixelRef.h"
-#include "SkRect.h"
-#include "SkStream.h"
-#include "SkString.h"
-#include "SkUnPreMultiply.h"
-
-static size_t get_uncompressed_size(const SkBitmap& bitmap,
-                                    const SkIRect& srcRect) {
-    switch (bitmap.colorType()) {
-        case kIndex_8_SkColorType:
-            return srcRect.width() * srcRect.height();
-        case kARGB_4444_SkColorType:
-            return ((srcRect.width() * 3 + 1) / 2) * srcRect.height();
-        case kRGB_565_SkColorType:
-            return srcRect.width() * 3 * srcRect.height();
-        case kRGBA_8888_SkColorType:
-        case kBGRA_8888_SkColorType:
-        case kGray_8_SkColorType:
-            return srcRect.width() * 3 * srcRect.height();
-        case kAlpha_8_SkColorType:
-            return 1;
-        default:
-            SkASSERT(false);
-            return 0;
-    }
-}
-
-static SkStream* extract_index8_image(const SkBitmap& bitmap,
-                                      const SkIRect& srcRect) {
-    const int rowBytes = srcRect.width();
-    SkStream* stream = SkNEW_ARGS(SkMemoryStream,
-                                  (get_uncompressed_size(bitmap, srcRect)));
-    uint8_t* dst = (uint8_t*)stream->getMemoryBase();
-
-    for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
-        memcpy(dst, bitmap.getAddr8(srcRect.fLeft, y), rowBytes);
-        dst += rowBytes;
-    }
-    return stream;
-}
-
-static SkStream* extract_argb4444_data(const SkBitmap& bitmap,
-                                       const SkIRect& srcRect,
-                                       bool extractAlpha,
-                                       bool* isOpaque,
-                                       bool* isTransparent) {
-    SkStream* stream;
-    uint8_t* dst = NULL;
-    if (extractAlpha) {
-        const int alphaRowBytes = (srcRect.width() + 1) / 2;
-        stream = SkNEW_ARGS(SkMemoryStream,
-                            (alphaRowBytes * srcRect.height()));
-    } else {
-        stream = SkNEW_ARGS(SkMemoryStream,
-                            (get_uncompressed_size(bitmap, srcRect)));
-    }
-    dst = (uint8_t*)stream->getMemoryBase();
-
-    for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
-        uint16_t* src = bitmap.getAddr16(0, y);
-        int x;
-        for (x = srcRect.fLeft; x + 1 < srcRect.fRight; x += 2) {
-            if (extractAlpha) {
-                dst[0] = (SkGetPackedA4444(src[x]) << 4) |
-                    SkGetPackedA4444(src[x + 1]);
-                *isOpaque &= dst[0] == SK_AlphaOPAQUE;
-                *isTransparent &= dst[0] == SK_AlphaTRANSPARENT;
-                dst++;
-            } else {
-                dst[0] = (SkGetPackedR4444(src[x]) << 4) |
-                    SkGetPackedG4444(src[x]);
-                dst[1] = (SkGetPackedB4444(src[x]) << 4) |
-                    SkGetPackedR4444(src[x + 1]);
-                dst[2] = (SkGetPackedG4444(src[x + 1]) << 4) |
-                    SkGetPackedB4444(src[x + 1]);
-                dst += 3;
-            }
-        }
-        if (srcRect.width() & 1) {
-            if (extractAlpha) {
-                dst[0] = (SkGetPackedA4444(src[x]) << 4);
-                *isOpaque &= dst[0] == (SK_AlphaOPAQUE & 0xF0);
-                *isTransparent &= dst[0] == (SK_AlphaTRANSPARENT & 0xF0);
-                dst++;
-
-            } else {
-                dst[0] = (SkGetPackedR4444(src[x]) << 4) |
-                    SkGetPackedG4444(src[x]);
-                dst[1] = (SkGetPackedB4444(src[x]) << 4);
-                dst += 2;
-            }
-        }
-    }
-    return stream;
-}
-
-static SkStream* extract_rgb565_image(const SkBitmap& bitmap,
-                                      const SkIRect& srcRect) {
-    SkStream* stream = SkNEW_ARGS(SkMemoryStream,
-                                  (get_uncompressed_size(bitmap,
-                                                         srcRect)));
-    uint8_t* dst = (uint8_t*)stream->getMemoryBase();
-    for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
-        uint16_t* src = bitmap.getAddr16(0, y);
-        for (int x = srcRect.fLeft; x < srcRect.fRight; x++) {
-            dst[0] = SkGetPackedR16(src[x]);
-            dst[1] = SkGetPackedG16(src[x]);
-            dst[2] = SkGetPackedB16(src[x]);
-            dst += 3;
-        }
-    }
-    return stream;
-}
-
-static SkStream* extract_gray8_image(const SkBitmap& bitmap, const SkIRect& srcRect) {
-    SkStream* stream = SkNEW_ARGS(SkMemoryStream,
-                                  (get_uncompressed_size(bitmap, srcRect)));
-    uint8_t* dst = (uint8_t*)stream->getMemoryBase();
-    for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
-        uint8_t* src = bitmap.getAddr8(0, y);
-        for (int x = srcRect.fLeft; x < srcRect.fRight; x++) {
-            dst[0] = dst[1] = dst[2] = src[x];
-            dst += 3;
-        }
-    }
-    return stream;
-}
-
-static uint32_t get_argb8888_neighbor_avg_color(const SkBitmap& bitmap,
-                                                int xOrig,
-                                                int yOrig);
-
-static SkStream* extract_argb8888_data(const SkBitmap& bitmap,
-                                       const SkIRect& srcRect,
-                                       bool extractAlpha,
-                                       bool* isOpaque,
-                                       bool* isTransparent) {
-    size_t streamSize = extractAlpha ? srcRect.width() * srcRect.height()
-                                     : get_uncompressed_size(bitmap, srcRect);
-    SkStream* stream = SkNEW_ARGS(SkMemoryStream, (streamSize));
-    uint8_t* dst = (uint8_t*)stream->getMemoryBase();
-
-    const SkUnPreMultiply::Scale* scaleTable = SkUnPreMultiply::GetScaleTable();
-
-    for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
-        uint32_t* src = bitmap.getAddr32(0, y);
-        for (int x = srcRect.fLeft; x < srcRect.fRight; x++) {
-            SkPMColor c = src[x];
-            U8CPU alpha = SkGetPackedA32(c);
-            if (extractAlpha) {
-                *isOpaque &= alpha == SK_AlphaOPAQUE;
-                *isTransparent &= alpha == SK_AlphaTRANSPARENT;
-                *dst++ = alpha;
-            } else {
-                if (SK_AlphaTRANSPARENT == alpha) {
-                    // It is necessary to average the color component of
-                    // transparent pixels with their surrounding neighbors
-                    // since the PDF renderer may separately re-sample the
-                    // alpha and color channels when the image is not
-                    // displayed at its native resolution. Since an alpha of
-                    // zero gives no information about the color component,
-                    // the pathological case is a white image with sharp
-                    // transparency bounds - the color channel goes to black,
-                    // and the should-be-transparent pixels are rendered
-                    // as grey because of the separate soft mask and color
-                    // resizing.
-                    c = get_argb8888_neighbor_avg_color(bitmap, x, y);
-                    *dst++ = SkGetPackedR32(c);
-                    *dst++ = SkGetPackedG32(c);
-                    *dst++ = SkGetPackedB32(c);
-                } else {
-                    SkUnPreMultiply::Scale s = scaleTable[alpha];
-                    *dst++ = SkUnPreMultiply::ApplyScale(s, SkGetPackedR32(c));
-                    *dst++ = SkUnPreMultiply::ApplyScale(s, SkGetPackedG32(c));
-                    *dst++ = SkUnPreMultiply::ApplyScale(s, SkGetPackedB32(c));
-                }
-            }
-        }
-    }
-    SkASSERT(dst == streamSize + (uint8_t*)stream->getMemoryBase());
-    return stream;
-}
-
-static SkStream* extract_a8_alpha(const SkBitmap& bitmap,
-                                  const SkIRect& srcRect,
-                                  bool* isOpaque,
-                                  bool* isTransparent) {
-    const int alphaRowBytes = srcRect.width();
-    SkStream* stream = SkNEW_ARGS(SkMemoryStream,
-                                  (alphaRowBytes * srcRect.height()));
-    uint8_t* alphaDst = (uint8_t*)stream->getMemoryBase();
-
-    for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
-        uint8_t* src = bitmap.getAddr8(0, y);
-        for (int x = srcRect.fLeft; x < srcRect.fRight; x++) {
-            alphaDst[0] = src[x];
-            *isOpaque &= alphaDst[0] == SK_AlphaOPAQUE;
-            *isTransparent &= alphaDst[0] == SK_AlphaTRANSPARENT;
-            alphaDst++;
-        }
-    }
-    return stream;
-}
-
-static SkStream* create_black_image() {
-    SkStream* stream = SkNEW_ARGS(SkMemoryStream, (1));
-    ((uint8_t*)stream->getMemoryBase())[0] = 0;
-    return stream;
-}
-
-/**
- * Extract either the color or image data from a SkBitmap into a SkStream.
- * @param bitmap        Bitmap to extract data from.
- * @param srcRect       Region in the bitmap to extract.
- * @param extractAlpha  Set to true to extract the alpha data or false to
- *                      extract the color data.
- * @param isTransparent Pointer to a bool to output whether the alpha is
- *                      completely transparent. May be NULL. Only valid when
- *                      extractAlpha == true.
- * @return              Unencoded image data, or NULL if either data was not
- *                      available or alpha data was requested but the image was
- *                      entirely transparent or opaque.
- */
-static SkStream* extract_image_data(const SkBitmap& bitmap,
-                                    const SkIRect& srcRect,
-                                    bool extractAlpha, bool* isTransparent) {
-    SkColorType colorType = bitmap.colorType();
-    if (extractAlpha && (kIndex_8_SkColorType == colorType ||
-                         kRGB_565_SkColorType == colorType ||
-                         kGray_8_SkColorType  == colorType)) {
-        if (isTransparent != NULL) {
-            *isTransparent = false;
-        }
-        return NULL;
-    }
-
-    SkAutoLockPixels lock(bitmap);
-    if (NULL == bitmap.getPixels()) {
-        return NULL;
-    }
-
-    bool isOpaque = true;
-    bool transparent = extractAlpha;
-    SkAutoTDelete<SkStream> stream;
-
-    switch (colorType) {
-        case kIndex_8_SkColorType:
-            if (!extractAlpha) {
-                stream.reset(extract_index8_image(bitmap, srcRect));
-            }
-            break;
-        case kARGB_4444_SkColorType:
-            stream.reset(extract_argb4444_data(bitmap, srcRect, extractAlpha,
-                                               &isOpaque, &transparent));
-            break;
-        case kRGB_565_SkColorType:
-            if (!extractAlpha) {
-                stream.reset(extract_rgb565_image(bitmap, srcRect));
-            }
-            break;
-        case kGray_8_SkColorType:
-            if (!extractAlpha) {
-                stream.reset(extract_gray8_image(bitmap, srcRect));
-            }
-            break;
-        case kN32_SkColorType:
-            stream.reset(extract_argb8888_data(bitmap, srcRect, extractAlpha,
-                                               &isOpaque, &transparent));
-            break;
-        case kAlpha_8_SkColorType:
-            if (!extractAlpha) {
-                stream.reset(create_black_image());
-            } else {
-                stream.reset(extract_a8_alpha(bitmap, srcRect,
-                                              &isOpaque, &transparent));
-            }
-            break;
-        default:
-            SkASSERT(false);
-    }
-
-    if (isTransparent != NULL) {
-        *isTransparent = transparent;
-    }
-    if (extractAlpha && (transparent || isOpaque)) {
-        return NULL;
-    }
-    return stream.detach();
-}
-
-static SkPDFArray* make_indexed_color_space(SkColorTable* table) {
-    SkPDFArray* result = new SkPDFArray();
-    result->reserve(4);
-    result->appendName("Indexed");
-    result->appendName("DeviceRGB");
-    result->appendInt(table->count() - 1);
-
-    // Potentially, this could be represented in fewer bytes with a stream.
-    // Max size as a string is 1.5k.
-    SkString index;
-    for (int i = 0; i < table->count(); i++) {
-        char buf[3];
-        SkColor color = SkUnPreMultiply::PMColorToColor((*table)[i]);
-        buf[0] = SkGetPackedR32(color);
-        buf[1] = SkGetPackedG32(color);
-        buf[2] = SkGetPackedB32(color);
-        index.append(buf, 3);
-    }
-    result->append(new SkPDFString(index))->unref();
-    return result;
-}
-
-/**
- * Removes the alpha component of an ARGB color (including unpremultiply) while
- * keeping the output in the same format as the input.
- */
-static uint32_t remove_alpha_argb8888(uint32_t pmColor) {
-    SkColor color = SkUnPreMultiply::PMColorToColor(pmColor);
-    return SkPackARGB32NoCheck(SK_AlphaOPAQUE,
-                               SkColorGetR(color),
-                               SkColorGetG(color),
-                               SkColorGetB(color));
-}
-
-static uint16_t remove_alpha_argb4444(uint16_t pmColor) {
-    return SkPixel32ToPixel4444(
-            remove_alpha_argb8888(SkPixel4444ToPixel32(pmColor)));
-}
-
-static uint32_t get_argb8888_neighbor_avg_color(const SkBitmap& bitmap,
-                                                int xOrig, int yOrig) {
-    uint8_t count = 0;
-    uint16_t r = 0;
-    uint16_t g = 0;
-    uint16_t b = 0;
-
-    for (int y = yOrig - 1; y <= yOrig + 1; y++) {
-        if (y < 0 || y >= bitmap.height()) {
-            continue;
-        }
-        uint32_t* src = bitmap.getAddr32(0, y);
-        for (int x = xOrig - 1; x <= xOrig + 1; x++) {
-            if (x < 0 || x >= bitmap.width()) {
-                continue;
-            }
-            if (SkGetPackedA32(src[x]) != SK_AlphaTRANSPARENT) {
-                uint32_t color = remove_alpha_argb8888(src[x]);
-                r += SkGetPackedR32(color);
-                g += SkGetPackedG32(color);
-                b += SkGetPackedB32(color);
-                count++;
-            }
-        }
-    }
-
-    if (count == 0) {
-        return SkPackARGB32NoCheck(SK_AlphaOPAQUE, 0, 0, 0);
-    } else {
-        return SkPackARGB32NoCheck(SK_AlphaOPAQUE,
-                                   r / count, g / count, b / count);
-    }
-}
-
-static uint16_t get_argb4444_neighbor_avg_color(const SkBitmap& bitmap,
-                                                int xOrig, int yOrig) {
-    uint8_t count = 0;
-    uint8_t r = 0;
-    uint8_t g = 0;
-    uint8_t b = 0;
-
-    for (int y = yOrig - 1; y <= yOrig + 1; y++) {
-        if (y < 0 || y >= bitmap.height()) {
-            continue;
-        }
-        uint16_t* src = bitmap.getAddr16(0, y);
-        for (int x = xOrig - 1; x <= xOrig + 1; x++) {
-            if (x < 0 || x >= bitmap.width()) {
-                continue;
-            }
-            if ((SkGetPackedA4444(src[x]) & 0x0F) != SK_AlphaTRANSPARENT) {
-                uint16_t color = remove_alpha_argb4444(src[x]);
-                r += SkGetPackedR4444(color);
-                g += SkGetPackedG4444(color);
-                b += SkGetPackedB4444(color);
-                count++;
-            }
-        }
-    }
-
-    if (count == 0) {
-        return SkPackARGB4444(SK_AlphaOPAQUE & 0x0F, 0, 0, 0);
-    } else {
-        return SkPackARGB4444(SK_AlphaOPAQUE & 0x0F,
-                                   r / count, g / count, b / count);
-    }
-}
-
-static SkBitmap unpremultiply_bitmap(const SkBitmap& bitmap,
-                                     const SkIRect& srcRect) {
-    SkBitmap outBitmap;
-    outBitmap.allocPixels(bitmap.info().makeWH(srcRect.width(), srcRect.height()));
-    int dstRow = 0;
-
-    SkAutoLockPixels outBitmapPixelLock(outBitmap);
-    SkAutoLockPixels bitmapPixelLock(bitmap);
-    switch (bitmap.colorType()) {
-        case kARGB_4444_SkColorType: {
-            for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
-                uint16_t* dst = outBitmap.getAddr16(0, dstRow);
-                uint16_t* src = bitmap.getAddr16(0, y);
-                for (int x = srcRect.fLeft; x < srcRect.fRight; x++) {
-                    uint8_t a = SkGetPackedA4444(src[x]);
-                    // It is necessary to average the color component of
-                    // transparent pixels with their surrounding neighbors
-                    // since the PDF renderer may separately re-sample the
-                    // alpha and color channels when the image is not
-                    // displayed at its native resolution. Since an alpha of
-                    // zero gives no information about the color component,
-                    // the pathological case is a white image with sharp
-                    // transparency bounds - the color channel goes to black,
-                    // and the should-be-transparent pixels are rendered
-                    // as grey because of the separate soft mask and color
-                    // resizing.
-                    if (a == (SK_AlphaTRANSPARENT & 0x0F)) {
-                        *dst = get_argb4444_neighbor_avg_color(bitmap, x, y);
-                    } else {
-                        *dst = remove_alpha_argb4444(src[x]);
-                    }
-                    dst++;
-                }
-                dstRow++;
-            }
-            break;
-        }
-        case kN32_SkColorType: {
-            for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
-                uint32_t* dst = outBitmap.getAddr32(0, dstRow);
-                uint32_t* src = bitmap.getAddr32(0, y);
-                for (int x = srcRect.fLeft; x < srcRect.fRight; x++) {
-                    uint8_t a = SkGetPackedA32(src[x]);
-                    if (a == SK_AlphaTRANSPARENT) {
-                        *dst = get_argb8888_neighbor_avg_color(bitmap, x, y);
-                    } else {
-                        *dst = remove_alpha_argb8888(src[x]);
-                    }
-                    dst++;
-                }
-                dstRow++;
-            }
-            break;
-        }
-        default:
-            SkASSERT(false);
-    }
-
-    outBitmap.setImmutable();
-
-    return outBitmap;
-}
-
-// static
-SkPDFImage* SkPDFImage::CreateImage(const SkBitmap& bitmap,
-                                    const SkIRect& srcRect) {
-    if (bitmap.colorType() == kUnknown_SkColorType) {
-        return NULL;
-    }
-
-    bool isTransparent = false;
-    SkAutoTDelete<SkStream> alphaData;
-    if (!bitmap.isOpaque()) {
-        // Note that isOpaque is not guaranteed to return false for bitmaps
-        // with alpha support but a completely opaque alpha channel,
-        // so alphaData may still be NULL if we have a completely opaque
-        // (or transparent) bitmap.
-        alphaData.reset(
-                extract_image_data(bitmap, srcRect, true, &isTransparent));
-    }
-    if (isTransparent) {
-        return NULL;
-    }
-
-    SkPDFImage* image;
-    SkColorType colorType = bitmap.colorType();
-    if (alphaData.get() != NULL && (kN32_SkColorType == colorType ||
-                                    kARGB_4444_SkColorType == colorType)) {
-        if (kN32_SkColorType == colorType) {
-            image = SkNEW_ARGS(SkPDFImage, (NULL, bitmap, false,
-                                            SkIRect::MakeWH(srcRect.width(),
-                                                            srcRect.height())));
-        } else {
-            SkBitmap unpremulBitmap = unpremultiply_bitmap(bitmap, srcRect);
-            image = SkNEW_ARGS(SkPDFImage, (NULL, unpremulBitmap, false,
-                                            SkIRect::MakeWH(srcRect.width(),
-                                                            srcRect.height())));
-        }
-    } else {
-        image = SkNEW_ARGS(SkPDFImage, (NULL, bitmap, false, srcRect));
-    }
-    if (alphaData.get() != NULL) {
-        SkAutoTUnref<SkPDFImage> mask(
-                SkNEW_ARGS(SkPDFImage, (alphaData.get(), bitmap, true, srcRect)));
-        image->insert("SMask", new SkPDFObjRef(mask))->unref();
-    }
-    return image;
-}
-
-SkPDFImage::~SkPDFImage() {}
-
-SkPDFImage::SkPDFImage(SkStream* stream,
-                       const SkBitmap& bitmap,
-                       bool isAlpha,
-                       const SkIRect& srcRect)
-    : fIsAlpha(isAlpha),
-      fSrcRect(srcRect) {
-
-    if (bitmap.isImmutable()) {
-        fBitmap = bitmap;
-    } else {
-        bitmap.deepCopyTo(&fBitmap);
-        fBitmap.setImmutable();
-    }
-
-    if (stream != NULL) {
-        this->setData(stream);
-        fStreamValid = true;
-    } else {
-        fStreamValid = false;
-    }
-
-    SkColorType colorType = fBitmap.colorType();
-
-    insertName("Type", "XObject");
-    insertName("Subtype", "Image");
-
-    bool alphaOnly = (kAlpha_8_SkColorType == colorType);
-
-    if (!isAlpha && alphaOnly) {
-        // For alpha only images, we stretch a single pixel of black for
-        // the color/shape part.
-        SkAutoTUnref<SkPDFInt> one(new SkPDFInt(1));
-        insert("Width", one.get());
-        insert("Height", one.get());
-    } else {
-        insertInt("Width", fSrcRect.width());
-        insertInt("Height", fSrcRect.height());
-    }
-
-    if (isAlpha || alphaOnly) {
-        insertName("ColorSpace", "DeviceGray");
-    } else if (kIndex_8_SkColorType == colorType) {
-        SkAutoLockPixels alp(fBitmap);
-        insert("ColorSpace",
-               make_indexed_color_space(fBitmap.getColorTable()))->unref();
-    } else {
-        insertName("ColorSpace", "DeviceRGB");
-    }
-
-    int bitsPerComp = 8;
-    if (kARGB_4444_SkColorType == colorType) {
-        bitsPerComp = 4;
-    }
-    insertInt("BitsPerComponent", bitsPerComp);
-
-    if (kRGB_565_SkColorType == colorType) {
-        SkASSERT(!isAlpha);
-        SkAutoTUnref<SkPDFInt> zeroVal(new SkPDFInt(0));
-        SkAutoTUnref<SkPDFScalar> scale5Val(
-                new SkPDFScalar(8.2258f));  // 255/2^5-1
-        SkAutoTUnref<SkPDFScalar> scale6Val(
-                new SkPDFScalar(4.0476f));  // 255/2^6-1
-        SkAutoTUnref<SkPDFArray> decodeValue(new SkPDFArray());
-        decodeValue->reserve(6);
-        decodeValue->append(zeroVal.get());
-        decodeValue->append(scale5Val.get());
-        decodeValue->append(zeroVal.get());
-        decodeValue->append(scale6Val.get());
-        decodeValue->append(zeroVal.get());
-        decodeValue->append(scale5Val.get());
-        insert("Decode", decodeValue.get());
-    }
-}
-
-SkPDFImage::SkPDFImage(SkPDFImage& pdfImage)
-    : SkPDFStream(pdfImage),
-      fBitmap(pdfImage.fBitmap),
-      fIsAlpha(pdfImage.fIsAlpha),
-      fSrcRect(pdfImage.fSrcRect),
-      fStreamValid(pdfImage.fStreamValid) {
-    // Nothing to do here - the image params are already copied in SkPDFStream's
-    // constructor, and the bitmap will be regenerated and encoded in
-    // populate.
-}
-
-bool SkPDFImage::populate(SkPDFCatalog* catalog) {
-    if (getState() == kUnused_State) {
-        // Initializing image data for the first time.
-        // Fallback method
-        if (!fStreamValid) {
-            SkAutoTDelete<SkStream> stream(
-                    extract_image_data(fBitmap, fSrcRect, fIsAlpha, NULL));
-            this->setData(stream);
-            fStreamValid = true;
-        }
-        return INHERITED::populate(catalog);
-    }
-#ifndef SK_NO_FLATE
-    else if (getState() == kNoCompression_State) {
-        // Compression has not been requested when the stream was first created,
-        // but the new catalog wants it compressed.
-        if (!getSubstitute()) {
-            SkPDFStream* substitute = SkNEW_ARGS(SkPDFImage, (*this));
-            setSubstitute(substitute);
-            catalog->setSubstitute(this, substitute);
-        }
-        return false;
-    }
-#endif  // SK_NO_FLATE
-    return true;
-}
-
-#if 0  // reenable when we can figure out the JPEG colorspace
-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 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"  // or DeviceGray
-            "/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
-#endif
-
-SkPDFObject* SkPDFCreateImageObject(SkPDFCanon* canon,
-                                    const SkBitmap& bitmap,
-                                    const SkIRect& subset) {
-    if (SkPDFObject* pdfBitmap = SkPDFBitmap::Create(canon, bitmap, subset)) {
-        return pdfBitmap;
-    }
-#if 0  // reenable when we can figure out the JPEG colorspace
-    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()));
-        }
-    }
-#endif
-    return SkPDFImage::CreateImage(bitmap, subset);
-}
diff --git a/src/pdf/SkPDFImage.h b/src/pdf/SkPDFImage.h
deleted file mode 100644
index 64be971..0000000
--- a/src/pdf/SkPDFImage.h
+++ /dev/null
@@ -1,91 +0,0 @@
-
-/*
- * Copyright 2010 The Android Open Source Project
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-
-#ifndef SkPDFImage_DEFINED
-#define SkPDFImage_DEFINED
-
-#include "SkPicture.h"
-#include "SkPDFDevice.h"
-#include "SkPDFStream.h"
-#include "SkPDFTypes.h"
-#include "SkRefCnt.h"
-
-class SkBitmap;
-class SkData;
-class SkPDFCatalog;
-struct SkIRect;
-
-/**
- *  Return the mose efficient availible encoding of the given bitmap.
- */
-SkPDFObject* SkPDFCreateImageObject(SkPDFCanon* canon,
-                                    const SkBitmap&,
-                                    const SkIRect& subset);
-
-/** \class SkPDFImage
-
-    An image XObject.
-*/
-
-// We could play the same trick here as is done in SkPDFGraphicState, storing
-// a copy of the Bitmap object (not the pixels), the pixel generation number,
-// and settings used from the paint to canonicalize image objects.
-class SkPDFImage : public SkPDFStream {
-public:
-    /** Create a new Image XObject to represent the passed bitmap.
-     *  @param bitmap   The image to encode.
-     *  @param srcRect  The rectangle to cut out of bitmap.
-     *  @param paint    Used to calculate alpha, masks, etc.
-     *  @return  The image XObject or NUll if there is nothing to draw for
-     *           the given parameters.
-     */
-    static SkPDFImage* CreateImage(const SkBitmap& bitmap,
-                                   const SkIRect& srcRect);
-
-    virtual ~SkPDFImage();
-
-    bool isEmpty() {
-        return fSrcRect.isEmpty();
-    }
-
-private:
-    SkBitmap fBitmap;
-    bool fIsAlpha;
-    SkIRect fSrcRect;
-    bool fStreamValid;
-
-    /** Create a PDF image XObject. Entries for the image properties are
-     *  automatically added to the stream dictionary.
-     *  @param stream     The image stream. May be NULL. Otherwise, this
-     *                    (instead of the input bitmap) will be used as the
-     *                    PDF's content stream, possibly with lossless encoding.
-     *                    Will be duplicated, and left in indeterminate state.
-     *  @param bitmap     The image. If a stream is not given, its color data
-     *                    will be used as the image. If a stream is given, this
-     *                    is used for configuration only.
-     *  @param isAlpha    Whether or not this is the alpha of an image.
-     *  @param srcRect    The clipping applied to bitmap before generating
-     *                    imageData.
-     */
-    SkPDFImage(SkStream* stream, const SkBitmap& bitmap, bool isAlpha,
-               const SkIRect& srcRect);
-
-    /** Copy constructor, used to generate substitutes.
-     *  @param image      The SkPDFImage to copy.
-     */
-    SkPDFImage(SkPDFImage& pdfImage);
-
-    // Populate the stream dictionary.  This method returns false if
-    // fSubstitute should be used.
-    virtual bool populate(SkPDFCatalog* catalog);
-
-    typedef SkPDFStream INHERITED;
-};
-
-#endif