kopia lustrzana https://github.com/peterhinch/micropython-font-to-py
V0.2 Adapted for improved framebuf module
rodzic
686d1c92bb
commit
d518b4a772
|
@ -43,12 +43,6 @@ The ``Writer`` class exposes the following class methods:
|
|||
the physical display. If ``col_clip`` is ``False`` characters will wrap onto
|
||||
the next line. If ``row_clip`` is ``False`` the display will, where necessary,
|
||||
scroll up to ensure the line is rendered.
|
||||
3. ``mapping`` Arg: an integer. This defines the mapping of bytes in the
|
||||
buffer onto pixels. The module exposes three constants for use here: ``VERT``
|
||||
``HORIZ`` and ``WEIRD``, the latter being specific to the official SSD1306
|
||||
driver. ``VERT`` is for true vertically mapped displays. ``HORIZ``, for
|
||||
horizontally mapped devices, is currently unsupported. By default the mapping
|
||||
is for SSD1306 devices using the official driver.
|
||||
|
||||
As class methods these settings apply to all font objects. The insertion point
|
||||
of characters is maintained regardless of the font in use.
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
import machine
|
||||
import utime
|
||||
from writer import Writer
|
||||
from ssd1306_drv import SSD1306_I2C, SSD1306_SPI # Until official module is fixed
|
||||
from ssd1306 import SSD1306_I2C, SSD1306_SPI
|
||||
import freeserif
|
||||
import freesans20
|
||||
import inconsolata16
|
||||
|
|
122
ssd1306_drv.py
122
ssd1306_drv.py
|
@ -1,122 +0,0 @@
|
|||
# ssd1306_drv.py An implementation of a Display class for SSD1306 based displays
|
||||
# V0.1 Peter Hinch Nov 2016
|
||||
|
||||
# https://learn.adafruit.com/monochrome-oled-breakouts/wiring-128x32-spi-oled-display
|
||||
# https://www.proto-pic.co.uk/monochrome-128x32-oled-graphic-display.html
|
||||
|
||||
# Version supports vertical and "horizontal" modes.
|
||||
|
||||
# The MIT License (MIT)
|
||||
#
|
||||
# Copyright (c) 2016 Peter Hinch
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
# SSD1306 classes to fix the official one whose scroll method is broken
|
||||
# This also demonstrates a way to do scrolling for devices with true vertical
|
||||
# mapping (the official driver sets the device into its "horizontal" mode).
|
||||
# This is a hybrid mode where bytes are aligned vertically but arranged
|
||||
# horizontally
|
||||
|
||||
import ssd1306
|
||||
|
||||
class SSD1306(object):
|
||||
def __init__(self, device):
|
||||
self.width = device.width # In pixels
|
||||
self.height = device.height
|
||||
self.bpc = (self.height + 7) >> 3
|
||||
self.device = device
|
||||
self.vmap = False # Currently the official driver uses "horizontal"
|
||||
|
||||
@property
|
||||
def buffer(self): # property emulates underlying device
|
||||
return self.device.buffer
|
||||
|
||||
def show(self):
|
||||
self.device.show()
|
||||
|
||||
# Return map-independent offset into buffer
|
||||
def _offset(self, x, y):
|
||||
if self.vmap:
|
||||
return y + x * self.bpc
|
||||
else:
|
||||
return y * self.width + x
|
||||
|
||||
def scroll(self, x, y):
|
||||
dy = abs(y)
|
||||
if dy:
|
||||
self._scrolly(dy, y > 0)
|
||||
dx = abs(x)
|
||||
if dx:
|
||||
self._scrollx(dx, x > 0)
|
||||
|
||||
def _scrolly(self, ystep, down):
|
||||
buf = self.device.buffer
|
||||
bpc = self.bpc
|
||||
ystep_bytes = (ystep >> 3) + 1
|
||||
ystep_bits = ystep & 7
|
||||
if down:
|
||||
for x in range(self.width):
|
||||
for ydest in range(bpc - 1, -1, -1):
|
||||
ysource = ydest - ystep_bytes
|
||||
data = 0
|
||||
if ysource + 1 >= 0:
|
||||
data = buf[self._offset(x, ysource + 1)] << ystep_bits
|
||||
if ysource >= 0:
|
||||
data |= buf[self._offset(x, ysource)] >> 8 - ystep_bits
|
||||
buf[self._offset(x, ydest)] = data
|
||||
else:
|
||||
for x in range(self.width):
|
||||
for ydest in range(bpc):
|
||||
ysource = ydest + ystep_bytes
|
||||
data = 0
|
||||
if ysource < bpc:
|
||||
data = buf[self._offset(x, ysource)] << (8-ystep_bits)
|
||||
if ysource - 1 < bpc:
|
||||
data |= buf[self._offset(x, ysource - 1)] >> ystep_bits
|
||||
buf[self._offset(x, ydest)] = data
|
||||
|
||||
def _scrollx(self, xstep, right): # scroll x
|
||||
buf = self.device.buffer
|
||||
bpc = self.bpc
|
||||
for y in range(bpc):
|
||||
if right: # Scroll right
|
||||
for xdest in range(self.width - 1, -1, -1):
|
||||
data = 0
|
||||
xsource = xdest - xstep
|
||||
if xsource >= 0:
|
||||
data = buf[self._offset(xsource, y)]
|
||||
buf[self._offset(xdest, y)] = data
|
||||
else:
|
||||
for xdest in range(0, self.width):
|
||||
data = 0
|
||||
xsource = xdest + xstep
|
||||
if xsource < self.width:
|
||||
data = buf[self._offset(xsource, y)]
|
||||
buf[self._offset(xdest, y)] = data
|
||||
|
||||
class SSD1306_I2C(SSD1306):
|
||||
def __init__(self, width, height, i2c, addr=0x3c, external_vcc=False):
|
||||
device = ssd1306.SSD1306_I2C(width, height, i2c, addr, external_vcc)
|
||||
super().__init__(device)
|
||||
|
||||
class SSD1306_SPI(SSD1306):
|
||||
def __init__(self, width, height, spi, dc, res, cs, external_vcc=False):
|
||||
device = ssd1306.SSD1306_SPI(width, height, spi, dc, res, cs, external_vcc)
|
||||
super().__init__(device)
|
54
writer.py
54
writer.py
|
@ -1,5 +1,5 @@
|
|||
# writer.py Implements the Writer class.
|
||||
# V0.1 Peter Hinch Nov 2016
|
||||
# V0.2 Peter Hinch Dec 2016
|
||||
|
||||
# The MIT License (MIT)
|
||||
#
|
||||
|
@ -24,21 +24,15 @@
|
|||
# THE SOFTWARE.
|
||||
|
||||
# A Writer supports rendering text to a Display instance in a given font.
|
||||
# Currently supports vertical mapping and the SSD1306 "pseudo-horizontal" map
|
||||
# only
|
||||
# Multiple Writer instances may be created, each rendering a font to the
|
||||
# same Display object.
|
||||
|
||||
VERT = 0
|
||||
HORIZ = 1
|
||||
WEIRD = 2
|
||||
|
||||
class Writer(object):
|
||||
text_row = 0 # attributes common to all Writer instances
|
||||
text_col = 0
|
||||
row_clip = False # Clip or scroll when screen full
|
||||
col_clip = False # Clip or new line when row is full
|
||||
bmap = WEIRD # SSD1306 pseudo-horizontal
|
||||
|
||||
@classmethod
|
||||
def set_textpos(cls, row, col):
|
||||
|
@ -50,13 +44,6 @@ class Writer(object):
|
|||
cls.row_clip = row_clip
|
||||
cls.col_clip = col_clip
|
||||
|
||||
@classmethod
|
||||
def mapping(cls, bmap):
|
||||
if bmap in (VERT, HORIZ):
|
||||
cls.bmap = bmap
|
||||
else:
|
||||
raise ValueError('Unsupported mapping')
|
||||
|
||||
def __init__(self, device, font):
|
||||
super().__init__()
|
||||
self.device = device
|
||||
|
@ -65,8 +52,6 @@ class Writer(object):
|
|||
raise OSError('Font must be vertically mapped')
|
||||
self.screenwidth = device.width # In pixels
|
||||
self.screenheight = device.height
|
||||
div, mod = divmod(device.height, 8)
|
||||
self.bytes_per_col = div + 1 if mod else div
|
||||
|
||||
def _newline(self):
|
||||
height = self.font.height()
|
||||
|
@ -83,41 +68,32 @@ class Writer(object):
|
|||
self._printchar(char)
|
||||
|
||||
def _printchar(self, char):
|
||||
bmap = Writer.bmap # Buffer mapping
|
||||
if char == '\n':
|
||||
self._newline()
|
||||
return
|
||||
fbuff = self.device.buffer
|
||||
glyph, char_height, char_width = self.font.get_ch(char)
|
||||
if Writer.text_row+char_height > self.screenheight and Writer.row_clip:
|
||||
if Writer.text_row + char_height > self.screenheight:
|
||||
if Writer.row_clip:
|
||||
return
|
||||
self._newline()
|
||||
if Writer.text_col + char_width > self.screenwidth:
|
||||
if Writer.col_clip:
|
||||
return
|
||||
else:
|
||||
self._newline()
|
||||
|
||||
div, mod = divmod(char_height, 8)
|
||||
gbytes = div + 1 if mod else div # No. of bytes per column of glyph
|
||||
start_row, align = divmod(Writer.text_row, 8)
|
||||
for scol in range(0, char_width): # Source column
|
||||
device = self.device
|
||||
for scol in range(char_width): # Source column
|
||||
dcol = scol + Writer.text_col # Destination column
|
||||
dest_row_byte = start_row
|
||||
for gbyte in range(gbytes): # Each glyph byte in column
|
||||
if bmap == VERT:
|
||||
dest = dcol * self.bytes_per_col + dest_row_byte
|
||||
elif bmap == WEIRD:
|
||||
dest = dcol + dest_row_byte * self.screenwidth
|
||||
source = scol * gbytes + gbyte
|
||||
data = fbuff[dest] & (0xff >> (8 - align))
|
||||
fbuff[dest] = data | glyph[source] << align
|
||||
if align and (dest_row_byte + 1) < self.bytes_per_col:
|
||||
if bmap == VERT:
|
||||
dest += 1
|
||||
elif bmap == WEIRD:
|
||||
dest += self.screenwidth
|
||||
data = fbuff[dest] & (0xff << align)
|
||||
fbuff[dest] = data | glyph[source] >> (8 - align)
|
||||
dest_row_byte += 1
|
||||
if dest_row_byte >= self.bytes_per_col:
|
||||
drow = Writer.text_row # Destination row
|
||||
for srow in range(char_height): # Source row
|
||||
gbyte, gbit = divmod(srow, 8)
|
||||
if drow >= self.screenheight:
|
||||
break
|
||||
if gbit == 0: # Next glyph byte
|
||||
data = glyph[scol * gbytes + gbyte]
|
||||
device.pixel(dcol, drow, data & (1 << gbit))
|
||||
drow += 1
|
||||
Writer.text_col += char_width
|
||||
|
|
Ładowanie…
Reference in New Issue