82 lines
5.0 KiB
Python
82 lines
5.0 KiB
Python
#!/usr/bin/env python3
|
|
"""Explain the retained failing CMYK comparison without relaxing its criterion."""
|
|
from io import BytesIO
|
|
import hashlib
|
|
import json
|
|
from pathlib import Path
|
|
|
|
from PIL import Image, ImageCms
|
|
from pypdf import PdfReader
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
RESULTS = ROOT / 'tests/results/cmyk-lut'
|
|
|
|
|
|
def sha(path):
|
|
with path.open('rb') as stream:
|
|
return hashlib.file_digest(stream, 'sha256').hexdigest()
|
|
|
|
|
|
def main():
|
|
corpus=ROOT/'tests/fixtures/pdf/cmyk-lut'
|
|
spec=json.loads((corpus/'manifest.json').read_text())
|
|
pdf=PdfReader(corpus/spec['file'])
|
|
assert b'/RelativeColorimetric ri' in pdf.pages[0].get_contents().get_data()
|
|
assert pdf.pages[0]['/Resources']['/XObject']['/Sample']['/Intent']=='/RelativeColorimetric'
|
|
source=json.loads((RESULTS/'pdfium-source/record.json').read_text())
|
|
for row in source['files']:
|
|
assert sha(RESULTS/'pdfium-source'/row['path'])==row['sha256']
|
|
transform_source=(RESULTS/'pdfium-source/core/fxcodec/icc/icc_transform.cpp').read_text()
|
|
assert 'TYPE_BGR_8, INTENT_PERCEPTUAL, /*dwFlags=*/0' in transform_source
|
|
profile=ImageCms.ImageCmsProfile(BytesIO((corpus/spec['profileFile']).read_bytes()))
|
|
transformations={intent:ImageCms.buildTransformFromOpenProfiles(profile,ImageCms.createProfile('sRGB'),
|
|
'CMYK','RGB',renderingIntent=value) for intent,value in [('perceptual',0),('relative',1)]}
|
|
colors={}
|
|
for probe in spec['probes']:
|
|
if probe['kind']!='icc-image': continue
|
|
pixel=Image.new('CMYK',(1,1),tuple(round(c*255) for c in probe['components']))
|
|
colors[probe['sample']]={name:list(ImageCms.applyTransform(pixel,t).getpixel((0,0))) for name,t in transformations.items()}
|
|
rows=[]
|
|
for os_name in ('arch','ubuntu'):
|
|
report=json.loads((RESULTS/os_name/'report.json').read_text())
|
|
assert not report['success'] and report['fixture']['sha256']==spec['sha256']
|
|
assert report['originalUnchanged'] and report['binariesUnchanged']
|
|
assert report['runnerSha256']==sha(ROOT/'tests/cmyk_lut/run.py')
|
|
for name,digest in report['evidenceSha256'].items():
|
|
assert sha(RESULTS/os_name/name)==digest
|
|
failed=0; matches=[]
|
|
for scale in report['scales']:
|
|
failed+=sum(not p['success'] for p in scale['probes'])
|
|
for probe in scale['probes']:
|
|
if probe['kind']!='icc-image': continue
|
|
pair=colors[probe['sample']]
|
|
errors={name:max(abs(a-b) for a,b in zip(probe['actualRgb'][name],pair[intent]))
|
|
for name,intent in [('pdfium','perceptual'),('poppler','relative')]}
|
|
matches.append({'scale':scale['scale'],'sample':probe['sample'],'actualRgb':probe['actualRgb'],
|
|
'cmmIntentColors':pair,'errorsAgainstRespectiveIntent':errors})
|
|
failed_by_renderer={name:sum(p['maxChannelError'].get(name,0)>spec['tolerance8Bit']
|
|
for scale in report['scales'] for p in scale['probes'])
|
|
for name in ('pdfium','poppler')}
|
|
maximum=max(p['maxChannelError'].get('pdfium',0) for scale in report['scales'] for p in scale['probes'])
|
|
assert failed==failed_by_renderer['pdfium']==30 and failed_by_renderer['poppler']==0 and maximum==74
|
|
assert all(max(m['errorsAgainstRespectiveIntent'].values())<=1 for m in matches)
|
|
rows.append({'os':os_name,'comparisonReportSha256':sha(RESULTS/os_name/'report.json'),
|
|
'analyticProbes':48,'failedPdfiumAnalyticProbes':failed,'failedPopplerAnalyticProbes':failed_by_renderer['poppler'],
|
|
'maximumPdfiumAnalyticChannelDifference':maximum,'intentMatchedImageProbes':matches})
|
|
result={'diagnosisVerified':True,'renderingAcceptance':False,'relativeIntentPreserved':False,
|
|
'toleranceUnchanged':spec['tolerance8Bit'],'profileSha256':spec['profileSha256'],
|
|
'sourceRevision':source['revision'],'sourceEvidenceSha256':sha(RESULTS/'pdfium-source/record.json'),
|
|
'diagnoserSha256':sha(Path(__file__)),'cmmVersion':ImageCms.core.littlecms_version,'results':rows,
|
|
'finding':'At this fixed PDFium revision, ICC conversion selects INTENT_PERCEPTUAL regardless of the '
|
|
'relative-colorimetric intent in the test PDF. On both OSs, all eight image swatches at all '
|
|
'three scales match LittleCMS perceptual output within one channel level. Poppler matches '
|
|
'relative-colorimetric output. This explains, but does not accept or repair, the difference.',
|
|
'remaining':'G-RENDER requires review and resolution/explicit compatibility judgment. No renderer '
|
|
'patch, engine substitution or user-visible detection was implemented in this comparison.'}
|
|
(RESULTS/'diagnosis.json').write_text(json.dumps(result,indent=2)+'\n')
|
|
print(json.dumps({'diagnosisVerified':True,'renderingAcceptance':False,'failedAnalyticProbes':60,
|
|
'intentMatchedImageProbes':48}))
|
|
|
|
|
|
if __name__=='__main__': main()
|