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, ©); 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, ©); 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