35 char timezoneSign = timeZoneMinutes >= 0 ?
'+' :
'-';
36 int timeZoneHours =
SkTAbs(timeZoneMinutes) / 60;
37 timeZoneMinutes =
SkTAbs(timeZoneMinutes) % 60;
39 "D:%04u%02u%02u%02u%02u%02u%c%02d'%02d'",
40 static_cast<unsigned>(dt.
fYear),
static_cast<unsigned>(dt.
fMonth),
41 static_cast<unsigned>(dt.
fDay),
static_cast<unsigned>(dt.
fHour),
42 static_cast<unsigned>(dt.
fMinute),
43 static_cast<unsigned>(dt.
fSecond), timezoneSign, timeZoneHours,
49 const char*
const key;
64 for (
const auto keyValuePtr : gMetadataKeys) {
66 if (
value.size() > 0) {
67 dict->insertTextString(keyValuePtr.key,
value);
83 const char uuidNamespace[] =
"org.skia.pdf\n";
84 md5.writeText(uuidNamespace);
86 md5.write(&msec,
sizeof(msec));
89 md5.write(&dateTime,
sizeof(dateTime));
93 for (
const auto keyValuePtr : gMetadataKeys) {
94 md5.writeText(keyValuePtr.key);
102 digest.
data[6] = (digest.
data[6] & 0x0F) | 0x30;
103 digest.
data[8] = (digest.
data[6] & 0x3F) | 0x80;
104 static_assert(
sizeof(digest) ==
sizeof(
SkUUID),
"uuid_size");
106 memcpy((
void*)&uuid, &digest,
sizeof(digest));
114 static_assert(
sizeof(
SkUUID) == 16,
"uuid_size");
115 array->appendByteString(
SkString(
reinterpret_cast<const char*
>(&doc ),
sizeof(
SkUUID)));
122static void hexify(
const uint8_t** inputPtr,
char** outputPtr,
int count) {
125 while (
count-- > 0) {
126 uint8_t
value = *(*inputPtr)++;
136 const uint8_t* data = uuid.
fData;
154 PDFXMLObject(
SkString xml) : fXML(
std::move(xml)) {}
157 dict.insertName(
"Subtype",
"XML");
158 dict.insertInt(
"Length", fXML.size());
159 dict.emitObject(stream);
160 static const char streamBegin[] =
" stream\n";
161 stream->writeText(streamBegin);
165 stream->write(fXML.c_str(), fXML.size());
166 static const char streamEnd[] =
"\nendstream";
167 stream->writeText(streamEnd);
177 for (
size_t i = 0; i < input.
size(); ++i) {
178 if (input[i] ==
'&') {
180 }
else if (input[i] ==
'<') {
188 const char* before =
nullptr,
189 const char* after =
nullptr) {
190 if (input.
size() == 0) {
196 size_t beforeLen = before ? strlen(before) : 0;
197 size_t afterLen = after ? strlen(after) : 0;
199 SkString output(input.
size() + extra + beforeLen + afterLen);
200 char* out = output.data();
202 strncpy(out, before, beforeLen);
205 static const char kAmp[] =
"&";
206 static const char kLt[] =
"<";
207 for (
size_t i = 0; i < input.
size(); ++i) {
208 if (input[i] ==
'&') {
209 memcpy(out, kAmp, strlen(kAmp));
211 }
else if (input[i] ==
'<') {
212 memcpy(out, kLt, strlen(kLt));
219 strncpy(out, after, afterLen);
223 SkASSERT(out == &output.data()[output.size()]);
233 static const char templateString[] =
234 "<?xpacket begin=\"\" id=\"W5M0MpCehiHzreSzNTczkc9d\"?>\n"
235 "<x:xmpmeta xmlns:x=\"adobe:ns:meta/\"\n"
236 " x:xmptk=\"Adobe XMP Core 5.4-c005 78.147326, "
237 "2012/08/23-13:03:03\">\n"
239 "xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">\n"
240 "<rdf:Description rdf:about=\"\"\n"
241 " xmlns:xmp=\"http://ns.adobe.com/xap/1.0/\"\n"
242 " xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\n"
243 " xmlns:xmpMM=\"http://ns.adobe.com/xap/1.0/mm/\"\n"
244 " xmlns:pdf=\"http://ns.adobe.com/pdf/1.3/\"\n"
245 " xmlns:pdfaid=\"http://www.aiim.org/pdfa/ns/id/\">\n"
246 "<pdfaid:part>2</pdfaid:part>\n"
247 "<pdfaid:conformance>B</pdfaid:conformance>\n"
251 "<dc:format>application/pdf</dc:format>\n"
256 "<xmpMM:DocumentID>uuid:%s</xmpMM:DocumentID>\n"
257 "<xmpMM:InstanceID>uuid:%s</xmpMM:InstanceID>\n"
260 "</rdf:Description>\n"
263 "<?xpacket end=\"w\"?>\n";
272 creationDate =
SkStringPrintf(
"<xmp:CreateDate>%s</xmp:CreateDate>\n",
280 "<xmp:ModifyDate>%s</xmp:ModifyDate>\n", tmp.
c_str());
284 "<dc:title><rdf:Alt><rdf:li xml:lang=\"x-default\">",
285 "</rdf:li></rdf:Alt></dc:title>\n");
288 "</rdf:li></rdf:Seq></dc:creator>\n");
292 "<dc:description><rdf:Alt><rdf:li xml:lang=\"x-default\">",
293 "</rdf:li></rdf:Alt></dc:description>\n");
296 "</rdf:li></rdf:Bag></dc:subject>\n");
298 "</pdf:Keywords>\n");
304 "</xmp:CreatorTool>\n");
312 templateString, modificationDate.
c_str(), creationDate.
c_str(),
318 dict->insertName(
"Subtype",
"XML");
324#undef SKPDF_CUSTOM_PRODUCER_KEY
327#undef SKPDF_STRING_IMPL
static SkMD5::Digest md5(const SkBitmap &bm)
SkPDFIndirectReference SkPDFStreamOut(std::unique_ptr< SkPDFDict > dict, std::unique_ptr< SkStreamAsset > content, SkPDFDocument *doc, SkPDFSteamCompressionEnabled compress)
static std::unique_ptr< SkPDFDict > SkPDFMakeDict(const char *type=nullptr)
static std::unique_ptr< SkPDFArray > SkPDFMakeArray(Args... args)
SK_API SkString static SkString SkStringPrintf()
constexpr int SkToInt(S x)
static std::unique_ptr< SkMemoryStream > MakeCopy(const void *data, size_t length)
virtual void emitObject(SkWStream *stream) const =0
const char * c_str() const
static const uint8_t buffer[]
void GetDateTime(SkPDF::DateTime *)
void toISO8601(SkString *dst) const
uint8_t fDayOfWeek
0..6, 0==Sunday