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 "SkPDFBitmap.h"
9
10#include "SkColorData.h"
11#include "SkData.h"
12#include "SkDeflate.h"
13#include "SkImage.h"
14#include "SkJpegInfo.h"
15#include "SkPDFCanon.h"
16#include "SkPDFTypes.h"
17#include "SkPDFUtils.h"
18#include "SkStream.h"
19#include "SkUnPreMultiply.h"
20
21bool image_compute_is_opaque(const SkImage* image) {
22    if (image->isOpaque()) {
23        return true;
24    }
25    // keep output PDF small at cost of possible resource use.
26    SkBitmap bm;
27    // if image can not be read, treat as transparent.
28    return SkPDFUtils::ToBitmap(image, &bm) && SkBitmap::ComputeIsOpaque(bm);
29}
30
31////////////////////////////////////////////////////////////////////////////////
32
33static const char kStreamBegin[] = " stream\n";
34
35static const char kStreamEnd[] = "\nendstream";
36
37////////////////////////////////////////////////////////////////////////////////
38
39// write a single byte to a stream n times.
40static void fill_stream(SkWStream* out, char value, size_t n) {
41    char buffer[4096];
42    memset(buffer, value, sizeof(buffer));
43    for (size_t i = 0; i < n / sizeof(buffer); ++i) {
44        out->write(buffer, sizeof(buffer));
45    }
46    out->write(buffer, n % sizeof(buffer));
47}
48
49// TODO(reed@): Decide if these five functions belong in SkColorData.h
50static bool SkIsBGRA(SkColorType ct) {
51    SkASSERT(kBGRA_8888_SkColorType == ct || kRGBA_8888_SkColorType == ct);
52    return kBGRA_8888_SkColorType == ct;
53}
54
55// Interpret value as the given 4-byte SkColorType (BGRA_8888 or
56// RGBA_8888) and return the appropriate component.  Each component
57// should be interpreted according to the associated SkAlphaType and
58// SkColorProfileType.
59static U8CPU SkGetA32Component(uint32_t value, SkColorType ct) {
60    return (value >> (SkIsBGRA(ct) ? SK_BGRA_A32_SHIFT : SK_RGBA_A32_SHIFT)) & 0xFF;
61}
62static U8CPU SkGetR32Component(uint32_t value, SkColorType ct) {
63    return (value >> (SkIsBGRA(ct) ? SK_BGRA_R32_SHIFT : SK_RGBA_R32_SHIFT)) & 0xFF;
64}
65static U8CPU SkGetG32Component(uint32_t value, SkColorType ct) {
66    return (value >> (SkIsBGRA(ct) ? SK_BGRA_G32_SHIFT : SK_RGBA_G32_SHIFT)) & 0xFF;
67}
68static U8CPU SkGetB32Component(uint32_t value, SkColorType ct) {
69    return (value >> (SkIsBGRA(ct) ? SK_BGRA_B32_SHIFT : SK_RGBA_B32_SHIFT)) & 0xFF;
70}
71
72// unpremultiply and extract R, G, B components.
73static void pmcolor_to_rgb24(uint32_t color, uint8_t* rgb, SkColorType ct) {
74    SkPMColorAssert(color);
75    uint32_t s = SkUnPreMultiply::GetScale(SkGetA32Component(color, ct));
76    rgb[0] = SkUnPreMultiply::ApplyScale(s, SkGetR32Component(color, ct));
77    rgb[1] = SkUnPreMultiply::ApplyScale(s, SkGetG32Component(color, ct));
78    rgb[2] = SkUnPreMultiply::ApplyScale(s, SkGetB32Component(color, ct));
79}
80
81/* It is necessary to average the color component of transparent
82   pixels with their surrounding neighbors since the PDF renderer may
83   separately re-sample the alpha and color channels when the image is
84   not displayed at its native resolution. Since an alpha of zero
85   gives no information about the color component, the pathological
86   case is a white image with sharp transparency bounds - the color
87   channel goes to black, and the should-be-transparent pixels are
88   rendered as grey because of the separate soft mask and color
89   resizing. e.g.: gm/bitmappremul.cpp */
90static void get_neighbor_avg_color(const SkBitmap& bm,
91                                   int xOrig,
92                                   int yOrig,
93                                   uint8_t rgb[3],
94                                   SkColorType ct) {
95    unsigned a = 0, r = 0, g = 0, b = 0;
96    // Clamp the range to the edge of the bitmap.
97    int ymin = SkTMax(0, yOrig - 1);
98    int ymax = SkTMin(yOrig + 1, bm.height() - 1);
99    int xmin = SkTMax(0, xOrig - 1);
100    int xmax = SkTMin(xOrig + 1, bm.width() - 1);
101    for (int y = ymin; y <= ymax; ++y) {
102        uint32_t* scanline = bm.getAddr32(0, y);
103        for (int x = xmin; x <= xmax; ++x) {
104            uint32_t color = scanline[x];
105            SkPMColorAssert(color);
106            a += SkGetA32Component(color, ct);
107            r += SkGetR32Component(color, ct);
108            g += SkGetG32Component(color, ct);
109            b += SkGetB32Component(color, ct);
110        }
111    }
112    if (a > 0) {
113        rgb[0] = SkToU8(255 * r / a);
114        rgb[1] = SkToU8(255 * g / a);
115        rgb[2] = SkToU8(255 * b / a);
116    } else {
117        rgb[0] = rgb[1] = rgb[2] = 0;
118    }
119}
120
121static size_t pixel_count(const SkBitmap& bm) {
122    return SkToSizeT(bm.width()) * SkToSizeT(bm.height());
123}
124
125static const SkBitmap& supported_colortype(const SkBitmap& input, SkBitmap* copy) {
126    switch (input.colorType()) {
127        case kUnknown_SkColorType:
128            SkDEBUGFAIL("kUnknown_SkColorType");
129        case kAlpha_8_SkColorType:
130        case kRGB_565_SkColorType:
131        case kRGBA_8888_SkColorType:
132        case kBGRA_8888_SkColorType:
133        case kGray_8_SkColorType:
134            return input;  // supported
135        default:
136            // if other colortypes are introduced in the future,
137            // they will hit this code.
138            break;
139    }
140    // Fallback for rarely used ARGB_4444 and ARGB_F16: do a wasteful tmp copy.
141    copy->allocPixels(input.info().makeColorType(kN32_SkColorType));
142    SkAssertResult(input.readPixels(copy->info(), copy->getPixels(), copy->rowBytes(), 0, 0));
143    copy->setImmutable();
144    return *copy;
145}
146
147static size_t pdf_color_component_count(SkColorType ct) {
148    switch (ct) {
149        case kUnknown_SkColorType:
150            SkDEBUGFAIL("kUnknown_SkColorType");
151        case kAlpha_8_SkColorType:
152        case kGray_8_SkColorType:
153            return 1;
154        case kRGB_565_SkColorType:
155        case kRGBA_8888_SkColorType:
156        case kBGRA_8888_SkColorType:
157        default:  // converted to N32
158            return 3;
159    }
160}
161
162static void bitmap_to_pdf_pixels(const SkBitmap& bitmap, SkWStream* out) {
163    if (!bitmap.getPixels()) {
164        size_t size = pixel_count(bitmap) *
165                      pdf_color_component_count(bitmap.colorType());
166        fill_stream(out, '\x00', size);
167        return;
168    }
169    SkBitmap copy;
170    const SkBitmap& bm = supported_colortype(bitmap, &copy);
171    SkColorType colorType = bm.colorType();
172    SkAlphaType alphaType = bm.alphaType();
173    switch (colorType) {
174        case kRGBA_8888_SkColorType:
175        case kBGRA_8888_SkColorType: {
176            SkASSERT(3 == pdf_color_component_count(colorType));
177            SkAutoTMalloc<uint8_t> scanline(3 * bm.width());
178            for (int y = 0; y < bm.height(); ++y) {
179                const uint32_t* src = bm.getAddr32(0, y);
180                uint8_t* dst = scanline.get();
181                for (int x = 0; x < bm.width(); ++x) {
182                    if (alphaType == kPremul_SkAlphaType) {
183                        uint32_t color = *src++;
184                        U8CPU alpha = SkGetA32Component(color, colorType);
185                        if (alpha != SK_AlphaTRANSPARENT) {
186                            pmcolor_to_rgb24(color, dst, colorType);
187                        } else {
188                            get_neighbor_avg_color(bm, x, y, dst, colorType);
189                        }
190                        dst += 3;
191                    } else {
192                        uint32_t color = *src++;
193                        *dst++ = SkGetR32Component(color, colorType);
194                        *dst++ = SkGetG32Component(color, colorType);
195                        *dst++ = SkGetB32Component(color, colorType);
196                    }
197                }
198                out->write(scanline.get(), 3 * bm.width());
199            }
200            return;
201        }
202        case kRGB_565_SkColorType: {
203            SkASSERT(3 == pdf_color_component_count(colorType));
204            SkAutoTMalloc<uint8_t> scanline(3 * bm.width());
205            for (int y = 0; y < bm.height(); ++y) {
206                const uint16_t* src = bm.getAddr16(0, y);
207                uint8_t* dst = scanline.get();
208                for (int x = 0; x < bm.width(); ++x) {
209                    U16CPU color565 = *src++;
210                    *dst++ = SkPacked16ToR32(color565);
211                    *dst++ = SkPacked16ToG32(color565);
212                    *dst++ = SkPacked16ToB32(color565);
213                }
214                out->write(scanline.get(), 3 * bm.width());
215            }
216            return;
217        }
218        case kAlpha_8_SkColorType:
219            SkASSERT(1 == pdf_color_component_count(colorType));
220            fill_stream(out, '\x00', pixel_count(bm));
221            return;
222        case kGray_8_SkColorType:
223            SkASSERT(1 == pdf_color_component_count(colorType));
224            // these two formats need no transformation to serialize.
225            for (int y = 0; y < bm.height(); ++y) {
226                out->write(bm.getAddr8(0, y), bm.width());
227            }
228            return;
229        case kUnknown_SkColorType:
230        case kARGB_4444_SkColorType:
231        default:
232            SkDEBUGFAIL("unexpected color type");
233    }
234}
235
236////////////////////////////////////////////////////////////////////////////////
237
238static void bitmap_alpha_to_a8(const SkBitmap& bitmap, SkWStream* out) {
239    if (!bitmap.getPixels()) {
240        fill_stream(out, '\xFF', pixel_count(bitmap));
241        return;
242    }
243    SkBitmap copy;
244    const SkBitmap& bm = supported_colortype(bitmap, &copy);
245    SkColorType colorType = bm.colorType();
246    switch (colorType) {
247        case kRGBA_8888_SkColorType:
248        case kBGRA_8888_SkColorType: {
249            SkAutoTMalloc<uint8_t> scanline(bm.width());
250            for (int y = 0; y < bm.height(); ++y) {
251                uint8_t* dst = scanline.get();
252                const SkPMColor* src = bm.getAddr32(0, y);
253                for (int x = 0; x < bm.width(); ++x) {
254                    *dst++ = SkGetA32Component(*src++, colorType);
255                }
256                out->write(scanline.get(), bm.width());
257            }
258            return;
259        }
260        case kAlpha_8_SkColorType:
261            for (int y = 0; y < bm.height(); ++y) {
262                out->write(bm.getAddr8(0, y), bm.width());
263            }
264            return;
265        case kRGB_565_SkColorType:
266        case kGray_8_SkColorType:
267            SkDEBUGFAIL("color type has no alpha");
268            return;
269        case kARGB_4444_SkColorType:
270            SkDEBUGFAIL("4444 color type should have been converted to N32");
271            return;
272        case kUnknown_SkColorType:
273        default:
274            SkDEBUGFAIL("unexpected color type");
275    }
276}
277
278static void emit_image_xobject(SkWStream* stream,
279                               const SkImage* image,
280                               bool alpha,
281                               const sk_sp<SkPDFObject>& smask,
282                               const SkPDFObjNumMap& objNumMap) {
283    SkBitmap bitmap;
284    if (!SkPDFUtils::ToBitmap(image, &bitmap)) {
285        // no pixels or wrong size: fill with zeros.
286        bitmap.setInfo(SkImageInfo::MakeN32(image->width(), image->height(), image->alphaType()));
287    }
288
289    // Write to a temporary buffer to get the compressed length.
290    SkDynamicMemoryWStream buffer;
291    SkDeflateWStream deflateWStream(&buffer);
292    if (alpha) {
293        bitmap_alpha_to_a8(bitmap, &deflateWStream);
294    } else {
295        bitmap_to_pdf_pixels(bitmap, &deflateWStream);
296    }
297    deflateWStream.finalize();  // call before buffer.bytesWritten().
298
299    SkPDFDict pdfDict("XObject");
300    pdfDict.insertName("Subtype", "Image");
301    pdfDict.insertInt("Width", bitmap.width());
302    pdfDict.insertInt("Height", bitmap.height());
303    if (alpha) {
304        pdfDict.insertName("ColorSpace", "DeviceGray");
305    } else if (1 == pdf_color_component_count(bitmap.colorType())) {
306        pdfDict.insertName("ColorSpace", "DeviceGray");
307    } else {
308        pdfDict.insertName("ColorSpace", "DeviceRGB");
309    }
310    if (smask) {
311        pdfDict.insertObjRef("SMask", smask);
312    }
313    pdfDict.insertInt("BitsPerComponent", 8);
314    pdfDict.insertName("Filter", "FlateDecode");
315    pdfDict.insertInt("Length", buffer.bytesWritten());
316    pdfDict.emitObject(stream, objNumMap);
317
318    stream->writeText(kStreamBegin);
319    buffer.writeToAndReset(stream);
320    stream->writeText(kStreamEnd);
321}
322
323////////////////////////////////////////////////////////////////////////////////
324
325namespace {
326// This SkPDFObject only outputs the alpha layer of the given bitmap.
327class PDFAlphaBitmap final : public SkPDFObject {
328public:
329    PDFAlphaBitmap(sk_sp<SkImage> image) : fImage(std::move(image)) { SkASSERT(fImage); }
330    void emitObject(SkWStream*  stream,
331                    const SkPDFObjNumMap& objNumMap) const override {
332        SkASSERT(fImage);
333        emit_image_xobject(stream, fImage.get(), true, nullptr, objNumMap);
334    }
335    void drop() override { fImage = nullptr; }
336
337private:
338    sk_sp<SkImage> fImage;
339};
340
341}  // namespace
342
343////////////////////////////////////////////////////////////////////////////////
344
345namespace {
346class PDFDefaultBitmap final : public SkPDFObject {
347public:
348    void emitObject(SkWStream* stream,
349                    const SkPDFObjNumMap& objNumMap) const override {
350        SkASSERT(fImage);
351        emit_image_xobject(stream, fImage.get(), false, fSMask, objNumMap);
352    }
353    void addResources(SkPDFObjNumMap* catalog) const override {
354        catalog->addObjectRecursively(fSMask.get());
355    }
356    void drop() override { fImage = nullptr; fSMask = nullptr; }
357    PDFDefaultBitmap(sk_sp<SkImage> image, sk_sp<SkPDFObject> smask)
358        : fImage(std::move(image)), fSMask(std::move(smask)) { SkASSERT(fImage); }
359
360private:
361    sk_sp<SkImage> fImage;
362    sk_sp<SkPDFObject> fSMask;
363};
364}  // namespace
365
366////////////////////////////////////////////////////////////////////////////////
367
368namespace {
369/**
370 *  This PDFObject assumes that its constructor was handed YUV or
371 *  Grayscale JFIF Jpeg-encoded data that can be directly embedded
372 *  into a PDF.
373 */
374class PDFJpegBitmap final : public SkPDFObject {
375public:
376    SkISize fSize;
377    sk_sp<SkData> fData;
378    bool fIsYUV;
379    PDFJpegBitmap(SkISize size, SkData* data, bool isYUV)
380        : fSize(size), fData(SkRef(data)), fIsYUV(isYUV) { SkASSERT(data); }
381    void emitObject(SkWStream*, const SkPDFObjNumMap&) const override;
382    void drop() override { fData = nullptr; }
383};
384
385void PDFJpegBitmap::emitObject(SkWStream* stream,
386                               const SkPDFObjNumMap& objNumMap) const {
387    SkASSERT(fData);
388    SkPDFDict pdfDict("XObject");
389    pdfDict.insertName("Subtype", "Image");
390    pdfDict.insertInt("Width", fSize.width());
391    pdfDict.insertInt("Height", fSize.height());
392    if (fIsYUV) {
393        pdfDict.insertName("ColorSpace", "DeviceRGB");
394    } else {
395        pdfDict.insertName("ColorSpace", "DeviceGray");
396    }
397    pdfDict.insertInt("BitsPerComponent", 8);
398    pdfDict.insertName("Filter", "DCTDecode");
399    pdfDict.insertInt("ColorTransform", 0);
400    pdfDict.insertInt("Length", SkToInt(fData->size()));
401    pdfDict.emitObject(stream, objNumMap);
402    stream->writeText(kStreamBegin);
403    stream->write(fData->data(), fData->size());
404    stream->writeText(kStreamEnd);
405}
406}  // namespace
407
408////////////////////////////////////////////////////////////////////////////////
409
410sk_sp<SkPDFObject> SkPDFCreateBitmapObject(sk_sp<SkImage> image, int encodingQuality) {
411    SkASSERT(image);
412    SkASSERT(encodingQuality >= 0);
413    sk_sp<SkData> data = image->refEncodedData();
414    SkJFIFInfo info;
415    if (data && SkIsJFIF(data.get(), &info)) {
416        bool yuv = info.fType == SkJFIFInfo::kYCbCr;
417        if (info.fSize == image->dimensions()) {  // Sanity check.
418            // hold on to data, not image.
419            #ifdef SK_PDF_IMAGE_STATS
420            gJpegImageObjects.fetch_add(1);
421            #endif
422            return sk_make_sp<PDFJpegBitmap>(info.fSize, data.get(), yuv);
423        }
424    }
425
426    const bool isOpaque = image_compute_is_opaque(image.get());
427
428    if (encodingQuality <= 100 && isOpaque) {
429        data = image->encodeToData(SkEncodedImageFormat::kJPEG, encodingQuality);
430        if (data && SkIsJFIF(data.get(), &info)) {
431            bool yuv = info.fType == SkJFIFInfo::kYCbCr;
432            if (info.fSize == image->dimensions()) {  // Sanity check.
433                return sk_make_sp<PDFJpegBitmap>(info.fSize, data.get(), yuv);
434            }
435        }
436    }
437
438    sk_sp<SkPDFObject> smask;
439    if (!isOpaque) {
440        smask = sk_make_sp<PDFAlphaBitmap>(image);
441    }
442    #ifdef SK_PDF_IMAGE_STATS
443    gRegularImageObjects.fetch_add(1);
444    #endif
445    return sk_make_sp<PDFDefaultBitmap>(std::move(image), std::move(smask));
446}
447