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

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-19 (Friday) 15:12:05 EST Created 4 years, 10 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
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 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, &copy); 212 const SkBitmap& bm = not4444(bitmap, &copy);
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, &copy); 281 const SkBitmap& bm = not4444(bitmap, &copy);
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
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
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 }
OLDNEW
« no previous file with comments | « gyp/pdf.gypi ('k') | src/pdf/SkPngPredictors.h » ('j') | src/pdf/SkPngPredictors.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698