This repository has been archived on 2025-01-25. You can view files and clone it, but cannot push or open issues or pull requests.
rp2040_projects/i2c/oled_i2c/img_to_array.py
Graham Sanderson 6e647c6f26
Additional examples for specific h/w by our interns (#171)
adc/microphone_adc - Read analog values from a microphone and plot the measured sound amplitude.
i2c/bmp280_i2c - Read and convert temperature and pressure data from a BMP280 sensor, attached to an I2C bus.
i2c/lis3dh_i2c - Read acceleration and temperature value from a LIS3DH sensor via I2C
i2c/mcp9808_i2c - Read temperature, set limits and raise alerts when limits are surpassed.
i2c/mma8451_i2c - Read acceleration from a MMA8451 accelerometer and set range and precision for the data.
i2c/mpl3115a2_i2c - Interface with an MPL3115A2 altimeter, exploring interrupts and advanced board features, via I2C.
i2c/oled_i2c - Convert and display a bitmap on a 128x32 SSD1306-driven OLED display
i2c/pa1010d_i2c - Read GPS location data, parse and display data via I2C.
i2c/pcf8523_i2c - Read time and date values from a real time clock. Set current time and alarms on it.
uart/lcd_uart - Display text and symbols on a 16x02 RGB LCD display via UART
2021-10-25 12:30:57 -05:00

82 lines
2.1 KiB
Python
Executable File

#!/usr/bin/env python3
# Converts a grayscale image into a format able to be
# displayed by the SSD1306 driver in horizontal addressing mode
# usage: python3 img_to_array.py <logo.bmp>
# depends on the Pillow library
# `python3 -m pip install --upgrade Pillow`
from PIL import Image
import sys
from pathlib import Path
OLED_HEIGHT = 32
OLED_WIDTH = 128
OLED_PAGE_HEIGHT = 8
if len(sys.argv) < 2:
print("No image path provided.")
sys.exit()
img_path = sys.argv[1]
try:
im = Image.open(img_path)
except OSError:
raise Exception("Oops! The image could not be opened.")
img_width = im.size[0]
img_height = im.size[1]
if img_width > OLED_WIDTH or img_height > OLED_HEIGHT:
print(f'Your image is f{img_width} pixels wide and {img_height} pixels high, but...')
raise Exception(f"OLED display only {OLED_WIDTH} pixels wide and {OLED_HEIGHT} pixels high!")
if not (im.mode == "1" or im.mode == "L"):
raise Exception("Image must be grayscale only")
# black or white
out = im.convert("1")
img_name = Path(im.filename).stem
# `pixels` is a flattened array with the top left pixel at index 0
# and bottom right pixel at the width*height-1
pixels = list(out.getdata())
# swap white for black and swap (255, 0) for (1, 0)
pixels = [0 if x == 255 else 1 for x in pixels]
# our goal is to divide the image into 8-pixel high pages
# and turn a pixel column into one byte, eg for one page:
# 0 1 0 ....
# 1 0 0
# 1 1 1
# 0 0 1
# 1 1 0
# 0 1 0
# 1 1 1
# 0 0 1 ....
# we get 0x6A, 0xAE, 0x33 ... and so on
# as `pixels` is flattened, each bit in a column is IMG_WIDTH apart from the next
buffer = []
for i in range(img_height // OLED_PAGE_HEIGHT):
start_index = i*img_width*OLED_PAGE_HEIGHT
for j in range(img_width):
out_byte = 0
for k in range(OLED_PAGE_HEIGHT):
out_byte |= pixels[k*img_width + start_index + j] << k
buffer.append(f'{out_byte:#04x}')
buffer = ", ".join(buffer)
buffer_hex = f'static uint8_t {img_name}[] = {{{buffer}}}\n'
with open(f'{img_name}.h', 'wt') as file:
file.write(f'#define IMG_WIDTH {img_width}\n')
file.write(f'#define IMG_HEIGHT {img_height}\n\n')
file.write(buffer_hex)