LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/pdf - SkPDFBitmap.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 291 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 36 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright 2015 Google Inc.
       3             :  *
       4             :  * Use of this source code is governed by a BSD-style license that can be
       5             :  * found in the LICENSE file.
       6             :  */
       7             : 
       8             : #include "SkColorPriv.h"
       9             : #include "SkData.h"
      10             : #include "SkDeflate.h"
      11             : #include "SkImage_Base.h"
      12             : #include "SkJpegInfo.h"
      13             : #include "SkPDFBitmap.h"
      14             : #include "SkPDFCanon.h"
      15             : #include "SkPDFTypes.h"
      16             : #include "SkStream.h"
      17             : #include "SkUnPreMultiply.h"
      18             : 
      19           0 : void image_get_ro_pixels(const SkImage* image, SkBitmap* dst) {
      20           0 :     SkColorSpace* legacyColorSpace = nullptr;
      21           0 :     if(as_IB(image)->getROPixels(dst, legacyColorSpace)
      22           0 :        && dst->dimensions() == image->dimensions()) {
      23           0 :         if (dst->colorType() != kIndex_8_SkColorType) {
      24           0 :             return;
      25             :         }
      26             :         // We must check to see if the bitmap has a color table.
      27           0 :         SkAutoLockPixels autoLockPixels(*dst);
      28           0 :         if (!dst->getColorTable()) {
      29             :             // We can't use an indexed bitmap with no colortable.
      30           0 :             dst->reset();
      31             :         } else {
      32           0 :             return;
      33             :         }
      34             :     }
      35             :     // no pixels or wrong size: fill with zeros.
      36           0 :     dst->setInfo(SkImageInfo::MakeN32(image->width(), image->height(), image->alphaType()));
      37             : }
      38             : 
      39           0 : bool image_compute_is_opaque(const SkImage* image) {
      40           0 :     if (image->isOpaque()) {
      41           0 :         return true;
      42             :     }
      43             :     // keep output PDF small at cost of possible resource use.
      44           0 :     SkBitmap bm;
      45           0 :     image_get_ro_pixels(image, &bm);
      46           0 :     return SkBitmap::ComputeIsOpaque(bm);
      47             : }
      48             : 
      49             : ////////////////////////////////////////////////////////////////////////////////
      50             : 
      51           0 : static void pdf_stream_begin(SkWStream* stream) {
      52             :     static const char streamBegin[] = " stream\n";
      53           0 :     stream->write(streamBegin, strlen(streamBegin));
      54           0 : }
      55             : 
      56           0 : static void pdf_stream_end(SkWStream* stream) {
      57             :     static const char streamEnd[] = "\nendstream";
      58           0 :     stream->write(streamEnd, strlen(streamEnd));
      59           0 : }
      60             : 
      61             : ////////////////////////////////////////////////////////////////////////////////
      62             : 
      63             : // write a single byte to a stream n times.
      64           0 : static void fill_stream(SkWStream* out, char value, size_t n) {
      65             :     char buffer[4096];
      66           0 :     memset(buffer, value, sizeof(buffer));
      67           0 :     for (size_t i = 0; i < n / sizeof(buffer); ++i) {
      68           0 :         out->write(buffer, sizeof(buffer));
      69             :     }
      70           0 :     out->write(buffer, n % sizeof(buffer));
      71           0 : }
      72             : 
      73             : // TODO(reed@): Decide if these five functions belong in SkColorPriv.h
      74           0 : static bool SkIsBGRA(SkColorType ct) {
      75           0 :     SkASSERT(kBGRA_8888_SkColorType == ct || kRGBA_8888_SkColorType == ct);
      76           0 :     return kBGRA_8888_SkColorType == ct;
      77             : }
      78             : 
      79             : // Interpret value as the given 4-byte SkColorType (BGRA_8888 or
      80             : // RGBA_8888) and return the appropriate component.  Each component
      81             : // should be interpreted according to the associated SkAlphaType and
      82             : // SkColorProfileType.
      83           0 : static U8CPU SkGetA32Component(uint32_t value, SkColorType ct) {
      84           0 :     return (value >> (SkIsBGRA(ct) ? SK_BGRA_A32_SHIFT : SK_RGBA_A32_SHIFT)) & 0xFF;
      85             : }
      86           0 : static U8CPU SkGetR32Component(uint32_t value, SkColorType ct) {
      87           0 :     return (value >> (SkIsBGRA(ct) ? SK_BGRA_R32_SHIFT : SK_RGBA_R32_SHIFT)) & 0xFF;
      88             : }
      89           0 : static U8CPU SkGetG32Component(uint32_t value, SkColorType ct) {
      90           0 :     return (value >> (SkIsBGRA(ct) ? SK_BGRA_G32_SHIFT : SK_RGBA_G32_SHIFT)) & 0xFF;
      91             : }
      92           0 : static U8CPU SkGetB32Component(uint32_t value, SkColorType ct) {
      93           0 :     return (value >> (SkIsBGRA(ct) ? SK_BGRA_B32_SHIFT : SK_RGBA_B32_SHIFT)) & 0xFF;
      94             : }
      95             : 
      96             : // unpremultiply and extract R, G, B components.
      97           0 : static void pmcolor_to_rgb24(uint32_t color, uint8_t* rgb, SkColorType ct) {
      98           0 :     uint32_t s = SkUnPreMultiply::GetScale(SkGetA32Component(color, ct));
      99           0 :     rgb[0] = SkUnPreMultiply::ApplyScale(s, SkGetR32Component(color, ct));
     100           0 :     rgb[1] = SkUnPreMultiply::ApplyScale(s, SkGetG32Component(color, ct));
     101           0 :     rgb[2] = SkUnPreMultiply::ApplyScale(s, SkGetB32Component(color, ct));
     102           0 : }
     103             : 
     104             : /* It is necessary to average the color component of transparent
     105             :    pixels with their surrounding neighbors since the PDF renderer may
     106             :    separately re-sample the alpha and color channels when the image is
     107             :    not displayed at its native resolution. Since an alpha of zero
     108             :    gives no information about the color component, the pathological
     109             :    case is a white image with sharp transparency bounds - the color
     110             :    channel goes to black, and the should-be-transparent pixels are
     111             :    rendered as grey because of the separate soft mask and color
     112             :    resizing. e.g.: gm/bitmappremul.cpp */
     113           0 : static void get_neighbor_avg_color(const SkBitmap& bm,
     114             :                                    int xOrig,
     115             :                                    int yOrig,
     116             :                                    uint8_t rgb[3],
     117             :                                    SkColorType ct) {
     118           0 :     unsigned a = 0, r = 0, g = 0, b = 0;
     119             :     // Clamp the range to the edge of the bitmap.
     120           0 :     int ymin = SkTMax(0, yOrig - 1);
     121           0 :     int ymax = SkTMin(yOrig + 1, bm.height() - 1);
     122           0 :     int xmin = SkTMax(0, xOrig - 1);
     123           0 :     int xmax = SkTMin(xOrig + 1, bm.width() - 1);
     124           0 :     for (int y = ymin; y <= ymax; ++y) {
     125           0 :         uint32_t* scanline = bm.getAddr32(0, y);
     126           0 :         for (int x = xmin; x <= xmax; ++x) {
     127           0 :             uint32_t color = scanline[x];
     128           0 :             a += SkGetA32Component(color, ct);
     129           0 :             r += SkGetR32Component(color, ct);
     130           0 :             g += SkGetG32Component(color, ct);
     131           0 :             b += SkGetB32Component(color, ct);
     132             :         }
     133             :     }
     134           0 :     if (a > 0) {
     135           0 :         rgb[0] = SkToU8(255 * r / a);
     136           0 :         rgb[1] = SkToU8(255 * g / a);
     137           0 :         rgb[2] = SkToU8(255 * b / a);
     138             :     } else {
     139           0 :         rgb[0] = rgb[1] = rgb[2] = 0;
     140             :     }
     141           0 : }
     142             : 
     143           0 : static size_t pixel_count(const SkBitmap& bm) {
     144           0 :     return SkToSizeT(bm.width()) * SkToSizeT(bm.height());
     145             : }
     146             : 
     147           0 : static const SkBitmap& not4444(const SkBitmap& input, SkBitmap* copy) {
     148           0 :     if (input.colorType() != kARGB_4444_SkColorType) {
     149           0 :         return input;
     150             :     }
     151             :     // ARGB_4444 is rarely used, so we can do a wasteful tmp copy.
     152           0 :     SkAssertResult(input.copyTo(copy, kN32_SkColorType));
     153           0 :     copy->setImmutable();
     154           0 :     return *copy;
     155             : }
     156             : 
     157           0 : static size_t pdf_color_component_count(SkColorType ct) {
     158           0 :     switch (ct) {
     159             :         case kRGB_565_SkColorType:
     160             :         case kARGB_4444_SkColorType:
     161             :         case kRGBA_8888_SkColorType:
     162             :         case kBGRA_8888_SkColorType:
     163           0 :             return 3;
     164             :         case kAlpha_8_SkColorType:
     165             :         case kIndex_8_SkColorType:
     166             :         case kGray_8_SkColorType:
     167           0 :             return 1;
     168             :         case kUnknown_SkColorType:
     169             :         default:
     170           0 :             SkDEBUGFAIL("unexpected color type");
     171           0 :             return 0;
     172             :     }
     173             : }
     174             : 
     175           0 : static void bitmap_to_pdf_pixels(const SkBitmap& bitmap, SkWStream* out) {
     176           0 :     if (!bitmap.getPixels()) {
     177           0 :         size_t size = pixel_count(bitmap) *
     178           0 :                       pdf_color_component_count(bitmap.colorType());
     179           0 :         fill_stream(out, '\x00', size);
     180           0 :         return;
     181             :     }
     182           0 :     SkBitmap copy;
     183           0 :     const SkBitmap& bm = not4444(bitmap, &copy);
     184           0 :     SkAutoLockPixels autoLockPixels(bm);
     185           0 :     SkColorType colorType = bm.colorType();
     186           0 :     SkAlphaType alphaType = bm.alphaType();
     187           0 :     switch (colorType) {
     188             :         case kRGBA_8888_SkColorType:
     189             :         case kBGRA_8888_SkColorType: {
     190           0 :             SkASSERT(3 == pdf_color_component_count(colorType));
     191           0 :             SkAutoTMalloc<uint8_t> scanline(3 * bm.width());
     192           0 :             for (int y = 0; y < bm.height(); ++y) {
     193           0 :                 const uint32_t* src = bm.getAddr32(0, y);
     194           0 :                 uint8_t* dst = scanline.get();
     195           0 :                 for (int x = 0; x < bm.width(); ++x) {
     196           0 :                     if (alphaType == kPremul_SkAlphaType) {
     197           0 :                         uint32_t color = *src++;
     198           0 :                         U8CPU alpha = SkGetA32Component(color, colorType);
     199           0 :                         if (alpha != SK_AlphaTRANSPARENT) {
     200           0 :                             pmcolor_to_rgb24(color, dst, colorType);
     201             :                         } else {
     202           0 :                             get_neighbor_avg_color(bm, x, y, dst, colorType);
     203             :                         }
     204           0 :                         dst += 3;
     205             :                     } else {
     206           0 :                         uint32_t color = *src++;
     207           0 :                         *dst++ = SkGetR32Component(color, colorType);
     208           0 :                         *dst++ = SkGetG32Component(color, colorType);
     209           0 :                         *dst++ = SkGetB32Component(color, colorType);
     210             :                     }
     211             :                 }
     212           0 :                 out->write(scanline.get(), 3 * bm.width());
     213             :             }
     214           0 :             return;
     215             :         }
     216             :         case kRGB_565_SkColorType: {
     217           0 :             SkASSERT(3 == pdf_color_component_count(colorType));
     218           0 :             SkAutoTMalloc<uint8_t> scanline(3 * bm.width());
     219           0 :             for (int y = 0; y < bm.height(); ++y) {
     220           0 :                 const uint16_t* src = bm.getAddr16(0, y);
     221           0 :                 uint8_t* dst = scanline.get();
     222           0 :                 for (int x = 0; x < bm.width(); ++x) {
     223           0 :                     U16CPU color565 = *src++;
     224           0 :                     *dst++ = SkPacked16ToR32(color565);
     225           0 :                     *dst++ = SkPacked16ToG32(color565);
     226           0 :                     *dst++ = SkPacked16ToB32(color565);
     227             :                 }
     228           0 :                 out->write(scanline.get(), 3 * bm.width());
     229             :             }
     230           0 :             return;
     231             :         }
     232             :         case kAlpha_8_SkColorType:
     233           0 :             SkASSERT(1 == pdf_color_component_count(colorType));
     234           0 :             fill_stream(out, '\x00', pixel_count(bm));
     235           0 :             return;
     236             :         case kGray_8_SkColorType:
     237             :         case kIndex_8_SkColorType:
     238           0 :             SkASSERT(1 == pdf_color_component_count(colorType));
     239             :             // these two formats need no transformation to serialize.
     240           0 :             for (int y = 0; y < bm.height(); ++y) {
     241           0 :                 out->write(bm.getAddr8(0, y), bm.width());
     242             :             }
     243           0 :             return;
     244             :         case kUnknown_SkColorType:
     245             :         case kARGB_4444_SkColorType:
     246             :         default:
     247           0 :             SkDEBUGFAIL("unexpected color type");
     248             :     }
     249             : }
     250             : 
     251             : ////////////////////////////////////////////////////////////////////////////////
     252             : 
     253           0 : static void bitmap_alpha_to_a8(const SkBitmap& bitmap, SkWStream* out) {
     254           0 :     if (!bitmap.getPixels()) {
     255           0 :         fill_stream(out, '\xFF', pixel_count(bitmap));
     256           0 :         return;
     257             :     }
     258           0 :     SkBitmap copy;
     259           0 :     const SkBitmap& bm = not4444(bitmap, &copy);
     260           0 :     SkAutoLockPixels autoLockPixels(bm);
     261           0 :     SkColorType colorType = bm.colorType();
     262           0 :     switch (colorType) {
     263             :         case kRGBA_8888_SkColorType:
     264             :         case kBGRA_8888_SkColorType: {
     265           0 :             SkAutoTMalloc<uint8_t> scanline(bm.width());
     266           0 :             for (int y = 0; y < bm.height(); ++y) {
     267           0 :                 uint8_t* dst = scanline.get();
     268           0 :                 const SkPMColor* src = bm.getAddr32(0, y);
     269           0 :                 for (int x = 0; x < bm.width(); ++x) {
     270           0 :                     *dst++ = SkGetA32Component(*src++, colorType);
     271             :                 }
     272           0 :                 out->write(scanline.get(), bm.width());
     273             :             }
     274           0 :             return;
     275             :         }
     276             :         case kAlpha_8_SkColorType:
     277           0 :             for (int y = 0; y < bm.height(); ++y) {
     278           0 :                 out->write(bm.getAddr8(0, y), bm.width());
     279             :             }
     280           0 :             return;
     281             :         case kIndex_8_SkColorType: {
     282           0 :             SkColorTable* ct = bm.getColorTable();
     283           0 :             SkASSERT(ct);
     284           0 :             SkAutoTMalloc<uint8_t> scanline(bm.width());
     285           0 :             for (int y = 0; y < bm.height(); ++y) {
     286           0 :                 uint8_t* dst = scanline.get();
     287           0 :                 const uint8_t* src = bm.getAddr8(0, y);
     288           0 :                 for (int x = 0; x < bm.width(); ++x) {
     289           0 :                     *dst++ = SkGetPackedA32((*ct)[*src++]);
     290             :                 }
     291           0 :                 out->write(scanline.get(), bm.width());
     292             :             }
     293           0 :             return;
     294             :         }
     295             :         case kRGB_565_SkColorType:
     296             :         case kGray_8_SkColorType:
     297           0 :             SkDEBUGFAIL("color type has no alpha");
     298           0 :             return;
     299             :         case kARGB_4444_SkColorType:
     300           0 :             SkDEBUGFAIL("4444 color type should have been converted to N32");
     301           0 :             return;
     302             :         case kUnknown_SkColorType:
     303             :         default:
     304           0 :             SkDEBUGFAIL("unexpected color type");
     305             :     }
     306             : }
     307             : 
     308           0 : static sk_sp<SkPDFArray> make_indexed_color_space(
     309             :         const SkColorTable* table,
     310             :         SkAlphaType alphaType) {
     311           0 :     auto result = sk_make_sp<SkPDFArray>();
     312           0 :     result->reserve(4);
     313           0 :     result->appendName("Indexed");
     314           0 :     result->appendName("DeviceRGB");
     315           0 :     SkASSERT(table);
     316           0 :     if (table->count() < 1) {
     317           0 :         result->appendInt(0);
     318           0 :         char shortTableArray[3] = {0, 0, 0};
     319           0 :         SkString tableString(shortTableArray, SK_ARRAY_COUNT(shortTableArray));
     320           0 :         result->appendString(tableString);
     321           0 :         return result;
     322             :     }
     323           0 :     result->appendInt(table->count() - 1);  // maximum color index.
     324             : 
     325             :     // Potentially, this could be represented in fewer bytes with a stream.
     326             :     // Max size as a string is 1.5k.
     327             :     char tableArray[256 * 3];
     328           0 :     SkASSERT(3u * table->count() <= SK_ARRAY_COUNT(tableArray));
     329           0 :     uint8_t* tablePtr = reinterpret_cast<uint8_t*>(tableArray);
     330           0 :     const SkPMColor* colors = table->readColors();
     331           0 :     for (int i = 0; i < table->count(); i++) {
     332           0 :         if (alphaType == kPremul_SkAlphaType) {
     333           0 :             pmcolor_to_rgb24(colors[i], tablePtr, kN32_SkColorType);
     334           0 :             tablePtr += 3;
     335             :         } else {
     336           0 :             *tablePtr++ = SkGetR32Component(colors[i], kN32_SkColorType);
     337           0 :             *tablePtr++ = SkGetG32Component(colors[i], kN32_SkColorType);
     338           0 :             *tablePtr++ = SkGetB32Component(colors[i], kN32_SkColorType);
     339             :         }
     340             :     }
     341           0 :     SkString tableString(tableArray, 3 * table->count());
     342           0 :     result->appendString(tableString);
     343           0 :     return result;
     344             : }
     345             : 
     346           0 : static void emit_image_xobject(SkWStream* stream,
     347             :                                const SkImage* image,
     348             :                                bool alpha,
     349             :                                const sk_sp<SkPDFObject>& smask,
     350             :                                const SkPDFObjNumMap& objNumMap) {
     351           0 :     SkBitmap bitmap;
     352           0 :     image_get_ro_pixels(image, &bitmap);      // TODO(halcanary): test
     353           0 :     SkAutoLockPixels autoLockPixels(bitmap);  // with malformed images.
     354             : 
     355             :     // Write to a temporary buffer to get the compressed length.
     356           0 :     SkDynamicMemoryWStream buffer;
     357           0 :     SkDeflateWStream deflateWStream(&buffer);
     358           0 :     if (alpha) {
     359           0 :         bitmap_alpha_to_a8(bitmap, &deflateWStream);
     360             :     } else {
     361           0 :         bitmap_to_pdf_pixels(bitmap, &deflateWStream);
     362             :     }
     363           0 :     deflateWStream.finalize();  // call before detachAsStream().
     364           0 :     std::unique_ptr<SkStreamAsset> asset(buffer.detachAsStream());
     365             : 
     366           0 :     SkPDFDict pdfDict("XObject");
     367           0 :     pdfDict.insertName("Subtype", "Image");
     368           0 :     pdfDict.insertInt("Width", bitmap.width());
     369           0 :     pdfDict.insertInt("Height", bitmap.height());
     370           0 :     if (alpha) {
     371           0 :         pdfDict.insertName("ColorSpace", "DeviceGray");
     372           0 :     } else if (bitmap.colorType() == kIndex_8_SkColorType) {
     373           0 :         SkASSERT(1 == pdf_color_component_count(bitmap.colorType()));
     374           0 :         pdfDict.insertObject("ColorSpace",
     375           0 :                              make_indexed_color_space(bitmap.getColorTable(),
     376           0 :                                                       bitmap.alphaType()));
     377           0 :     } else if (1 == pdf_color_component_count(bitmap.colorType())) {
     378           0 :         pdfDict.insertName("ColorSpace", "DeviceGray");
     379             :     } else {
     380           0 :         pdfDict.insertName("ColorSpace", "DeviceRGB");
     381             :     }
     382           0 :     if (smask) {
     383           0 :         pdfDict.insertObjRef("SMask", smask);
     384             :     }
     385           0 :     pdfDict.insertInt("BitsPerComponent", 8);
     386           0 :     pdfDict.insertName("Filter", "FlateDecode");
     387           0 :     pdfDict.insertInt("Length", asset->getLength());
     388           0 :     pdfDict.emitObject(stream, objNumMap);
     389             : 
     390           0 :     pdf_stream_begin(stream);
     391           0 :     stream->writeStream(asset.get(), asset->getLength());
     392           0 :     pdf_stream_end(stream);
     393           0 : }
     394             : 
     395             : ////////////////////////////////////////////////////////////////////////////////
     396             : 
     397             : namespace {
     398             : // This SkPDFObject only outputs the alpha layer of the given bitmap.
     399           0 : class PDFAlphaBitmap final : public SkPDFObject {
     400             : public:
     401           0 :     PDFAlphaBitmap(sk_sp<SkImage> image) : fImage(std::move(image)) { SkASSERT(fImage); }
     402           0 :     void emitObject(SkWStream*  stream,
     403             :                     const SkPDFObjNumMap& objNumMap) const override {
     404           0 :         SkASSERT(fImage);
     405           0 :         emit_image_xobject(stream, fImage.get(), true, nullptr, objNumMap);
     406           0 :     }
     407           0 :     void drop() override { fImage = nullptr; }
     408             : 
     409             : private:
     410             :     sk_sp<SkImage> fImage;
     411             : };
     412             : 
     413             : }  // namespace
     414             : 
     415             : ////////////////////////////////////////////////////////////////////////////////
     416             : 
     417             : namespace {
     418           0 : class PDFDefaultBitmap final : public SkPDFObject {
     419             : public:
     420           0 :     void emitObject(SkWStream* stream,
     421             :                     const SkPDFObjNumMap& objNumMap) const override {
     422           0 :         SkASSERT(fImage);
     423           0 :         emit_image_xobject(stream, fImage.get(), false, fSMask, objNumMap);
     424           0 :     }
     425           0 :     void addResources(SkPDFObjNumMap* catalog) const override {
     426           0 :         catalog->addObjectRecursively(fSMask.get());
     427           0 :     }
     428           0 :     void drop() override { fImage = nullptr; fSMask = nullptr; }
     429           0 :     PDFDefaultBitmap(sk_sp<SkImage> image, sk_sp<SkPDFObject> smask)
     430           0 :         : fImage(std::move(image)), fSMask(std::move(smask)) { SkASSERT(fImage); }
     431             : 
     432             : private:
     433             :     sk_sp<SkImage> fImage;
     434             :     sk_sp<SkPDFObject> fSMask;
     435             : };
     436             : }  // namespace
     437             : 
     438             : ////////////////////////////////////////////////////////////////////////////////
     439             : 
     440             : namespace {
     441             : /**
     442             :  *  This PDFObject assumes that its constructor was handed YUV or
     443             :  *  Grayscale JFIF Jpeg-encoded data that can be directly embedded
     444             :  *  into a PDF.
     445             :  */
     446           0 : class PDFJpegBitmap final : public SkPDFObject {
     447             : public:
     448             :     SkISize fSize;
     449             :     sk_sp<SkData> fData;
     450             :     bool fIsYUV;
     451           0 :     PDFJpegBitmap(SkISize size, SkData* data, bool isYUV)
     452           0 :         : fSize(size), fData(SkRef(data)), fIsYUV(isYUV) { SkASSERT(data); }
     453             :     void emitObject(SkWStream*, const SkPDFObjNumMap&) const override;
     454           0 :     void drop() override { fData = nullptr; }
     455             : };
     456             : 
     457           0 : void PDFJpegBitmap::emitObject(SkWStream* stream,
     458             :                                const SkPDFObjNumMap& objNumMap) const {
     459           0 :     SkASSERT(fData);
     460           0 :     SkPDFDict pdfDict("XObject");
     461           0 :     pdfDict.insertName("Subtype", "Image");
     462           0 :     pdfDict.insertInt("Width", fSize.width());
     463           0 :     pdfDict.insertInt("Height", fSize.height());
     464           0 :     if (fIsYUV) {
     465           0 :         pdfDict.insertName("ColorSpace", "DeviceRGB");
     466             :     } else {
     467           0 :         pdfDict.insertName("ColorSpace", "DeviceGray");
     468             :     }
     469           0 :     pdfDict.insertInt("BitsPerComponent", 8);
     470           0 :     pdfDict.insertName("Filter", "DCTDecode");
     471           0 :     pdfDict.insertInt("ColorTransform", 0);
     472           0 :     pdfDict.insertInt("Length", SkToInt(fData->size()));
     473           0 :     pdfDict.emitObject(stream, objNumMap);
     474           0 :     pdf_stream_begin(stream);
     475           0 :     stream->write(fData->data(), fData->size());
     476           0 :     pdf_stream_end(stream);
     477           0 : }
     478             : }  // namespace
     479             : 
     480             : ////////////////////////////////////////////////////////////////////////////////
     481             : 
     482           0 : sk_sp<SkPDFObject> SkPDFCreateBitmapObject(sk_sp<SkImage> image,
     483             :                                            SkPixelSerializer* pixelSerializer) {
     484           0 :     SkASSERT(image);
     485           0 :     sk_sp<SkData> data(image->refEncoded());
     486             :     SkJFIFInfo info;
     487           0 :     if (data && SkIsJFIF(data.get(), &info) &&
     488           0 :         (!pixelSerializer ||
     489           0 :          pixelSerializer->useEncodedData(data->data(), data->size()))) {
     490             :         // If there is a SkPixelSerializer, give it a chance to
     491             :         // re-encode the JPEG with more compression by returning false
     492             :         // from useEncodedData.
     493           0 :         bool yuv = info.fType == SkJFIFInfo::kYCbCr;
     494           0 :         if (info.fSize == image->dimensions()) {  // Sanity check.
     495             :             // hold on to data, not image.
     496             :             #ifdef SK_PDF_IMAGE_STATS
     497             :             gJpegImageObjects.fetch_add(1);
     498             :             #endif
     499           0 :             return sk_make_sp<PDFJpegBitmap>(info.fSize, data.get(), yuv);
     500             :         }
     501             :     }
     502             : 
     503           0 :     if (pixelSerializer) {
     504           0 :         SkBitmap bm;
     505           0 :         SkAutoPixmapUnlock apu;
     506           0 :         SkColorSpace* legacyColorSpace = nullptr;
     507           0 :         if (as_IB(image.get())->getROPixels(&bm, legacyColorSpace) &&
     508           0 :             bm.requestLock(&apu)) {
     509           0 :             data.reset(pixelSerializer->encode(apu.pixmap()));
     510           0 :             if (data && SkIsJFIF(data.get(), &info)) {
     511           0 :                 bool yuv = info.fType == SkJFIFInfo::kYCbCr;
     512           0 :                 if (info.fSize == image->dimensions()) {  // Sanity check.
     513           0 :                     return sk_make_sp<PDFJpegBitmap>(info.fSize, data.get(), yuv);
     514             :                 }
     515             :             }
     516             :         }
     517             :     }
     518             : 
     519           0 :     sk_sp<SkPDFObject> smask;
     520           0 :     if (!image_compute_is_opaque(image.get())) {
     521           0 :         smask = sk_make_sp<PDFAlphaBitmap>(image);
     522             :     }
     523             :     #ifdef SK_PDF_IMAGE_STATS
     524             :     gRegularImageObjects.fetch_add(1);
     525             :     #endif
     526           0 :     return sk_make_sp<PDFDefaultBitmap>(std::move(image), std::move(smask));
     527             : }

Generated by: LCOV version 1.13