barkest_lcd 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +11 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +21 -0
- data/README.md +112 -0
- data/Rakefile +12 -0
- data/barkest_lcd.gemspec +29 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/fonts/label.png +0 -0
- data/fonts/slkscr.ttf +0 -0
- data/fonts/slkscrb.ttf +0 -0
- data/lib/barkest_lcd.rb +10 -0
- data/lib/barkest_lcd/version.rb +3 -0
- data/lib/models/error_logger.rb +21 -0
- data/lib/models/font.rb +404 -0
- data/lib/models/font/silkscr.rb +1628 -0
- data/lib/models/font/silkscrb.rb +1627 -0
- data/lib/models/hash_enum.rb +91 -0
- data/lib/models/pico_lcd_graphic.rb +184 -0
- data/lib/models/pico_lcd_graphic/display.rb +97 -0
- data/lib/models/pico_lcd_graphic/enums.rb +107 -0
- data/lib/models/pico_lcd_graphic/flasher.rb +126 -0
- data/lib/models/pico_lcd_graphic/ir.rb +31 -0
- data/lib/models/pico_lcd_graphic/key.rb +92 -0
- data/lib/models/pico_lcd_graphic/splash.rb +40 -0
- data/lib/models/pico_lcd_graphic/version.rb +40 -0
- data/lib/models/simple_graphic.rb +467 -0
- metadata +128 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 5a99d7096928cf7602e31e972939a1c563943e3e
|
4
|
+
data.tar.gz: f0dc18d42e43c626695111307ebec7de8af86431
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0702a57c8942c02aa0bcafd8a1ce43297e41f2f1e067c1f7496853b5326874729a9ed6dce65d88fa01bf1ef29bd5407554de3663fd9c9c8bd1d599a66e974896
|
7
|
+
data.tar.gz: 927118633b5bc710774e8077112a84c8b3f64fdfc2c9f18864e57b6bb267bf2cca88b207be20dc3d69a4287cf8688fae5137dd7ec5abb41e51cf0fd1eb24f847
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2016 Beau Barker
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
# BarkestLcd
|
2
|
+
|
3
|
+
This gem is designed to make it easy to interface with some LCD displays.
|
4
|
+
|
5
|
+
I wanted to add a front panel LCD to a server I was building, so I started this project to address interacting with
|
6
|
+
the LCD panel I picked up.
|
7
|
+
|
8
|
+
Currently it works with the PicoLCD from [www.mini-box.com](http://www.mini-box.com/picoLCD-256x64-Sideshow-CDROM-Bay).
|
9
|
+
|
10
|
+
|
11
|
+
## Installation
|
12
|
+
|
13
|
+
This gem depends on [HID API](http://www.signal11.us/oss/hidapi/).
|
14
|
+
|
15
|
+
Installation of the dependency is specific to the environment.
|
16
|
+
|
17
|
+
For OS X (using homebrew):
|
18
|
+
|
19
|
+
$ brew install hidapi
|
20
|
+
|
21
|
+
For Ubuntu/Debian:
|
22
|
+
|
23
|
+
$ sudo apt-get install libhidapi-libusb0
|
24
|
+
$ cd /usr/lib/x86_64-linux-gnu
|
25
|
+
$ sudo ln -s libhidapi-libusb.so.0.0.0 libhidapi.so
|
26
|
+
|
27
|
+
|
28
|
+
Add this line to your application's Gemfile:
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
gem 'barkest_lcd'
|
32
|
+
```
|
33
|
+
|
34
|
+
And then execute:
|
35
|
+
|
36
|
+
$ bundle
|
37
|
+
|
38
|
+
Or install it yourself as:
|
39
|
+
|
40
|
+
$ gem install barkest_lcd
|
41
|
+
|
42
|
+
|
43
|
+
## Usage
|
44
|
+
|
45
|
+
Let's assume you have one picoLCD 256x64 device attached to your computer. Usage is fairly simple.
|
46
|
+
|
47
|
+
This example will draw a 32x32 rectangle with an X in it.
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
my_device = BarkestLcd::PicoLcdGraphic.first
|
51
|
+
my_device.open
|
52
|
+
my_device.draw_rect(40, 4, 32, 32).draw_line(40, 4, 72, 36).draw_line(40, 36, 72, 4)
|
53
|
+
my_device.paint
|
54
|
+
```
|
55
|
+
|
56
|
+
As you can see, most of the methods are chainable. Unless the method has an explicit return value (like `open?`) then
|
57
|
+
the method should be returning the device model. The `open`, `close`, and `paint` methods are all chainable as well.
|
58
|
+
|
59
|
+
There are currently some very basic drawing methods included by the `SimpleGraphic` module. These include `set_bit`,
|
60
|
+
`draw_vline`, `draw_hline`, `draw_line`, and `draw_rect`. The `clear` method will clear the screen.
|
61
|
+
|
62
|
+
Continuing, we will wait for the user to press the OK button.
|
63
|
+
|
64
|
+
```ruby
|
65
|
+
OK_BUTTON = 6
|
66
|
+
ok_pressed = false
|
67
|
+
|
68
|
+
# set the callback to process keys when they are released.
|
69
|
+
my_device.on_key_up do |key|
|
70
|
+
if key == OK_BUTTON
|
71
|
+
ok_pressed = true
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# use the "loop" function to process events with the device and update the screen.
|
76
|
+
until ok_pressed
|
77
|
+
my_device.loop
|
78
|
+
end
|
79
|
+
```
|
80
|
+
|
81
|
+
In this case we set the `on_key_up` callback to set a flag when the OK button is pressed. If we wanted to do repeating
|
82
|
+
keys when a user holds down a button, we may want to set the `on_key_down` or use the `key_state` method within the loop.
|
83
|
+
|
84
|
+
Finally, I recommend closing the device when you are finished. Ruby will close the device when it exits, but if you
|
85
|
+
are handling errors and such, closing the device explicitly in an `ensure` block will help to protect you against being
|
86
|
+
unable to open the device again.
|
87
|
+
|
88
|
+
```ruby
|
89
|
+
my_device.clear.paint
|
90
|
+
my_device.close
|
91
|
+
```
|
92
|
+
|
93
|
+
It is not necessary to clear the screen before closing, but doing so ensures that you do not leave weird information
|
94
|
+
or screen artifacts up when your application is done.
|
95
|
+
|
96
|
+
|
97
|
+
|
98
|
+
## Credits
|
99
|
+
|
100
|
+
* The [picoLCD 256x64 Suite Source](http://resources.mini-box.com/online/picolcd/256x64/1003/PicoLCD256x64_src.zip)
|
101
|
+
provided most of the information needed to make this gem interact with the picoLCD 256x64 from
|
102
|
+
[mini-box](http://www.mini-box.com).
|
103
|
+
* The [picoLCD256x64](https://github.com/itszero/picoLCD256x64) project provided some inspiration, but I ended up going
|
104
|
+
a completely different direction.
|
105
|
+
* The font came from [Silkscreen](http://www.kottke.org/plus/type/silkscreen/index.html).
|
106
|
+
|
107
|
+
## License
|
108
|
+
|
109
|
+
Copyright (c) 2016 [Beau Barker](mailto:beau@barkerest.com)
|
110
|
+
|
111
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
112
|
+
|
data/Rakefile
ADDED
data/barkest_lcd.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'barkest_lcd/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "barkest_lcd"
|
8
|
+
spec.version = BarkestLcd::VERSION
|
9
|
+
spec.authors = ["Beau Barker"]
|
10
|
+
spec.email = ["rtecoder@gmail.com"]
|
11
|
+
|
12
|
+
spec.summary = "Provides a simple interface to LCD displays."
|
13
|
+
spec.description = "This gem was originally created to interface with a PicoLCD 256x64 from www.mini-box.com."
|
14
|
+
spec.homepage = "http://www.barkerest.com/"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
|
18
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
19
|
+
spec.bindir = "exe"
|
20
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
21
|
+
spec.require_paths = ["lib"]
|
22
|
+
|
23
|
+
spec.add_dependency 'libusb', '~>0.5.1'
|
24
|
+
spec.add_dependency 'hidapi', '>=0.1.4'
|
25
|
+
|
26
|
+
|
27
|
+
spec.add_development_dependency 'bundler', '~> 1.12'
|
28
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
29
|
+
end
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "barkest_lcd"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
data/fonts/label.png
ADDED
Binary file
|
data/fonts/slkscr.ttf
ADDED
Binary file
|
data/fonts/slkscrb.ttf
ADDED
Binary file
|
data/lib/barkest_lcd.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
module BarkestLcd
|
2
|
+
module ErrorLogger
|
3
|
+
|
4
|
+
public
|
5
|
+
|
6
|
+
##
|
7
|
+
# Contains the last 100 errors that have occurred in this instance.
|
8
|
+
def error_history
|
9
|
+
@error_history ||= []
|
10
|
+
end
|
11
|
+
|
12
|
+
protected
|
13
|
+
|
14
|
+
def log_error(code, msg)
|
15
|
+
HIDAPI.debug "Encountered error (#{code.to_s(16).rjust(8, '0')}) #{msg}"
|
16
|
+
error_history << [ code, msg, Time.now ]
|
17
|
+
error_history.delete_at(0) while error_history.count > 100
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
data/lib/models/font.rb
ADDED
@@ -0,0 +1,404 @@
|
|
1
|
+
module BarkestLcd
|
2
|
+
##
|
3
|
+
# A basic bitmap font.
|
4
|
+
class Font
|
5
|
+
|
6
|
+
##
|
7
|
+
# Gets or sets the name of this font.
|
8
|
+
attr_accessor :name
|
9
|
+
|
10
|
+
##
|
11
|
+
# Gets or sets the size of this font.
|
12
|
+
attr_accessor :size
|
13
|
+
|
14
|
+
##
|
15
|
+
# Gets or sets the bold flag.
|
16
|
+
attr_accessor :bold
|
17
|
+
|
18
|
+
##
|
19
|
+
# Creates a new bitmap font from a hash.
|
20
|
+
#
|
21
|
+
# glyphs = {
|
22
|
+
# :name => "Font Name", # optional
|
23
|
+
# :size => 8, # optional
|
24
|
+
# :bold => false, # optional
|
25
|
+
# 97 => { # ASCII character code.
|
26
|
+
# :char => "a", # printed character.
|
27
|
+
# :width => 8, # width in pixels
|
28
|
+
# :height => 8, # height in pixels
|
29
|
+
# :data => [ # array containing row data.
|
30
|
+
# " ", # rows may be strings or arrays.
|
31
|
+
# " ", # when strings, non-space characters are set pixels.
|
32
|
+
# " ** ", # when arrays, values of true or 1 are set pixels.
|
33
|
+
# " * ",
|
34
|
+
# " **** ",
|
35
|
+
# " * * ",
|
36
|
+
# " **** ",
|
37
|
+
# " ",
|
38
|
+
# ],
|
39
|
+
# },
|
40
|
+
# ...
|
41
|
+
# }
|
42
|
+
def initialize(glyphs)
|
43
|
+
raise ArgumentError unless glyphs.is_a?(Hash)
|
44
|
+
|
45
|
+
@name = glyphs.delete(:name) || 'Font'
|
46
|
+
@size = glyphs.delete(:size) || 8
|
47
|
+
@bold = glyphs.delete(:bold) || false
|
48
|
+
@glyphs = {}
|
49
|
+
|
50
|
+
glyphs.each do |k,v|
|
51
|
+
k = k.to_i
|
52
|
+
raise ArgumentError, 'hash must have numeric keys greater than or equal to 32 and less than 127' if k < 32 || k > 127
|
53
|
+
raise ArgumentError, 'hash must have hashes as values' unless v.is_a?(Hash)
|
54
|
+
raise ArgumentError, 'hash values must have a :char key' unless v[:char]
|
55
|
+
raise ArgumentError, 'hash values must have a :width key' unless v[:width]
|
56
|
+
raise ArgumentError, 'hash values must have a :height key' unless v[:height]
|
57
|
+
raise ArgumentError, 'hash values must have a :data key' unless v[:data]
|
58
|
+
raise ArgumentError, 'hash :data key must have an array value' unless v[:data].is_a?(Array)
|
59
|
+
|
60
|
+
glyph = {
|
61
|
+
char: v[:char].to_s.freeze,
|
62
|
+
width: v[:width].to_i.freeze,
|
63
|
+
height: v[:height].to_i.freeze,
|
64
|
+
data: []
|
65
|
+
}
|
66
|
+
|
67
|
+
raise ArgumentError, 'hash :data value must have exactly :height members' unless v[:data].length == glyph[:height]
|
68
|
+
v[:data].each_with_index do |row, row_index|
|
69
|
+
raise ArgumentError, 'hash :data value members must be arrays or strings' unless row.is_a?(Array) || row.is_a?(String)
|
70
|
+
raise ArgumentError, 'hash :data value members must have :width values' unless row.length == glyph[:width]
|
71
|
+
|
72
|
+
glyph[:data][row_index] = [ false ] * glyph[:width]
|
73
|
+
if row.is_a?(String)
|
74
|
+
row.chars.each_with_index do |ch, ch_index|
|
75
|
+
glyph[:data][row_index][ch_index] = true unless ch == ' ' # spaces are false, everything else is true.
|
76
|
+
end
|
77
|
+
else
|
78
|
+
row.each_with_index do |bit, bit_index|
|
79
|
+
glyph[:data][row_index][bit_index] = true if bit == true || bit == 1
|
80
|
+
end
|
81
|
+
end
|
82
|
+
glyph[:data][row_index].freeze
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
add_glyph_helpers_to glyph
|
87
|
+
|
88
|
+
glyph[:data].freeze
|
89
|
+
|
90
|
+
glyph.freeze
|
91
|
+
|
92
|
+
@glyphs[k] = glyph
|
93
|
+
end
|
94
|
+
|
95
|
+
@height = @glyphs.inject(0) { |h,(key,g)| g.height > h ? g.height : h }
|
96
|
+
@nil_glyph = add_glyph_helpers_to(
|
97
|
+
{
|
98
|
+
char: '',
|
99
|
+
width: 0,
|
100
|
+
height: 0,
|
101
|
+
data: []
|
102
|
+
}
|
103
|
+
).freeze
|
104
|
+
end
|
105
|
+
|
106
|
+
|
107
|
+
##
|
108
|
+
# Gets the height of the font.
|
109
|
+
attr_reader :height
|
110
|
+
|
111
|
+
##
|
112
|
+
# Gets a glyph for the specified character.
|
113
|
+
#
|
114
|
+
# +char+ should be a string containing the character.
|
115
|
+
#
|
116
|
+
# Glyphs are hashes that also include helper methods.
|
117
|
+
#
|
118
|
+
# g = {
|
119
|
+
# char: ' ',
|
120
|
+
# width: 2,
|
121
|
+
# height: 8,
|
122
|
+
# data: [[false,false],[false,false],[false,false],[false,false],[false,false],[false,false],[false,false],[false,false]]
|
123
|
+
# }
|
124
|
+
# g.char == g[:char]
|
125
|
+
# g.width == g[:width]
|
126
|
+
# g.height == g[:height]
|
127
|
+
# g.data == g[:data]
|
128
|
+
#
|
129
|
+
def glyph(char)
|
130
|
+
char = char.to_s
|
131
|
+
ch = char.getbyte(0).to_i
|
132
|
+
@glyphs[ch] || @nil_glyph
|
133
|
+
end
|
134
|
+
|
135
|
+
##
|
136
|
+
# Gets the glyphs to draw the specified string with.
|
137
|
+
def glyphs(string)
|
138
|
+
string.to_s.chars.map { |char| glyph(char) }
|
139
|
+
end
|
140
|
+
|
141
|
+
##
|
142
|
+
# Measures the specified string.
|
143
|
+
#
|
144
|
+
# If you supply a +max_width+ it will try to fit the string into the specified width.
|
145
|
+
#
|
146
|
+
# With a +max_width+ it returns [ width, height, lines ].
|
147
|
+
# Without a +max_width+ it returns [ width, height ].
|
148
|
+
def measure(string, max_width = -1)
|
149
|
+
|
150
|
+
# handle newlines properly.
|
151
|
+
if string.include?("\n")
|
152
|
+
w = 0
|
153
|
+
h = 0
|
154
|
+
lines = []
|
155
|
+
string.split("\n").each do |line|
|
156
|
+
w2, h2, lines2 = measure(line, max_width)
|
157
|
+
w = w2 if w2 > w
|
158
|
+
h += h2
|
159
|
+
lines += lines2 if lines2
|
160
|
+
end
|
161
|
+
return [ w, h, lines ] if max_width > 0
|
162
|
+
return [ w, h ]
|
163
|
+
end
|
164
|
+
|
165
|
+
# convert to string and replace all whitespace with actual spaces.
|
166
|
+
# we don't support tabs or care about carriage returns.
|
167
|
+
# we also want to reduce all whitespace sequences to a single space.
|
168
|
+
string = string.to_s.gsub(/\s/, ' ').gsub(/\s\s+/, ' ')
|
169
|
+
|
170
|
+
if max_width > 0
|
171
|
+
# we are trying to fit the string into a specific width.
|
172
|
+
|
173
|
+
# no need to measure an empty string.
|
174
|
+
return [ 0, height, [ string ]] if string == ''
|
175
|
+
|
176
|
+
# measure the initial string.
|
177
|
+
w, h = measure(string)
|
178
|
+
|
179
|
+
# we fit or there are no spaces to wrap on.
|
180
|
+
if w <= max_width || !string.include?(' ')
|
181
|
+
return [w, h, [ string ]]
|
182
|
+
else
|
183
|
+
|
184
|
+
# prepare to wrap on word boundaries.
|
185
|
+
cur_line,_,next_line = string.rpartition(' ')
|
186
|
+
|
187
|
+
# keep chopping off words until we can't chop any more off or we fit.
|
188
|
+
while true
|
189
|
+
# measure the current line.
|
190
|
+
w, h = measure(cur_line)
|
191
|
+
|
192
|
+
if w <= max_width || !cur_line.include?(' ')
|
193
|
+
# we fit or we can't split anymore.
|
194
|
+
|
195
|
+
# measure up the rest of the string.
|
196
|
+
w2, h2, lines = measure(next_line, max_width)
|
197
|
+
|
198
|
+
# and adjust the size as needed.
|
199
|
+
w = w2 if w2 > w
|
200
|
+
h += h2
|
201
|
+
|
202
|
+
# return the adjusted size and the lines.
|
203
|
+
return [ w, h, [ cur_line ] + lines ]
|
204
|
+
end
|
205
|
+
|
206
|
+
# chop off the next word.
|
207
|
+
cur_line,_,next_word = cur_line.rpartition(' ')
|
208
|
+
|
209
|
+
# add the chopped off word to the beginning of the next line.
|
210
|
+
next_line = next_word + ' ' + next_line
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
|
215
|
+
else
|
216
|
+
# we are not trying to fit the string.
|
217
|
+
|
218
|
+
# no need to measure an empty string.
|
219
|
+
return [ 0, height ] if string == ''
|
220
|
+
|
221
|
+
h = height
|
222
|
+
w = glyphs(string).inject(0) { |_w,g| _w + g[:width] }
|
223
|
+
|
224
|
+
[w, h]
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
##
|
229
|
+
# Generates a hash that can be loaded into a font.
|
230
|
+
def inspect(formatted = false)
|
231
|
+
ret = '{'
|
232
|
+
ret += "\n " if formatted
|
233
|
+
ret += ":name => #{name.inspect},"
|
234
|
+
ret += "\n " if formatted
|
235
|
+
ret += ":size => #{size.inspect},"
|
236
|
+
ret += "\n " if formatted
|
237
|
+
ret += ":bold => #{bold.inspect},"
|
238
|
+
ret += "\n " if formatted
|
239
|
+
@glyphs.each do |key, glyph|
|
240
|
+
ret += "#{key.inspect} => {"
|
241
|
+
ret += "\n " if formatted
|
242
|
+
ret += ":char => #{glyph[:char].inspect},"
|
243
|
+
ret += "\n " if formatted
|
244
|
+
ret += ":width => #{glyph[:width].inspect},"
|
245
|
+
ret += "\n " if formatted
|
246
|
+
ret += ":height => #{glyph[:height].inspect},"
|
247
|
+
ret += "\n " if formatted
|
248
|
+
ret += ':data => ['
|
249
|
+
ret += "\n " if formatted
|
250
|
+
glyph[:data].each do |row|
|
251
|
+
ret += "#{row.map{|bit| bit ? '#' : ' '}.join('').inspect},"
|
252
|
+
ret += "\n " if formatted
|
253
|
+
end
|
254
|
+
ret = ret.rstrip + "\n " if formatted
|
255
|
+
ret += '],'
|
256
|
+
ret += "\n " if formatted
|
257
|
+
ret += '},'
|
258
|
+
ret += "\n " if formatted
|
259
|
+
end
|
260
|
+
ret = ret.rstrip + "\n" if formatted
|
261
|
+
ret + '}'
|
262
|
+
end
|
263
|
+
|
264
|
+
def to_s # :nodoc:
|
265
|
+
"#{name} #{bold ? 'Bold' : 'Regular'} #{size}pt"
|
266
|
+
end
|
267
|
+
|
268
|
+
def freeze # :nodoc
|
269
|
+
name.freeze
|
270
|
+
size.freeze
|
271
|
+
bold.freeze
|
272
|
+
super
|
273
|
+
end
|
274
|
+
|
275
|
+
##
|
276
|
+
# Attempts to load and process a font.
|
277
|
+
#
|
278
|
+
# Returns a Font on success, or nil on failure.
|
279
|
+
#
|
280
|
+
# There is a possibility that it will load an incorrect font.
|
281
|
+
#
|
282
|
+
# REQUIRES: rmagick
|
283
|
+
#
|
284
|
+
# Since the BarkestLcd gem doesn't require 'rmagick', this will always return false by default.
|
285
|
+
# If your application includes the 'rmagick' gem, then you can create fonts. Or you can use an
|
286
|
+
# IRB console to create fonts.
|
287
|
+
#
|
288
|
+
# The created fonts should be stored as a ruby object. The constants defined in the BarkestLcd::Font class
|
289
|
+
# were created in this manner.
|
290
|
+
def self.create(font_name = 'Helvetica', size = 8, bold = false)
|
291
|
+
return nil if font_name.to_s == ''
|
292
|
+
return nil if size < 4 || size > 144
|
293
|
+
|
294
|
+
begin
|
295
|
+
require 'rmagick'
|
296
|
+
|
297
|
+
max_black = (Magick::QuantumRange * 0.5).to_i
|
298
|
+
|
299
|
+
img = Magick::Image.new(200,200)
|
300
|
+
|
301
|
+
def img.char_width
|
302
|
+
get_pixels(0, 0, columns, 1).each_with_index do |px, x|
|
303
|
+
return x if px.to_color == 'magenta'
|
304
|
+
end
|
305
|
+
nil
|
306
|
+
end
|
307
|
+
|
308
|
+
def img.char_height
|
309
|
+
get_pixels(0, 0, 1, rows).each_with_index do |px, y|
|
310
|
+
return y if px.to_color == 'magenta'
|
311
|
+
end
|
312
|
+
nil
|
313
|
+
end
|
314
|
+
|
315
|
+
img.background_color = 'magenta'
|
316
|
+
img.erase!
|
317
|
+
|
318
|
+
draw = Magick::Draw.new
|
319
|
+
draw.font = font_name
|
320
|
+
draw.font_weight bold ? 'bold' : 'normal'
|
321
|
+
draw.pointsize = size
|
322
|
+
draw.gravity = Magick::NorthWestGravity
|
323
|
+
draw.text_antialias = false
|
324
|
+
draw.fill = 'black'
|
325
|
+
draw.undercolor = 'white'
|
326
|
+
draw.stroke = 'transparent'
|
327
|
+
|
328
|
+
font = {
|
329
|
+
name: font_name,
|
330
|
+
size: size,
|
331
|
+
bold: !!bold,
|
332
|
+
}
|
333
|
+
|
334
|
+
" 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ(){}[]<>`~!@#$%^&*-_=+\\|;:'\",./?".chars.each do |ch|
|
335
|
+
|
336
|
+
glyph = {
|
337
|
+
char: ch
|
338
|
+
}
|
339
|
+
|
340
|
+
char_code = ch.getbyte(0)
|
341
|
+
|
342
|
+
ch = "\\\\" if ch == "\\"
|
343
|
+
ch = "\\\"" if ch == "\""
|
344
|
+
|
345
|
+
img.erase!
|
346
|
+
draw.annotate img, 0, 0, 0, 0, ch
|
347
|
+
|
348
|
+
width = img.char_width
|
349
|
+
height = img.char_height
|
350
|
+
|
351
|
+
if width.nil?
|
352
|
+
puts "Error on char #{ch.inspect}: no width"
|
353
|
+
elsif height.nil?
|
354
|
+
puts "Error on char #{ch.inspect}: no height"
|
355
|
+
else
|
356
|
+
glyph[:width] = width
|
357
|
+
glyph[:height] = height
|
358
|
+
glyph[:data] = []
|
359
|
+
|
360
|
+
img.get_pixels(0, 0, width, height).each_with_index do |px, index|
|
361
|
+
x = (index % width).to_i
|
362
|
+
y = (index / width).to_i
|
363
|
+
|
364
|
+
glyph[:data][y] ||= []
|
365
|
+
glyph[:data][y][x] = px.intensity <= max_black
|
366
|
+
end
|
367
|
+
|
368
|
+
font[char_code] = glyph
|
369
|
+
end
|
370
|
+
|
371
|
+
end
|
372
|
+
|
373
|
+
Font.new(font)
|
374
|
+
rescue LoadError
|
375
|
+
nil
|
376
|
+
end
|
377
|
+
end
|
378
|
+
|
379
|
+
private
|
380
|
+
|
381
|
+
def add_glyph_helpers_to(glyph)
|
382
|
+
def glyph.char
|
383
|
+
self[:char]
|
384
|
+
end
|
385
|
+
def glyph.width
|
386
|
+
self[:width]
|
387
|
+
end
|
388
|
+
def glyph.height
|
389
|
+
self[:height]
|
390
|
+
end
|
391
|
+
def glyph.data
|
392
|
+
self[:data]
|
393
|
+
end
|
394
|
+
glyph
|
395
|
+
end
|
396
|
+
|
397
|
+
end
|
398
|
+
end
|
399
|
+
|
400
|
+
|
401
|
+
# Include the components of the model.
|
402
|
+
Dir.glob(File.expand_path('../font/*.rb', __FILE__)).each do |file|
|
403
|
+
require file
|
404
|
+
end
|