xref: /third_party/skia/src/pdf/SkPDFBitmap.cpp (revision cb93a386)
1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2015 Google Inc.
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include "src/pdf/SkPDFBitmap.h"
9cb93a386Sopenharmony_ci
10cb93a386Sopenharmony_ci#include "include/core/SkBitmap.h"
11cb93a386Sopenharmony_ci#include "include/core/SkData.h"
12cb93a386Sopenharmony_ci#include "include/core/SkExecutor.h"
13cb93a386Sopenharmony_ci#include "include/core/SkImage.h"
14cb93a386Sopenharmony_ci#include "include/core/SkStream.h"
15cb93a386Sopenharmony_ci#include "include/private/SkColorData.h"
16cb93a386Sopenharmony_ci#include "include/private/SkImageInfoPriv.h"
17cb93a386Sopenharmony_ci#include "include/private/SkTo.h"
18cb93a386Sopenharmony_ci#include "src/pdf/SkDeflate.h"
19cb93a386Sopenharmony_ci#include "src/pdf/SkJpegInfo.h"
20cb93a386Sopenharmony_ci#include "src/pdf/SkPDFDocumentPriv.h"
21cb93a386Sopenharmony_ci#include "src/pdf/SkPDFTypes.h"
22cb93a386Sopenharmony_ci#include "src/pdf/SkPDFUtils.h"
23cb93a386Sopenharmony_ci
24cb93a386Sopenharmony_ci////////////////////////////////////////////////////////////////////////////////
25cb93a386Sopenharmony_ci
26cb93a386Sopenharmony_ci// write a single byte to a stream n times.
27cb93a386Sopenharmony_cistatic void fill_stream(SkWStream* out, char value, size_t n) {
28cb93a386Sopenharmony_ci    char buffer[4096];
29cb93a386Sopenharmony_ci    memset(buffer, value, sizeof(buffer));
30cb93a386Sopenharmony_ci    for (size_t i = 0; i < n / sizeof(buffer); ++i) {
31cb93a386Sopenharmony_ci        out->write(buffer, sizeof(buffer));
32cb93a386Sopenharmony_ci    }
33cb93a386Sopenharmony_ci    out->write(buffer, n % sizeof(buffer));
34cb93a386Sopenharmony_ci}
35cb93a386Sopenharmony_ci
36cb93a386Sopenharmony_ci/* It is necessary to average the color component of transparent
37cb93a386Sopenharmony_ci   pixels with their surrounding neighbors since the PDF renderer may
38cb93a386Sopenharmony_ci   separately re-sample the alpha and color channels when the image is
39cb93a386Sopenharmony_ci   not displayed at its native resolution. Since an alpha of zero
40cb93a386Sopenharmony_ci   gives no information about the color component, the pathological
41cb93a386Sopenharmony_ci   case is a white image with sharp transparency bounds - the color
42cb93a386Sopenharmony_ci   channel goes to black, and the should-be-transparent pixels are
43cb93a386Sopenharmony_ci   rendered as grey because of the separate soft mask and color
44cb93a386Sopenharmony_ci   resizing. e.g.: gm/bitmappremul.cpp */
45cb93a386Sopenharmony_cistatic SkColor get_neighbor_avg_color(const SkPixmap& bm, int xOrig, int yOrig) {
46cb93a386Sopenharmony_ci    SkASSERT(kBGRA_8888_SkColorType == bm.colorType());
47cb93a386Sopenharmony_ci    unsigned r = 0, g = 0, b = 0, n = 0;
48cb93a386Sopenharmony_ci    // Clamp the range to the edge of the bitmap.
49cb93a386Sopenharmony_ci    int ymin = std::max(0, yOrig - 1);
50cb93a386Sopenharmony_ci    int ymax = std::min(yOrig + 1, bm.height() - 1);
51cb93a386Sopenharmony_ci    int xmin = std::max(0, xOrig - 1);
52cb93a386Sopenharmony_ci    int xmax = std::min(xOrig + 1, bm.width() - 1);
53cb93a386Sopenharmony_ci    for (int y = ymin; y <= ymax; ++y) {
54cb93a386Sopenharmony_ci        const SkColor* scanline = bm.addr32(0, y);
55cb93a386Sopenharmony_ci        for (int x = xmin; x <= xmax; ++x) {
56cb93a386Sopenharmony_ci            SkColor color = scanline[x];
57cb93a386Sopenharmony_ci            if (color != SK_ColorTRANSPARENT) {
58cb93a386Sopenharmony_ci                r += SkColorGetR(color);
59cb93a386Sopenharmony_ci                g += SkColorGetG(color);
60cb93a386Sopenharmony_ci                b += SkColorGetB(color);
61cb93a386Sopenharmony_ci                n++;
62cb93a386Sopenharmony_ci            }
63cb93a386Sopenharmony_ci        }
64cb93a386Sopenharmony_ci    }
65cb93a386Sopenharmony_ci    return n > 0 ? SkColorSetRGB(SkToU8(r / n), SkToU8(g / n), SkToU8(b / n))
66cb93a386Sopenharmony_ci                 : SK_ColorTRANSPARENT;
67cb93a386Sopenharmony_ci}
68cb93a386Sopenharmony_ci
69cb93a386Sopenharmony_citemplate <typename T>
70cb93a386Sopenharmony_cistatic void emit_image_stream(SkPDFDocument* doc,
71cb93a386Sopenharmony_ci                              SkPDFIndirectReference ref,
72cb93a386Sopenharmony_ci                              T writeStream,
73cb93a386Sopenharmony_ci                              SkISize size,
74cb93a386Sopenharmony_ci                              const char* colorSpace,
75cb93a386Sopenharmony_ci                              SkPDFIndirectReference sMask,
76cb93a386Sopenharmony_ci                              int length,
77cb93a386Sopenharmony_ci                              bool isJpeg) {
78cb93a386Sopenharmony_ci    SkPDFDict pdfDict("XObject");
79cb93a386Sopenharmony_ci    pdfDict.insertName("Subtype", "Image");
80cb93a386Sopenharmony_ci    pdfDict.insertInt("Width", size.width());
81cb93a386Sopenharmony_ci    pdfDict.insertInt("Height", size.height());
82cb93a386Sopenharmony_ci    pdfDict.insertName("ColorSpace", colorSpace);
83cb93a386Sopenharmony_ci    if (sMask) {
84cb93a386Sopenharmony_ci        pdfDict.insertRef("SMask", sMask);
85cb93a386Sopenharmony_ci    }
86cb93a386Sopenharmony_ci    pdfDict.insertInt("BitsPerComponent", 8);
87cb93a386Sopenharmony_ci    #ifdef SK_PDF_BASE85_BINARY
88cb93a386Sopenharmony_ci    auto filters = SkPDFMakeArray();
89cb93a386Sopenharmony_ci    filters->appendName("ASCII85Decode");
90cb93a386Sopenharmony_ci    filters->appendName(isJpeg ? "DCTDecode" : "FlateDecode");
91cb93a386Sopenharmony_ci    pdfDict.insertObject("Filter", std::move(filters));
92cb93a386Sopenharmony_ci    #else
93cb93a386Sopenharmony_ci    pdfDict.insertName("Filter", isJpeg ? "DCTDecode" : "FlateDecode");
94cb93a386Sopenharmony_ci    #endif
95cb93a386Sopenharmony_ci    if (isJpeg) {
96cb93a386Sopenharmony_ci        pdfDict.insertInt("ColorTransform", 0);
97cb93a386Sopenharmony_ci    }
98cb93a386Sopenharmony_ci    pdfDict.insertInt("Length", length);
99cb93a386Sopenharmony_ci    doc->emitStream(pdfDict, std::move(writeStream), ref);
100cb93a386Sopenharmony_ci}
101cb93a386Sopenharmony_ci
102cb93a386Sopenharmony_cistatic void do_deflated_alpha(const SkPixmap& pm, SkPDFDocument* doc, SkPDFIndirectReference ref) {
103cb93a386Sopenharmony_ci    SkDynamicMemoryWStream buffer;
104cb93a386Sopenharmony_ci    SkDeflateWStream deflateWStream(&buffer);
105cb93a386Sopenharmony_ci    if (kAlpha_8_SkColorType == pm.colorType()) {
106cb93a386Sopenharmony_ci        SkASSERT(pm.rowBytes() == (size_t)pm.width());
107cb93a386Sopenharmony_ci        buffer.write(pm.addr8(), pm.width() * pm.height());
108cb93a386Sopenharmony_ci    } else {
109cb93a386Sopenharmony_ci        SkASSERT(pm.alphaType() == kUnpremul_SkAlphaType);
110cb93a386Sopenharmony_ci        SkASSERT(pm.colorType() == kBGRA_8888_SkColorType);
111cb93a386Sopenharmony_ci        SkASSERT(pm.rowBytes() == (size_t)pm.width() * 4);
112cb93a386Sopenharmony_ci        const uint32_t* ptr = pm.addr32();
113cb93a386Sopenharmony_ci        const uint32_t* stop = ptr + pm.height() * pm.width();
114cb93a386Sopenharmony_ci
115cb93a386Sopenharmony_ci        uint8_t byteBuffer[4092];
116cb93a386Sopenharmony_ci        uint8_t* bufferStop = byteBuffer + SK_ARRAY_COUNT(byteBuffer);
117cb93a386Sopenharmony_ci        uint8_t* dst = byteBuffer;
118cb93a386Sopenharmony_ci        while (ptr != stop) {
119cb93a386Sopenharmony_ci            *dst++ = 0xFF & ((*ptr++) >> SK_BGRA_A32_SHIFT);
120cb93a386Sopenharmony_ci            if (dst == bufferStop) {
121cb93a386Sopenharmony_ci                deflateWStream.write(byteBuffer, sizeof(byteBuffer));
122cb93a386Sopenharmony_ci                dst = byteBuffer;
123cb93a386Sopenharmony_ci            }
124cb93a386Sopenharmony_ci        }
125cb93a386Sopenharmony_ci        deflateWStream.write(byteBuffer, dst - byteBuffer);
126cb93a386Sopenharmony_ci    }
127cb93a386Sopenharmony_ci    deflateWStream.finalize();
128cb93a386Sopenharmony_ci
129cb93a386Sopenharmony_ci    #ifdef SK_PDF_BASE85_BINARY
130cb93a386Sopenharmony_ci    SkPDFUtils::Base85Encode(buffer.detachAsStream(), &buffer);
131cb93a386Sopenharmony_ci    #endif
132cb93a386Sopenharmony_ci    int length = SkToInt(buffer.bytesWritten());
133cb93a386Sopenharmony_ci    emit_image_stream(doc, ref, [&buffer](SkWStream* stream) { buffer.writeToAndReset(stream); },
134cb93a386Sopenharmony_ci                      pm.info().dimensions(), "DeviceGray", SkPDFIndirectReference(),
135cb93a386Sopenharmony_ci                      length, false);
136cb93a386Sopenharmony_ci}
137cb93a386Sopenharmony_ci
138cb93a386Sopenharmony_cistatic void do_deflated_image(const SkPixmap& pm,
139cb93a386Sopenharmony_ci                              SkPDFDocument* doc,
140cb93a386Sopenharmony_ci                              bool isOpaque,
141cb93a386Sopenharmony_ci                              SkPDFIndirectReference ref) {
142cb93a386Sopenharmony_ci    SkPDFIndirectReference sMask;
143cb93a386Sopenharmony_ci    if (!isOpaque) {
144cb93a386Sopenharmony_ci        sMask = doc->reserveRef();
145cb93a386Sopenharmony_ci    }
146cb93a386Sopenharmony_ci    SkDynamicMemoryWStream buffer;
147cb93a386Sopenharmony_ci    SkDeflateWStream deflateWStream(&buffer);
148cb93a386Sopenharmony_ci    const char* colorSpace = "DeviceGray";
149cb93a386Sopenharmony_ci    switch (pm.colorType()) {
150cb93a386Sopenharmony_ci        case kAlpha_8_SkColorType:
151cb93a386Sopenharmony_ci            fill_stream(&deflateWStream, '\x00', pm.width() * pm.height());
152cb93a386Sopenharmony_ci            break;
153cb93a386Sopenharmony_ci        case kGray_8_SkColorType:
154cb93a386Sopenharmony_ci            SkASSERT(sMask.fValue = -1);
155cb93a386Sopenharmony_ci            SkASSERT(pm.rowBytes() == (size_t)pm.width());
156cb93a386Sopenharmony_ci            deflateWStream.write(pm.addr8(), pm.width() * pm.height());
157cb93a386Sopenharmony_ci            break;
158cb93a386Sopenharmony_ci        default:
159cb93a386Sopenharmony_ci            colorSpace = "DeviceRGB";
160cb93a386Sopenharmony_ci            SkASSERT(pm.alphaType() == kUnpremul_SkAlphaType);
161cb93a386Sopenharmony_ci            SkASSERT(pm.colorType() == kBGRA_8888_SkColorType);
162cb93a386Sopenharmony_ci            SkASSERT(pm.rowBytes() == (size_t)pm.width() * 4);
163cb93a386Sopenharmony_ci            uint8_t byteBuffer[3072];
164cb93a386Sopenharmony_ci            static_assert(SK_ARRAY_COUNT(byteBuffer) % 3 == 0, "");
165cb93a386Sopenharmony_ci            uint8_t* bufferStop = byteBuffer + SK_ARRAY_COUNT(byteBuffer);
166cb93a386Sopenharmony_ci            uint8_t* dst = byteBuffer;
167cb93a386Sopenharmony_ci            for (int y = 0; y < pm.height(); ++y) {
168cb93a386Sopenharmony_ci                const SkColor* src = pm.addr32(0, y);
169cb93a386Sopenharmony_ci                for (int x = 0; x < pm.width(); ++x) {
170cb93a386Sopenharmony_ci                    SkColor color = *src++;
171cb93a386Sopenharmony_ci                    if (SkColorGetA(color) == SK_AlphaTRANSPARENT) {
172cb93a386Sopenharmony_ci                        color = get_neighbor_avg_color(pm, x, y);
173cb93a386Sopenharmony_ci                    }
174cb93a386Sopenharmony_ci                    *dst++ = SkColorGetR(color);
175cb93a386Sopenharmony_ci                    *dst++ = SkColorGetG(color);
176cb93a386Sopenharmony_ci                    *dst++ = SkColorGetB(color);
177cb93a386Sopenharmony_ci                    if (dst == bufferStop) {
178cb93a386Sopenharmony_ci                        deflateWStream.write(byteBuffer, sizeof(byteBuffer));
179cb93a386Sopenharmony_ci                        dst = byteBuffer;
180cb93a386Sopenharmony_ci                    }
181cb93a386Sopenharmony_ci                }
182cb93a386Sopenharmony_ci            }
183cb93a386Sopenharmony_ci            deflateWStream.write(byteBuffer, dst - byteBuffer);
184cb93a386Sopenharmony_ci    }
185cb93a386Sopenharmony_ci    deflateWStream.finalize();
186cb93a386Sopenharmony_ci    #ifdef SK_PDF_BASE85_BINARY
187cb93a386Sopenharmony_ci    SkPDFUtils::Base85Encode(buffer.detachAsStream(), &buffer);
188cb93a386Sopenharmony_ci    #endif
189cb93a386Sopenharmony_ci    int length = SkToInt(buffer.bytesWritten());
190cb93a386Sopenharmony_ci    emit_image_stream(doc, ref, [&buffer](SkWStream* stream) { buffer.writeToAndReset(stream); },
191cb93a386Sopenharmony_ci                      pm.info().dimensions(), colorSpace, sMask, length, false);
192cb93a386Sopenharmony_ci    if (!isOpaque) {
193cb93a386Sopenharmony_ci        do_deflated_alpha(pm, doc, sMask);
194cb93a386Sopenharmony_ci    }
195cb93a386Sopenharmony_ci}
196cb93a386Sopenharmony_ci
197cb93a386Sopenharmony_cistatic bool do_jpeg(sk_sp<SkData> data, SkPDFDocument* doc, SkISize size,
198cb93a386Sopenharmony_ci                    SkPDFIndirectReference ref) {
199cb93a386Sopenharmony_ci    SkISize jpegSize;
200cb93a386Sopenharmony_ci    SkEncodedInfo::Color jpegColorType;
201cb93a386Sopenharmony_ci    SkEncodedOrigin exifOrientation;
202cb93a386Sopenharmony_ci    if (!SkGetJpegInfo(data->data(), data->size(), &jpegSize,
203cb93a386Sopenharmony_ci                       &jpegColorType, &exifOrientation)) {
204cb93a386Sopenharmony_ci        return false;
205cb93a386Sopenharmony_ci    }
206cb93a386Sopenharmony_ci    bool yuv = jpegColorType == SkEncodedInfo::kYUV_Color;
207cb93a386Sopenharmony_ci    bool goodColorType = yuv || jpegColorType == SkEncodedInfo::kGray_Color;
208cb93a386Sopenharmony_ci    if (jpegSize != size  // Safety check.
209cb93a386Sopenharmony_ci            || !goodColorType
210cb93a386Sopenharmony_ci            || kTopLeft_SkEncodedOrigin != exifOrientation) {
211cb93a386Sopenharmony_ci        return false;
212cb93a386Sopenharmony_ci    }
213cb93a386Sopenharmony_ci    #ifdef SK_PDF_BASE85_BINARY
214cb93a386Sopenharmony_ci    SkDynamicMemoryWStream buffer;
215cb93a386Sopenharmony_ci    SkPDFUtils::Base85Encode(SkMemoryStream::MakeDirect(data->data(), data->size()), &buffer);
216cb93a386Sopenharmony_ci    data = buffer.detachAsData();
217cb93a386Sopenharmony_ci    #endif
218cb93a386Sopenharmony_ci
219cb93a386Sopenharmony_ci    emit_image_stream(doc, ref,
220cb93a386Sopenharmony_ci                      [&data](SkWStream* dst) { dst->write(data->data(), data->size()); },
221cb93a386Sopenharmony_ci                      jpegSize, yuv ? "DeviceRGB" : "DeviceGray",
222cb93a386Sopenharmony_ci                      SkPDFIndirectReference(), SkToInt(data->size()), true);
223cb93a386Sopenharmony_ci    return true;
224cb93a386Sopenharmony_ci}
225cb93a386Sopenharmony_ci
226cb93a386Sopenharmony_cistatic SkBitmap to_pixels(const SkImage* image) {
227cb93a386Sopenharmony_ci    SkBitmap bm;
228cb93a386Sopenharmony_ci    int w = image->width(),
229cb93a386Sopenharmony_ci        h = image->height();
230cb93a386Sopenharmony_ci    switch (image->colorType()) {
231cb93a386Sopenharmony_ci        case kAlpha_8_SkColorType:
232cb93a386Sopenharmony_ci            bm.allocPixels(SkImageInfo::MakeA8(w, h));
233cb93a386Sopenharmony_ci            break;
234cb93a386Sopenharmony_ci        case kGray_8_SkColorType:
235cb93a386Sopenharmony_ci            bm.allocPixels(SkImageInfo::Make(w, h, kGray_8_SkColorType, kOpaque_SkAlphaType));
236cb93a386Sopenharmony_ci            break;
237cb93a386Sopenharmony_ci        default: {
238cb93a386Sopenharmony_ci            // TODO: makeColorSpace(sRGB) or actually tag the images
239cb93a386Sopenharmony_ci            SkAlphaType at = bm.isOpaque() ? kOpaque_SkAlphaType : kUnpremul_SkAlphaType;
240cb93a386Sopenharmony_ci            bm.allocPixels(SkImageInfo::Make(w, h, kBGRA_8888_SkColorType, at));
241cb93a386Sopenharmony_ci        }
242cb93a386Sopenharmony_ci    }
243cb93a386Sopenharmony_ci    // TODO: support GPU images in PDFs
244cb93a386Sopenharmony_ci    if (!image->readPixels(nullptr, bm.pixmap(), 0, 0)) {
245cb93a386Sopenharmony_ci        bm.eraseColor(SkColorSetARGB(0xFF, 0, 0, 0));
246cb93a386Sopenharmony_ci    }
247cb93a386Sopenharmony_ci    return bm;
248cb93a386Sopenharmony_ci}
249cb93a386Sopenharmony_ci
250cb93a386Sopenharmony_civoid serialize_image(const SkImage* img,
251cb93a386Sopenharmony_ci                     int encodingQuality,
252cb93a386Sopenharmony_ci                     SkPDFDocument* doc,
253cb93a386Sopenharmony_ci                     SkPDFIndirectReference ref) {
254cb93a386Sopenharmony_ci    SkASSERT(img);
255cb93a386Sopenharmony_ci    SkASSERT(doc);
256cb93a386Sopenharmony_ci    SkASSERT(encodingQuality >= 0);
257cb93a386Sopenharmony_ci    SkISize dimensions = img->dimensions();
258cb93a386Sopenharmony_ci    if (sk_sp<SkData> data = img->refEncodedData()) {
259cb93a386Sopenharmony_ci        if (do_jpeg(std::move(data), doc, dimensions, ref)) {
260cb93a386Sopenharmony_ci            return;
261cb93a386Sopenharmony_ci        }
262cb93a386Sopenharmony_ci    }
263cb93a386Sopenharmony_ci    SkBitmap bm = to_pixels(img);
264cb93a386Sopenharmony_ci    const SkPixmap& pm = bm.pixmap();
265cb93a386Sopenharmony_ci    bool isOpaque = pm.isOpaque() || pm.computeIsOpaque();
266cb93a386Sopenharmony_ci    if (encodingQuality <= 100 && isOpaque) {
267cb93a386Sopenharmony_ci        if (sk_sp<SkData> data = img->encodeToData(SkEncodedImageFormat::kJPEG, encodingQuality)) {
268cb93a386Sopenharmony_ci            if (do_jpeg(std::move(data), doc, dimensions, ref)) {
269cb93a386Sopenharmony_ci                return;
270cb93a386Sopenharmony_ci            }
271cb93a386Sopenharmony_ci        }
272cb93a386Sopenharmony_ci    }
273cb93a386Sopenharmony_ci    do_deflated_image(pm, doc, isOpaque, ref);
274cb93a386Sopenharmony_ci}
275cb93a386Sopenharmony_ci
276cb93a386Sopenharmony_ciSkPDFIndirectReference SkPDFSerializeImage(const SkImage* img,
277cb93a386Sopenharmony_ci                                           SkPDFDocument* doc,
278cb93a386Sopenharmony_ci                                           int encodingQuality) {
279cb93a386Sopenharmony_ci    SkASSERT(img);
280cb93a386Sopenharmony_ci    SkASSERT(doc);
281cb93a386Sopenharmony_ci    SkPDFIndirectReference ref = doc->reserveRef();
282cb93a386Sopenharmony_ci    if (SkExecutor* executor = doc->executor()) {
283cb93a386Sopenharmony_ci        SkRef(img);
284cb93a386Sopenharmony_ci        doc->incrementJobCount();
285cb93a386Sopenharmony_ci        executor->add([img, encodingQuality, doc, ref]() {
286cb93a386Sopenharmony_ci            serialize_image(img, encodingQuality, doc, ref);
287cb93a386Sopenharmony_ci            SkSafeUnref(img);
288cb93a386Sopenharmony_ci            doc->signalJobComplete();
289cb93a386Sopenharmony_ci        });
290cb93a386Sopenharmony_ci        return ref;
291cb93a386Sopenharmony_ci    }
292cb93a386Sopenharmony_ci    serialize_image(img, encodingQuality, doc, ref);
293cb93a386Sopenharmony_ci    return ref;
294cb93a386Sopenharmony_ci}
295