Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(256)

Side by Side Diff: src/pdf/SkPDFBitmap.cpp

Issue 1686313005: SkPDF: Implement Paeth predictor for images. (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: 2016-02-25 (Thursday) 14:57:16 EST Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « gyp/pdf.gypi ('k') | src/pdf/SkPngPredictors.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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, &copy); 242 const SkBitmap& bm = not4444(bitmap, &copy);
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, &copy); 311 const SkBitmap& bm = not4444(bitmap, &copy);
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
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
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 }
OLDNEW
« no previous file with comments | « gyp/pdf.gypi ('k') | src/pdf/SkPngPredictors.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698