| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2015 Google Inc. | 2 * Copyright 2015 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #include "SkColorPriv.h" | 8 #include "SkColorPriv.h" |
| 9 #include "SkData.h" | 9 #include "SkData.h" |
| 10 #include "SkDeflate.h" | 10 #include "SkDeflate.h" |
| 11 #include "SkImage_Base.h" | 11 #include "SkImage_Base.h" |
| 12 #include "SkJpegInfo.h" | 12 #include "SkJpegInfo.h" |
| 13 #include "SkPDFBitmap.h" | 13 #include "SkPDFBitmap.h" |
| 14 #include "SkPDFCanon.h" | 14 #include "SkPDFCanon.h" |
| 15 #include "SkStream.h" | 15 #include "SkStream.h" |
| 16 #include "SkUnPreMultiply.h" | 16 #include "SkUnPreMultiply.h" |
| 17 #include "SkPngPredictors.h" |
| 17 | 18 |
| 18 void image_get_ro_pixels(const SkImage* image, SkBitmap* dst) { | 19 void image_get_ro_pixels(const SkImage* image, SkBitmap* dst) { |
| 19 if(as_IB(image)->getROPixels(dst) | 20 if(as_IB(image)->getROPixels(dst) |
| 20 && dst->dimensions() == image->dimensions()) { | 21 && dst->dimensions() == image->dimensions()) { |
| 21 if (dst->colorType() != kIndex_8_SkColorType) { | 22 if (dst->colorType() != kIndex_8_SkColorType) { |
| 22 return; | 23 return; |
| 23 } | 24 } |
| 24 // We must check to see if the bitmap has a color table. | 25 // We must check to see if the bitmap has a color table. |
| 25 SkAutoLockPixels autoLockPixels(*dst); | 26 SkAutoLockPixels autoLockPixels(*dst); |
| 26 if (!dst->getColorTable()) { | 27 if (!dst->getColorTable()) { |
| (...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 165 case kIndex_8_SkColorType: | 166 case kIndex_8_SkColorType: |
| 166 case kGray_8_SkColorType: | 167 case kGray_8_SkColorType: |
| 167 return 1; | 168 return 1; |
| 168 case kUnknown_SkColorType: | 169 case kUnknown_SkColorType: |
| 169 default: | 170 default: |
| 170 SkDEBUGFAIL("unexpected color type"); | 171 SkDEBUGFAIL("unexpected color type"); |
| 171 return 0; | 172 return 0; |
| 172 } | 173 } |
| 173 } | 174 } |
| 174 | 175 |
| 175 static void bitmap_to_pdf_pixels(const SkBitmap& bitmap, SkWStream* out) { | 176 //#define SK_PDF_USE_BEST_PNG_PREDICTOR |
| 177 //#define SK_PDF_USE_PAETH_PNG_PREDICTOR |
| 178 namespace { |
| 179 #if defined(SK_PDF_USE_BEST_PNG_PREDICTOR) || defined(SK_PDF_USE_PAETH_PNG_PREDI
CTOR) |
| 180 template<int BPP> |
| 181 class PngPredictor { |
| 182 public: |
| 183 PngPredictor(int widthInPixels) |
| 184 : fBuffer(2 * (BPP * widthInPixels + 1)) |
| 185 , fWidth(widthInPixels) |
| 186 , fFirstline(true) { |
| 187 fScanline = fBuffer.get(); |
| 188 fPrevScanline = &fScanline[BPP * widthInPixels + 1]; |
| 189 } |
| 190 bool predicts() { return true; } |
| 191 uint8_t* scanline() { return &fScanline[1]; } |
| 192 void write(SkWStream* out) { |
| 193 static_assert(3 == BPP || 1 == BPP, ""); |
| 194 #if defined(SK_PDF_USE_BEST_PNG_PREDICTOR) // smaller |
| 195 auto encode = (3 == BPP) ? &SkPngEncode3 : &SkPngEncode1; |
| 196 #elif defined(SK_PDF_USE_PAETH_PNG_PREDICTOR) // faster |
| 197 auto encode = (3 == BPP) ? &SkPaethEncode3 : &SkPaethEncode1; |
| 198 #endif |
| 199 fPrevScanline[0] = encode( |
| 200 fWidth, fFirstline ? nullptr : &fPrevScanline[1], |
| 201 &fScanline[1], &fPrevScanline[1]); |
| 202 out->write(fPrevScanline, BPP * fWidth + 1); |
| 203 SkTSwap(fScanline, fPrevScanline); |
| 204 fFirstline = false; |
| 205 } |
| 206 private: |
| 207 SkAutoTMalloc<uint8_t> fBuffer; |
| 208 uint8_t* fScanline; |
| 209 uint8_t* fPrevScanline; |
| 210 uint8_t* fScratch; |
| 211 int fWidth; |
| 212 bool fFirstline; |
| 213 }; |
| 214 #else |
| 215 template<int BPP> |
| 216 class PngPredictor { |
| 217 public: |
| 218 PngPredictor(int widthInPixels) |
| 219 : fBuffer(BPP * widthInPixels) |
| 220 , fWidthInBytes(BPP * widthInPixels) { |
| 221 } |
| 222 bool predicts() { return false; } |
| 223 uint8_t* scanline() { return fBuffer.get(); } |
| 224 void write(SkWStream* out) { |
| 225 out->write(fBuffer.get(), fWidthInBytes); |
| 226 } |
| 227 private: |
| 228 SkAutoTMalloc<uint8_t> fBuffer; |
| 229 int fWidthInBytes; |
| 230 }; |
| 231 #endif |
| 232 } // namespace |
| 233 |
| 234 static bool bitmap_to_pdf_pixels(const SkBitmap& bitmap, SkWStream* out) { |
| 176 if (!bitmap.getPixels()) { | 235 if (!bitmap.getPixels()) { |
| 177 size_t size = pixel_count(bitmap) * | 236 size_t size = pixel_count(bitmap) * |
| 178 pdf_color_component_count(bitmap.colorType()); | 237 pdf_color_component_count(bitmap.colorType()); |
| 179 fill_stream(out, '\x00', size); | 238 fill_stream(out, '\x00', size); |
| 180 return; | 239 return false; |
| 181 } | 240 } |
| 182 SkBitmap copy; | 241 SkBitmap copy; |
| 183 const SkBitmap& bm = not4444(bitmap, ©); | 242 const SkBitmap& bm = not4444(bitmap, ©); |
| 184 SkAutoLockPixels autoLockPixels(bm); | 243 SkAutoLockPixels autoLockPixels(bm); |
| 185 SkColorType colorType = bm.colorType(); | 244 SkColorType colorType = bm.colorType(); |
| 186 switch (colorType) { | 245 switch (colorType) { |
| 187 case kRGBA_8888_SkColorType: | 246 case kRGBA_8888_SkColorType: |
| 188 case kBGRA_8888_SkColorType: { | 247 case kBGRA_8888_SkColorType: { |
| 189 SkASSERT(3 == pdf_color_component_count(colorType)); | 248 SkASSERT(3 == pdf_color_component_count(colorType)); |
| 190 SkAutoTMalloc<uint8_t> scanline(3 * bm.width()); | 249 PngPredictor<3> pngPredictorFilter(bm.width()); |
| 191 for (int y = 0; y < bm.height(); ++y) { | 250 for (int y = 0; y < bm.height(); ++y) { |
| 192 const uint32_t* src = bm.getAddr32(0, y); | 251 const uint32_t* src = bm.getAddr32(0, y); |
| 193 uint8_t* dst = scanline.get(); | 252 uint8_t* dst = pngPredictorFilter.scanline(); |
| 194 for (int x = 0; x < bm.width(); ++x) { | 253 for (int x = 0; x < bm.width(); ++x) { |
| 195 uint32_t color = *src++; | 254 uint32_t color = *src++; |
| 196 U8CPU alpha = SkGetA32Component(color, colorType); | 255 U8CPU alpha = SkGetA32Component(color, colorType); |
| 197 if (alpha != SK_AlphaTRANSPARENT) { | 256 if (alpha != SK_AlphaTRANSPARENT) { |
| 198 pmcolor_to_rgb24(color, dst, colorType); | 257 pmcolor_to_rgb24(color, dst, colorType); |
| 199 } else { | 258 } else { |
| 200 get_neighbor_avg_color(bm, x, y, dst, colorType); | 259 get_neighbor_avg_color(bm, x, y, dst, colorType); |
| 201 } | 260 } |
| 202 dst += 3; | 261 dst += 3; |
| 203 } | 262 } |
| 204 out->write(scanline.get(), 3 * bm.width()); | 263 pngPredictorFilter.write(out); |
| 205 } | 264 } |
| 206 return; | 265 return pngPredictorFilter.predicts(); |
| 207 } | 266 } |
| 208 case kRGB_565_SkColorType: { | 267 case kRGB_565_SkColorType: { |
| 209 SkASSERT(3 == pdf_color_component_count(colorType)); | 268 SkASSERT(3 == pdf_color_component_count(colorType)); |
| 210 SkAutoTMalloc<uint8_t> scanline(3 * bm.width()); | 269 PngPredictor<3> pngPredictorFilter(bm.width()); |
| 211 for (int y = 0; y < bm.height(); ++y) { | 270 for (int y = 0; y < bm.height(); ++y) { |
| 212 const uint16_t* src = bm.getAddr16(0, y); | 271 const uint16_t* src = bm.getAddr16(0, y); |
| 213 uint8_t* dst = scanline.get(); | 272 uint8_t* dst = pngPredictorFilter.scanline(); |
| 214 for (int x = 0; x < bm.width(); ++x) { | 273 for (int x = 0; x < bm.width(); ++x) { |
| 215 U16CPU color565 = *src++; | 274 U16CPU color565 = *src++; |
| 216 *dst++ = SkPacked16ToR32(color565); | 275 *dst++ = SkPacked16ToR32(color565); |
| 217 *dst++ = SkPacked16ToG32(color565); | 276 *dst++ = SkPacked16ToG32(color565); |
| 218 *dst++ = SkPacked16ToB32(color565); | 277 *dst++ = SkPacked16ToB32(color565); |
| 219 } | 278 } |
| 220 out->write(scanline.get(), 3 * bm.width()); | 279 pngPredictorFilter.write(out); |
| 221 } | 280 } |
| 222 return; | 281 return pngPredictorFilter.predicts(); |
| 223 } | 282 } |
| 224 case kAlpha_8_SkColorType: | 283 case kAlpha_8_SkColorType: |
| 225 SkASSERT(1 == pdf_color_component_count(colorType)); | 284 SkASSERT(1 == pdf_color_component_count(colorType)); |
| 226 fill_stream(out, '\x00', pixel_count(bm)); | 285 fill_stream(out, '\x00', pixel_count(bm)); |
| 227 return; | 286 return false; |
| 228 case kGray_8_SkColorType: | 287 case kGray_8_SkColorType: |
| 229 case kIndex_8_SkColorType: | 288 case kIndex_8_SkColorType: |
| 230 SkASSERT(1 == pdf_color_component_count(colorType)); | 289 SkASSERT(1 == pdf_color_component_count(colorType)); |
| 231 // these two formats need no transformation to serialize. | 290 // these two formats need no transformation to serialize. |
| 232 for (int y = 0; y < bm.height(); ++y) { | 291 for (int y = 0; y < bm.height(); ++y) { |
| 233 out->write(bm.getAddr8(0, y), bm.width()); | 292 out->write(bm.getAddr8(0, y), bm.width()); |
| 234 } | 293 } |
| 235 return; | 294 return false; |
| 236 case kUnknown_SkColorType: | 295 case kUnknown_SkColorType: |
| 237 case kARGB_4444_SkColorType: | 296 case kARGB_4444_SkColorType: |
| 238 default: | 297 default: |
| 239 SkDEBUGFAIL("unexpected color type"); | 298 SkDEBUGFAIL("unexpected color type"); |
| 299 return false; |
| 240 } | 300 } |
| 241 } | 301 } |
| 242 | 302 |
| 243 //////////////////////////////////////////////////////////////////////////////// | 303 //////////////////////////////////////////////////////////////////////////////// |
| 244 | 304 |
| 245 static void bitmap_alpha_to_a8(const SkBitmap& bitmap, SkWStream* out) { | 305 static bool bitmap_alpha_to_a8(const SkBitmap& bitmap, SkWStream* out) { |
| 246 if (!bitmap.getPixels()) { | 306 if (!bitmap.getPixels()) { |
| 247 fill_stream(out, '\xFF', pixel_count(bitmap)); | 307 fill_stream(out, '\xFF', pixel_count(bitmap)); |
| 248 return; | 308 return false; |
| 249 } | 309 } |
| 250 SkBitmap copy; | 310 SkBitmap copy; |
| 251 const SkBitmap& bm = not4444(bitmap, ©); | 311 const SkBitmap& bm = not4444(bitmap, ©); |
| 252 SkAutoLockPixels autoLockPixels(bm); | 312 SkAutoLockPixels autoLockPixels(bm); |
| 253 SkColorType colorType = bm.colorType(); | 313 SkColorType colorType = bm.colorType(); |
| 254 switch (colorType) { | 314 switch (colorType) { |
| 255 case kRGBA_8888_SkColorType: | 315 case kRGBA_8888_SkColorType: |
| 256 case kBGRA_8888_SkColorType: { | 316 case kBGRA_8888_SkColorType: { |
| 257 SkAutoTMalloc<uint8_t> scanline(bm.width()); | 317 PngPredictor<1> pngPredictorFilter(bm.width()); |
| 258 for (int y = 0; y < bm.height(); ++y) { | 318 for (int y = 0; y < bm.height(); ++y) { |
| 259 uint8_t* dst = scanline.get(); | 319 uint8_t* dst = pngPredictorFilter.scanline(); |
| 260 const SkPMColor* src = bm.getAddr32(0, y); | 320 const SkPMColor* src = bm.getAddr32(0, y); |
| 261 for (int x = 0; x < bm.width(); ++x) { | 321 for (int x = 0; x < bm.width(); ++x) { |
| 262 *dst++ = SkGetA32Component(*src++, colorType); | 322 *dst++ = SkGetA32Component(*src++, colorType); |
| 263 } | 323 } |
| 264 out->write(scanline.get(), bm.width()); | 324 pngPredictorFilter.write(out); |
| 265 } | 325 } |
| 266 return; | 326 return pngPredictorFilter.predicts(); |
| 267 } | 327 } |
| 268 case kAlpha_8_SkColorType: | 328 case kAlpha_8_SkColorType: |
| 269 for (int y = 0; y < bm.height(); ++y) { | 329 for (int y = 0; y < bm.height(); ++y) { |
| 270 out->write(bm.getAddr8(0, y), bm.width()); | 330 out->write(bm.getAddr8(0, y), bm.width()); |
| 271 } | 331 } |
| 272 return; | 332 return false; |
| 273 case kIndex_8_SkColorType: { | 333 case kIndex_8_SkColorType: { |
| 274 SkColorTable* ct = bm.getColorTable(); | 334 SkColorTable* ct = bm.getColorTable(); |
| 275 SkASSERT(ct); | 335 SkASSERT(ct); |
| 276 SkAutoTMalloc<uint8_t> scanline(bm.width()); | 336 SkAutoTMalloc<uint8_t> scanline(bm.width()); |
| 277 for (int y = 0; y < bm.height(); ++y) { | 337 for (int y = 0; y < bm.height(); ++y) { |
| 278 uint8_t* dst = scanline.get(); | 338 uint8_t* dst = scanline.get(); |
| 279 const uint8_t* src = bm.getAddr8(0, y); | 339 const uint8_t* src = bm.getAddr8(0, y); |
| 280 for (int x = 0; x < bm.width(); ++x) { | 340 for (int x = 0; x < bm.width(); ++x) { |
| 281 *dst++ = SkGetPackedA32((*ct)[*src++]); | 341 *dst++ = SkGetPackedA32((*ct)[*src++]); |
| 282 } | 342 } |
| 283 out->write(scanline.get(), bm.width()); | 343 out->write(scanline.get(), bm.width()); |
| 284 } | 344 } |
| 285 return; | 345 return false; |
| 286 } | 346 } |
| 287 case kRGB_565_SkColorType: | 347 case kRGB_565_SkColorType: |
| 288 case kGray_8_SkColorType: | 348 case kGray_8_SkColorType: |
| 289 SkDEBUGFAIL("color type has no alpha"); | 349 SkDEBUGFAIL("color type has no alpha"); |
| 290 return; | 350 return false; |
| 291 case kARGB_4444_SkColorType: | 351 case kARGB_4444_SkColorType: |
| 292 SkDEBUGFAIL("4444 color type should have been converted to N32"); | 352 SkDEBUGFAIL("4444 color type should have been converted to N32"); |
| 293 return; | 353 return false; |
| 294 case kUnknown_SkColorType: | 354 case kUnknown_SkColorType: |
| 295 default: | 355 default: |
| 296 SkDEBUGFAIL("unexpected color type"); | 356 SkDEBUGFAIL("unexpected color type"); |
| 357 return false; |
| 297 } | 358 } |
| 298 } | 359 } |
| 299 | 360 |
| 300 static SkPDFArray* make_indexed_color_space(const SkColorTable* table) { | 361 static SkPDFArray* make_indexed_color_space(const SkColorTable* table) { |
| 301 SkPDFArray* result = new SkPDFArray; | 362 SkPDFArray* result = new SkPDFArray; |
| 302 result->reserve(4); | 363 result->reserve(4); |
| 303 result->appendName("Indexed"); | 364 result->appendName("Indexed"); |
| 304 result->appendName("DeviceRGB"); | 365 result->appendName("DeviceRGB"); |
| 305 SkASSERT(table); | 366 SkASSERT(table); |
| 306 if (table->count() < 1) { | 367 if (table->count() < 1) { |
| (...skipping 26 matching lines...) Expand all Loading... |
| 333 SkPDFObject* smask, | 394 SkPDFObject* smask, |
| 334 const SkPDFObjNumMap& objNumMap, | 395 const SkPDFObjNumMap& objNumMap, |
| 335 const SkPDFSubstituteMap& substitutes) { | 396 const SkPDFSubstituteMap& substitutes) { |
| 336 SkBitmap bitmap; | 397 SkBitmap bitmap; |
| 337 image_get_ro_pixels(image, &bitmap); // TODO(halcanary): test | 398 image_get_ro_pixels(image, &bitmap); // TODO(halcanary): test |
| 338 SkAutoLockPixels autoLockPixels(bitmap); // with malformed images. | 399 SkAutoLockPixels autoLockPixels(bitmap); // with malformed images. |
| 339 | 400 |
| 340 // Write to a temporary buffer to get the compressed length. | 401 // Write to a temporary buffer to get the compressed length. |
| 341 SkDynamicMemoryWStream buffer; | 402 SkDynamicMemoryWStream buffer; |
| 342 SkDeflateWStream deflateWStream(&buffer); | 403 SkDeflateWStream deflateWStream(&buffer); |
| 404 bool usePngPredictor = false; |
| 343 if (alpha) { | 405 if (alpha) { |
| 344 bitmap_alpha_to_a8(bitmap, &deflateWStream); | 406 usePngPredictor = bitmap_alpha_to_a8(bitmap, &deflateWStream); |
| 345 } else { | 407 } else { |
| 346 bitmap_to_pdf_pixels(bitmap, &deflateWStream); | 408 usePngPredictor = bitmap_to_pdf_pixels(bitmap, &deflateWStream); |
| 347 } | 409 } |
| 348 deflateWStream.finalize(); // call before detachAsStream(). | 410 deflateWStream.finalize(); // call before detachAsStream(). |
| 349 SkAutoTDelete<SkStreamAsset> asset(buffer.detachAsStream()); | 411 SkAutoTDelete<SkStreamAsset> asset(buffer.detachAsStream()); |
| 350 | 412 |
| 351 SkPDFDict pdfDict("XObject"); | 413 SkPDFDict pdfDict("XObject"); |
| 352 pdfDict.insertName("Subtype", "Image"); | 414 pdfDict.insertName("Subtype", "Image"); |
| 353 pdfDict.insertInt("Width", bitmap.width()); | 415 pdfDict.insertInt("Width", bitmap.width()); |
| 354 pdfDict.insertInt("Height", bitmap.height()); | 416 pdfDict.insertInt("Height", bitmap.height()); |
| 355 if (alpha) { | 417 if (alpha) { |
| 356 pdfDict.insertName("ColorSpace", "DeviceGray"); | 418 pdfDict.insertName("ColorSpace", "DeviceGray"); |
| 357 } else if (bitmap.colorType() == kIndex_8_SkColorType) { | 419 } else if (bitmap.colorType() == kIndex_8_SkColorType) { |
| 358 SkASSERT(1 == pdf_color_component_count(bitmap.colorType())); | 420 SkASSERT(1 == pdf_color_component_count(bitmap.colorType())); |
| 359 pdfDict.insertObject("ColorSpace", | 421 pdfDict.insertObject("ColorSpace", |
| 360 make_indexed_color_space(bitmap.getColorTable())); | 422 make_indexed_color_space(bitmap.getColorTable())); |
| 361 } else if (1 == pdf_color_component_count(bitmap.colorType())) { | 423 } else if (1 == pdf_color_component_count(bitmap.colorType())) { |
| 362 pdfDict.insertName("ColorSpace", "DeviceGray"); | 424 pdfDict.insertName("ColorSpace", "DeviceGray"); |
| 363 } else { | 425 } else { |
| 364 pdfDict.insertName("ColorSpace", "DeviceRGB"); | 426 pdfDict.insertName("ColorSpace", "DeviceRGB"); |
| 365 } | 427 } |
| 366 if (smask) { | 428 if (smask) { |
| 367 pdfDict.insertObjRef("SMask", SkRef(smask)); | 429 pdfDict.insertObjRef("SMask", SkRef(smask)); |
| 368 } | 430 } |
| 369 pdfDict.insertInt("BitsPerComponent", 8); | 431 pdfDict.insertInt("BitsPerComponent", 8); |
| 370 pdfDict.insertName("Filter", "FlateDecode"); | 432 pdfDict.insertName("Filter", "FlateDecode"); |
| 433 if (usePngPredictor) { |
| 434 SkAutoTUnref<SkPDFDict> params(new SkPDFDict); |
| 435 params->insertInt("BitsPerComponent", 8); |
| 436 params->insertInt("Predictor", 15); |
| 437 params->insertInt("Colors", alpha ? 1 : 3); |
| 438 params->insertInt("Columns", bitmap.width()); |
| 439 pdfDict.insertObject("DecodeParms", params.detach()); |
| 440 } |
| 371 pdfDict.insertInt("Length", asset->getLength()); | 441 pdfDict.insertInt("Length", asset->getLength()); |
| 372 pdfDict.emitObject(stream, objNumMap, substitutes); | 442 pdfDict.emitObject(stream, objNumMap, substitutes); |
| 373 | 443 |
| 374 pdf_stream_begin(stream); | 444 pdf_stream_begin(stream); |
| 375 stream->writeStream(asset.get(), asset->getLength()); | 445 stream->writeStream(asset.get(), asset->getLength()); |
| 376 pdf_stream_end(stream); | 446 pdf_stream_end(stream); |
| 377 } | 447 } |
| 378 | 448 |
| 379 //////////////////////////////////////////////////////////////////////////////// | 449 //////////////////////////////////////////////////////////////////////////////// |
| 380 | 450 |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 497 } | 567 } |
| 498 } | 568 } |
| 499 | 569 |
| 500 SkPDFObject* smask = | 570 SkPDFObject* smask = |
| 501 image_compute_is_opaque(image) ? nullptr : new PDFAlphaBitmap(image)
; | 571 image_compute_is_opaque(image) ? nullptr : new PDFAlphaBitmap(image)
; |
| 502 #ifdef SK_PDF_IMAGE_STATS | 572 #ifdef SK_PDF_IMAGE_STATS |
| 503 gRegularImageObjects.fetch_add(1); | 573 gRegularImageObjects.fetch_add(1); |
| 504 #endif | 574 #endif |
| 505 return new PDFDefaultBitmap(image, smask); | 575 return new PDFDefaultBitmap(image, smask); |
| 506 } | 576 } |
| OLD | NEW |