All checks were successful
Build and deploy / Validate source (push) Successful in 1m23s
Build and deploy / Integration suite on a real stack (push) Successful in 3m13s
Build and deploy / Secret scan and release gate (push) Successful in 10s
Build and deploy / Publish images (push) Successful in 1m25s
The price depends on the grade, which the browser worked out and the API took on trust. Before a cart is approved at checkout the API now recomputes it from the uploaded files by the Site's own rules: the pixel size in a PNG, JPG or WebP header across the printed width (rotation included), and the area-weighted DPI of the images placed in a PDF of up to 150 MB, 300 for vectors. Sheets take the worst grade, artworks the average. A claim more than 2 points above the file's grade, or a discount on a file the server cannot grade, waits for an operator, with the reason on the Kanban. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
87 lines
3.9 KiB
Python
87 lines
3.9 KiB
Python
"""The server's grade against real image and PDF files.
|
|
|
|
Runs where Pillow and pikepdf are installed (the API image).
|
|
"""
|
|
import io
|
|
import tempfile
|
|
import unittest
|
|
|
|
import pikepdf
|
|
from PIL import Image
|
|
|
|
from app import grade_check
|
|
|
|
|
|
class FakeFiles:
|
|
def __init__(self, blobs):
|
|
self.blobs = blobs
|
|
|
|
def head(self, row):
|
|
return self.blobs[row['name']][:grade_check.HEAD_BYTES]
|
|
|
|
def pdf_dpi(self, row):
|
|
with tempfile.NamedTemporaryFile(suffix='.pdf') as handle:
|
|
handle.write(self.blobs[row['name']])
|
|
handle.flush()
|
|
return grade_check.pdf_dpi(handle.name)
|
|
|
|
|
|
def encoded(fmt, size, **options):
|
|
out = io.BytesIO()
|
|
Image.new('RGBA' if fmt in ('PNG', 'WEBP') else 'RGB', size, (200, 30, 30)).save(out, fmt, **options)
|
|
return out.getvalue()
|
|
|
|
|
|
def item(kind, grade, sources):
|
|
return {'grade': grade, 'production': {'sources': [
|
|
{'upload_id': name, 'kind': kind, 'width_cm': width, 'rotation_degrees': rotation}
|
|
for name, width, rotation in sources]}}
|
|
|
|
|
|
class GradeCheckTests(unittest.TestCase):
|
|
def test_image_sizes_from_the_first_bytes(self):
|
|
for fmt, options in (('PNG', {}), ('JPEG', {'quality': 80}), ('JPEG', {'progressive': True}),
|
|
('WEBP', {'lossless': True}), ('WEBP', {'quality': 80})):
|
|
self.assertEqual(grade_check.image_size(encoded(fmt, (1234, 567), **options)), (1234, 567), (fmt, options))
|
|
# A JPEG with a large metadata block before the frame header.
|
|
exif = Image.Exif()
|
|
exif[0x010E] = 'x' * 60000
|
|
self.assertEqual(grade_check.image_size(encoded('JPEG', (800, 600), exif=exif)), (800, 600))
|
|
self.assertIsNone(grade_check.image_size(b'not an image at all'))
|
|
|
|
def test_pdf_dpi_is_the_images_area_weighted(self):
|
|
out = io.BytesIO()
|
|
Image.new('RGB', (1500, 750), 'white').save(out, 'PDF', resolution=150)
|
|
with tempfile.NamedTemporaryFile(suffix='.pdf') as handle:
|
|
handle.write(out.getvalue()); handle.flush()
|
|
self.assertEqual(grade_check.pdf_dpi(handle.name), 150)
|
|
vector = pikepdf.new()
|
|
vector.add_blank_page(page_size=(1615, 850))
|
|
with tempfile.NamedTemporaryFile(suffix='.pdf') as handle:
|
|
vector.save(handle.name)
|
|
self.assertEqual(grade_check.pdf_dpi(handle.name), 300)
|
|
|
|
def test_grades_follow_the_site(self):
|
|
# 57 cm is 22.44 in: 6059 px is 270 DPI, grade 90; 3366 px is 150 DPI, grade 50.
|
|
files = FakeFiles({'a.png': encoded('PNG', (6059, 100)), 'b.jpg': encoded('JPEG', (3366, 100)),
|
|
'tall.png': encoded('PNG', (100, 2362)), 'x.cdr': b'CDR'})
|
|
rows = {n: {'name': n, 'size': 1} for n in files.blobs}
|
|
# A sheet takes the worst sheet's grade.
|
|
self.assertEqual(grade_check.item_grade(files, item('sheet', 0, [('a.png', 57, 0)]), rows), 90)
|
|
self.assertEqual(grade_check.item_grade(files, item('sheet', 0, [('a.png', 57, 0), ('b.jpg', 57, 0)]), rows), 50)
|
|
# Artworks average; a rotated one is measured along its height.
|
|
self.assertEqual(grade_check.item_grade(files, item('artwork', 0, [('a.png', 57, 0), ('b.jpg', 57, 0)]), rows), 70)
|
|
self.assertEqual(grade_check.item_grade(files, item('artwork', 0, [('tall.png', 20, 90)]), rows), 100)
|
|
self.assertIsNone(grade_check.item_grade(files, item('sheet', 0, [('x.cdr', 57, 0)]), rows))
|
|
# What the cart claims is checked, with a point or two of rounding.
|
|
claim = lambda g, src: grade_check.mismatch(files, [item('sheet', g, src)], rows)
|
|
self.assertIsNone(claim(90, [('a.png', 57, 0)]))
|
|
self.assertIsNone(claim(92, [('a.png', 57, 0)]))
|
|
self.assertEqual(claim(100, [('a.png', 57, 0)]), 'Nota 100 maior que a do arquivo (90)')
|
|
self.assertEqual(claim(40, [('x.cdr', 57, 0)]), 'Nota não conferida no servidor')
|
|
self.assertIsNone(claim(0, [('x.cdr', 57, 0)]))
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|