Skip to content

Commit b9f62c4

Browse files
authored
Merge pull request #16 from ladyada/master
Add rotation support
2 parents 57938f9 + cd1c6be commit b9f62c4

File tree

1 file changed

+81
-52
lines changed

1 file changed

+81
-52
lines changed

adafruit_framebuf.py

Lines changed: 81 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,16 @@ def get_pixel(framebuf, x, y):
6868
offset = 7 - x & 0x07
6969
return (framebuf.buf[index] >> offset) & 0x01
7070

71+
@staticmethod
72+
def fill(framebuf, color):
73+
"""completely fill/clear the buffer with a color"""
74+
if color:
75+
fill = 0xFF
76+
else:
77+
fill = 0x00
78+
for i in range(len(framebuf.buf)):
79+
framebuf.buf[i] = fill
80+
7181
@staticmethod
7282
def fill_rect(framebuf, x, y, width, height, color):
7383
"""Draw a rectangle at the given location, size and color. The ``fill_rect`` method draws
@@ -96,6 +106,16 @@ def get_pixel(framebuf, x, y):
96106
offset = y & 0x07
97107
return (framebuf.buf[index] >> offset) & 0x01
98108

109+
@staticmethod
110+
def fill(framebuf, color):
111+
"""completely fill/clear the buffer with a color"""
112+
if color:
113+
fill = 0xFF
114+
else:
115+
fill = 0x00
116+
for i in range(len(framebuf.buf)):
117+
framebuf.buf[i] = fill
118+
99119
@staticmethod
100120
def fill_rect(framebuf, x, y, width, height, color):
101121
"""Draw a rectangle at the given location, size and color. The ``fill_rect`` method draws
@@ -110,36 +130,6 @@ def fill_rect(framebuf, x, y, width, height, color):
110130
y += 1
111131
height -= 1
112132

113-
114-
class RGB565Format:
115-
"""RGB565Format"""
116-
@staticmethod
117-
def set_pixel(framebuf, x, y, color):
118-
"""Set a given pixel to a color."""
119-
index = (x + y * framebuf.stride) * 2
120-
framebuf.buf[index] = (color >> 8) & 0xFF
121-
framebuf.buf[index + 1] = color & 0xFF
122-
123-
@staticmethod
124-
def get_pixel(framebuf, x, y):
125-
"""Get the color of a given pixel"""
126-
index = (x + y * framebuf.stride) * 2
127-
return (framebuf.buf[index] << 8) | framebuf.buf[index + 1]
128-
129-
@staticmethod
130-
def fill_rect(framebuf, x, y, width, height, color):
131-
# pylint: disable=too-many-arguments
132-
"""Draw a rectangle at the given location, size and color. The ``fill_rect`` method draws
133-
both the outline and interior."""
134-
while height > 0:
135-
for w_w in range(width):
136-
index = (w_w + x + y * framebuf.stride) * 2
137-
framebuf.buf[index] = (color >> 8) & 0xFF
138-
framebuf.buf[index + 1] = color & 0xFF
139-
y += 1
140-
height -= 1
141-
142-
143133
class FrameBuffer:
144134
"""FrameBuffer object.
145135
@@ -171,31 +161,44 @@ def __init__(self, buf, width, height, buf_format=MVLSB, stride=None):
171161
self.format = MVLSBFormat()
172162
elif buf_format == MHMSB:
173163
self.format = MHMSBFormat()
174-
elif buf_format == RGB565:
175-
self.format = RGB565Format()
176164
else:
177165
raise ValueError('invalid format')
166+
self._rotation = 0
167+
168+
@property
169+
def rotation(self):
170+
"""The rotation setting of the display, can be one of (0, 1, 2, 3)"""
171+
return self._rotation
172+
173+
@rotation.setter
174+
def rotation(self, val):
175+
if not val in (0, 1, 2, 3):
176+
raise RuntimeError("Bad rotation setting")
177+
self._rotation = val
178178

179179
def fill(self, color):
180180
"""Fill the entire FrameBuffer with the specified color."""
181-
self.format.fill_rect(self, 0, 0, self.width, self.height, color)
181+
self.format.fill(self, color)
182182

183183
def fill_rect(self, x, y, width, height, color):
184184
"""Draw a rectangle at the given location, size and color. The ``fill_rect`` method draws
185185
both the outline and interior."""
186186
# pylint: disable=too-many-arguments, too-many-boolean-expressions
187-
if width < 1 or height < 1 or (x + width) <= 0 or (y + height) <= 0 or y >= self.height \
188-
or x >= self.width:
189-
return
190-
x_end = min(self.width, x + width)
191-
y_end = min(self.height, y + height)
192-
x = max(x, 0)
193-
y = max(y, 0)
194-
self.format.fill_rect(self, x, y, x_end - x, y_end - y, color)
187+
self.rect(x, y, width, height, color, fill=True)
195188

196189
def pixel(self, x, y, color=None):
197190
"""If ``color`` is not given, get the color value of the specified pixel. If ``color`` is
198191
given, set the specified pixel to the given color."""
192+
if self.rotation == 1:
193+
x, y = y, x
194+
x = self.width - x - 1
195+
if self.rotation == 2:
196+
x = self.width - x - 1
197+
y = self.height - y - 1
198+
if self.rotation == 3:
199+
x, y = y, x
200+
y = self.height - y - 1
201+
199202
if x < 0 or x >= self.width or y < 0 or y >= self.height:
200203
return None
201204
if color is None:
@@ -205,20 +208,43 @@ def pixel(self, x, y, color=None):
205208

206209
def hline(self, x, y, width, color):
207210
"""Draw a horizontal line up to a given length."""
208-
self.fill_rect(x, y, width, 1, color)
211+
self.rect(x, y, width, 1, color, fill=True)
209212

210213
def vline(self, x, y, height, color):
211214
"""Draw a vertical line up to a given length."""
212-
self.fill_rect(x, y, 1, height, color)
215+
self.rect(x, y, 1, height, color, fill=True)
213216

214-
def rect(self, x, y, width, height, color):
217+
def rect(self, x, y, width, height, color, *, fill=False):
215218
"""Draw a rectangle at the given location, size and color. The ```rect``` method draws only
216219
a 1 pixel outline."""
217220
# pylint: disable=too-many-arguments
218-
self.fill_rect(x, y, width, 1, color)
219-
self.fill_rect(x, y + height-1, width, 1, color)
220-
self.fill_rect(x, y, 1, height, color)
221-
self.fill_rect(x + width - 1, y, 1, height, color)
221+
if self.rotation == 1:
222+
x, y = y, x
223+
width, height = height, width
224+
x = self.width - x - width
225+
if self.rotation == 2:
226+
x = self.width - x - width
227+
y = self.height - y - height
228+
if self.rotation == 3:
229+
x, y = y, x
230+
width, height = height, width
231+
y = self.height - y - height
232+
233+
# pylint: disable=too-many-boolean-expressions
234+
if width < 1 or height < 1 or (x + width) <= 0 or (y + height) <= 0 or \
235+
y >= self.height or x >= self.width:
236+
return
237+
x_end = min(self.width-1, x + width-1)
238+
y_end = min(self.height-1, y + height-1)
239+
x = max(x, 0)
240+
y = max(y, 0)
241+
if fill:
242+
self.format.fill_rect(self, x, y, x_end-x+1, y_end-y+1, color)
243+
else:
244+
self.format.fill_rect(self, x, y, x_end-x+1, 1, color)
245+
self.format.fill_rect(self, x, y, 1, y_end-y+1, color)
246+
self.format.fill_rect(self, x, y_end, x_end-x+1, 1, color)
247+
self.format.fill_rect(self, x_end, y, 1, y_end-y+1, color)
222248

223249
def line(self, x_0, y_0, x_1, y_1, color):
224250
# pylint: disable=too-many-arguments
@@ -356,14 +382,17 @@ def draw_char(self, char, x, y, framebuffer, color):
356382
# pylint: disable=too-many-arguments
357383
"""Draw one character at position (x,y) to a framebuffer in a given color"""
358384
# Don't draw the character if it will be clipped off the visible area.
359-
if x < -self.font_width or x >= framebuffer.width or \
360-
y < -self.font_height or y >= framebuffer.height:
361-
return
385+
#if x < -self.font_width or x >= framebuffer.width or \
386+
# y < -self.font_height or y >= framebuffer.height:
387+
# return
362388
# Go through each column of the character.
363389
for char_x in range(self.font_width):
364390
# Grab the byte for the current column of font data.
365391
self._font.seek(2 + (ord(char) * self.font_width) + char_x)
366-
line = struct.unpack('B', self._font.read(1))[0]
392+
try:
393+
line = struct.unpack('B', self._font.read(1))[0]
394+
except RuntimeError:
395+
continue # maybe character isnt there? go to next
367396
# Go through each row in the column byte.
368397
for char_y in range(self.font_height):
369398
# Draw a pixel for each bit that's flipped on.

0 commit comments

Comments
 (0)