barkest_lcd 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|