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