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 "SkFlate.h" | 10 #include "SkFlate.h" |
| 11 #include "SkImageGenerator.h" |
10 #include "SkPDFBitmap.h" | 12 #include "SkPDFBitmap.h" |
11 #include "SkPDFCanon.h" | 13 #include "SkPDFCanon.h" |
| 14 #include "SkPixelRef.h" |
12 #include "SkStream.h" | 15 #include "SkStream.h" |
13 #include "SkUnPreMultiply.h" | 16 #include "SkUnPreMultiply.h" |
14 | 17 |
15 //////////////////////////////////////////////////////////////////////////////// | 18 //////////////////////////////////////////////////////////////////////////////// |
16 | 19 |
17 static void pdf_stream_begin(SkWStream* stream) { | 20 static void pdf_stream_begin(SkWStream* stream) { |
18 static const char streamBegin[] = " stream\n"; | 21 static const char streamBegin[] = " stream\n"; |
19 stream->write(streamBegin, strlen(streamBegin)); | 22 stream->write(streamBegin, strlen(streamBegin)); |
20 } | 23 } |
21 | 24 |
(...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
276 pdfDict.emitObject(stream, objNumMap, substitutes); | 279 pdfDict.emitObject(stream, objNumMap, substitutes); |
277 | 280 |
278 pdf_stream_begin(stream); | 281 pdf_stream_begin(stream); |
279 stream->writeStream(asset.get(), asset->getLength()); | 282 stream->writeStream(asset.get(), asset->getLength()); |
280 pdf_stream_end(stream); | 283 pdf_stream_end(stream); |
281 } | 284 } |
282 } // namespace | 285 } // namespace |
283 | 286 |
284 //////////////////////////////////////////////////////////////////////////////// | 287 //////////////////////////////////////////////////////////////////////////////// |
285 | 288 |
286 void SkPDFBitmap::addResources(SkPDFObjNumMap* catalog, | 289 namespace { |
287 const SkPDFSubstituteMap& substitutes) const { | 290 class PDFDefaultBitmap : public SkPDFBitmap { |
| 291 public: |
| 292 const SkAutoTUnref<SkPDFObject> fSMask; |
| 293 void emitObject(SkWStream*, |
| 294 const SkPDFObjNumMap&, |
| 295 const SkPDFSubstituteMap&) override; |
| 296 void addResources(SkPDFObjNumMap*, |
| 297 const SkPDFSubstituteMap&) const override; |
| 298 PDFDefaultBitmap(const SkBitmap& bm, SkPDFObject* smask) |
| 299 : SkPDFBitmap(bm), fSMask(smask) {} |
| 300 }; |
| 301 } // namespace |
| 302 |
| 303 void PDFDefaultBitmap::addResources( |
| 304 SkPDFObjNumMap* catalog, |
| 305 const SkPDFSubstituteMap& substitutes) const { |
288 if (fSMask.get()) { | 306 if (fSMask.get()) { |
289 SkPDFObject* obj = substitutes.getSubstitute(fSMask.get()); | 307 SkPDFObject* obj = substitutes.getSubstitute(fSMask.get()); |
290 SkASSERT(obj); | 308 SkASSERT(obj); |
291 if (catalog->addObject(obj)) { | 309 if (catalog->addObject(obj)) { |
292 obj->addResources(catalog, substitutes); | 310 obj->addResources(catalog, substitutes); |
293 } | 311 } |
294 } | 312 } |
295 } | 313 } |
296 | 314 |
297 static SkPDFArray* make_indexed_color_space(const SkColorTable* table) { | 315 static SkPDFArray* make_indexed_color_space(const SkColorTable* table) { |
(...skipping 19 matching lines...) Expand all Loading... |
317 const SkPMColor* colors = table->readColors(); | 335 const SkPMColor* colors = table->readColors(); |
318 for (int i = 0; i < table->count(); i++) { | 336 for (int i = 0; i < table->count(); i++) { |
319 pmcolor_to_rgb24(colors[i], tablePtr); | 337 pmcolor_to_rgb24(colors[i], tablePtr); |
320 tablePtr += 3; | 338 tablePtr += 3; |
321 } | 339 } |
322 SkString tableString(tableArray, 3 * table->count()); | 340 SkString tableString(tableArray, 3 * table->count()); |
323 result->append(new SkPDFString(tableString))->unref(); | 341 result->append(new SkPDFString(tableString))->unref(); |
324 return result; | 342 return result; |
325 } | 343 } |
326 | 344 |
327 void SkPDFBitmap::emitObject(SkWStream* stream, | 345 void PDFDefaultBitmap::emitObject(SkWStream* stream, |
328 const SkPDFObjNumMap& objNumMap, | 346 const SkPDFObjNumMap& objNumMap, |
329 const SkPDFSubstituteMap& substitutes) { | 347 const SkPDFSubstituteMap& substitutes) { |
330 SkAutoLockPixels autoLockPixels(fBitmap); | 348 SkAutoLockPixels autoLockPixels(fBitmap); |
331 SkASSERT(fBitmap.colorType() != kIndex_8_SkColorType || | 349 SkASSERT(fBitmap.colorType() != kIndex_8_SkColorType || |
332 fBitmap.getColorTable()); | 350 fBitmap.getColorTable()); |
333 | 351 |
334 // Write to a temporary buffer to get the compressed length. | 352 // Write to a temporary buffer to get the compressed length. |
335 SkDynamicMemoryWStream buffer; | 353 SkDynamicMemoryWStream buffer; |
336 SkDeflateWStream deflateWStream(&buffer); | 354 SkDeflateWStream deflateWStream(&buffer); |
337 bitmap_to_pdf_pixels(fBitmap, &deflateWStream); | 355 bitmap_to_pdf_pixels(fBitmap, &deflateWStream); |
338 deflateWStream.finalize(); // call before detachAsStream(). | 356 deflateWStream.finalize(); // call before detachAsStream(). |
339 SkAutoTDelete<SkStreamAsset> asset(buffer.detachAsStream()); | 357 SkAutoTDelete<SkStreamAsset> asset(buffer.detachAsStream()); |
(...skipping 10 matching lines...) Expand all Loading... |
350 pdfDict.insertName("ColorSpace", "DeviceGray"); | 368 pdfDict.insertName("ColorSpace", "DeviceGray"); |
351 } else { | 369 } else { |
352 pdfDict.insertName("ColorSpace", "DeviceRGB"); | 370 pdfDict.insertName("ColorSpace", "DeviceRGB"); |
353 } | 371 } |
354 pdfDict.insertInt("BitsPerComponent", 8); | 372 pdfDict.insertInt("BitsPerComponent", 8); |
355 if (fSMask) { | 373 if (fSMask) { |
356 pdfDict.insert("SMask", new SkPDFObjRef(fSMask))->unref(); | 374 pdfDict.insert("SMask", new SkPDFObjRef(fSMask))->unref(); |
357 } | 375 } |
358 pdfDict.insertName("Filter", "FlateDecode"); | 376 pdfDict.insertName("Filter", "FlateDecode"); |
359 pdfDict.insertInt("Length", asset->getLength()); | 377 pdfDict.insertInt("Length", asset->getLength()); |
360 pdfDict.emitObject(stream, objNumMap,substitutes); | 378 pdfDict.emitObject(stream, objNumMap, substitutes); |
361 | 379 |
362 pdf_stream_begin(stream); | 380 pdf_stream_begin(stream); |
363 stream->writeStream(asset.get(), asset->getLength()); | 381 stream->writeStream(asset.get(), asset->getLength()); |
364 pdf_stream_end(stream); | 382 pdf_stream_end(stream); |
365 } | 383 } |
366 | 384 |
367 SkPDFBitmap::SkPDFBitmap(const SkBitmap& bm, | |
368 SkPDFObject* smask) | |
369 : fBitmap(bm), fSMask(smask) {} | |
370 | |
371 SkPDFBitmap::~SkPDFBitmap() {} | |
372 | |
373 //////////////////////////////////////////////////////////////////////////////// | 385 //////////////////////////////////////////////////////////////////////////////// |
374 | 386 |
375 static const SkBitmap& immutable_bitmap(const SkBitmap& bm, SkBitmap* copy) { | 387 static const SkBitmap& immutable_bitmap(const SkBitmap& bm, SkBitmap* copy) { |
376 if (bm.isImmutable()) { | 388 if (bm.isImmutable()) { |
377 return bm; | 389 return bm; |
378 } | 390 } |
379 bm.copyTo(copy); | 391 bm.copyTo(copy); |
380 copy->setImmutable(); | 392 copy->setImmutable(); |
381 return *copy; | 393 return *copy; |
382 } | 394 } |
383 | 395 |
| 396 namespace { |
| 397 /** |
| 398 * This PDFObject assumes that its constructor was handed YUV JFIF |
| 399 * Jpeg-encoded data that can be directly embedded into a PDF. |
| 400 */ |
| 401 class PDFJpegBitmap : public SkPDFBitmap { |
| 402 public: |
| 403 SkAutoTUnref<SkData> fData; |
| 404 PDFJpegBitmap(const SkBitmap& bm, SkData* data) |
| 405 : SkPDFBitmap(bm), fData(SkRef(data)) {} |
| 406 void emitObject(SkWStream*, |
| 407 const SkPDFObjNumMap&, |
| 408 const SkPDFSubstituteMap&) override; |
| 409 }; |
| 410 |
| 411 void PDFJpegBitmap::emitObject(SkWStream* stream, |
| 412 const SkPDFObjNumMap& objNumMap, |
| 413 const SkPDFSubstituteMap& substituteMap) { |
| 414 SkPDFDict pdfDict("XObject"); |
| 415 pdfDict.insertName("Subtype", "Image"); |
| 416 pdfDict.insertInt("Width", fBitmap.width()); |
| 417 pdfDict.insertInt("Height", fBitmap.height()); |
| 418 pdfDict.insertName("ColorSpace", "DeviceRGB"); |
| 419 pdfDict.insertInt("BitsPerComponent", 8); |
| 420 pdfDict.insertName("Filter", "DCTDecode"); |
| 421 pdfDict.insertInt("ColorTransform", 0); |
| 422 pdfDict.insertInt("Length", SkToInt(fData->size())); |
| 423 pdfDict.emitObject(stream, objNumMap, substituteMap); |
| 424 pdf_stream_begin(stream); |
| 425 stream->write(fData->data(), fData->size()); |
| 426 pdf_stream_end(stream); |
| 427 } |
| 428 } // namespace |
| 429 |
| 430 //////////////////////////////////////////////////////////////////////////////// |
| 431 |
| 432 static bool is_jfif_yuv_jpeg(SkData* data) { |
| 433 const uint8_t bytesZeroToThree[] = {0xFF, 0xD8, 0xFF, 0xE0}; |
| 434 const uint8_t bytesSixToTen[] = {'J', 'F', 'I', 'F', 0}; |
| 435 // 0 1 2 3 4 5 6 7 8 9 10 |
| 436 // FF D8 FF E0 ?? ?? 'J' 'F' 'I' 'F' 00 ... |
| 437 if (data->size() < 11 || |
| 438 0 != memcmp(data->bytes(), bytesZeroToThree, |
| 439 sizeof(bytesZeroToThree)) || |
| 440 0 != memcmp(data->bytes() + 6, bytesSixToTen, sizeof(bytesSixToTen))) { |
| 441 return false; |
| 442 } |
| 443 SkAutoTDelete<SkImageGenerator> gen(SkImageGenerator::NewFromData(data)); |
| 444 SkISize sizes[3]; |
| 445 // Only YUV JPEG allows access to YUV planes. |
| 446 return gen && gen->getYUV8Planes(sizes, NULL, NULL, NULL); |
| 447 } |
| 448 |
384 SkPDFBitmap* SkPDFBitmap::Create(SkPDFCanon* canon, const SkBitmap& bitmap) { | 449 SkPDFBitmap* SkPDFBitmap::Create(SkPDFCanon* canon, const SkBitmap& bitmap) { |
385 SkASSERT(canon); | 450 SkASSERT(canon); |
386 if (!SkColorTypeIsValid(bitmap.colorType()) || | 451 if (!SkColorTypeIsValid(bitmap.colorType()) || |
387 kUnknown_SkColorType == bitmap.colorType()) { | 452 kUnknown_SkColorType == bitmap.colorType()) { |
388 return NULL; | 453 return NULL; |
389 } | 454 } |
390 SkBitmap copy; | 455 SkBitmap copy; |
391 const SkBitmap& bm = immutable_bitmap(bitmap, ©); | 456 const SkBitmap& bm = immutable_bitmap(bitmap, ©); |
392 if (bm.drawsNothing()) { | 457 if (bm.drawsNothing()) { |
393 return NULL; | 458 return NULL; |
394 } | 459 } |
395 if (SkPDFBitmap* canonBitmap = canon->findBitmap(bm)) { | 460 if (SkPDFBitmap* canonBitmap = canon->findBitmap(bm)) { |
396 return SkRef(canonBitmap); | 461 return SkRef(canonBitmap); |
397 } | 462 } |
| 463 |
| 464 if (bm.pixelRef() && bm.pixelRefOrigin().isZero() && |
| 465 bm.dimensions() == bm.pixelRef()->info().dimensions()) { |
| 466 // Requires the bitmap to be backed by lazy pixels. |
| 467 SkAutoTUnref<SkData> data(bm.pixelRef()->refEncodedData()); |
| 468 if (data && is_jfif_yuv_jpeg(data)) { |
| 469 SkPDFBitmap* pdfBitmap = SkNEW_ARGS(PDFJpegBitmap, (bm, data)); |
| 470 canon->addBitmap(pdfBitmap); |
| 471 return pdfBitmap; |
| 472 } |
| 473 } |
| 474 |
398 SkPDFObject* smask = NULL; | 475 SkPDFObject* smask = NULL; |
399 if (!bm.isOpaque() && !SkBitmap::ComputeIsOpaque(bm)) { | 476 if (!bm.isOpaque() && !SkBitmap::ComputeIsOpaque(bm)) { |
400 smask = SkNEW_ARGS(PDFAlphaBitmap, (bm)); | 477 smask = SkNEW_ARGS(PDFAlphaBitmap, (bm)); |
401 } | 478 } |
402 SkPDFBitmap* pdfBitmap = SkNEW_ARGS(SkPDFBitmap, (bm, smask)); | 479 SkPDFBitmap* pdfBitmap = SkNEW_ARGS(PDFDefaultBitmap, (bm, smask)); |
403 canon->addBitmap(pdfBitmap); | 480 canon->addBitmap(pdfBitmap); |
404 return pdfBitmap; | 481 return pdfBitmap; |
405 } | 482 } |
OLD | NEW |