test: the lab prints from a signed-in lesson, and judges black and white on the job
A lesson site for the lab (session cookie, one-time addresses, a second origin, a request log) and real right-clicks on its words and on a JPEG, a PNG, a transparent PNG, a one-time picture, another site's, a blob:, a WebP, a canvas, a linked picture, a broken one, and Cancel. Each is judged on the job CUPS kept — where and how large, no other ink — and on the site log: nothing was fetched again. The clipboard is the teacher's afterwards. Black and white: a colourful lesson turned back and forth five times on page 2, a worksheet, a picture at 50% top left, a page full of pictures, back to Color, and Cancel. Every grey preview is grey pixel for pixel and the job is byte-for-byte the file shown, through pxlmono. The three 0.2.6.2 black-and-white scenarios now wait for the grey file before Print, as a teacher has to. 343 checks, none failing. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
594fbd810e
commit
cb12e59dea
@@ -3,6 +3,7 @@
|
||||
wonderink-picture-measure.py make DIRECTORY
|
||||
wonderink-picture-measure.py measure PDF WIDTHxHEIGHT SIZE POSITION PAPER FILL
|
||||
wonderink-picture-measure.py darkness PDF
|
||||
wonderink-picture-measure.py colour PDF
|
||||
|
||||
Run inside the lab by tools/lab/wonderink-print-check. The pictures are
|
||||
white with a black border drawn on their own edges and a pink mark near
|
||||
@@ -55,10 +56,42 @@ def make(directory):
|
||||
# Transparent around the drawing: on paper that has to be white, not
|
||||
# black, which is what a careless composite would make of it.
|
||||
art(1200, 1200, "ark-clear.png", "Clear", transparent=True)
|
||||
webp(directory)
|
||||
|
||||
|
||||
def page_pixels(pdf):
|
||||
ppm = subprocess.run(["pdftoppm", "-r", "72", "-f", "1", "-l", "1", "-singlefile", pdf],
|
||||
def webp(directory):
|
||||
"""ark-wide.png as WebP. Qt cannot write WebP, or read it; Chromium does both."""
|
||||
import base64
|
||||
|
||||
from PyQt6.QtCore import QTimer, QUrl
|
||||
from PyQt6.QtWebEngineWidgets import QWebEngineView
|
||||
from PyQt6.QtWidgets import QApplication
|
||||
|
||||
app = QApplication.instance() or QApplication(sys.argv[:1])
|
||||
source = base64.b64encode(open(f"{directory}/ark-wide.png", "rb").read()).decode()
|
||||
view = QWebEngineView()
|
||||
|
||||
def made(answer):
|
||||
if isinstance(answer, str) and answer.startswith("data:image/webp;base64,"):
|
||||
with open(f"{directory}/ark-wide.webp", "wb") as handle:
|
||||
handle.write(base64.b64decode(answer.split(",", 1)[1]))
|
||||
app.quit()
|
||||
|
||||
def loaded(_ok):
|
||||
view.page().runJavaScript("""var i = new Image(); i.onload = function(){
|
||||
var c = document.createElement('canvas'); c.width = i.width; c.height = i.height;
|
||||
c.getContext('2d').drawImage(i, 0, 0); window.__webp = c.toDataURL('image/webp', 0.95); };
|
||||
i.src = 'data:image/png;base64,%s'; 0""" % source)
|
||||
QTimer.singleShot(1500, lambda: view.page().runJavaScript("window.__webp", made))
|
||||
|
||||
view.loadFinished.connect(loaded)
|
||||
view.setHtml("<html></html>")
|
||||
QTimer.singleShot(20000, app.quit)
|
||||
app.exec()
|
||||
|
||||
|
||||
def page_pixels(pdf, page=1):
|
||||
ppm = subprocess.run(["pdftoppm", "-r", "72", "-f", str(page), "-l", str(page), "-singlefile", pdf],
|
||||
capture_output=True, check=True).stdout
|
||||
# P6 header: magic, width, height, maxval, then raw RGB.
|
||||
fields, index = [], 0
|
||||
@@ -106,6 +139,19 @@ def measure(pdf, picture, size, position, paper, fill):
|
||||
if magenta:
|
||||
pink += 1
|
||||
|
||||
# The corner mark, wherever it landed and whatever colour it came out:
|
||||
# pink on a colour page, grey on a black-and-white one. Inked if most
|
||||
# of the middle of where it should be is not paper.
|
||||
mark_left = max(x + w * 0.07, MARGIN_POINTS)
|
||||
mark_right = min(x + w * 0.13, width - MARGIN_POINTS)
|
||||
mark_top = max(y + h * 0.82, MARGIN_POINTS)
|
||||
mark_bottom = min(y + h * 0.88, height - MARGIN_POINTS)
|
||||
mark = [
|
||||
sum(rgb[(row * width + column) * 3:(row * width + column) * 3 + 3]) < 3 * 200
|
||||
for row in range(int(mark_top), int(mark_bottom))
|
||||
for column in range(int(mark_left), int(mark_right))
|
||||
]
|
||||
|
||||
found = (min(xs), min(ys), max(xs) + 1, max(ys) + 1) if xs else None
|
||||
expected = (round(left), round(top), round(right), round(bottom))
|
||||
off = max(abs(a - b) for a, b in zip(found, expected)) if found else None
|
||||
@@ -119,9 +165,24 @@ def measure(pdf, picture, size, position, paper, fill):
|
||||
"off_by_points": off,
|
||||
"ink_outside_picture": outside,
|
||||
"pink_pixels": pink,
|
||||
"mark_inked": bool(mark) and sum(mark) > 0.8 * len(mark),
|
||||
"colour_spread": spread(rgb),
|
||||
}))
|
||||
|
||||
|
||||
def spread(rgb):
|
||||
"""The most any pixel's red, green and blue differ: 0 on a grey page."""
|
||||
return max((max(rgb[i:i + 3]) - min(rgb[i:i + 3]) for i in range(0, len(rgb) - 2, 3)), default=0)
|
||||
|
||||
|
||||
def colour(pdf):
|
||||
"""Is every page grey? The colour spread of each page, and how many."""
|
||||
pages = int(subprocess.run(["pdfinfo", pdf], capture_output=True, text=True).stdout
|
||||
.split("Pages:")[1].split()[0])
|
||||
spreads = [spread(page_pixels(pdf, n)[2]) for n in range(1, pages + 1)]
|
||||
print(json.dumps({"pages": pages, "spreads": spreads, "gray": max(spreads) == 0}))
|
||||
|
||||
|
||||
def darkness(pdf):
|
||||
"""How much of the first page is dark, 0 to 1."""
|
||||
width, height, rgb = page_pixels(pdf)
|
||||
@@ -140,5 +201,7 @@ if __name__ == "__main__":
|
||||
make(sys.argv[2])
|
||||
elif sys.argv[1] == "darkness":
|
||||
darkness(sys.argv[2])
|
||||
elif sys.argv[1] == "colour":
|
||||
colour(sys.argv[2])
|
||||
else:
|
||||
measure(*sys.argv[2:])
|
||||
|
||||
Reference in New Issue
Block a user