I have recently been working on a small emulated 8-bit CPU that I wish to have graphics capabilities. At the moment, it dumps the upper 16K of ram as a binary file every cycle for it to be read as "video memory." I've made a simple pygame-based program that reads the file and then attempts to convert it to a 128x128 grayscale 3d array for it to be directly blit as a surface. It does not work. I thought I could directly cut to the chase and just ask, Is there a way to read a binary file and convert its bytes into 3-3-2 colour, regardless of the file's actual content?
Here's my current code:
import pygame
import numpy as np
from time import sleep
class Viewer:
def __init__(self, update_func, display_size):
self.display_size = display_size
self.update_func = update_func
pygame.init()
self.display = pygame.display.set_mode(display_size)
def set_title(self, title):
pygame.display.set_caption(title)
def start(self):
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
z = self.update_func()
surf = pygame.surfarray.make_surface(z)
new = pygame.transform.scale(surf, self.display_size)
self.display.blit(new, (0, 0))
pygame.display.update()
pygame.quit()
def update():
file = open("core.bin", "rb")
value = bytearray(file.read())
lst = list(value)
file.close()
image = [[ [lst for col in range(len(lst))] for col in range(len(lst))] for row in range(len(lst))]
print(image)
sleep(0.25)
return image
viewer = Viewer(update, (512, 512))
viewer.start()
update()
I've tried numpy.dstack in the past, and normal 3d arrays work fine with my code, just not binary files. And yes, my bin files are exactly 16k. No error messages either.
Made a 128 *128 8-bit image, for testing; assuming RRRGGGBB, as opposed to BBGGGRRR. Flip 'em around, if that's the case. Found that numpy's reshape()
wrecked images. Injecting values directly into the expected numpy location gave better results. Should be faster, too.
#! /usr/bin/env python3
import pygame
import numpy as np
from time import sleep
from random import randint
class Viewer:
def __init__(self, update_func, display_size):
self.display_size = display_size
self.update_func = update_func
pygame.init()
self.display = pygame.display.set_mode(display_size)
def set_title(self, title):
pygame.display.set_caption(title)
def start(self):
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
z = self.update_func()
surf = pygame.surfarray.make_surface(z)
new = pygame.transform.scale(surf, self.display_size)
self.display.blit(new, (0, 0))
pygame.display.update()
pygame.quit()
'''
32 111 000 00 = randint( 0, 7 ) << 5 r
64 000 111 00 = randint( 0, 7 ) << 2 g
96 000 000 11 = randint( 0, 3 ) b
128 111 111 11 = randint( 0, 255 ) w
'''
screenshot = bytearray( 128 *128 ) ## 128 *128 8-bit image, just for testing
for red in range( 0, 128 *32 ): screenshot[ red ] = randint( 0, 7 ) << 5
for green in range( 128 *32, 128 *64 ): screenshot[ green ] = randint( 0, 7 ) << 2
for blue in range( 128 *64, 128 *96 ): screenshot[ blue ] = randint( 0, 3 )
for white in range( 128 *96, 128 *128 ): screenshot[ white ] = randint( 0, 255 )
row, col = 0, 0
arr = np .zeros( ( 128, 128, 3 ) ) ## generate empty numpy array
for byte in screenshot:
rrr = int( ( ( byte & 0b11100000 ) >> 5 ) *36.4285714286 ) ## red
ggg = int( ( ( byte & 0b00011100 ) >> 2 ) *36.4285714286 ) ## green
bb = int( ( byte & 0b00000011 ) *85 ) ## blue -- multiplied to max 255 range
arr[ col ][ row ][ 0 ] = rrr ## insert color values directly into numpy cells
arr[ col ][ row ][ 1 ] = ggg
arr[ col ][ row ][ 2 ] = bb
col += 1
if col == 128:
col = 0 ## \r carriage return
row += 1 ## \n newline
def update():
image = arr
sleep(0.25)
return image
viewer = Viewer(update, (512, 512))
viewer.start()
update()