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