oxedyne/fe2o3/fe2o3_graphics/tests/png/gen.py
2.5 KiB, 1 run
created by r1870400018:14157, which is this file's identity for as long as the history lasts, whatever it is later renamed to
download · who wrote it · its history
| 1 | #!/usr/bin/env python3 |
| 2 | """Generate tRNS-bearing PNGs with PIL, and record what PIL says each pixel means. |
| 3 | |
| 4 | PIL writes the files and PIL says what they decode to. Our decoder is not consulted, |
| 5 | so agreeing with this file is agreement with an implementation that is not ours. |
| 6 | """ |
| 7 | import json |
| 8 | import os |
| 9 | |
| 10 | from PIL import Image, ImagePalette |
| 11 | |
| 12 | OUT = os.path.dirname(os.path.abspath(__file__)) |
| 13 | cases = {} |
| 14 | |
| 15 | |
| 16 | def record(name, img): |
| 17 | """Write the PNG, then record PIL's own RGBA reading of it.""" |
| 18 | path = os.path.join(OUT, name + ".png") |
| 19 | img.save(path) |
| 20 | # Re-open from disk, so we record what the *file* says, not what we held in memory. |
| 21 | reopened = Image.open(path).convert("RGBA") |
| 22 | w, h = reopened.size |
| 23 | cases[name] = { |
| 24 | "w": w, |
| 25 | "h": h, |
| 26 | "rgba": [list(px) for px in reopened.getdata()], |
| 27 | } |
| 28 | |
| 29 | |
| 30 | # 1. Palette image with a tRNS chunk: per-entry alpha, some fully transparent. |
| 31 | pal_img = Image.new("P", (4, 4)) |
| 32 | palette = [] |
| 33 | for i in range(256): |
| 34 | palette += [(i * 7) % 256, (i * 13) % 256, (i * 29) % 256] |
| 35 | pal_img.putpalette(palette) |
| 36 | pal_img.putdata([0, 1, 2, 3] * 4) |
| 37 | # Entry 0 fully transparent, entry 1 half, entries 2+ opaque. |
| 38 | pal_img.info["transparency"] = bytes([0, 128, 255, 255]) |
| 39 | record("palette_trns", pal_img) |
| 40 | |
| 41 | # 2. Greyscale image with a tRNS chunk: one luminance value is the transparent one. |
| 42 | grey = Image.new("L", (4, 4)) |
| 43 | grey.putdata([0, 64, 128, 255] * 4) |
| 44 | grey.info["transparency"] = 128 # Every pixel of luminance 128 is transparent. |
| 45 | record("grey_trns", grey) |
| 46 | |
| 47 | # 3. Truecolour image with a tRNS chunk: one RGB triple is the transparent one. |
| 48 | rgb = Image.new("RGB", (4, 4)) |
| 49 | rgb.putdata([(255, 0, 0), (0, 255, 0), (0, 0, 255), (10, 20, 30)] * 4) |
| 50 | rgb.info["transparency"] = (0, 255, 0) # Every pure-green pixel is transparent. |
| 51 | record("rgb_trns", rgb) |
| 52 | |
| 53 | # 4. Controls: images with no tRNS at all must stay fully opaque. |
| 54 | plain_rgb = Image.new("RGB", (4, 4)) |
| 55 | plain_rgb.putdata([(1, 2, 3), (4, 5, 6), (7, 8, 9), (10, 11, 12)] * 4) |
| 56 | record("rgb_plain", plain_rgb) |
| 57 | |
| 58 | rgba = Image.new("RGBA", (4, 4)) |
| 59 | rgba.putdata([(1, 2, 3, 0), (4, 5, 6, 85), (7, 8, 9, 170), (10, 11, 12, 255)] * 4) |
| 60 | record("rgba_plain", rgba) |
| 61 | |
| 62 | with open(os.path.join(OUT, "expected.json"), "w") as f: |
| 63 | json.dump(cases, f, indent=1) |
| 64 | |
| 65 | print("wrote {} cases: {}".format(len(cases), ", ".join(sorted(cases)))) |
| 66 | for name, c in sorted(cases.items()): |
| 67 | alphas = [px[3] for px in c["rgba"]] |
| 68 | print(" {:14s} transparent px = {:2d}/{:2d}".format( |
| 69 | name, sum(1 for a in alphas if a == 0), len(alphas))) |