kopia lustrzana https://github.com/peterhinch/micropython-micro-gui
start to implement full color mode
rodzic
fa41a0ac9b
commit
bfde1ca694
|
@ -36,6 +36,24 @@ DFR0995 = (34, 0, 0) # DFR0995 Contributed by @EdgarKluge
|
||||||
WAVESHARE_13 = (0, 0, 16) # Waveshare 1.3" 240x240 LCD contributed by Aaron Mittelmeier
|
WAVESHARE_13 = (0, 0, 16) # Waveshare 1.3" 240x240 LCD contributed by Aaron Mittelmeier
|
||||||
ADAFRUIT_1_9 = (35, 0, PORTRAIT) # 320x170 TFT https://www.adafruit.com/product/5394
|
ADAFRUIT_1_9 = (35, 0, PORTRAIT) # 320x170 TFT https://www.adafruit.com/product/5394
|
||||||
|
|
||||||
|
# ST7789 commands
|
||||||
|
_ST7789_SWRESET = b"\x01"
|
||||||
|
_ST7789_SLPIN = b"\x10"
|
||||||
|
_ST7789_SLPOUT = b"\x11"
|
||||||
|
_ST7789_NORON = b"\x13"
|
||||||
|
_ST7789_INVOFF = b"\x20"
|
||||||
|
_ST7789_INVON = b"\x21"
|
||||||
|
_ST7789_DISPOFF = b"\x28"
|
||||||
|
_ST7789_DISPON = b"\x29"
|
||||||
|
_ST7789_CASET = b"\x2a"
|
||||||
|
_ST7789_RASET = b"\x2b"
|
||||||
|
_ST7789_RAMWR = b"\x2c"
|
||||||
|
_ST7789_VSCRDEF = b"\x33"
|
||||||
|
_ST7789_COLMOD = b"\x3a"
|
||||||
|
_ST7789_MADCTL = b"\x36"
|
||||||
|
_ST7789_VSCSAD = b"\x37"
|
||||||
|
_ST7789_RAMCTL = b"\xb0"
|
||||||
|
|
||||||
@micropython.viper
|
@micropython.viper
|
||||||
def _lcopy(dest: ptr16, source: ptr8, lut: ptr16, length: int, gscale: bool):
|
def _lcopy(dest: ptr16, source: ptr8, lut: ptr16, length: int, gscale: bool):
|
||||||
# rgb565 - 16bit/pixel
|
# rgb565 - 16bit/pixel
|
||||||
|
@ -143,13 +161,13 @@ class ST7789(framebuf.FrameBuffer):
|
||||||
self._spi_init(self._spi) # Bus may be shared
|
self._spi_init(self._spi) # Bus may be shared
|
||||||
cmd = self._wcmd
|
cmd = self._wcmd
|
||||||
wcd = self._wcd
|
wcd = self._wcd
|
||||||
cmd(b"\x01") # SW reset datasheet specifies 120ms before SLPOUT
|
cmd(_ST7789_SWRESET) # SW reset datasheet specifies 120ms before SLPOUT
|
||||||
sleep_ms(150)
|
sleep_ms(150)
|
||||||
cmd(b"\x11") # SLPOUT: exit sleep mode
|
cmd(_ST7789_SLPOUT) # SLPOUT: exit sleep mode
|
||||||
sleep_ms(10) # Adafruit delay 500ms (datsheet 5ms)
|
sleep_ms(10) # Adafruit delay 500ms (datsheet 5ms)
|
||||||
wcd(b"\x3a", b"\x55") # _COLMOD 16 bit/pixel, 65Kbit color space
|
wcd(_ST7789_COLMOD, b"\x55") # _COLMOD 16 bit/pixel, 65Kbit color space
|
||||||
cmd(b"\x20") # INVOFF Adafruit turn inversion on. This driver fixes .rgb
|
cmd(_ST7789_INVOFF) # INVOFF Adafruit turn inversion on. This driver fixes .rgb
|
||||||
cmd(b"\x13") # NORON Normal display mode
|
cmd(_ST7789_NORON) # NORON Normal display mode
|
||||||
|
|
||||||
# Table maps user request onto hardware values. index values:
|
# Table maps user request onto hardware values. index values:
|
||||||
# 0 Normal
|
# 0 Normal
|
||||||
|
@ -171,8 +189,8 @@ class ST7789(framebuf.FrameBuffer):
|
||||||
mode = (0x60, 0xE0, 0xA0, 0x20, 0, 0x40, 0xC0, 0x80)[user_mode]
|
mode = (0x60, 0xE0, 0xA0, 0x20, 0, 0x40, 0xC0, 0x80)[user_mode]
|
||||||
# Set display window depending on mode, .height and .width.
|
# Set display window depending on mode, .height and .width.
|
||||||
self.set_window(mode)
|
self.set_window(mode)
|
||||||
wcd(b"\x36", int.to_bytes(mode, 1, "little"))
|
wcd(_ST7789_MADCTL, int.to_bytes(mode, 1, "little"))
|
||||||
cmd(b"\x29") # DISPON. Adafruit then delay 500ms.
|
cmd(_ST7789_DISPON) # DISPON. Adafruit then delay 500ms.
|
||||||
|
|
||||||
# Define the mapping between RAM and the display.
|
# Define the mapping between RAM and the display.
|
||||||
# Datasheet section 8.12 p124.
|
# Datasheet section 8.12 p124.
|
||||||
|
@ -210,9 +228,9 @@ class ST7789(framebuf.FrameBuffer):
|
||||||
xe = rwd - xoff - 1
|
xe = rwd - xoff - 1
|
||||||
|
|
||||||
# Col address set.
|
# Col address set.
|
||||||
self._wcd(b"\x2a", int.to_bytes((xs << 16) + xe, 4, "big"))
|
self._wcd(_ST7789_CASET, int.to_bytes((xs << 16) + xe, 4, "big"))
|
||||||
# Row address set
|
# Row address set
|
||||||
self._wcd(b"\x2b", int.to_bytes((ys << 16) + ye, 4, "big"))
|
self._wcd(_ST7789_RASET, int.to_bytes((ys << 16) + ye, 4, "big"))
|
||||||
|
|
||||||
def greyscale(self, gs=None):
|
def greyscale(self, gs=None):
|
||||||
if gs is not None:
|
if gs is not None:
|
||||||
|
|
|
@ -0,0 +1,158 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Convert an image file to a python module for use with the bitmap method. Use redirection to save the
|
||||||
|
output to a file. The image is converted to a bitmap using the number of bits per pixel you specify.
|
||||||
|
The bitmap is saved as a python module that can be imported and used with the bitmap method.
|
||||||
|
|
||||||
|
.. seealso::
|
||||||
|
- :ref:`alien.py<alien>`.
|
||||||
|
|
||||||
|
Example
|
||||||
|
^^^^^^^
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
./create_png_examples.py cat.png 4 > cat_bitmap.py
|
||||||
|
|
||||||
|
The python file can be imported and displayed with the bitmap method. For example:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
import tft_config
|
||||||
|
import cat_bitmap
|
||||||
|
tft = tft_config.config(1)
|
||||||
|
tft.bitmap(cat_bitmap, 0, 0)
|
||||||
|
|
||||||
|
Usage
|
||||||
|
^^^^^
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
usage: image_converter.py [-h] image_file bits_per_pixel
|
||||||
|
|
||||||
|
Convert image file to python module for use with bitmap method.
|
||||||
|
|
||||||
|
positional arguments: image_file Name of file containing image to convert bits_per_pixel
|
||||||
|
The number of bits to use per pixel (1..8)
|
||||||
|
|
||||||
|
optional arguments: -h, --help show this help message and exit
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import argparse
|
||||||
|
from PIL import Image
|
||||||
|
|
||||||
|
|
||||||
|
def rgb_to_color565(r, g, b):
|
||||||
|
"""
|
||||||
|
Convert RGB color to the 16-bit color format (565).
|
||||||
|
|
||||||
|
Args:
|
||||||
|
r (int): Red component of the RGB color (0-255).
|
||||||
|
g (int): Green component of the RGB color (0-255).
|
||||||
|
b (int): Blue component of the RGB color (0-255).
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
int: Converted color value in the 16-bit color format (565).
|
||||||
|
"""
|
||||||
|
|
||||||
|
return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b & 0xF8)
|
||||||
|
|
||||||
|
|
||||||
|
def convert_to_bitmap(image_file, bits_requested):
|
||||||
|
"""
|
||||||
|
Convert image file to python module for use with bitmap method.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
image_file (str): Name of file containing image to convert.
|
||||||
|
bits (int): The number of bits to use per pixel (1..8).
|
||||||
|
"""
|
||||||
|
|
||||||
|
colors_requested = 1 << bits_requested
|
||||||
|
img = Image.open(image_file).convert("RGB")
|
||||||
|
img = img.convert("P", palette=Image.Palette.ADAPTIVE, colors=colors_requested)
|
||||||
|
palette = img.getpalette()
|
||||||
|
palette_colors = len(palette) // 3
|
||||||
|
actual_colors = min(palette_colors, colors_requested)
|
||||||
|
bits_required = actual_colors.bit_length()
|
||||||
|
if bits_required < bits_requested:
|
||||||
|
print(
|
||||||
|
f"\nNOTE: Quantization reduced colors to {palette_colors} from the {bits_requested} "
|
||||||
|
f"requested, reconverting using {bits_required} bit per pixel could save memory.\n",
|
||||||
|
file=sys.stderr,
|
||||||
|
)
|
||||||
|
|
||||||
|
colors = [
|
||||||
|
f"{rgb_to_color565(palette[color * 3], palette[color * 3 + 1], palette[color * 3 + 2]):04x}"
|
||||||
|
for color in range(actual_colors)
|
||||||
|
]
|
||||||
|
|
||||||
|
image_bitstring = "".join(
|
||||||
|
"".join(
|
||||||
|
"1" if (img.getpixel((x, y)) & (1 << bit - 1)) else "0"
|
||||||
|
for bit in range(bits_required, 0, -1)
|
||||||
|
)
|
||||||
|
for y in range(img.height)
|
||||||
|
for x in range(img.width)
|
||||||
|
)
|
||||||
|
|
||||||
|
bitmap_bits = len(image_bitstring)
|
||||||
|
|
||||||
|
print(f"HEIGHT = {img.height}")
|
||||||
|
print(f"WIDTH = {img.width}")
|
||||||
|
print(f"COLORS = {actual_colors}")
|
||||||
|
print(f"BITS = {bitmap_bits}")
|
||||||
|
print(f"BPP = {bits_required}")
|
||||||
|
print("PALETTE = [", end="")
|
||||||
|
|
||||||
|
for i, rgb in enumerate(colors):
|
||||||
|
if i > 0:
|
||||||
|
print(",", end="")
|
||||||
|
print(f"0x{rgb}", end="")
|
||||||
|
|
||||||
|
print("]")
|
||||||
|
|
||||||
|
print("_bitmap =\\\nb'", end="")
|
||||||
|
|
||||||
|
for i in range(0, bitmap_bits, 8):
|
||||||
|
if i and i % (16 * 8) == 0:
|
||||||
|
print("'\\\nb'", end="")
|
||||||
|
value = image_bitstring[i : i + 8]
|
||||||
|
color = int(value, 2)
|
||||||
|
print(f"\\x{color:02x}", end="")
|
||||||
|
|
||||||
|
print("'\nBITMAP = memoryview(_bitmap)")
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""
|
||||||
|
Convert image file to python module for use with bitmap method.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
image_file (str): Name of file containing image to convert.
|
||||||
|
bits_per_pixel (int): The number of bits to use per pixel (1..8).
|
||||||
|
"""
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description="Convert image file to python module for use with bitmap method.",
|
||||||
|
)
|
||||||
|
|
||||||
|
parser.add_argument("image_file", help="Name of file containing image to convert")
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
"bits_per_pixel",
|
||||||
|
type=int,
|
||||||
|
choices=range(1, 9),
|
||||||
|
default=1,
|
||||||
|
metavar="bits_per_pixel",
|
||||||
|
help="The number of bits to use per pixel (1..8)",
|
||||||
|
)
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
bits = args.bits_per_pixel
|
||||||
|
convert_to_bitmap(args.image_file, bits)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
Ładowanie…
Reference in New Issue