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 "SkMilestone.h" | 8 #include "SkMilestone.h" |
9 #include "SkPDFMetadata.h" | 9 #include "SkPDFMetadata.h" |
10 #include "SkPDFTypes.h" | 10 #include "SkPDFTypes.h" |
(...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
256 *out++ = input[i]; | 256 *out++ = input[i]; |
257 } | 257 } |
258 } | 258 } |
259 if (after) { | 259 if (after) { |
260 strncpy(out, after, afterLen); | 260 strncpy(out, after, afterLen); |
261 out += afterLen; | 261 out += afterLen; |
262 } | 262 } |
263 // Validate that we haven't written outside of our string. | 263 // Validate that we haven't written outside of our string. |
264 SkASSERT(out == &output.writable_str()[output.size()]); | 264 SkASSERT(out == &output.writable_str()[output.size()]); |
265 *out = '\0'; | 265 *out = '\0'; |
266 return std::move(output); | 266 return output; |
267 } | 267 } |
268 | 268 |
269 SkPDFObject* SkPDFMetadata::createXMPObject(const UUID& doc, | 269 SkPDFObject* SkPDFMetadata::createXMPObject(const UUID& doc, |
270 const UUID& instance) const { | 270 const UUID& instance) const { |
271 static const char templateString[] = | 271 static const char templateString[] = |
272 "<?xpacket begin=\"\" id=\"W5M0MpCehiHzreSzNTczkc9d\"?>\n" | 272 "<?xpacket begin=\"\" id=\"W5M0MpCehiHzreSzNTczkc9d\"?>\n" |
273 "<x:xmpmeta xmlns:x=\"adobe:ns:meta/\"\n" | 273 "<x:xmpmeta xmlns:x=\"adobe:ns:meta/\"\n" |
274 " x:xmptk=\"Adobe XMP Core 5.4-c005 78.147326, " | 274 " x:xmptk=\"Adobe XMP Core 5.4-c005 78.147326, " |
275 "2012/08/23-13:03:03\">\n" | 275 "2012/08/23-13:03:03\">\n" |
276 "<rdf:RDF " | 276 "<rdf:RDF " |
277 "xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">\n" | 277 "xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">\n" |
278 "<rdf:Description rdf:about=\"\"\n" | 278 "<rdf:Description rdf:about=\"\"\n" |
279 " xmlns:xmp=\"http://ns.adobe.com/xap/1.0/\"\n" | 279 " xmlns:xmp=\"http://ns.adobe.com/xap/1.0/\"\n" |
280 " xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\n" | 280 " xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\n" |
281 " xmlns:xmpMM=\"http://ns.adobe.com/xap/1.0/mm/\"\n" | 281 " xmlns:xmpMM=\"http://ns.adobe.com/xap/1.0/mm/\"\n" |
282 " xmlns:pdf=\"http://ns.adobe.com/pdf/1.3/\"\n" | 282 " xmlns:pdf=\"http://ns.adobe.com/pdf/1.3/\"\n" |
283 " xmlns:pdfaid=\"http://www.aiim.org/pdfa/ns/id/\">\n" | 283 " xmlns:pdfaid=\"http://www.aiim.org/pdfa/ns/id/\">\n" |
284 "<pdfaid:part>2</pdfaid:part>\n" | 284 "<pdfaid:part>2</pdfaid:part>\n" |
285 "<pdfaid:conformance>B</pdfaid:conformance>\n" | 285 "<pdfaid:conformance>B</pdfaid:conformance>\n" |
286 "%s" // ModifyDate | 286 "%s" // ModifyDate |
287 "%s" // CreateDate | 287 "%s" // CreateDate |
288 "%s" // MetadataDate | |
289 "%s" // xmp:CreatorTool | 288 "%s" // xmp:CreatorTool |
290 "<dc:format>application/pdf</dc:format>\n" | 289 "<dc:format>application/pdf</dc:format>\n" |
291 "%s" // dc:title | 290 "%s" // dc:title |
292 "%s" // dc:description | 291 "%s" // dc:description |
293 "%s" // author | 292 "%s" // author |
294 "%s" // keywords | 293 "%s" // keywords |
295 "<xmpMM:DocumentID>uuid:%s</xmpMM:DocumentID>\n" | 294 "<xmpMM:DocumentID>uuid:%s</xmpMM:DocumentID>\n" |
296 "<xmpMM:InstanceID>uuid:%s</xmpMM:InstanceID>\n" | 295 "<xmpMM:InstanceID>uuid:%s</xmpMM:InstanceID>\n" |
297 "<pdf:Producer>Skia/PDF m" SKPDF_STRING(SK_MILESTONE) "</pdf:Produce
r>\n" | 296 "<pdf:Producer>Skia/PDF m" SKPDF_STRING(SK_MILESTONE) "</pdf:Produce
r>\n" |
298 "%s" // pdf:Keywords | 297 "%s" // pdf:Keywords |
299 "</rdf:Description>\n" | 298 "</rdf:Description>\n" |
300 "</rdf:RDF>\n" | 299 "</rdf:RDF>\n" |
301 "</x:xmpmeta>\n" // Note: the standard suggests 4k of padding. | 300 "</x:xmpmeta>\n" // Note: the standard suggests 4k of padding. |
302 "<?xpacket end=\"w\"?>\n"; | 301 "<?xpacket end=\"w\"?>\n"; |
303 | 302 |
304 SkString creationDate; | 303 SkString creationDate; |
305 SkString modificationDate; | 304 SkString modificationDate; |
306 SkString metadataDate; | |
307 if (fCreation) { | 305 if (fCreation) { |
308 SkString tmp; | 306 SkString tmp; |
309 fCreation->toISO8601(&tmp); | 307 fCreation->toISO8601(&tmp); |
310 SkASSERT(0 == count_xml_escape_size(tmp)); | 308 SkASSERT(0 == count_xml_escape_size(tmp)); |
311 // YYYY-mm-ddTHH:MM:SS[+|-]ZZ:ZZ; no need to escape | 309 // YYYY-mm-ddTHH:MM:SS[+|-]ZZ:ZZ; no need to escape |
312 creationDate = sk_string_printf("<xmp:CreateDate>%s</xmp:CreateDate>\n", | 310 creationDate = sk_string_printf("<xmp:CreateDate>%s</xmp:CreateDate>\n", |
313 tmp.c_str()); | 311 tmp.c_str()); |
314 } | 312 } |
315 if (fModified) { | 313 if (fModified) { |
316 SkString tmp; | 314 SkString tmp; |
317 fModified->toISO8601(&tmp); | 315 fModified->toISO8601(&tmp); |
318 SkASSERT(0 == count_xml_escape_size(tmp)); | 316 SkASSERT(0 == count_xml_escape_size(tmp)); |
319 modificationDate = sk_string_printf( | 317 modificationDate = sk_string_printf( |
320 "<xmp:ModifyDate>%s</xmp:ModifyDate>\n", tmp.c_str()); | 318 "<xmp:ModifyDate>%s</xmp:ModifyDate>\n", tmp.c_str()); |
321 metadataDate = sk_string_printf( | |
322 "<xmp:MetadataDate>%s</xmp:MetadataDate>\n", tmp.c_str()); | |
323 } | 319 } |
324 | 320 SkString title = escape_xml( |
325 SkString title = | 321 get(fInfo, "Title"), |
326 escape_xml(get(fInfo, "Title"), "<dc:title><rdf:Alt><rdf:li>", | 322 "<dc:title><rdf:Alt><rdf:li xml:lang=\"x-default\">", |
327 "</rdf:li></rdf:Alt></dc:title>\n"); | 323 "</rdf:li></rdf:Alt></dc:title>\n"); |
328 SkString author = | 324 SkString author = escape_xml( |
329 escape_xml(get(fInfo, "Author"), "<dc:creator><rdf:Bag><rdf:li>", | 325 get(fInfo, "Author"), "<dc:creator><rdf:Bag><rdf:li>", |
330 "</rdf:li></rdf:Bag></dc:creator>\n"); | 326 "</rdf:li></rdf:Bag></dc:creator>\n"); |
331 // TODO: in theory, XMP can support multiple authors. Split on a delimiter? | 327 // TODO: in theory, XMP can support multiple authors. Split on a delimiter? |
332 SkString subject = escape_xml(get(fInfo, "Subject"), | 328 SkString subject = escape_xml( |
333 "<dc:description><rdf:Alt><rdf:li>", | 329 get(fInfo, "Subject"), |
334 "</rdf:li></rdf:Alt></dc:description>\n"); | 330 "<dc:description><rdf:Alt><rdf:li xml:lang=\"x-default\">", |
335 SkString keywords1 = | 331 "</rdf:li></rdf:Alt></dc:description>\n"); |
336 escape_xml(get(fInfo, "Keywords"), "<dc:subject><rdf:Bag><rdf:li>", | 332 SkString keywords1 = escape_xml( |
337 "</rdf:li></rdf:Bag></dc:subject>\n"); | 333 get(fInfo, "Keywords"), "<dc:subject><rdf:Bag><rdf:li>", |
338 SkString keywords2 = escape_xml(get(fInfo, "Keywords"), "<pdf:Keywords>", | 334 "</rdf:li></rdf:Bag></dc:subject>\n"); |
339 "</pdf:Keywords>\n"); | 335 SkString keywords2 = escape_xml( |
| 336 get(fInfo, "Keywords"), "<pdf:Keywords>", |
| 337 "</pdf:Keywords>\n"); |
340 | 338 |
341 // TODO: in theory, keywords can be a list too. | 339 // TODO: in theory, keywords can be a list too. |
342 SkString creator = escape_xml(get(fInfo, "Creator"), "<xmp:CreatorTool>", | 340 SkString creator = escape_xml(get(fInfo, "Creator"), "<xmp:CreatorTool>", |
343 "</xmp:CreatorTool>\n"); | 341 "</xmp:CreatorTool>\n"); |
344 SkString documentID = uuid_to_string(doc); // no need to escape | 342 SkString documentID = uuid_to_string(doc); // no need to escape |
345 SkASSERT(0 == count_xml_escape_size(documentID)); | 343 SkASSERT(0 == count_xml_escape_size(documentID)); |
346 SkString instanceID = uuid_to_string(instance); | 344 SkString instanceID = uuid_to_string(instance); |
347 SkASSERT(0 == count_xml_escape_size(instanceID)); | 345 SkASSERT(0 == count_xml_escape_size(instanceID)); |
348 return new PDFXMLObject(sk_string_printf( | 346 return new PDFXMLObject(sk_string_printf( |
349 templateString, modificationDate.c_str(), creationDate.c_str(), | 347 templateString, modificationDate.c_str(), creationDate.c_str(), |
350 metadataDate.c_str(), creator.c_str(), title.c_str(), | 348 creator.c_str(), title.c_str(), |
351 subject.c_str(), author.c_str(), keywords1.c_str(), | 349 subject.c_str(), author.c_str(), keywords1.c_str(), |
352 documentID.c_str(), instanceID.c_str(), keywords2.c_str())); | 350 documentID.c_str(), instanceID.c_str(), keywords2.c_str())); |
353 } | 351 } |
354 | 352 |
355 #endif // SK_PDF_GENERATE_PDFA | 353 #endif // SK_PDF_GENERATE_PDFA |
356 | 354 |
357 #undef SKPDF_STRING | 355 #undef SKPDF_STRING |
358 #undef SKPDF_STRING_IMPL | 356 #undef SKPDF_STRING_IMPL |
359 | 357 |
OLD | NEW |