Simplify /shape/shape_color_to_mono.py so it correctly handles the new processing...
authorNick Downing <nick.downing@lifx.co>
Fri, 19 Jul 2024 13:15:19 +0000 (05:15 -0800)
committerNick Downing <nick.downing@lifx.co>
Fri, 19 Jul 2024 13:18:59 +0000 (05:18 -0800)
.gitignore
shape/Makefile
shape/shape_color_to_mono.py
shape/shape_dhgr.png
shape/shape_hgr.png
shape/shape_mono_to_mono.py [new file with mode: 0755]

index 4712116..e830bcc 100644 (file)
@@ -45,6 +45,7 @@
 /shape/shape1.png
 /shape/shape2.png
 /shape/shape3.png
+/shape/shape4.png
 /shape/shape_data.inc
 /shape/shape_index.inc
 /shape/sky_blazer_shape.png
index c199a84..6cdae21 100644 (file)
@@ -18,6 +18,7 @@ shape0d.png \
 shape1.png \
 shape2.png \
 shape3.png \
+shape4.png \
 sky_blazer_shape.png
 
 dhgr_pixel_shape_index.inc: pixel.txt dhgr_shape.txt shape0c.png
@@ -56,6 +57,9 @@ shape2.png: shape0.png
        ./shape_mono_to_color.py $< $@
 
 shape3.png: shape2.png
+       ./shape_round.py $< $@
+
+shape4.png: shape2.png
        ./shape_round.py --enhance $< $@
 
 shape0a.png: shape_hgr.png
@@ -120,7 +124,7 @@ pixel_shape_data.inc \
 shape_index.inc \
 shape_data.inc \
 shape0[abcd].png \
-shape[0123].png \
+shape[01234].png \
 sky_blazer_shape.png \
 Sky\ Blazer\ \(4am\ and\ san\ inc\ crack\).dsk \
 Sky\ Blazer\ \(4am\ and\ san\ inc\ crack\).nib
index b279495..e9354cd 100755 (executable)
@@ -1,5 +1,14 @@
 #!/usr/bin/env python3
 
+# this can be run on any shape file from the pipeline (mono, colour, rounded),
+# it auto detects which processing steps have been done and trims extra padding
+
+# resulting file is normalized for the Apple II: vertical pixels are doubled,
+# and if HGR mode, horizontal pixels are doubled and each line is hibit or not
+
+# it has been tested to restore the original file (undoes colour and rounding),
+# but does not restore the original file if it has been rounded with --enhance
+
 import numpy
 import sys
 import PIL.Image
@@ -81,28 +90,22 @@ for i in range(0x100):
     continue
   shape = shape[:ys, :xs]
 
-  # temporary, for shape_(d)hgr.png
-  if (ys & 1) == 1:
-    shape = shape[1:, :]
-    ys -= 1
-  if (xs & 3) == 0:
-    assert False
-  elif (xs & 3) == 1:
+  # normal file has ys even with pairs of identical lines
+  # rounded file has ys odd and we will only use the odd lines
+  if (ys & 1) == 0:
+    assert numpy.all(shape[::2, :] == shape[1::2, :])
+  shape = shape[1::2, :]
+  ys //= 2
+
+  # mono file has xs = a multiple of 4 + 1
+  # colour file has xs = a multiple of 4 + 3, trim the sides
+  if (xs & 3) == 1:
+    pass
+  elif (xs & 3) == 3:
     shape = shape[:, 1:-1]
     xs -= 2
-  elif (xs & 3) == 2:
-    shape = shape[:, 1:-2]
-    xs -= 3
-
-  # only look at even lines, they will be duplicated again at the end
-  shape = shape[::2]
-  ys >>= 1
-
-  # remove 2 pixels that were added by shape_colour_to_mono.py decoder
-  assert xs >= 2
-  shape = shape[:, 1:-1]
-  xs -= 2
-  assert (xs & 3) == 1
+  else:
+    assert False
 
   # take a single bit from each 4-bit colour value, according to x % 4
   shape = (
index 0d73f00..b514702 100644 (file)
Binary files a/shape/shape_dhgr.png and b/shape/shape_dhgr.png differ
index a446e06..3b5ed8e 100644 (file)
Binary files a/shape/shape_hgr.png and b/shape/shape_hgr.png differ
diff --git a/shape/shape_mono_to_mono.py b/shape/shape_mono_to_mono.py
new file mode 100755 (executable)
index 0000000..8cadd87
--- /dev/null
@@ -0,0 +1,94 @@
+#!/usr/bin/env python3
+
+# hack to pad mono image with one black pixel to left and right
+# makes it easier to put mono images (parachute, derrick, etc) alongside color
+
+import numpy
+import sys
+import PIL.Image
+
+EXIT_SUCCESS = 0
+EXIT_FAILURE = 1
+
+PITCH_X = 256
+PITCH_Y = 64
+
+# see palette.py
+PALETTE = numpy.array(
+  [
+    [0x00, 0x00, 0x00],
+    [0xbc, 0x00, 0x89],
+    [0x00, 0x00, 0xbc],
+    [0xbc, 0x00, 0xe1],
+    [0x00, 0xbc, 0x89],
+    [0x80, 0x80, 0x80], #[0xbc, 0xbc, 0xbc],
+    [0x00, 0xbc, 0xe1],
+    [0xbc, 0xbc, 0xff],
+    [0xbc, 0xbc, 0x00],
+    [0xff, 0xbc, 0x89],
+    [0xc0, 0xc0, 0xc0], #[0xbc, 0xbc, 0xbc],
+    [0xff, 0xbc, 0xe1],
+    [0xbc, 0xff, 0x89],
+    [0xff, 0xff, 0xbc],
+    [0xbc, 0xff, 0xe1],
+    [0xff, 0xff, 0xff],
+  ],
+  numpy.uint8
+)
+
+if len(sys.argv) < 3:
+  print(f'usage: {sys.argv[0]:s} in.png out.png')
+  sys.exit(EXIT_FAILURE)
+in_png = sys.argv[1]
+out_png = sys.argv[2]
+
+image_in_pil = PIL.Image.open(in_png)
+assert image_in_pil.mode == 'P'
+image_in = numpy.frombuffer(
+  image_in_pil.tobytes(),
+  dtype = numpy.uint8
+).reshape((image_in_pil.size[1], image_in_pil.size[0]))
+
+image_out = numpy.zeros((PITCH_Y * 32, PITCH_X * 8), numpy.uint8)
+assert image_out.shape == image_in.shape
+
+for i in range(0x100):
+  j = i & 7
+  k = i >> 3
+  x = j * PITCH_X
+  y = k * PITCH_Y
+  bg = 0xa if (j ^ k) & 1 else 5
+  image_out[y:y + PITCH_Y, x:x + PITCH_X] = bg
+
+  shape = image_in[y:y + PITCH_Y, x:x + PITCH_X]
+  xs = shape.shape[1]
+  while xs:
+    if numpy.any(shape[:, xs - 1] != bg):
+      break
+    xs -= 1
+  else:
+    continue
+  ys = shape.shape[0]
+  while ys:
+    if numpy.any(shape[ys - 1, :] != bg):
+      break
+    ys -= 1
+  else:
+    continue
+  shape = shape[:ys, :xs]
+
+  shape1 = numpy.zeros((ys, xs + 2), numpy.uint8)
+  shape1[:, 1:-1] = shape
+  shape = shape1
+  xs += 2
+
+  image_out[y:y + ys, x:x + xs] = shape
+
+image_out_pil = PIL.Image.new(
+  'P',
+  (image_out.shape[1], image_out.shape[0]),
+  None
+)
+image_out_pil.frombytes(image_out.tobytes())
+image_out_pil.putpalette(list(PALETTE.reshape((0x30,))))
+image_out_pil.save(out_png)