OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2011 Google Inc. | 2 * Copyright 2011 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 "SkPDFCanon.h" | 8 #include "SkPDFCanon.h" |
9 #include "SkPDFCanvas.h" | 9 #include "SkPDFCanvas.h" |
10 #include "SkPDFDevice.h" | 10 #include "SkPDFDevice.h" |
(...skipping 17 matching lines...) Expand all Loading... |
28 fObjNumMap.addObjectRecursively(object.get(), fSubstituteMap); | 28 fObjNumMap.addObjectRecursively(object.get(), fSubstituteMap); |
29 } | 29 } |
30 | 30 |
31 #define SKPDF_MAGIC "\xD3\xEB\xE9\xE1" | 31 #define SKPDF_MAGIC "\xD3\xEB\xE9\xE1" |
32 #ifndef SK_BUILD_FOR_WIN32 | 32 #ifndef SK_BUILD_FOR_WIN32 |
33 static_assert((SKPDF_MAGIC[0] & 0x7F) == "Skia"[0], ""); | 33 static_assert((SKPDF_MAGIC[0] & 0x7F) == "Skia"[0], ""); |
34 static_assert((SKPDF_MAGIC[1] & 0x7F) == "Skia"[1], ""); | 34 static_assert((SKPDF_MAGIC[1] & 0x7F) == "Skia"[1], ""); |
35 static_assert((SKPDF_MAGIC[2] & 0x7F) == "Skia"[2], ""); | 35 static_assert((SKPDF_MAGIC[2] & 0x7F) == "Skia"[2], ""); |
36 static_assert((SKPDF_MAGIC[3] & 0x7F) == "Skia"[3], ""); | 36 static_assert((SKPDF_MAGIC[3] & 0x7F) == "Skia"[3], ""); |
37 #endif | 37 #endif |
38 void SkPDFObjectSerializer::serializeHeader(SkWStream* wStream, const SkPDFMetad
ata& md) { | 38 void SkPDFObjectSerializer::serializeHeader(SkWStream* wStream, |
| 39 const SkDocument::PDFMetadata& md) { |
39 fBaseOffset = wStream->bytesWritten(); | 40 fBaseOffset = wStream->bytesWritten(); |
40 static const char kHeader[] = "%PDF-1.4\n%" SKPDF_MAGIC "\n"; | 41 static const char kHeader[] = "%PDF-1.4\n%" SKPDF_MAGIC "\n"; |
41 wStream->write(kHeader, strlen(kHeader)); | 42 wStream->write(kHeader, strlen(kHeader)); |
42 // The PDF spec recommends including a comment with four | 43 // The PDF spec recommends including a comment with four |
43 // bytes, all with their high bits set. "\xD3\xEB\xE9\xE1" is | 44 // bytes, all with their high bits set. "\xD3\xEB\xE9\xE1" is |
44 // "Skia" with the high bits set. | 45 // "Skia" with the high bits set. |
45 fInfoDict.reset(md.createDocumentInformationDict()); | 46 fInfoDict = SkPDFMetadata::MakeDocumentInformationDict(md); |
46 this->addObjectRecursively(fInfoDict); | 47 this->addObjectRecursively(fInfoDict); |
47 this->serializeObjects(wStream); | 48 this->serializeObjects(wStream); |
48 } | 49 } |
49 #undef SKPDF_MAGIC | 50 #undef SKPDF_MAGIC |
50 | 51 |
51 // Serialize all objects in the fObjNumMap that have not yet been serialized; | 52 // Serialize all objects in the fObjNumMap that have not yet been serialized; |
52 void SkPDFObjectSerializer::serializeObjects(SkWStream* wStream) { | 53 void SkPDFObjectSerializer::serializeObjects(SkWStream* wStream) { |
53 const SkTArray<sk_sp<SkPDFObject>>& objects = fObjNumMap.objects(); | 54 const SkTArray<sk_sp<SkPDFObject>>& objects = fObjNumMap.objects(); |
54 while (fNextToBeSerialized < objects.count()) { | 55 while (fNextToBeSerialized < objects.count()) { |
55 SkPDFObject* object = objects[fNextToBeSerialized].get(); | 56 SkPDFObject* object = objects[fNextToBeSerialized].get(); |
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
208 } | 209 } |
209 } | 210 } |
210 #endif | 211 #endif |
211 | 212 |
212 template <typename T> static T* clone(const T* o) { return o ? new T(*o) : nullp
tr; } | 213 template <typename T> static T* clone(const T* o) { return o ? new T(*o) : nullp
tr; } |
213 //////////////////////////////////////////////////////////////////////////////// | 214 //////////////////////////////////////////////////////////////////////////////// |
214 | 215 |
215 SkPDFDocument::SkPDFDocument(SkWStream* stream, | 216 SkPDFDocument::SkPDFDocument(SkWStream* stream, |
216 void (*doneProc)(SkWStream*, bool), | 217 void (*doneProc)(SkWStream*, bool), |
217 SkScalar rasterDpi, | 218 SkScalar rasterDpi, |
218 SkPixelSerializer* jpegEncoder, | 219 const SkDocument::PDFMetadata& metadata, |
| 220 sk_sp<SkPixelSerializer> jpegEncoder, |
219 bool pdfa) | 221 bool pdfa) |
220 : SkDocument(stream, doneProc) | 222 : SkDocument(stream, doneProc) |
221 , fRasterDpi(rasterDpi) | 223 , fRasterDpi(rasterDpi) |
| 224 , fMetadata(metadata) |
222 , fPDFA(pdfa) { | 225 , fPDFA(pdfa) { |
223 fCanon.setPixelSerializer(SkSafeRef(jpegEncoder)); | 226 fCanon.setPixelSerializer(std::move(jpegEncoder)); |
224 } | 227 } |
225 | 228 |
226 SkPDFDocument::~SkPDFDocument() { | 229 SkPDFDocument::~SkPDFDocument() { |
227 // subclasses of SkDocument must call close() in their destructors. | 230 // subclasses of SkDocument must call close() in their destructors. |
228 this->close(); | 231 this->close(); |
229 } | 232 } |
230 | 233 |
231 void SkPDFDocument::serialize(const sk_sp<SkPDFObject>& object) { | 234 void SkPDFDocument::serialize(const sk_sp<SkPDFObject>& object) { |
232 fObjectSerializer.addObjectRecursively(object); | 235 fObjectSerializer.addObjectRecursively(object); |
233 fObjectSerializer.serializeObjects(this->getStream()); | 236 fObjectSerializer.serializeObjects(this->getStream()); |
234 } | 237 } |
235 | 238 |
236 SkCanvas* SkPDFDocument::onBeginPage(SkScalar width, SkScalar height, | 239 SkCanvas* SkPDFDocument::onBeginPage(SkScalar width, SkScalar height, |
237 const SkRect& trimBox) { | 240 const SkRect& trimBox) { |
238 SkASSERT(!fCanvas.get()); // endPage() was called before this. | 241 SkASSERT(!fCanvas.get()); // endPage() was called before this. |
239 if (fPages.empty()) { | 242 if (fPages.empty()) { |
240 // if this is the first page if the document. | 243 // if this is the first page if the document. |
241 fObjectSerializer.serializeHeader(this->getStream(), fMetadata); | 244 fObjectSerializer.serializeHeader(this->getStream(), fMetadata); |
242 fDests = sk_make_sp<SkPDFDict>(); | 245 fDests = sk_make_sp<SkPDFDict>(); |
243 if (fPDFA) { | 246 if (fPDFA) { |
244 SkPDFMetadata::UUID uuid = fMetadata.uuid(); | 247 SkPDFMetadata::UUID uuid = SkPDFMetadata::CreateUUID(fMetadata); |
245 // We use the same UUID for Document ID and Instance ID since this | 248 // We use the same UUID for Document ID and Instance ID since this |
246 // is the first revision of this document (and Skia does not | 249 // is the first revision of this document (and Skia does not |
247 // support revising existing PDF documents). | 250 // support revising existing PDF documents). |
248 // If we are not in PDF/A mode, don't use a UUID since testing | 251 // If we are not in PDF/A mode, don't use a UUID since testing |
249 // works best with reproducible outputs. | 252 // works best with reproducible outputs. |
250 fID.reset(SkPDFMetadata::CreatePdfId(uuid, uuid)); | 253 fID = SkPDFMetadata::MakePdfId(uuid, uuid); |
251 fXMP.reset(fMetadata.createXMPObject(uuid, uuid)); | 254 fXMP = SkPDFMetadata::MakeXMPObject(fMetadata, uuid, uuid); |
252 fObjectSerializer.addObjectRecursively(fXMP); | 255 fObjectSerializer.addObjectRecursively(fXMP); |
253 fObjectSerializer.serializeObjects(this->getStream()); | 256 fObjectSerializer.serializeObjects(this->getStream()); |
254 } | 257 } |
255 } | 258 } |
256 SkISize pageSize = SkISize::Make( | 259 SkISize pageSize = SkISize::Make( |
257 SkScalarRoundToInt(width), SkScalarRoundToInt(height)); | 260 SkScalarRoundToInt(width), SkScalarRoundToInt(height)); |
258 fPageDevice.reset( | 261 fPageDevice.reset( |
259 SkPDFDevice::Create(pageSize, fRasterDpi, this)); | 262 SkPDFDevice::Create(pageSize, fRasterDpi, this)); |
260 fCanvas = sk_make_sp<SkPDFCanvas>(fPageDevice); | 263 fCanvas = sk_make_sp<SkPDFCanvas>(fPageDevice); |
261 fCanvas->clipRect(trimBox); | 264 fCanvas->clipRect(trimBox); |
(...skipping 24 matching lines...) Expand all Loading... |
286 fPageDevice.reset(nullptr); | 289 fPageDevice.reset(nullptr); |
287 } | 290 } |
288 | 291 |
289 void SkPDFDocument::onAbort() { | 292 void SkPDFDocument::onAbort() { |
290 fCanvas.reset(nullptr); | 293 fCanvas.reset(nullptr); |
291 fPages.reset(); | 294 fPages.reset(); |
292 fCanon.reset(); | 295 fCanon.reset(); |
293 renew(&fObjectSerializer); | 296 renew(&fObjectSerializer); |
294 } | 297 } |
295 | 298 |
| 299 #ifdef SK_SUPPORT_LEGACY_DOCUMENT_API |
296 void SkPDFDocument::setMetadata(const SkDocument::Attribute info[], | 300 void SkPDFDocument::setMetadata(const SkDocument::Attribute info[], |
297 int infoCount, | 301 int infoCount, |
298 const SkTime::DateTime* creationDate, | 302 const SkTime::DateTime* creationDate, |
299 const SkTime::DateTime* modifiedDate) { | 303 const SkTime::DateTime* modifiedDate) { |
300 fMetadata.fInfo.reset(info, infoCount); | 304 for (int i = 0; i < infoCount; ++i) { |
301 fMetadata.fCreation.reset(clone(creationDate)); | 305 const SkDocument::Attribute& kv = info[i]; |
302 fMetadata.fModified.reset(clone(modifiedDate)); | 306 SkPDFMetadata::SetMetadataByKey(kv.fKey, kv.fValue, &fMetadata); |
| 307 } |
| 308 if (creationDate) { |
| 309 fMetadata.fCreation.fEnabled = true; |
| 310 fMetadata.fCreation.fDateTime = *creationDate; |
| 311 } |
| 312 if (modifiedDate) { |
| 313 fMetadata.fModified.fEnabled = true; |
| 314 fMetadata.fModified.fDateTime = *modifiedDate; |
| 315 } |
303 } | 316 } |
| 317 #endif // SK_SUPPORT_LEGACY_DOCUMENT_API |
304 | 318 |
305 static sk_sp<SkData> SkSrgbIcm() { | 319 static sk_sp<SkData> SkSrgbIcm() { |
306 // Source: http://www.argyllcms.com/icclibsrc.html | 320 // Source: http://www.argyllcms.com/icclibsrc.html |
307 static const char kProfile[] = | 321 static const char kProfile[] = |
308 "\0\0\14\214argl\2 \0\0mntrRGB XYZ \7\336\0\1\0\6\0\26\0\17\0:acspM" | 322 "\0\0\14\214argl\2 \0\0mntrRGB XYZ \7\336\0\1\0\6\0\26\0\17\0:acspM" |
309 "SFT\0\0\0\0IEC sRGB\0\0\0\0\0\0\0\0\0\0\0\0\0\0\366\326\0\1\0\0\0\0" | 323 "SFT\0\0\0\0IEC sRGB\0\0\0\0\0\0\0\0\0\0\0\0\0\0\366\326\0\1\0\0\0\0" |
310 "\323-argl\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" | 324 "\323-argl\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" |
311 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\21desc\0\0\1P\0\0\0\231cprt\0" | 325 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\21desc\0\0\1P\0\0\0\231cprt\0" |
312 "\0\1\354\0\0\0gdmnd\0\0\2T\0\0\0pdmdd\0\0\2\304\0\0\0\210tech\0\0\3" | 326 "\0\1\354\0\0\0gdmnd\0\0\2T\0\0\0pdmdd\0\0\2\304\0\0\0\210tech\0\0\3" |
313 "L\0\0\0\14vued\0\0\3X\0\0\0gview\0\0\3\300\0\0\0$lumi\0\0\3\344\0\0" | 327 "L\0\0\0\14vued\0\0\3X\0\0\0gview\0\0\3\300\0\0\0$lumi\0\0\3\344\0\0" |
(...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
486 fCanon.reset(); | 500 fCanon.reset(); |
487 renew(&fObjectSerializer); | 501 renew(&fObjectSerializer); |
488 return true; | 502 return true; |
489 } | 503 } |
490 | 504 |
491 /////////////////////////////////////////////////////////////////////////////// | 505 /////////////////////////////////////////////////////////////////////////////// |
492 | 506 |
493 sk_sp<SkDocument> SkPDFMakeDocument(SkWStream* stream, | 507 sk_sp<SkDocument> SkPDFMakeDocument(SkWStream* stream, |
494 void (*proc)(SkWStream*, bool), | 508 void (*proc)(SkWStream*, bool), |
495 SkScalar dpi, | 509 SkScalar dpi, |
496 SkPixelSerializer* jpeg, | 510 const SkDocument::PDFMetadata& metadata, |
| 511 sk_sp<SkPixelSerializer> jpeg, |
497 bool pdfa) { | 512 bool pdfa) { |
498 return stream ? sk_make_sp<SkPDFDocument>(stream, proc, dpi, jpeg, pdfa) | 513 return stream ? sk_make_sp<SkPDFDocument>(stream, proc, dpi, metadata, |
| 514 std::move(jpeg), pdfa) |
499 : nullptr; | 515 : nullptr; |
500 } | 516 } |
501 | 517 |
502 #ifdef SK_PDF_GENERATE_PDFA | 518 sk_sp<SkDocument> SkDocument::MakePDF(const char path[], SkScalar dpi) { |
503 static const bool kPDFA = true; | |
504 #else | |
505 static const bool kPDFA = false; | |
506 #endif | |
507 | |
508 SkDocument* SkDocument::CreatePDF(SkWStream* stream, SkScalar dpi) { | |
509 return SkPDFMakeDocument(stream, nullptr, dpi, nullptr, kPDFA).release(); | |
510 } | |
511 | |
512 SkDocument* SkDocument::CreatePDF(SkWStream* stream, | |
513 SkScalar dpi, | |
514 SkPixelSerializer* jpegEncoder) { | |
515 return SkPDFMakeDocument(stream, nullptr, dpi, | |
516 jpegEncoder, kPDFA).release(); | |
517 } | |
518 | |
519 SkDocument* SkDocument::CreatePDF(const char path[], SkScalar dpi) { | |
520 auto delete_wstream = [](SkWStream* stream, bool) { delete stream; }; | 519 auto delete_wstream = [](SkWStream* stream, bool) { delete stream; }; |
521 std::unique_ptr<SkFILEWStream> stream(new SkFILEWStream(path)); | 520 std::unique_ptr<SkFILEWStream> stream(new SkFILEWStream(path)); |
522 return stream->isValid() | 521 return stream->isValid() |
523 ? SkPDFMakeDocument(stream.release(), delete_wstream, dpi, | 522 ? SkPDFMakeDocument(stream.release(), delete_wstream, dpi, |
524 nullptr, kPDFA).release() | 523 SkDocument::PDFMetadata(), nullptr, |
525 : nullptr; | 524 false) |
| 525 : nullptr; |
526 } | 526 } |
| 527 |
| 528 sk_sp<SkDocument> SkDocument::MakePDF(SkWStream* stream, |
| 529 SkScalar dpi, |
| 530 const SkDocument::PDFMetadata& metadata, |
| 531 sk_sp<SkPixelSerializer> jpegEncoder, |
| 532 bool pdfa) { |
| 533 return SkPDFMakeDocument(stream, nullptr, dpi, metadata, |
| 534 std::move(jpegEncoder), pdfa); |
| 535 } |
OLD | NEW |