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

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

Issue 1372783003: SkPDF: Implement drawImage*() properly (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: 2015-09-29 (Tuesday) 14:09:03 EDT Created 5 years, 2 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 "SkImageGenerator.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 "SkPixelRef.h"
16 #include "SkStream.h" 15 #include "SkStream.h"
17 #include "SkUnPreMultiply.h" 16 #include "SkUnPreMultiply.h"
18 17
18 void image_get_ro_pixels(const SkImage* image, SkBitmap* dst) {
19 if(as_IB(image)->getROPixels(dst)
20 && dst->dimensions() == image->dimensions()) {
21 return;
22 }
23 // no pixels or wrong size: fill with zeros.
24 SkAlphaType at = image->isOpaque() ? kOpaque_SkAlphaType : kPremul_SkAlphaTy pe;
25 dst->setInfo(SkImageInfo::MakeN32(image->width(), image->height(), at));
26 }
27
19 //////////////////////////////////////////////////////////////////////////////// 28 ////////////////////////////////////////////////////////////////////////////////
20 29
21 static void pdf_stream_begin(SkWStream* stream) { 30 static void pdf_stream_begin(SkWStream* stream) {
22 static const char streamBegin[] = " stream\n"; 31 static const char streamBegin[] = " stream\n";
23 stream->write(streamBegin, strlen(streamBegin)); 32 stream->write(streamBegin, strlen(streamBegin));
24 } 33 }
25 34
26 static void pdf_stream_end(SkWStream* stream) { 35 static void pdf_stream_end(SkWStream* stream) {
27 static const char streamEnd[] = "\nendstream"; 36 static const char streamEnd[] = "\nendstream";
28 stream->write(streamEnd, strlen(streamEnd)); 37 stream->write(streamEnd, strlen(streamEnd));
(...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after
238 SkDEBUGFAIL("unexpected color type"); 247 SkDEBUGFAIL("unexpected color type");
239 } 248 }
240 } 249 }
241 250
242 //////////////////////////////////////////////////////////////////////////////// 251 ////////////////////////////////////////////////////////////////////////////////
243 252
244 namespace { 253 namespace {
245 // This SkPDFObject only outputs the alpha layer of the given bitmap. 254 // This SkPDFObject only outputs the alpha layer of the given bitmap.
246 class PDFAlphaBitmap : public SkPDFObject { 255 class PDFAlphaBitmap : public SkPDFObject {
247 public: 256 public:
248 PDFAlphaBitmap(const SkBitmap& bm) : fBitmap(bm) {} 257 PDFAlphaBitmap(const SkImage* image) : fImage(SkRef(image)) {}
249 ~PDFAlphaBitmap() {} 258 ~PDFAlphaBitmap() {}
250 void emitObject(SkWStream*, 259 void emitObject(SkWStream*,
251 const SkPDFObjNumMap&, 260 const SkPDFObjNumMap&,
252 const SkPDFSubstituteMap&) const override; 261 const SkPDFSubstituteMap&) const override;
253 262
254 private: 263 private:
255 const SkBitmap fBitmap; 264 SkAutoTUnref<const SkImage> fImage;
256 }; 265 };
257 266
258 void PDFAlphaBitmap::emitObject(SkWStream* stream, 267 void PDFAlphaBitmap::emitObject(SkWStream* stream,
259 const SkPDFObjNumMap& objNumMap, 268 const SkPDFObjNumMap& objNumMap,
260 const SkPDFSubstituteMap& substitutes) const { 269 const SkPDFSubstituteMap& substitutes) const {
261 SkAutoLockPixels autoLockPixels(fBitmap); 270 SkBitmap bitmap;
262 SkASSERT(fBitmap.colorType() != kIndex_8_SkColorType || 271 image_get_ro_pixels(fImage, &bitmap);
263 fBitmap.getColorTable()); 272 SkAutoLockPixels autoLockPixels(bitmap);
273 SkASSERT(bitmap.colorType() != kIndex_8_SkColorType ||
274 bitmap.getColorTable());
264 275
265 // Write to a temporary buffer to get the compressed length. 276 // Write to a temporary buffer to get the compressed length.
266 SkDynamicMemoryWStream buffer; 277 SkDynamicMemoryWStream buffer;
267 SkDeflateWStream deflateWStream(&buffer); 278 SkDeflateWStream deflateWStream(&buffer);
268 bitmap_alpha_to_a8(fBitmap, &deflateWStream); 279 bitmap_alpha_to_a8(bitmap, &deflateWStream);
269 deflateWStream.finalize(); // call before detachAsStream(). 280 deflateWStream.finalize(); // call before detachAsStream().
270 SkAutoTDelete<SkStreamAsset> asset(buffer.detachAsStream()); 281 SkAutoTDelete<SkStreamAsset> asset(buffer.detachAsStream());
271 282
272 SkPDFDict pdfDict("XObject"); 283 SkPDFDict pdfDict("XObject");
273 pdfDict.insertName("Subtype", "Image"); 284 pdfDict.insertName("Subtype", "Image");
274 pdfDict.insertInt("Width", fBitmap.width()); 285 pdfDict.insertInt("Width", bitmap.width());
275 pdfDict.insertInt("Height", fBitmap.height()); 286 pdfDict.insertInt("Height", bitmap.height());
276 pdfDict.insertName("ColorSpace", "DeviceGray"); 287 pdfDict.insertName("ColorSpace", "DeviceGray");
277 pdfDict.insertInt("BitsPerComponent", 8); 288 pdfDict.insertInt("BitsPerComponent", 8);
278 pdfDict.insertName("Filter", "FlateDecode"); 289 pdfDict.insertName("Filter", "FlateDecode");
279 pdfDict.insertInt("Length", asset->getLength()); 290 pdfDict.insertInt("Length", asset->getLength());
280 pdfDict.emitObject(stream, objNumMap, substitutes); 291 pdfDict.emitObject(stream, objNumMap, substitutes);
281 292
282 pdf_stream_begin(stream); 293 pdf_stream_begin(stream);
283 stream->writeStream(asset.get(), asset->getLength()); 294 stream->writeStream(asset.get(), asset->getLength());
284 pdf_stream_end(stream); 295 pdf_stream_end(stream);
285 } 296 }
286 } // namespace 297 } // namespace
287 298
288 //////////////////////////////////////////////////////////////////////////////// 299 ////////////////////////////////////////////////////////////////////////////////
289 300
290 namespace { 301 namespace {
291 class PDFDefaultBitmap : public SkPDFBitmap { 302 class PDFDefaultBitmap : public SkPDFObject {
292 public: 303 public:
293 const SkAutoTUnref<SkPDFObject> fSMask;
294 void emitObject(SkWStream*, 304 void emitObject(SkWStream*,
295 const SkPDFObjNumMap&, 305 const SkPDFObjNumMap&,
296 const SkPDFSubstituteMap&) const override; 306 const SkPDFSubstituteMap&) const override;
297 void addResources(SkPDFObjNumMap*, 307 void addResources(SkPDFObjNumMap*,
298 const SkPDFSubstituteMap&) const override; 308 const SkPDFSubstituteMap&) const override;
299 PDFDefaultBitmap(const SkBitmap& bm, SkPDFObject* smask) 309 PDFDefaultBitmap(const SkImage* image, SkPDFObject* smask)
300 : SkPDFBitmap(bm), fSMask(smask) {} 310 : fImage(SkRef(image)), fSMask(smask) {}
311
312 private:
313 SkAutoTUnref<const SkImage> fImage;
314 const SkAutoTUnref<SkPDFObject> fSMask;
301 }; 315 };
302 } // namespace 316 } // namespace
303 317
304 void PDFDefaultBitmap::addResources( 318 void PDFDefaultBitmap::addResources(
305 SkPDFObjNumMap* catalog, 319 SkPDFObjNumMap* catalog,
306 const SkPDFSubstituteMap& substitutes) const { 320 const SkPDFSubstituteMap& substitutes) const {
307 if (fSMask.get()) { 321 if (fSMask.get()) {
308 SkPDFObject* obj = substitutes.getSubstitute(fSMask.get()); 322 SkPDFObject* obj = substitutes.getSubstitute(fSMask.get());
309 SkASSERT(obj); 323 SkASSERT(obj);
310 if (catalog->addObject(obj)) { 324 if (catalog->addObject(obj)) {
(...skipping 25 matching lines...) Expand all
336 const SkPMColor* colors = table->readColors(); 350 const SkPMColor* colors = table->readColors();
337 for (int i = 0; i < table->count(); i++) { 351 for (int i = 0; i < table->count(); i++) {
338 pmcolor_to_rgb24(colors[i], tablePtr); 352 pmcolor_to_rgb24(colors[i], tablePtr);
339 tablePtr += 3; 353 tablePtr += 3;
340 } 354 }
341 SkString tableString(tableArray, 3 * table->count()); 355 SkString tableString(tableArray, 3 * table->count());
342 result->appendString(tableString); 356 result->appendString(tableString);
343 return result; 357 return result;
344 } 358 }
345 359
346 void PDFDefaultBitmap::emitObject(SkWStream* stream, 360 void PDFDefaultBitmap::emitObject(SkWStream* stream,
tomhudson 2015/09/30 16:10:29 There's a lot of redundancy between this and PDFAl
hal.canary 2015/10/01 01:24:55 Done.
347 const SkPDFObjNumMap& objNumMap, 361 const SkPDFObjNumMap& objNumMap,
348 const SkPDFSubstituteMap& substitutes) const { 362 const SkPDFSubstituteMap& substitutes) const {
349 SkAutoLockPixels autoLockPixels(fBitmap); 363 SkBitmap bitmap;
350 SkASSERT(fBitmap.colorType() != kIndex_8_SkColorType || 364 image_get_ro_pixels(fImage, &bitmap); // TODO(halcanary): test
tomhudson 2015/09/30 16:10:29 note TODO?
hal.canary 2015/10/01 01:24:55 Acknowledged.
351 fBitmap.getColorTable()); 365 SkAutoLockPixels autoLockPixels(bitmap); // with malformed images?
366 SkASSERT(bitmap.colorType() != kIndex_8_SkColorType ||
367 bitmap.getColorTable());
352 368
353 // Write to a temporary buffer to get the compressed length. 369 // Write to a temporary buffer to get the compressed length.
354 SkDynamicMemoryWStream buffer; 370 SkDynamicMemoryWStream buffer;
355 SkDeflateWStream deflateWStream(&buffer); 371 SkDeflateWStream deflateWStream(&buffer);
356 bitmap_to_pdf_pixels(fBitmap, &deflateWStream); 372 bitmap_to_pdf_pixels(bitmap, &deflateWStream);
357 deflateWStream.finalize(); // call before detachAsStream(). 373 deflateWStream.finalize(); // call before detachAsStream().
358 SkAutoTDelete<SkStreamAsset> asset(buffer.detachAsStream()); 374 SkAutoTDelete<SkStreamAsset> asset(buffer.detachAsStream());
359 375
360 SkPDFDict pdfDict("XObject"); 376 SkPDFDict pdfDict("XObject");
361 pdfDict.insertName("Subtype", "Image"); 377 pdfDict.insertName("Subtype", "Image");
362 pdfDict.insertInt("Width", fBitmap.width()); 378 pdfDict.insertInt("Width", bitmap.width());
363 pdfDict.insertInt("Height", fBitmap.height()); 379 pdfDict.insertInt("Height", bitmap.height());
364 if (fBitmap.colorType() == kIndex_8_SkColorType) { 380 if (bitmap.colorType() == kIndex_8_SkColorType) {
365 SkASSERT(1 == pdf_color_component_count(fBitmap.colorType())); 381 SkASSERT(1 == pdf_color_component_count(bitmap.colorType()));
366 pdfDict.insertObject("ColorSpace", 382 pdfDict.insertObject("ColorSpace",
367 make_indexed_color_space(fBitmap.getColorTable())); 383 make_indexed_color_space(bitmap.getColorTable()));
368 } else if (1 == pdf_color_component_count(fBitmap.colorType())) { 384 } else if (1 == pdf_color_component_count(bitmap.colorType())) {
369 pdfDict.insertName("ColorSpace", "DeviceGray"); 385 pdfDict.insertName("ColorSpace", "DeviceGray");
370 } else { 386 } else {
371 pdfDict.insertName("ColorSpace", "DeviceRGB"); 387 pdfDict.insertName("ColorSpace", "DeviceRGB");
372 } 388 }
373 pdfDict.insertInt("BitsPerComponent", 8); 389 pdfDict.insertInt("BitsPerComponent", 8);
374 if (fSMask) { 390 if (fSMask) {
375 pdfDict.insertObjRef("SMask", SkRef(fSMask.get())); 391 pdfDict.insertObjRef("SMask", SkRef(fSMask.get()));
376 } 392 }
377 pdfDict.insertName("Filter", "FlateDecode"); 393 pdfDict.insertName("Filter", "FlateDecode");
378 pdfDict.insertInt("Length", asset->getLength()); 394 pdfDict.insertInt("Length", asset->getLength());
379 pdfDict.emitObject(stream, objNumMap, substitutes); 395 pdfDict.emitObject(stream, objNumMap, substitutes);
380 396
381 pdf_stream_begin(stream); 397 pdf_stream_begin(stream);
382 stream->writeStream(asset.get(), asset->getLength()); 398 stream->writeStream(asset.get(), asset->getLength());
383 pdf_stream_end(stream); 399 pdf_stream_end(stream);
384 } 400 }
385 401
386 //////////////////////////////////////////////////////////////////////////////// 402 ////////////////////////////////////////////////////////////////////////////////
387 403
388 static const SkBitmap& immutable_bitmap(const SkBitmap& bm, SkBitmap* copy) {
389 if (bm.isImmutable()) {
390 return bm;
391 }
392 bm.copyTo(copy);
393 copy->setImmutable();
394 return *copy;
395 }
396
397 namespace { 404 namespace {
398 /** 405 /**
399 * This PDFObject assumes that its constructor was handed YUV JFIF 406 * This PDFObject assumes that its constructor was handed YUV or
400 * Jpeg-encoded data that can be directly embedded into a PDF. 407 * Grayscale JFIF Jpeg-encoded data that can be directly embedded
408 * into a PDF.
401 */ 409 */
402 class PDFJpegBitmap : public SkPDFBitmap { 410 class PDFJpegBitmap : public SkPDFObject {
403 public: 411 public:
412 SkISize fSize;
404 SkAutoTUnref<SkData> fData; 413 SkAutoTUnref<SkData> fData;
405 bool fIsYUV; 414 bool fIsYUV;
406 PDFJpegBitmap(const SkBitmap& bm, SkData* data, bool isYUV) 415 PDFJpegBitmap(SkISize size, SkData* data, bool isYUV)
407 : SkPDFBitmap(bm), fData(SkRef(data)), fIsYUV(isYUV) {} 416 : fSize(size), fData(SkRef(data)), fIsYUV(isYUV) {}
408 void emitObject(SkWStream*, 417 void emitObject(SkWStream*,
409 const SkPDFObjNumMap&, 418 const SkPDFObjNumMap&,
410 const SkPDFSubstituteMap&) const override; 419 const SkPDFSubstituteMap&) const override;
411 }; 420 };
412 421
413 void PDFJpegBitmap::emitObject(SkWStream* stream, 422 void PDFJpegBitmap::emitObject(SkWStream* stream,
414 const SkPDFObjNumMap& objNumMap, 423 const SkPDFObjNumMap& objNumMap,
415 const SkPDFSubstituteMap& substituteMap) const { 424 const SkPDFSubstituteMap& substituteMap) const {
416 SkPDFDict pdfDict("XObject"); 425 SkPDFDict pdfDict("XObject");
417 pdfDict.insertName("Subtype", "Image"); 426 pdfDict.insertName("Subtype", "Image");
418 pdfDict.insertInt("Width", fBitmap.width()); 427 pdfDict.insertInt("Width", fSize.width());
419 pdfDict.insertInt("Height", fBitmap.height()); 428 pdfDict.insertInt("Height", fSize.height());
420 if (fIsYUV) { 429 if (fIsYUV) {
421 pdfDict.insertName("ColorSpace", "DeviceRGB"); 430 pdfDict.insertName("ColorSpace", "DeviceRGB");
422 } else { 431 } else {
423 pdfDict.insertName("ColorSpace", "DeviceGray"); 432 pdfDict.insertName("ColorSpace", "DeviceGray");
424 } 433 }
425 pdfDict.insertInt("BitsPerComponent", 8); 434 pdfDict.insertInt("BitsPerComponent", 8);
426 pdfDict.insertName("Filter", "DCTDecode"); 435 pdfDict.insertName("Filter", "DCTDecode");
427 pdfDict.insertInt("ColorTransform", 0); 436 pdfDict.insertInt("ColorTransform", 0);
428 pdfDict.insertInt("Length", SkToInt(fData->size())); 437 pdfDict.insertInt("Length", SkToInt(fData->size()));
429 pdfDict.emitObject(stream, objNumMap, substituteMap); 438 pdfDict.emitObject(stream, objNumMap, substituteMap);
430 pdf_stream_begin(stream); 439 pdf_stream_begin(stream);
431 stream->write(fData->data(), fData->size()); 440 stream->write(fData->data(), fData->size());
432 pdf_stream_end(stream); 441 pdf_stream_end(stream);
433 } 442 }
434 } // namespace 443 } // namespace
435 444
436 //////////////////////////////////////////////////////////////////////////////// 445 ////////////////////////////////////////////////////////////////////////////////
437 446
438 SkPDFBitmap* SkPDFBitmap::Create(SkPDFCanon* canon, const SkBitmap& bitmap) { 447 SkPDFObject* SkPDFCreateBitmapObject(const SkImage* image) {
439 SkASSERT(canon); 448 SkAutoTUnref<SkData> data(image->refEncoded());
440 if (!SkColorTypeIsValid(bitmap.colorType()) || 449 SkJFIFInfo info;
441 kUnknown_SkColorType == bitmap.colorType()) { 450 if (data && SkIsJFIF(data, &info)) {
442 return nullptr; 451 bool yuv = info.fType == SkJFIFInfo::kYCbCr;
443 } 452 if (info.fSize == image->dimensions()) { // Sanity check.
444 SkBitmap copy; 453 // hold on to data, not image.
445 const SkBitmap& bm = immutable_bitmap(bitmap, &copy); 454 #ifdef SK_PDF_IMAGE_STATS
446 if (bm.drawsNothing()) { 455 gJpegImageObjects.fetch_add(1);
447 return nullptr; 456 #endif
448 } 457 return new PDFJpegBitmap(info.fSize, data, yuv);
449 if (SkPDFBitmap* canonBitmap = canon->findBitmap(bm)) {
450 return SkRef(canonBitmap);
451 }
452
453 if (bm.pixelRef() && bm.pixelRefOrigin().isZero() &&
454 bm.dimensions() == bm.pixelRef()->info().dimensions()) {
455 // Requires the bitmap to be backed by lazy pixels.
456 SkAutoTUnref<SkData> data(bm.pixelRef()->refEncodedData());
457 SkJFIFInfo info;
458 if (data && SkIsJFIF(data, &info)) {
459 bool yuv = info.fType == SkJFIFInfo::kYCbCr;
460 SkPDFBitmap* pdfBitmap = new PDFJpegBitmap(bm, data, yuv);
461 canon->addBitmap(pdfBitmap);
462 return pdfBitmap;
463 } 458 }
464 } 459 }
465 460 SkPDFObject* smask =
466 SkPDFObject* smask = nullptr; 461 image->isOpaque() ? nullptr : new PDFAlphaBitmap(image);
467 if (!bm.isOpaque() && !SkBitmap::ComputeIsOpaque(bm)) { 462 #ifdef SK_PDF_IMAGE_STATS
468 smask = new PDFAlphaBitmap(bm); 463 gRegularImageObjects.fetch_add(1);
469 } 464 #endif
470 SkPDFBitmap* pdfBitmap = new PDFDefaultBitmap(bm, smask); 465 return new PDFDefaultBitmap(image, smask);
471 canon->addBitmap(pdfBitmap);
472 return pdfBitmap;
473 } 466 }
OLDNEW
« no previous file with comments | « src/pdf/SkPDFBitmap.h ('k') | src/pdf/SkPDFCanon.h » ('j') | src/pdf/SkPDFDevice.cpp » ('J')

Powered by Google App Engine
This is Rietveld 408576698