"""#48: contact-sheet gallery of every gauge bitmap, so the artifact can be identified by eye instead of by theory. Page 0 = CANDIDATES: small, mostly-solid images (the artifacts are featureless blocks/bars), sorted most-solid first -- the shapes worth checking. Pages 1+= the complete set, name-sorted, for manual browsing. Each tile is labelled with its filename and native pixel size. Mono-MFD art is stored paletted and gets tinted green at draw time, so judge SHAPE and SIZE, not colour. """ import os from PIL import Image, ImageDraw SRC = r"C:\git\bt411\content\GAUGE" OUT = r"C:\git\bt411\scratchpad\gallery" os.makedirs(OUT, exist_ok=True) COLS, ROWS = 10, 8 IMGW, IMGH = 186, 126 LBL = 26 TILEW, TILEH = IMGW, IMGH + LBL names = sorted(f for f in os.listdir(SRC) if f.upper().endswith((".PCC", ".PCX"))) loaded = [] for n in names: try: im = Image.open(os.path.join(SRC, n)).convert("RGB") loaded.append((n, im)) except Exception: pass print("decoded %d of %d" % (len(loaded), len(names))) def solidity(im): """fraction of pixels that are not background-black""" small = im.resize((min(im.size[0], 64), min(im.size[1], 64))) px = list(small.getdata()) nz = sum(1 for r, g, b in px if r + g + b > 40) return nz / float(len(px)) def tile_for(name, im): t = Image.new("RGB", (TILEW, TILEH), (18, 18, 18)) w, h = im.size s = min(float(IMGW - 6) / w, float(IMGH - 6) / h) if s > 6: s = 6 # do not blow tiny art up beyond 6x d = im.resize((max(1, int(w * s)), max(1, int(h * s))), Image.NEAREST) t.paste(d, ((TILEW - d.size[0]) // 2, (IMGH - d.size[1]) // 2)) dr = ImageDraw.Draw(t) dr.rectangle([0, 0, TILEW - 1, TILEH - 1], outline=(60, 60, 60)) dr.text((4, IMGH + 2), "%s" % name, fill=(210, 210, 210)) dr.text((4, IMGH + 13), "%dx%d" % (w, h), fill=(130, 170, 130)) return t def make_page(items, path, title): pw, ph = COLS * TILEW, ROWS * TILEH + 30 page = Image.new("RGB", (pw, ph), (8, 8, 8)) dr = ImageDraw.Draw(page) dr.text((8, 9), title, fill=(255, 235, 120)) for i, (n, im) in enumerate(items): r, c = divmod(i, COLS) page.paste(tile_for(n, im), (c * TILEW, 30 + r * TILEH)) page.save(path) return path # ---- page 0: candidates (small + solid = featureless block/bar shapes) ------- cands = [] for n, im in loaded: w, h = im.size if w <= 80 and h <= 80: # the artifacts were ~12x54 / ~18x30 cands.append((solidity(im), n, im)) cands.sort(reverse=True, key=lambda t: t[0]) top = [(n, im) for _s, n, im in cands[:COLS * ROWS]] pages = [make_page(top, os.path.join(OUT, "page0_CANDIDATES.png"), "PAGE 0 -- BEST CANDIDATES: small (<=80px) and mostly SOLID, " "most-solid first. Artifacts were ~12x54 and ~18x30 native.")] # ---- pages 1+: everything, name-sorted -------------------------------------- per = COLS * ROWS for p in range((len(loaded) + per - 1) // per): chunk = loaded[p * per:(p + 1) * per] pages.append(make_page( chunk, os.path.join(OUT, "page%d.png" % (p + 1)), "PAGE %d/%d -- all gauge art, name-sorted (%s .. %s)" % (p + 1, (len(loaded) + per - 1) // per, chunk[0][0], chunk[-1][0]))) print("wrote %d pages to %s" % (len(pages), OUT)) for p in pages: print(" " + os.path.basename(p))