| 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 namespace { |
| 177 template<int COMPONENT_COUNT, void(*FN)(int, const uint8_t*, const uint8_t*, uin
t8_t*)> |
| 178 class PngPredictor { |
| 179 public: |
| 180 PngPredictor(int widthInPixels) |
| 181 : fBuffer(2 * (COMPONENT_COUNT * widthInPixels + 1)) |
| 182 , fWidth(widthInPixels) |
| 183 , fFirstline(true) { |
| 184 fScanline = fBuffer.get(); |
| 185 fPrevScanline = &fScanline[COMPONENT_COUNT * widthInPixels + 1]; |
| 186 } |
| 187 uint8_t* scanline() { return &fScanline[1]; } |
| 188 void write(SkWStream* out) { |
| 189 fPrevScanline[0] = 4; |
| 190 FN(fWidth, fFirstline ? nullptr : &fPrevScanline[1], &fScanline[1], &fPr
evScanline[1]); |
| 191 out->write(fPrevScanline, COMPONENT_COUNT * fWidth + 1); |
| 192 SkTSwap(fScanline, fPrevScanline); |
| 193 fFirstline = false; |
| 194 } |
| 195 private: |
| 196 SkAutoTMalloc<uint8_t> fBuffer; |
| 197 uint8_t* fScanline; |
| 198 uint8_t* fPrevScanline; |
| 199 int fWidth; |
| 200 bool fFirstline; |
| 201 }; |
| 202 } // namespace |
| 203 |
| 204 static bool bitmap_to_pdf_pixels(const SkBitmap& bitmap, SkWStream* out) { |
| 176 if (!bitmap.getPixels()) { | 205 if (!bitmap.getPixels()) { |
| 177 size_t size = pixel_count(bitmap) * | 206 size_t size = pixel_count(bitmap) * |
| 178 pdf_color_component_count(bitmap.colorType()); | 207 pdf_color_component_count(bitmap.colorType()); |
| 179 fill_stream(out, '\x00', size); | 208 fill_stream(out, '\x00', size); |
| 180 return; | 209 return false; |
| 181 } | 210 } |
| 182 SkBitmap copy; | 211 SkBitmap copy; |
| 183 const SkBitmap& bm = not4444(bitmap, ©); | 212 const SkBitmap& bm = not4444(bitmap, ©); |
| 184 SkAutoLockPixels autoLockPixels(bm); | 213 SkAutoLockPixels autoLockPixels(bm); |
| 185 SkColorType colorType = bm.colorType(); | 214 SkColorType colorType = bm.colorType(); |
| 186 switch (colorType) { | 215 switch (colorType) { |
| 187 case kRGBA_8888_SkColorType: | 216 case kRGBA_8888_SkColorType: |
| 188 case kBGRA_8888_SkColorType: { | 217 case kBGRA_8888_SkColorType: { |
| 189 SkASSERT(3 == pdf_color_component_count(colorType)); | 218 SkASSERT(3 == pdf_color_component_count(colorType)); |
| 190 SkAutoTMalloc<uint8_t> scanline(3 * bm.width()); | 219 PngPredictor<3, SkPaethEncode3> paether(bm.width()); |
| 191 for (int y = 0; y < bm.height(); ++y) { | 220 for (int y = 0; y < bm.height(); ++y) { |
| 192 const uint32_t* src = bm.getAddr32(0, y); | 221 const uint32_t* src = bm.getAddr32(0, y); |
| 193 uint8_t* dst = scanline.get(); | 222 uint8_t* dst = paether.scanline(); |
| 194 for (int x = 0; x < bm.width(); ++x) { | 223 for (int x = 0; x < bm.width(); ++x) { |
| 195 uint32_t color = *src++; | 224 uint32_t color = *src++; |
| 196 U8CPU alpha = SkGetA32Component(color, colorType); | 225 U8CPU alpha = SkGetA32Component(color, colorType); |
| 197 if (alpha != SK_AlphaTRANSPARENT) { | 226 if (alpha != SK_AlphaTRANSPARENT) { |
| 198 pmcolor_to_rgb24(color, dst, colorType); | 227 pmcolor_to_rgb24(color, dst, colorType); |
| 199 } else { | 228 } else { |
| 200 get_neighbor_avg_color(bm, x, y, dst, colorType); | 229 get_neighbor_avg_color(bm, x, y, dst, colorType); |
| 201 } | 230 } |
| 202 dst += 3; | 231 dst += 3; |
| 203 } | 232 } |
| 204 out->write(scanline.get(), 3 * bm.width()); | 233 paether.write(out); |
| 205 } | 234 } |
| 206 return; | 235 return true; |
| 207 } | 236 } |
| 208 case kRGB_565_SkColorType: { | 237 case kRGB_565_SkColorType: { |
| 209 SkASSERT(3 == pdf_color_component_count(colorType)); | 238 SkASSERT(3 == pdf_color_component_count(colorType)); |
| 210 SkAutoTMalloc<uint8_t> scanline(3 * bm.width()); | 239 PngPredictor<3, SkPaethEncode3> paether(bm.width()); |
| 211 for (int y = 0; y < bm.height(); ++y) { | 240 for (int y = 0; y < bm.height(); ++y) { |
| 212 const uint16_t* src = bm.getAddr16(0, y); | 241 const uint16_t* src = bm.getAddr16(0, y); |
| 213 uint8_t* dst = scanline.get(); | 242 uint8_t* dst = paether.scanline(); |
| 214 for (int x = 0; x < bm.width(); ++x) { | 243 for (int x = 0; x < bm.width(); ++x) { |
| 215 U16CPU color565 = *src++; | 244 U16CPU color565 = *src++; |
| 216 *dst++ = SkPacked16ToR32(color565); | 245 *dst++ = SkPacked16ToR32(color565); |
| 217 *dst++ = SkPacked16ToG32(color565); | 246 *dst++ = SkPacked16ToG32(color565); |
| 218 *dst++ = SkPacked16ToB32(color565); | 247 *dst++ = SkPacked16ToB32(color565); |
| 219 } | 248 } |
| 220 out->write(scanline.get(), 3 * bm.width()); | 249 paether.write(out); |
| 221 } | 250 } |
| 222 return; | 251 return true; |
| 223 } | 252 } |
| 224 case kAlpha_8_SkColorType: | 253 case kAlpha_8_SkColorType: |
| 225 SkASSERT(1 == pdf_color_component_count(colorType)); | 254 SkASSERT(1 == pdf_color_component_count(colorType)); |
| 226 fill_stream(out, '\x00', pixel_count(bm)); | 255 fill_stream(out, '\x00', pixel_count(bm)); |
| 227 return; | 256 return false; |
| 228 case kGray_8_SkColorType: | 257 case kGray_8_SkColorType: |
| 229 case kIndex_8_SkColorType: | 258 case kIndex_8_SkColorType: |
| 230 SkASSERT(1 == pdf_color_component_count(colorType)); | 259 SkASSERT(1 == pdf_color_component_count(colorType)); |
| 231 // these two formats need no transformation to serialize. | 260 // these two formats need no transformation to serialize. |
| 232 for (int y = 0; y < bm.height(); ++y) { | 261 for (int y = 0; y < bm.height(); ++y) { |
| 233 out->write(bm.getAddr8(0, y), bm.width()); | 262 out->write(bm.getAddr8(0, y), bm.width()); |
| 234 } | 263 } |
| 235 return; | 264 return false; |
| 236 case kUnknown_SkColorType: | 265 case kUnknown_SkColorType: |
| 237 case kARGB_4444_SkColorType: | 266 case kARGB_4444_SkColorType: |
| 238 default: | 267 default: |
| 239 SkDEBUGFAIL("unexpected color type"); | 268 SkDEBUGFAIL("unexpected color type"); |
| 269 return false; |
| 240 } | 270 } |
| 241 } | 271 } |
| 242 | 272 |
| 243 //////////////////////////////////////////////////////////////////////////////// | 273 //////////////////////////////////////////////////////////////////////////////// |
| 244 | 274 |
| 245 static void bitmap_alpha_to_a8(const SkBitmap& bitmap, SkWStream* out) { | 275 static bool bitmap_alpha_to_a8(const SkBitmap& bitmap, SkWStream* out) { |
| 246 if (!bitmap.getPixels()) { | 276 if (!bitmap.getPixels()) { |
| 247 fill_stream(out, '\xFF', pixel_count(bitmap)); | 277 fill_stream(out, '\xFF', pixel_count(bitmap)); |
| 248 return; | 278 return false; |
| 249 } | 279 } |
| 250 SkBitmap copy; | 280 SkBitmap copy; |
| 251 const SkBitmap& bm = not4444(bitmap, ©); | 281 const SkBitmap& bm = not4444(bitmap, ©); |
| 252 SkAutoLockPixels autoLockPixels(bm); | 282 SkAutoLockPixels autoLockPixels(bm); |
| 253 SkColorType colorType = bm.colorType(); | 283 SkColorType colorType = bm.colorType(); |
| 254 switch (colorType) { | 284 switch (colorType) { |
| 255 case kRGBA_8888_SkColorType: | 285 case kRGBA_8888_SkColorType: |
| 256 case kBGRA_8888_SkColorType: { | 286 case kBGRA_8888_SkColorType: { |
| 257 SkAutoTMalloc<uint8_t> scanline(bm.width()); | 287 PngPredictor<1, SkPaethEncode1> paether(bm.width()); |
| 258 for (int y = 0; y < bm.height(); ++y) { | 288 for (int y = 0; y < bm.height(); ++y) { |
| 259 uint8_t* dst = scanline.get(); | 289 uint8_t* dst = paether.scanline(); |
| 260 const SkPMColor* src = bm.getAddr32(0, y); | 290 const SkPMColor* src = bm.getAddr32(0, y); |
| 261 for (int x = 0; x < bm.width(); ++x) { | 291 for (int x = 0; x < bm.width(); ++x) { |
| 262 *dst++ = SkGetA32Component(*src++, colorType); | 292 *dst++ = SkGetA32Component(*src++, colorType); |
| 263 } | 293 } |
| 264 out->write(scanline.get(), bm.width()); | 294 paether.write(out); |
| 265 } | 295 } |
| 266 return; | 296 return true; |
| 267 } | 297 } |
| 268 case kAlpha_8_SkColorType: | 298 case kAlpha_8_SkColorType: |
| 269 for (int y = 0; y < bm.height(); ++y) { | 299 for (int y = 0; y < bm.height(); ++y) { |
| 270 out->write(bm.getAddr8(0, y), bm.width()); | 300 out->write(bm.getAddr8(0, y), bm.width()); |
| 271 } | 301 } |
| 272 return; | 302 return false; |
| 273 case kIndex_8_SkColorType: { | 303 case kIndex_8_SkColorType: { |
| 274 SkColorTable* ct = bm.getColorTable(); | 304 SkColorTable* ct = bm.getColorTable(); |
| 275 SkASSERT(ct); | 305 SkASSERT(ct); |
| 276 SkAutoTMalloc<uint8_t> scanline(bm.width()); | 306 SkAutoTMalloc<uint8_t> scanline(bm.width()); |
| 277 for (int y = 0; y < bm.height(); ++y) { | 307 for (int y = 0; y < bm.height(); ++y) { |
| 278 uint8_t* dst = scanline.get(); | 308 uint8_t* dst = scanline.get(); |
| 279 const uint8_t* src = bm.getAddr8(0, y); | 309 const uint8_t* src = bm.getAddr8(0, y); |
| 280 for (int x = 0; x < bm.width(); ++x) { | 310 for (int x = 0; x < bm.width(); ++x) { |
| 281 *dst++ = SkGetPackedA32((*ct)[*src++]); | 311 *dst++ = SkGetPackedA32((*ct)[*src++]); |
| 282 } | 312 } |
| 283 out->write(scanline.get(), bm.width()); | 313 out->write(scanline.get(), bm.width()); |
| 284 } | 314 } |
| 285 return; | 315 return false; |
| 286 } | 316 } |
| 287 case kRGB_565_SkColorType: | 317 case kRGB_565_SkColorType: |
| 288 case kGray_8_SkColorType: | 318 case kGray_8_SkColorType: |
| 289 SkDEBUGFAIL("color type has no alpha"); | 319 SkDEBUGFAIL("color type has no alpha"); |
| 290 return; | 320 return false; |
| 291 case kARGB_4444_SkColorType: | 321 case kARGB_4444_SkColorType: |
| 292 SkDEBUGFAIL("4444 color type should have been converted to N32"); | 322 SkDEBUGFAIL("4444 color type should have been converted to N32"); |
| 293 return; | 323 return false; |
| 294 case kUnknown_SkColorType: | 324 case kUnknown_SkColorType: |
| 295 default: | 325 default: |
| 296 SkDEBUGFAIL("unexpected color type"); | 326 SkDEBUGFAIL("unexpected color type"); |
| 327 return false; |
| 297 } | 328 } |
| 298 } | 329 } |
| 299 | 330 |
| 300 static SkPDFArray* make_indexed_color_space(const SkColorTable* table) { | 331 static SkPDFArray* make_indexed_color_space(const SkColorTable* table) { |
| 301 SkPDFArray* result = new SkPDFArray; | 332 SkPDFArray* result = new SkPDFArray; |
| 302 result->reserve(4); | 333 result->reserve(4); |
| 303 result->appendName("Indexed"); | 334 result->appendName("Indexed"); |
| 304 result->appendName("DeviceRGB"); | 335 result->appendName("DeviceRGB"); |
| 305 SkASSERT(table); | 336 SkASSERT(table); |
| 306 if (table->count() < 1) { | 337 if (table->count() < 1) { |
| (...skipping 26 matching lines...) Expand all Loading... |
| 333 SkPDFObject* smask, | 364 SkPDFObject* smask, |
| 334 const SkPDFObjNumMap& objNumMap, | 365 const SkPDFObjNumMap& objNumMap, |
| 335 const SkPDFSubstituteMap& substitutes) { | 366 const SkPDFSubstituteMap& substitutes) { |
| 336 SkBitmap bitmap; | 367 SkBitmap bitmap; |
| 337 image_get_ro_pixels(image, &bitmap); // TODO(halcanary): test | 368 image_get_ro_pixels(image, &bitmap); // TODO(halcanary): test |
| 338 SkAutoLockPixels autoLockPixels(bitmap); // with malformed images. | 369 SkAutoLockPixels autoLockPixels(bitmap); // with malformed images. |
| 339 | 370 |
| 340 // Write to a temporary buffer to get the compressed length. | 371 // Write to a temporary buffer to get the compressed length. |
| 341 SkDynamicMemoryWStream buffer; | 372 SkDynamicMemoryWStream buffer; |
| 342 SkDeflateWStream deflateWStream(&buffer); | 373 SkDeflateWStream deflateWStream(&buffer); |
| 374 bool paethPredictor = false; |
| 343 if (alpha) { | 375 if (alpha) { |
| 344 bitmap_alpha_to_a8(bitmap, &deflateWStream); | 376 paethPredictor = bitmap_alpha_to_a8(bitmap, &deflateWStream); |
| 345 } else { | 377 } else { |
| 346 bitmap_to_pdf_pixels(bitmap, &deflateWStream); | 378 paethPredictor = bitmap_to_pdf_pixels(bitmap, &deflateWStream); |
| 347 } | 379 } |
| 348 deflateWStream.finalize(); // call before detachAsStream(). | 380 deflateWStream.finalize(); // call before detachAsStream(). |
| 349 SkAutoTDelete<SkStreamAsset> asset(buffer.detachAsStream()); | 381 SkAutoTDelete<SkStreamAsset> asset(buffer.detachAsStream()); |
| 350 | 382 |
| 351 SkPDFDict pdfDict("XObject"); | 383 SkPDFDict pdfDict("XObject"); |
| 352 pdfDict.insertName("Subtype", "Image"); | 384 pdfDict.insertName("Subtype", "Image"); |
| 353 pdfDict.insertInt("Width", bitmap.width()); | 385 pdfDict.insertInt("Width", bitmap.width()); |
| 354 pdfDict.insertInt("Height", bitmap.height()); | 386 pdfDict.insertInt("Height", bitmap.height()); |
| 355 if (alpha) { | 387 if (alpha) { |
| 356 pdfDict.insertName("ColorSpace", "DeviceGray"); | 388 pdfDict.insertName("ColorSpace", "DeviceGray"); |
| 357 } else if (bitmap.colorType() == kIndex_8_SkColorType) { | 389 } else if (bitmap.colorType() == kIndex_8_SkColorType) { |
| 358 SkASSERT(1 == pdf_color_component_count(bitmap.colorType())); | 390 SkASSERT(1 == pdf_color_component_count(bitmap.colorType())); |
| 359 pdfDict.insertObject("ColorSpace", | 391 pdfDict.insertObject("ColorSpace", |
| 360 make_indexed_color_space(bitmap.getColorTable())); | 392 make_indexed_color_space(bitmap.getColorTable())); |
| 361 } else if (1 == pdf_color_component_count(bitmap.colorType())) { | 393 } else if (1 == pdf_color_component_count(bitmap.colorType())) { |
| 362 pdfDict.insertName("ColorSpace", "DeviceGray"); | 394 pdfDict.insertName("ColorSpace", "DeviceGray"); |
| 363 } else { | 395 } else { |
| 364 pdfDict.insertName("ColorSpace", "DeviceRGB"); | 396 pdfDict.insertName("ColorSpace", "DeviceRGB"); |
| 365 } | 397 } |
| 366 if (smask) { | 398 if (smask) { |
| 367 pdfDict.insertObjRef("SMask", SkRef(smask)); | 399 pdfDict.insertObjRef("SMask", SkRef(smask)); |
| 368 } | 400 } |
| 369 pdfDict.insertInt("BitsPerComponent", 8); | 401 pdfDict.insertInt("BitsPerComponent", 8); |
| 370 pdfDict.insertName("Filter", "FlateDecode"); | 402 pdfDict.insertName("Filter", "FlateDecode"); |
| 403 if (paethPredictor) { |
| 404 SkAutoTUnref<SkPDFDict> params(new SkPDFDict); |
| 405 params->insertInt("BitsPerComponent", 8); |
| 406 params->insertInt("Predictor", 15); |
| 407 params->insertInt("Colors", alpha ? 1 : 3); |
| 408 params->insertInt("Columns", bitmap.width()); |
| 409 pdfDict.insertObject("DecodeParms", params.detach()); |
| 410 } |
| 371 pdfDict.insertInt("Length", asset->getLength()); | 411 pdfDict.insertInt("Length", asset->getLength()); |
| 372 pdfDict.emitObject(stream, objNumMap, substitutes); | 412 pdfDict.emitObject(stream, objNumMap, substitutes); |
| 373 | 413 |
| 374 pdf_stream_begin(stream); | 414 pdf_stream_begin(stream); |
| 375 stream->writeStream(asset.get(), asset->getLength()); | 415 stream->writeStream(asset.get(), asset->getLength()); |
| 376 pdf_stream_end(stream); | 416 pdf_stream_end(stream); |
| 377 } | 417 } |
| 378 | 418 |
| 379 //////////////////////////////////////////////////////////////////////////////// | 419 //////////////////////////////////////////////////////////////////////////////// |
| 380 | 420 |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 497 } | 537 } |
| 498 } | 538 } |
| 499 | 539 |
| 500 SkPDFObject* smask = | 540 SkPDFObject* smask = |
| 501 image_compute_is_opaque(image) ? nullptr : new PDFAlphaBitmap(image)
; | 541 image_compute_is_opaque(image) ? nullptr : new PDFAlphaBitmap(image)
; |
| 502 #ifdef SK_PDF_IMAGE_STATS | 542 #ifdef SK_PDF_IMAGE_STATS |
| 503 gRegularImageObjects.fetch_add(1); | 543 gRegularImageObjects.fetch_add(1); |
| 504 #endif | 544 #endif |
| 505 return new PDFDefaultBitmap(image, smask); | 545 return new PDFDefaultBitmap(image, smask); |
| 506 } | 546 } |
| OLD | NEW |