Skip to content

Commit 4a2f5a6

Browse files
authored
Merge pull request #71 from makermelissa/master
Add 16, 24, and 32-bit bmp support
2 parents 1bf25b5 + f6ddfce commit 4a2f5a6

File tree

2 files changed

+104
-3
lines changed

2 files changed

+104
-3
lines changed

adafruit_imageload/bmp/__init__.py

100644100755
Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,20 @@ def load(
6262
file.seek(0x2E) # Number of colors in the color palette
6363
colors = int.from_bytes(file.read(4), "little")
6464

65-
if colors == 0 and color_depth >= 16:
66-
raise NotImplementedError("True color BMP unsupported")
67-
6865
if compression > 2:
6966
raise NotImplementedError("bitmask compression unsupported")
7067

68+
if colors == 0 and color_depth >= 16:
69+
from . import truecolor
70+
71+
return truecolor.load(
72+
file,
73+
_width,
74+
_height,
75+
data_start,
76+
color_depth,
77+
bitmap=bitmap,
78+
)
7179
if colors == 0:
7280
colors = 2**color_depth
7381
from . import indexed

adafruit_imageload/bmp/truecolor.py

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
# SPDX-FileCopyrightText: 2018 Scott Shawcroft for Adafruit Industries
2+
# SPDX-FileCopyrightText: 2022-2023 Melissa LeBlanc-Williams
3+
#
4+
# SPDX-License-Identifier: MIT
5+
6+
"""
7+
`adafruit_imageload.bmp.truecolor`
8+
====================================================
9+
10+
Load pixel colors into a bitmap from an truecolor BMP and return the correct colorconverter.
11+
12+
* Author(s): Melissa LeBlanc-Williams
13+
14+
"""
15+
16+
import sys
17+
18+
try:
19+
from typing import Tuple, Optional
20+
from io import BufferedReader
21+
from displayio import Bitmap
22+
from ..displayio_types import BitmapConstructor
23+
except ImportError:
24+
pass
25+
26+
from displayio import ColorConverter, Colorspace
27+
28+
__version__ = "0.0.0+auto.0"
29+
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_ImageLoad.git"
30+
31+
32+
def load(
33+
file: BufferedReader,
34+
width: int,
35+
height: int,
36+
data_start: int,
37+
color_depth: int,
38+
*,
39+
bitmap: Optional[BitmapConstructor] = None,
40+
) -> Tuple[Optional[Bitmap], Optional[ColorConverter]]:
41+
"""Loads truecolor bitmap data into bitmap and palette objects. Due to the 16-bit limit
42+
that the bitmap object can hold, colors will be converted to 16-bit RGB565 values.
43+
44+
:param file file: The open bmp file
45+
:param int width: Image width in pixels
46+
:param int height: Image height in pixels
47+
:param int data_start: Byte location where the data starts (after headers)
48+
:param int color_depth: Number of bits used to store a value
49+
:param BitmapConstructor bitmap: a function that returns a displayio.Bitmap
50+
"""
51+
# pylint: disable=too-many-arguments,too-many-locals,too-many-branches
52+
converter_obj = None
53+
bitmap_obj = None
54+
if bitmap:
55+
# Set up a ColorConverter object and set appropriate colorspace
56+
# to convert from based on the color depth
57+
input_colorspace = Colorspace.RGB888
58+
if color_depth == 16:
59+
input_colorspace = Colorspace.RGB555
60+
converter_obj = ColorConverter(input_colorspace=input_colorspace)
61+
if sys.maxsize > 1073741823:
62+
# pylint: disable=import-outside-toplevel, relative-beyond-top-level
63+
from .negative_height_check import negative_height_check
64+
65+
# convert unsigned int to signed int when height is negative
66+
height = negative_height_check(height)
67+
bitmap_obj = bitmap(width, abs(height), 65535)
68+
file.seek(data_start)
69+
line_size = width * (color_depth // 8)
70+
# Set the seek direction based on whether the height value is negative or positive
71+
if height > 0:
72+
range1 = height - 1
73+
range2 = -1
74+
range3 = -1
75+
else:
76+
range1 = 0
77+
range2 = abs(height)
78+
range3 = 1
79+
chunk = bytearray(line_size)
80+
for y in range(range1, range2, range3):
81+
file.readinto(chunk)
82+
bytes_per_pixel = color_depth // 8
83+
offset = y * width
84+
85+
for x in range(width):
86+
i = x * bytes_per_pixel
87+
if color_depth == 16:
88+
pixel = chunk[i] | chunk[i + 1] << 8
89+
else:
90+
pixel = chunk[i + 2] << 16 | chunk[i + 1] << 8 | chunk[i]
91+
bitmap_obj[offset + x] = converter_obj.convert(pixel)
92+
93+
return bitmap_obj, ColorConverter(input_colorspace=Colorspace.RGB565)

0 commit comments

Comments
 (0)