(frame: Image.Image, settings: ConvertSettings)
| 122 | |
| 123 | |
| 124 | def convert_frame(frame: Image.Image, settings: ConvertSettings) -> list[tuple[int, int, int]]: |
| 125 | frame = fit_frame(frame.convert("L"), settings) |
| 126 | invert_frame = bool_from_mode(settings.invert_mode, frame) |
| 127 | canvas = Image.new("L", (settings.target_w, settings.target_h), 255 if invert_frame else 0) |
| 128 | canvas.paste(frame, ((settings.target_w - frame.width) // 2, (settings.target_h - frame.height) // 2)) |
| 129 | |
| 130 | points: list[tuple[int, int, int]] = [] |
| 131 | step = max(1, settings.sample_step) |
| 132 | for y in range(0, settings.target_h, step): |
| 133 | for x in range(0, settings.target_w, step): |
| 134 | vals = [] |
| 135 | for yy in range(step): |
| 136 | for xx in range(step): |
| 137 | px = min(settings.target_w - 1, x + xx) |
| 138 | py = min(settings.target_h - 1, y + yy) |
| 139 | vals.append(canvas.getpixel((px, py))) |
| 140 | source = dither_adjust(sum(vals) // len(vals), x, y, settings) |
| 141 | if invert_frame: |
| 142 | ink = 255 - source |
| 143 | if ink <= settings.ink_threshold: |
| 144 | continue |
| 145 | shade = max(52, min(255, ink + 58)) |
| 146 | else: |
| 147 | if source <= settings.ink_threshold: |
| 148 | continue |
| 149 | shade = max(48, min(255, source)) |
| 150 | points.append((settings.offset_x + x, settings.offset_y + y, shade)) |
| 151 | return reduce_points_evenly(points, max(1, settings.max_points_per_frame)) |
| 152 | |
| 153 | |
| 154 | def convert_source(src: Path, settings: ConvertSettings) -> ConversionResult: |
no test coverage detected