diff options
Diffstat (limited to 'lib/python')
| -rw-r--r-- | lib/python/qmk/painter.py | 80 | 
1 files changed, 75 insertions, 5 deletions
| diff --git a/lib/python/qmk/painter.py b/lib/python/qmk/painter.py index d0cc1dddec..7ecdc55404 100644 --- a/lib/python/qmk/painter.py +++ b/lib/python/qmk/painter.py @@ -7,6 +7,20 @@ from PIL import Image, ImageOps  # The list of valid formats Quantum Painter supports  valid_formats = { +    'rgb888': { +        'image_format': 'IMAGE_FORMAT_RGB888', +        'bpp': 24, +        'has_palette': False, +        'num_colors': 16777216, +        'image_format_byte': 0x09,  # see qp_internal_formats.h +    }, +    'rgb565': { +        'image_format': 'IMAGE_FORMAT_RGB565', +        'bpp': 16, +        'has_palette': False, +        'num_colors': 65536, +        'image_format_byte': 0x08,  # see qp_internal_formats.h +    },      'pal256': {          'image_format': 'IMAGE_FORMAT_PALETTE',          'bpp': 8, @@ -144,19 +158,33 @@ def convert_requested_format(im, format):      ncolors = format["num_colors"]      image_format = format["image_format"] -    # Ensure we have a valid number of colors for the palette -    if ncolors <= 0 or ncolors > 256 or (ncolors & (ncolors - 1) != 0): -        raise ValueError("Number of colors must be 2, 4, 16, or 256.") -      # Work out where we're getting the bytes from      if image_format == 'IMAGE_FORMAT_GRAYSCALE': +        # Ensure we have a valid number of colors for the palette +        if ncolors <= 0 or ncolors > 256 or (ncolors & (ncolors - 1) != 0): +            raise ValueError("Number of colors must be 2, 4, 16, or 256.")          # If mono, convert input to grayscale, then to RGB, then grab the raw bytes corresponding to the intensity of the red channel          im = ImageOps.grayscale(im)          im = im.convert("RGB")      elif image_format == 'IMAGE_FORMAT_PALETTE': +        # Ensure we have a valid number of colors for the palette +        if ncolors <= 0 or ncolors > 256 or (ncolors & (ncolors - 1) != 0): +            raise ValueError("Number of colors must be 2, 4, 16, or 256.")          # If color, convert input to RGB, palettize based on the supplied number of colors, then get the raw palette bytes          im = im.convert("RGB")          im = im.convert("P", palette=Image.ADAPTIVE, colors=ncolors) +    elif image_format == 'IMAGE_FORMAT_RGB565': +        # Ensure we have a valid number of colors for the palette +        if ncolors != 65536: +            raise ValueError("Number of colors must be 65536.") +        # If color, convert input to RGB +        im = im.convert("RGB") +    elif image_format == 'IMAGE_FORMAT_RGB888': +        # Ensure we have a valid number of colors for the palette +        if ncolors != 1677216: +            raise ValueError("Number of colors must be 16777216.") +        # If color, convert input to RGB +        im = im.convert("RGB")      return im @@ -170,8 +198,12 @@ def convert_image_bytes(im, format):      image_format = format["image_format"]      shifter = int(math.log2(ncolors))      pixels_per_byte = int(8 / math.log2(ncolors)) +    bytes_per_pixel = math.ceil(math.log2(ncolors) / 8)      (width, height) = im.size -    expected_byte_count = ((width * height) + (pixels_per_byte - 1)) // pixels_per_byte +    if (pixels_per_byte != 0): +        expected_byte_count = ((width * height) + (pixels_per_byte - 1)) // pixels_per_byte +    else: +        expected_byte_count = width * height * bytes_per_pixel      if image_format == 'IMAGE_FORMAT_GRAYSCALE':          # Take the red channel @@ -212,6 +244,44 @@ def convert_image_bytes(im, format):                      byte = byte | ((image_bytes[byte_offset] & (ncolors - 1)) << int(n * shifter))              bytearray.append(byte) +    if image_format == 'IMAGE_FORMAT_RGB565': +        # Take the red, green, and blue channels +        image_bytes_red = im.tobytes("raw", "R") +        image_bytes_green = im.tobytes("raw", "G") +        image_bytes_blue = im.tobytes("raw", "B") +        image_pixels_len = len(image_bytes_red) + +        # No palette +        palette = None + +        bytearray = [] +        for x in range(image_pixels_len): +            # 5 bits of red, 3 MSb of green +            byte = ((image_bytes_red[x] >> 3 & 0x1F) << 3) + (image_bytes_green[x] >> 5 & 0x07) +            bytearray.append(byte) +            # 3 LSb of green, 5 bits of blue +            byte = ((image_bytes_green[x] >> 2 & 0x07) << 5) + (image_bytes_blue[x] >> 3 & 0x1F) +            bytearray.append(byte) + +    if image_format == 'IMAGE_FORMAT_RGB888': +        # Take the red, green, and blue channels +        image_bytes_red = im.tobytes("raw", "R") +        image_bytes_green = im.tobytes("raw", "G") +        image_bytes_blue = im.tobytes("raw", "B") +        image_pixels_len = len(image_bytes_red) + +        # No palette +        palette = None + +        bytearray = [] +        for x in range(image_pixels_len): +            byte = image_bytes_red[x] +            bytearray.append(byte) +            byte = image_bytes_green[x] +            bytearray.append(byte) +            byte = image_bytes_blue[x] +            bytearray.append(byte) +      if len(bytearray) != expected_byte_count:          raise Exception(f"Wrong byte count, was {len(bytearray)}, expected {expected_byte_count}") | 
