32
32
__version__ = "0.0.0-auto.0"
33
33
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_ImageLoad.git"
34
34
35
- def load (file , width , height , data_start , colors , color_depth , * , bitmap = None , palette = None ):
35
+ def load (file , width , height , data_start , colors , color_depth , compression , * , bitmap = None , palette = None ):
36
36
"""Loads indexed bitmap data into bitmap and palette objects.
37
37
38
38
:param file file: The open bmp file
39
39
:param int width: Image width in pixels
40
40
:param int height: Image height in pixels
41
41
:param int data_start: Byte location where the data starts (after headers)
42
42
:param int colors: Number of distinct colors in the image
43
- :param int color_depth: Number of bits used to store a value"""
43
+ :param int color_depth: Number of bits used to store a value
44
+ :param int compression: 0 - none, 1 - 8bit RLE, 2 - 4bit RLE"""
44
45
# pylint: disable=too-many-arguments,too-many-locals
45
46
if palette :
46
47
palette = palette (colors )
@@ -70,7 +71,6 @@ def load(file, width, height, data_start, colors, color_depth, *, bitmap=None, p
70
71
if line_size % 4 != 0 :
71
72
line_size += (4 - line_size % 4 )
72
73
73
- chunk = bytearray (line_size )
74
74
mask = (1 << minimum_color_depth ) - 1
75
75
if height > 0 :
76
76
range1 = height - 1
@@ -80,14 +80,138 @@ def load(file, width, height, data_start, colors, color_depth, *, bitmap=None, p
80
80
range1 = 0
81
81
range2 = abs (height )
82
82
range3 = 1
83
- for y in range (range1 , range2 , range3 ):
84
- file .readinto (chunk )
85
- pixels_per_byte = 8 // color_depth
86
- offset = y * width
87
-
88
- for x in range (width ):
89
- i = x // pixels_per_byte
90
- pixel = (chunk [i ] >> (8 - color_depth * (x % pixels_per_byte + 1 ))) & mask
91
- bitmap [offset + x ] = pixel
83
+
84
+ if compression == 0 :
85
+ chunk = bytearray (line_size )
86
+ for y in range (range1 , range2 , range3 ):
87
+ file .readinto (chunk )
88
+ pixels_per_byte = 8 // color_depth
89
+ offset = y * width
90
+
91
+ for x in range (width ):
92
+ i = x // pixels_per_byte
93
+ pixel = (chunk [i ] >> (8 - color_depth * (x % pixels_per_byte + 1 ))) & mask
94
+ bitmap [offset + x ] = pixel
95
+ elif compression == 1 or compression == 2 :
96
+ # RLE algorithm, either 8-bit (1) or 4-bit (2)
97
+ #
98
+ # Ref: http://www.fileformat.info/format/bmp/egff.htm
99
+
100
+ is_4bit = compression == 2
101
+
102
+ # This will store the 2-byte run commands, which are either an
103
+ # amount to repeat and a value to repeat, or a 0x00 and command
104
+ # marker.
105
+ run_buf = bytearray (2 )
106
+
107
+ # We need to be prepared to load up to 256 pixels of literal image
108
+ # data. (0xFF is max literal length, but odd literal runs are padded
109
+ # up to an even byte count, so we need space for 256 in the case of
110
+ # 8-bit.) 4-bit images can get away with half that.
111
+ literal_buf = bytearray (128 if is_4bit else 256 )
112
+
113
+ # We iterate with numbers rather than a range because the "delta"
114
+ # command can cause us to jump forward arbitrarily in the output
115
+ # image.
116
+ #
117
+ # In theory RLE images are only stored in bottom-up scan line order,
118
+ # but we support either.
119
+ y = range1
120
+ x = 0
121
+
122
+ while y * range3 < range2 * range3 :
123
+ offset = y * width + x
124
+
125
+ # We keep track of how much space is left in our row so that we
126
+ # can avoid writing extra data outside of the Bitmap. While the
127
+ # reference above seems to say that the "end run" command is
128
+ # optional and that image data should wrap from one scan line to
129
+ # the next, in practice (looking at the output of ImageMagick
130
+ # and GIMP, and what Preview renders) the bitmap part of the
131
+ # image can contain data that goes beyond the image’s stated
132
+ # width that should just be ignored. For example, the 8bit RLE
133
+ # file is 15px wide but has data for 16px.
134
+ width_remaining = width - x
135
+
136
+ file .readinto (run_buf )
137
+
138
+ if run_buf [0 ] == 0 :
139
+ # A repeat length of "0" is a special command. The next byte
140
+ # tells us what needs to happen.
141
+ if run_buf [1 ] == 0 :
142
+ # end of the current scan line
143
+ y = y + range3
144
+ x = 0
145
+ elif run_buf [1 ] == 1 :
146
+ # end of image
147
+ break
148
+ elif run_buf [1 ] == 2 :
149
+ # delta command jumps us ahead in the bitmap output by
150
+ # the x, y amounts stored in the next 2 bytes.
151
+ file .readinto (run_buf )
152
+
153
+ x = x + run_buf [0 ]
154
+ y = y + run_buf [1 ] * range3
155
+ else :
156
+ # command values of 3 or more indicate that many pixels
157
+ # of literal (uncompressed) image data. For 8-bit mode,
158
+ # this is raw bytes, but 4-bit mode counts in nibbles.
159
+ literal_length_px = run_buf [1 ]
160
+
161
+ # Inverting the value here to get round-up integer division
162
+ read_length_bytes = - (- literal_length_px // 2 ) if is_4bit else literal_length_px
163
+
164
+ # If the run has an odd length then there’s a 1-byte padding
165
+ # we need to consume but not write into the output
166
+ if read_length_bytes % 2 == 1 :
167
+ read_length_bytes += 1
168
+
169
+ # We use memoryview to artificially limit the length of
170
+ # literal_buf so that readinto only reads the amount
171
+ # that we want.
172
+ literal_buf_mem = memoryview (literal_buf )
173
+ file .readinto (literal_buf_mem [0 :read_length_bytes ])
174
+
175
+ if is_4bit :
176
+ for i in range (0 , min (literal_length_px , width_remaining )):
177
+ # Expanding the two nibbles of the 4-bit data
178
+ # into two bytes for our output bitmap.
179
+ if i % 2 == 0 :
180
+ bitmap [offset + i ] = literal_buf [i // 2 ] >> 4
181
+ else :
182
+ bitmap [offset + i ] = literal_buf [i // 2 ] & 0x0F
183
+ else :
184
+ # 8-bit values are just a raw copy (limited by
185
+ # what’s left in the row so we don’t overflow out of
186
+ # the buffer)
187
+ for i in range (0 , min (literal_length_px , width_remaining )):
188
+ bitmap [offset + i ] = literal_buf [i ]
189
+
190
+ x = x + literal_length_px
191
+ else :
192
+ # first byte was not 0, which means it tells us how much to
193
+ # repeat the next byte into the output
194
+ run_length_px = run_buf [0 ]
195
+
196
+ if is_4bit :
197
+ # In 4 bit mode, we repeat the *two* values that are
198
+ # packed into the next byte. The repeat amount is based
199
+ # on pixels, not bytes, though, so if we were to repeat
200
+ # 0xab 3 times, the output pixel values would be: 0x0a
201
+ # 0x0b 0x0a (notice how it ends at 0x0a) rather than
202
+ # 0x0a 0x0b 0x0a 0x0b 0x0a 0x0b
203
+ run_values = [
204
+ run_buf [1 ] >> 4 ,
205
+ run_buf [1 ] & 0x0F
206
+ ]
207
+ for i in range (0 , min (run_length_px , width_remaining )):
208
+ bitmap [offset + i ] = run_values [i % 2 ]
209
+ else :
210
+ run_value = run_buf [1 ]
211
+ for i in range (0 , min (run_length_px , width_remaining )):
212
+ bitmap [offset + i ] = run_value
213
+
214
+
215
+ x = x + run_length_px
92
216
93
217
return bitmap , palette
0 commit comments