Skip to content

Instantly share code, notes, and snippets.

@kaecy
Created March 9, 2024 02:54
Show Gist options
  • Save kaecy/469e94c15e746a502e995ef79418aa78 to your computer and use it in GitHub Desktop.
Save kaecy/469e94c15e746a502e995ef79418aa78 to your computer and use it in GitHub Desktop.
Bit Image Viewer

Bit Image Viewer

An image viewer for bit image files. These files are just 1-bit images with a very simple structure. 2 bytes at the beginning are used for width and height and the rest of the bytes are the bit array for the bit image.

To open an image pass main.py a bits file.

> main stairs.bits

You need wx for python to use this. The command to install wxpython is pip install -U wxpython.

import binascii
import math
# Colours
DR = chr(0x2591) # Dark
MD = chr(0x2592) # More dark
LD = chr(0x2593) # Light dark
LT = chr(0x2588) # Light
# Box characters
BOXCLT = chr(0x250C) # Top, left
BOXCRT = chr(0x2510) # Top, right
BOXCLB = chr(0x2514) # Bottom, left
BOXCRB = chr(0x2518) # Bottom, right
BOXLH = " " # chr(0x2500) # Horizontal line
BOXLV = chr(0x2502) # Vertical line
# Cell size
CEL = 2
# Returns the number of bytes needed for a 1-bit image with the
# size provided.
def bytes_needed(width, height):
area = width * height
bytes_needed = math.ceil(area / 8)
bytes_needed = bytes_needed + 2 # for width and height,
# and these are put at the beginning.
return bytes_needed
def create(width, height):
img = bytearray(bytes_needed(width, height))
img[0] = width
img[1] = height
return img
def place(img, data):
gendata = unhexlify(data)
ib_len = len(img) - 2
gd_len = len(gendata)
if gd_len > ib_len:
limit = ib_len
else:
limit = gd_len
for x in range(limit):
img[x+2] = gendata[x]
return img
def unhexlify(hex):
img = []
odd = len(hex) % 2
length = len(hex) - odd
for x in range(0, length, 2):
img.append( ( int(hex[x], 16) & 0x0f ) << 4 | int(hex[x+1], 16))
if odd:
img.append(int(hex[-1], 16) << 4)
return bytes(img)
def hexlify(img):
return str(binascii.hexlify(img), "latin-1")
def blit(img):
bitstream = img[2:]
stop = img[0] * img[1]
for i in range(stop):
if bitstream[i // 8] & (0x80 >> (i % 8)):
print(LT * CEL, end="")
else:
print(DR * CEL, end="")
if (i + 1) % img[0] == 0:
print()
def flip(img, x, y):
if x < 0 or x >= img[0]:
raise BaseException("Outside the range of width.")
if y < 0 or y >= img[1]:
raise BaseException("Outside the range of height.")
bits_total = (y * img[0]) + x
index = bits_total // 8
bit_mask = 0x80 >> (bits_total % 8)
img[2+index] = img[2+index] ^ bit_mask
#print("Bit-Access: %d" % bits_total)
#print("Index: %d" % index)
#print("Bit-Mask: %d" % bit_mask)
def get(img, x, y):
bits_total = (y * img[0]) + x
index = bits_total // 8
bit_mask = 0x80 >> (bits_total % 8)
return img[2+index] & bit_mask
def rect(img, x1, y1, x2, y2):
y = y1
while (y <= y2):
x = x1
while (x <= x2):
flip(img, x, y)
x = x + 1
y = y + 1
try:
import os
from PIL import Image
from PIL import ImageDraw
def bitmap(img, outputname):
border = 5
cell = 32
size = ((img[0]) * (cell + 1) + (border * 2) - 1,
(img[1]) * (cell + 1) + (border * 2) - 1)
image = Image.new("1", size, 1)
drawing = ImageDraw.Draw(image)
for i in range(img[0] * img[1]):
bit_set = img[2 + (i // 8)] & (0x80 >> (i % 8))
x = i % img[0]
y = i // img[0]
ox = border + (x * (cell + 1))
oy = border + (y * (cell + 1))
rect = (ox, oy, ox + cell - 1, oy + cell - 1)
if bit_set:
drawing.rectangle(rect, 0, 0, 0)
#else:
# drawing.rectangle(rect, 1, 0)
try:
image.save(outputname)
except FileNotFoundError:
os.makedirs(os.path.dirname(outputname))
image.save(outputname)
except ModuleNotFoundError:
print("Init: imaging lib not present.")
if __name__ == "__main__":
import sys
if len(sys.argv)-1 == 1:
img = open(sys.argv[1], "rb").read()
blit(img)
#! python3.11
import wx
import sys
import bit
if len(sys.argv) - 1 == 1:
with open(sys.argv[1], "rb") as file:
img = file.read()
else:
exit()
# Create a wx.App instance
app = wx.App()
# Create a wx.Frame instance
frame = wx.Frame(None, title="Bit Image Viewer", size=(410, 310))
# Create a wx.Panel instance
panel = wx.Panel(frame)
# Draw the grid pattern
def draw_grid(dc):
num_rows = 32
num_cols = 48
square_size = min(panel.GetSize().width // num_cols, panel.GetSize().height // num_rows)
# Calculate the offset to center the grid
offset_x = (panel.GetSize().width - num_cols * square_size) // 2
offset_y = (panel.GetSize().height - num_rows * square_size) // 2
for i in range(num_rows + 1):
dc.DrawLine(offset_x, offset_y + i * square_size, offset_x + num_cols * square_size, offset_y + i * square_size)
for j in range(num_cols + 1):
dc.DrawLine(offset_x + j * square_size, offset_y, offset_x + j * square_size, offset_y + num_rows * square_size)
dc.SetBrush(wx.Brush(wx.BLACK))
for i in range(img[1]):
for j in range(img[0]):
if bit.get(img, j, i):
x = offset_x + j * square_size
y = offset_y + i * square_size
# Draw black border
dc.DrawRectangle(x, y, square_size, square_size)
def on_paint(event):
dc = wx.PaintDC(panel)
draw_grid(dc)
def on_size(event):
panel.Refresh()
panel.Bind(wx.EVT_PAINT, on_paint)
panel.Bind(wx.EVT_SIZE, on_size)
# Show the frame
frame.Show()
# Start the event loop
app.MainLoop()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment