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