Fix XMP validation issue with /CreationDate

Related to previous validation issue. If the /CreationDate had no
timezone, Ghostscript also creates invalid metadata. Work around this.
Also fix up PDF date decoding, and transcode dates to standardize them.
This commit is contained in:
James R. Barlow
2018-05-03 16:30:20 -07:00
parent 98a0786c32
commit 8a9f174f63
2 changed files with 30 additions and 20 deletions
+21 -16
View File
@@ -125,31 +125,31 @@ def encode_pdf_date(d: datetime) -> str:
s = d.strftime(pdfmark_date_fmt)
tz = d.strftime('%z')
if tz == 'Z':
if tz == 'Z' or tz == '':
# Ghostscript <= 9.23 handles missing timezones incorrectly, so if
# timezone is missing, move it into GMT.
# https://bugs.ghostscript.com/show_bug.cgi?id=699182
s += "+00'00'"
elif tz != '':
else:
sign, tz_hours, tz_mins = tz[0], tz[1:3], tz[3:5]
s += "{}{}'{}'".format(sign, tz_hours, tz_mins)
else:
raise ValueError("Naive timezone not supported")
return s
def decode_pdf_date(s: str) -> datetime:
pdfmark_date_fmts = (
r'%Y%m%d%H%M%S%z', # +0430 etc
r'%Y%m%d%H%M%S', # no time zone
r'%Y%m%d%H%M%SZ') # trailing Z
if s.startswith('D:'):
s = s[2:]
# Literal Z00'00', is incorrect but found in the wild,
# probably made by OS X Quartz -- standardize
if s.endswith("Z00'00'"):
s = s.replace("Z00'00'", '+0000')
elif s.endswith('Z'):
s = s.replace('Z', '+0000')
s = s.replace("'", "") # Remove apos from PDF time strings
for fmt in pdfmark_date_fmts:
try:
return datetime.strptime(s, fmt)
except ValueError:
continue
return None
return datetime.strptime(s, r'%Y%m%d%H%M%S%z')
def _get_pdfmark_dates(pdfmark):
@@ -170,7 +170,12 @@ def _get_pdfmark_dates(pdfmark):
date_str = pdfmark[key]
if date_str.startswith('D:'):
date_str = date_str[2:]
yield ' {} (D:{})'.format(key, date_str)
try:
yield ' {} (D:{})'.format(
key,
encode_pdf_date(decode_pdf_date(date_str)))
except ValueError:
yield ' {} null'.format(key)
def _get_pdfa_def(icc_profile, icc_identifier, pdfmark):
+9 -4
View File
@@ -73,11 +73,16 @@ def test_override_metadata(spoof_tesseract_noop, output_type, resources,
assert p.returncode == ExitCode.ok, err
reader = pypdf.PdfFileReader(outpdf)
before = pypdf.PdfFileReader(str(input_file))
after = pypdf.PdfFileReader(outpdf)
assert reader.documentInfo['/Title'] == german
assert reader.documentInfo['/Author'] == chinese
assert reader.documentInfo.get('/Keywords', '') == ''
assert after.documentInfo['/Title'] == german
assert after.documentInfo['/Author'] == chinese
assert after.documentInfo.get('/Keywords', '') == ''
before_date = decode_pdf_date(before.documentInfo['/CreationDate'])
after_date = decode_pdf_date(after.documentInfo['/CreationDate'])
assert before_date == after_date
pdfa_info = file_claims_pdfa(outpdf)
assert pdfa_info['output'] == output_type