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 physical display. If ``col_clip`` is ``False`` characters will wrap onto
|
||||||
the next line. If ``row_clip`` is ``False`` the display will, where necessary,
|
the next line. If ``row_clip`` is ``False`` the display will, where necessary,
|
||||||
scroll up to ensure the line is rendered.
|
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
|
As class methods these settings apply to all font objects. The insertion point
|
||||||
of characters is maintained regardless of the font in use.
|
of characters is maintained regardless of the font in use.
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
import machine
|
import machine
|
||||||
import utime
|
import utime
|
||||||
from writer import Writer
|
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 freeserif
|
||||||
import freesans20
|
import freesans20
|
||||||
import inconsolata16
|
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)
|
|
66
writer.py
66
writer.py
|
@ -1,5 +1,5 @@
|
||||||
# writer.py Implements the Writer class.
|
# writer.py Implements the Writer class.
|
||||||
# V0.1 Peter Hinch Nov 2016
|
# V0.2 Peter Hinch Dec 2016
|
||||||
|
|
||||||
# The MIT License (MIT)
|
# The MIT License (MIT)
|
||||||
#
|
#
|
||||||
|
@ -24,21 +24,15 @@
|
||||||
# THE SOFTWARE.
|
# THE SOFTWARE.
|
||||||
|
|
||||||
# A Writer supports rendering text to a Display instance in a given font.
|
# 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
|
# Multiple Writer instances may be created, each rendering a font to the
|
||||||
# same Display object.
|
# same Display object.
|
||||||
|
|
||||||
VERT = 0
|
|
||||||
HORIZ = 1
|
|
||||||
WEIRD = 2
|
|
||||||
|
|
||||||
class Writer(object):
|
class Writer(object):
|
||||||
text_row = 0 # attributes common to all Writer instances
|
text_row = 0 # attributes common to all Writer instances
|
||||||
text_col = 0
|
text_col = 0
|
||||||
row_clip = False # Clip or scroll when screen full
|
row_clip = False # Clip or scroll when screen full
|
||||||
col_clip = False # Clip or new line when row is full
|
col_clip = False # Clip or new line when row is full
|
||||||
bmap = WEIRD # SSD1306 pseudo-horizontal
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def set_textpos(cls, row, col):
|
def set_textpos(cls, row, col):
|
||||||
|
@ -50,13 +44,6 @@ class Writer(object):
|
||||||
cls.row_clip = row_clip
|
cls.row_clip = row_clip
|
||||||
cls.col_clip = col_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):
|
def __init__(self, device, font):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.device = device
|
self.device = device
|
||||||
|
@ -65,8 +52,6 @@ class Writer(object):
|
||||||
raise OSError('Font must be vertically mapped')
|
raise OSError('Font must be vertically mapped')
|
||||||
self.screenwidth = device.width # In pixels
|
self.screenwidth = device.width # In pixels
|
||||||
self.screenheight = device.height
|
self.screenheight = device.height
|
||||||
div, mod = divmod(device.height, 8)
|
|
||||||
self.bytes_per_col = div + 1 if mod else div
|
|
||||||
|
|
||||||
def _newline(self):
|
def _newline(self):
|
||||||
height = self.font.height()
|
height = self.font.height()
|
||||||
|
@ -83,41 +68,32 @@ class Writer(object):
|
||||||
self._printchar(char)
|
self._printchar(char)
|
||||||
|
|
||||||
def _printchar(self, char):
|
def _printchar(self, char):
|
||||||
bmap = Writer.bmap # Buffer mapping
|
|
||||||
if char == '\n':
|
if char == '\n':
|
||||||
self._newline()
|
self._newline()
|
||||||
return
|
return
|
||||||
fbuff = self.device.buffer
|
|
||||||
glyph, char_height, char_width = self.font.get_ch(char)
|
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:
|
||||||
return
|
if Writer.row_clip:
|
||||||
|
return
|
||||||
|
self._newline()
|
||||||
if Writer.text_col + char_width > self.screenwidth:
|
if Writer.text_col + char_width > self.screenwidth:
|
||||||
if Writer.col_clip:
|
if Writer.col_clip:
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
self._newline()
|
self._newline()
|
||||||
|
|
||||||
div, mod = divmod(char_height, 8)
|
div, mod = divmod(char_height, 8)
|
||||||
gbytes = div + 1 if mod else div # No. of bytes per column of glyph
|
gbytes = div + 1 if mod else div # No. of bytes per column of glyph
|
||||||
start_row, align = divmod(Writer.text_row, 8)
|
device = self.device
|
||||||
for scol in range(0, char_width): # Source column
|
for scol in range(char_width): # Source column
|
||||||
dcol = scol + Writer.text_col # Destination column
|
dcol = scol + Writer.text_col # Destination column
|
||||||
dest_row_byte = start_row
|
drow = Writer.text_row # Destination row
|
||||||
for gbyte in range(gbytes): # Each glyph byte in column
|
for srow in range(char_height): # Source row
|
||||||
if bmap == VERT:
|
gbyte, gbit = divmod(srow, 8)
|
||||||
dest = dcol * self.bytes_per_col + dest_row_byte
|
if drow >= self.screenheight:
|
||||||
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:
|
|
||||||
break
|
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
|
Writer.text_col += char_width
|
||||||
|
|
Ładowanie…
Reference in New Issue