papirus 0.3.0 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +82 -75
- data/lib/papirus.rb +10 -2
- data/lib/papirus/chunky.rb +24 -10
- data/lib/papirus/rmagick.rb +44 -12
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7922a759efaac058b340469a65cb2ae523805fc3
|
4
|
+
data.tar.gz: 8b47d280f358a191fdc2682f1a5eeccb1daa2694
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f2431df7210edc30a3f5983156968b8eeaec567f737982976f8a483e6fa3541eb309813d54ceb3abcd0b8a36d7d0a8ecccca7d4079aff29212568bab47bc1a3f
|
7
|
+
data.tar.gz: 5a21d57e6c0f22c98fb0d8ac7789bc02d18e6fb8e913b2f012b064570cf09d9ade75c07e558b7989e698129d637387ddab12622370403fd8c9457a11a56fff11
|
data/README.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
ruby gem to talk to the [PaPiRus](https://www.pi-supply.com/?s=papirus&post_type=product&tags=1&limit=5&ixwps=1) display
|
4
4
|
|
5
|
-
before you start playing make sure you got the edp-fuse
|
5
|
+
before you start playing make sure you got the display driver installed (gratis/edp-fuse)
|
6
6
|
|
7
7
|
## epaper fuse driver installation instructions (if you have not done that already ::)
|
8
8
|
```bash
|
@@ -16,13 +16,14 @@ systemctl enable epd-fuse.service
|
|
16
16
|
systemctl start epd-fuse
|
17
17
|
```
|
18
18
|
|
19
|
-
You can find more detailed instructions [https://github.com/repaper/gratis](
|
19
|
+
You can find more detailed instructions and updates at the [https://github.com/repaper/gratis](gratis) repo
|
20
20
|
|
21
|
-
## gem installation
|
21
|
+
## gem installation (add sudo if your not useing [https://rvm.io/](rvm))
|
22
22
|
|
23
23
|
```bash
|
24
24
|
$ gem install papirus
|
25
25
|
```
|
26
|
+
|
26
27
|
## usage
|
27
28
|
|
28
29
|
```ruby
|
@@ -32,6 +33,45 @@ require 'papirus'
|
|
32
33
|
display = PaPiRus::Display.new()
|
33
34
|
```
|
34
35
|
|
36
|
+
## there are multiple screen commands ['F', 'P', 'U', 'C']
|
37
|
+
|
38
|
+
The `image.to_bit_stream` will be explained for both RMagic and ChunkyPNG below
|
39
|
+
|
40
|
+
Full update (with screen cleaning):
|
41
|
+
|
42
|
+
`display.show(image.to_bit_stream(display.width, display.height))`
|
43
|
+
|
44
|
+
Fast update:
|
45
|
+
|
46
|
+
`display.show(image.to_bit_stream(display.width, display.height)), 'F')`
|
47
|
+
|
48
|
+
Partial update:
|
49
|
+
|
50
|
+
`display.show(image.to_bit_stream(display.width, display.height), 'P')`
|
51
|
+
|
52
|
+
# Playing with RMagic
|
53
|
+
|
54
|
+
First install rmagick
|
55
|
+
|
56
|
+
```bash
|
57
|
+
$ # install native Image Magick library
|
58
|
+
$ (OSX) brew install imagemagick@6 && brew link imagemagick@6 --force
|
59
|
+
$ (debian/ubuntu) sudo apt-get install imagemagick
|
60
|
+
$ (Windows) no idea (did not use windows for 20 years, and would like to add some more)
|
61
|
+
$ # install the gem that talks to the native Image Magick library
|
62
|
+
$ gem install rmagick
|
63
|
+
```
|
64
|
+
|
65
|
+
Then, start an irb session to play around
|
66
|
+
```ruby
|
67
|
+
require 'papirus'
|
68
|
+
require 'papirus/rmagick'
|
69
|
+
|
70
|
+
display = PaPiRus::Display.new()
|
71
|
+
image = Magick::Image::read('/path/to/img/file.(png|jpg|etc)'.first
|
72
|
+
display.show(image.to_bit_stream(display.width, display.height))
|
73
|
+
```
|
74
|
+
|
35
75
|
# Playing with Chunky_PNG
|
36
76
|
|
37
77
|
First install chunky_png
|
@@ -39,11 +79,33 @@ First install chunky_png
|
|
39
79
|
```bash
|
40
80
|
$ (OSX) brew install chunky_png
|
41
81
|
$ (debian/ubuntu) sudo apt-get install chunky_png
|
42
|
-
$ (Windows) no idea (did not use windows for 20
|
82
|
+
$ (Windows) no idea (did not use windows for 20 years, and would like to add some more)
|
43
83
|
$ gem install chunky_png
|
44
84
|
```
|
45
85
|
|
46
|
-
|
86
|
+
## Load an image from a png file
|
87
|
+
|
88
|
+
```ruby
|
89
|
+
irb
|
90
|
+
require 'papirus'
|
91
|
+
require 'papirus/chunky'
|
92
|
+
display = PaPiRus::Display.new()
|
93
|
+
image = ChunkyPNG::Image.from_file('out.png')
|
94
|
+
display.show(image.to_bit_stream(display.width, display.height))
|
95
|
+
```
|
96
|
+
|
97
|
+
The only problem here is the aspect ration of the image is not ok anymore. is a todo
|
98
|
+
But for now you could also use Image magick's convert tool to rescale the image and place it in the middle
|
99
|
+
|
100
|
+
First, let's use Image Magick's `convert` tool to convert any image into an scaled, centered png
|
101
|
+
```bash
|
102
|
+
convert in.jpg -resize '264x176' -gravity center -extent '264x176' out.png
|
103
|
+
```
|
104
|
+
|
105
|
+
now, load it like explaned above and the image should be in the right aspect ration
|
106
|
+
|
107
|
+
## Playing with drawing circles
|
108
|
+
|
47
109
|
```ruby
|
48
110
|
irb
|
49
111
|
require 'papirus'
|
@@ -75,74 +137,7 @@ display.clear
|
|
75
137
|
end
|
76
138
|
```
|
77
139
|
|
78
|
-
##
|
79
|
-
|
80
|
-
Full update (with screen cleaning):
|
81
|
-
|
82
|
-
```display.show(image.to_bit_stream); display.update``` or
|
83
|
-
|
84
|
-
```display.show(image.to_bit_stream, 'U')```
|
85
|
-
|
86
|
-
Fast update:
|
87
|
-
|
88
|
-
```display.show(image.to_bit_stream); display.fast_update```
|
89
|
-
```display.show(image.to_bit_stream, 'F')```
|
90
|
-
|
91
|
-
Partial update:
|
92
|
-
|
93
|
-
```display.show(image.to_bit_stream); display.partial_update``` or
|
94
|
-
|
95
|
-
```display.show(image.to_bit_stream, 'P')```
|
96
|
-
|
97
|
-
## Load an image from a png file with convert and chunky
|
98
|
-
|
99
|
-
First, let's use Image Magick's `convert` tool to convert any image into a b/w image the way the diplay likes it
|
100
|
-
```bash
|
101
|
-
convert in.jpg -resize '264x176' -gravity center -extent '264x176' -colorspace gray -colors 2 -type bilevel out.png
|
102
|
-
```
|
103
|
-
|
104
|
-
Where
|
105
|
-
* the -resize scales the image to fit the display
|
106
|
-
* The -gravity and -extent combination (order is important!) makes sure the image stays at the size of the display and in the centre
|
107
|
-
* The -colorspace -colors -type combi makes the image a 1-bit grayscale b/w image
|
108
|
-
|
109
|
-
Then we use chucky with our extension to show
|
110
|
-
|
111
|
-
```ruby
|
112
|
-
irb
|
113
|
-
require 'papirus'
|
114
|
-
require 'papirus/chunky'
|
115
|
-
display = PaPiRus::Display.new()
|
116
|
-
image = ChunkyPNG::Image.from_file('out.png')
|
117
|
-
display.show(image.to_bit_stream(true))
|
118
|
-
```
|
119
|
-
result:
|
120
|
-
![that's me](https://raw.githubusercontent.com/mmolhoek/papirus/master/example_output.jpg)
|
121
|
-
|
122
|
-
# Playing with RMagic (does not work yet), did not figure out right command
|
123
|
-
|
124
|
-
First install rmagick
|
125
|
-
|
126
|
-
```bash
|
127
|
-
$ # install native Image Magick library
|
128
|
-
$ (OSX) brew install imagemagick@6 && brew link imagemagick@6 --force
|
129
|
-
$ (debian/ubuntu) sudo apt-get install imagemagick
|
130
|
-
$ (Windows) no idea (did not use windows for 20 year, yes that is possible)
|
131
|
-
$ # install the gem that talks to the native Image Magick library
|
132
|
-
$ gem install rmagick
|
133
|
-
```
|
134
|
-
|
135
|
-
The, start an irb session to play around
|
136
|
-
```ruby
|
137
|
-
require 'papirus'
|
138
|
-
require 'papirus/rmagick'
|
139
|
-
|
140
|
-
display = PaPiRus::Display.new()
|
141
|
-
img = Magick::Image::read('/path/to/img/file.(png|jpg|etc').first
|
142
|
-
img.to_papirus(display)
|
143
|
-
```
|
144
|
-
|
145
|
-
## Testing without a PAPiRus display
|
140
|
+
## Testing without a PaPiRus display
|
146
141
|
|
147
142
|
If you want to test the gem, but don't have your PaPiRus available, you can do the following
|
148
143
|
|
@@ -154,14 +149,26 @@ If you want to test the gem, but don't have your PaPiRus available, you can do t
|
|
154
149
|
* play with the examples above
|
155
150
|
* when you run `display.show` the **fake** display /tmp/epd/LE/display is filled with your image
|
156
151
|
* now you can use a bin editor like xxd to have a look at the result: `xxd -b /tmp/epd/LE/display`
|
152
|
+
* or, use `image.inspect_bitstream(display.width, display.height)` to dump the image as 1's and 0's to the terminal
|
153
|
+
* make sure you have your terminal font small enought so the image fits the terminal :)
|
154
|
+
|
155
|
+
## handy convert command
|
156
|
+
|
157
|
+
This Image Magick convert command creates a 1-bit 2-color png
|
158
|
+
```bash
|
159
|
+
convert in.jpg -resize '264x176' -gravity center -extent '264x176' -colorspace gray -colors 2 -type bilevel out.png
|
160
|
+
```
|
161
|
+
Where
|
162
|
+
* the -resize scales the image to fit the display
|
163
|
+
* The -gravity and -extent combination (order is important!) makes sure the image stays at the size of the display and in the centre
|
164
|
+
* The -colorspace -colors -type combi makes the image a 1-bit grayscale b/w image
|
157
165
|
|
158
166
|
## TODO
|
159
167
|
|
160
168
|
* make the image.to_bit_stream routine faster (as it is now to slow to do animations with partial updates)
|
161
169
|
* add support for reading the temperature of the display
|
162
170
|
* add support for changing the update rate
|
163
|
-
* make load png image with chunky_png
|
164
|
-
* make a display.load(image) that takes multiple formats and figures out how to present them
|
171
|
+
* make load png image with chunky_png scale keeping aspect ratio in mind
|
165
172
|
* create an issue to add your own requests :)
|
166
173
|
|
167
174
|
## Other resources
|
data/lib/papirus.rb
CHANGED
@@ -4,6 +4,13 @@ module PaPiRus
|
|
4
4
|
class Display
|
5
5
|
attr_reader :epd_path, :width, :height, :panel, :cog, :film, :auto, :allowed_commands, :display_path
|
6
6
|
attr_accessor :rotation, :inverse, :image
|
7
|
+
# The possible commands to send to the display with {PaPiRus::Display.command}
|
8
|
+
# can be eitheri
|
9
|
+
# 'U' for update
|
10
|
+
# 'F' for fast update
|
11
|
+
# 'P' for partial update
|
12
|
+
# or 'C' for clearing the screen
|
13
|
+
attr_reader :allowed_commands
|
7
14
|
|
8
15
|
def initialize(epd_path: '/dev/epd', width: 200, height: 96, panel: 'EPD 2.0', cog: 0, film: 0, auto: false, inverse: false, rotation: 0)
|
9
16
|
#transver all vars to attr's
|
@@ -42,6 +49,8 @@ module PaPiRus
|
|
42
49
|
command('C')
|
43
50
|
end
|
44
51
|
|
52
|
+
# send's the display command to the driver
|
53
|
+
# @param c [string] command to execute, have a look at {}
|
45
54
|
def command(c)
|
46
55
|
raise "command #{c} does not exist" unless @allowed_commands.include?(c)
|
47
56
|
File.open(File.join(@epd_path, "command"), "wb") do |io|
|
@@ -50,9 +59,8 @@ module PaPiRus
|
|
50
59
|
end
|
51
60
|
|
52
61
|
private
|
62
|
+
# Reads all panel info and updates the according attributes
|
53
63
|
def get_display_info_from_edp
|
54
|
-
#now we will read the info of the installed display
|
55
|
-
#and update the properties accordingly
|
56
64
|
if File.exists?(File.join(@epd_path, 'panel'))
|
57
65
|
info = File.read(File.join(@epd_path, 'panel'))
|
58
66
|
@display_path = File.join([@epd_path, 'LE', 'display'])
|
data/lib/papirus/chunky.rb
CHANGED
@@ -1,25 +1,39 @@
|
|
1
1
|
require 'chunky_png'
|
2
2
|
|
3
3
|
module ChunkyPNG::Canvas::StreamExporting
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
4
|
+
# Creates a simple map of the image of '0's and '1's to STDERR
|
5
|
+
# this way you can view your image from the terminal
|
6
|
+
# set your terminals font very small, so the image will fit on your screen
|
7
|
+
# @param width[integer] The width of the image to inspect
|
8
|
+
# @param height[integer] The height of the image to inspect
|
9
|
+
def inspect_bitstream(width, height)
|
10
|
+
STDERR.puts to_1_bit_2_color_bw_image(width, height).each_slice(width).map{|row| row.each_slice(8).map{|pixels|pixels.map{|pixel| pixel < 128 ? '0' : '1'}.join}.join(' ')}.join("\n")
|
8
11
|
end
|
9
12
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
13
|
+
# Creates a rescaled image of whatever image is loaded
|
14
|
+
# image is rescaled to fit the width/height and is placed in the middle
|
15
|
+
# @param width[integer] width the image should be scaled to
|
16
|
+
# @param height[integer] height the image should be scaled to
|
17
|
+
def to_1_bit_2_color_bw_image(width, height)
|
18
|
+
resize(width, height).pixels.map{|pixel| ChunkyPNG::Color.grayscale_teint(pixel)}
|
19
|
+
end
|
20
|
+
# As the EPD display needs 1-bit per pixel, which get written as a string to the fuse-fs display file
|
21
|
+
# and the ChunkyPNG library works with 4 bytes data per pixel (1 byte for R, G, B and transparancy)
|
22
|
+
# we need to load all the bits together in bytes, and packed those bytes into a string
|
23
|
+
# @param width[integer] width the image should be scaled to
|
24
|
+
# @param height[integer] height the image should be scaled to
|
25
|
+
# @param inverse[boolean] wether the image should be made negative
|
26
|
+
# @param mingray{intergeri (0-255)] what grayscale value or higher is needed, to turn a bit on
|
27
|
+
def to_bit_stream(width, height, inverse = false, mingray = 128)
|
14
28
|
bytes = []
|
15
29
|
#for each 8 pixels (the ChunkyPNG library keeps an array of all pixels used, containing ChunkyPNG::Color elements)
|
16
|
-
|
30
|
+
to_1_bit_2_color_bw_image(width, height).each_slice(8).map do |pixels|
|
17
31
|
#we create a byte with its bits set to 00000000
|
18
32
|
byte = 0
|
19
33
|
0.upto(7) do |bit|
|
20
34
|
#and switch the bit to 1 (or 0 if not inverse) for each pixel if it was white
|
21
35
|
#we have to check pixels[7-bit] as the order is right to left
|
22
|
-
byte |= 1 << bit if (inverse && pixels[7-bit]
|
36
|
+
byte |= 1 << bit if (inverse && pixels[7-bit] > mingray) || (!inverse && pixels[7-bit] < mingray)
|
23
37
|
end
|
24
38
|
#and add it to the output byte stream
|
25
39
|
bytes.push(byte)
|
data/lib/papirus/rmagick.rb
CHANGED
@@ -1,28 +1,60 @@
|
|
1
1
|
require 'rmagick'
|
2
2
|
|
3
3
|
class Magick::Image
|
4
|
-
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
|
4
|
+
# Creates a simple map of the image of '0's and '1's to STDERR
|
5
|
+
# this way you can view your image from the terminal
|
6
|
+
# set your terminals font very small, so the image will fit on your screen
|
7
|
+
# @param width[integer] The width of the image to inspect
|
8
|
+
# @param height[integer] The height of the image to inspect
|
9
|
+
def inspect_bitstream(width, height)
|
10
|
+
STDERR.puts to_1_bit_2_color_bw_image(width, height).get_pixels(0, 0, width, height).each_slice(width).map{|row| row.each_slice(8).map{|pixels|pixels.map{|pixel| pixel.blue == 0 ? '1' : '0'}.join}.join(' ')}.join("\n")
|
11
|
+
end
|
12
|
+
|
13
|
+
# Creates a 1-bit 2-color image of whatever image is loaded
|
14
|
+
# image is rescaled to fit the width/height and is placed in the middle
|
15
|
+
# @param width[integer] width the image should be scaled to
|
16
|
+
# @param height[integer] height the image should be scaled to
|
17
|
+
def to_1_bit_2_color_bw_image(width, height)
|
8
18
|
# Resize to fit the screen
|
9
|
-
resized = resize_to_fit(
|
19
|
+
resized = resize_to_fit(width, height)
|
10
20
|
# Reduce the image to a limited number of colors for a "poster" effect, brings it donw to 4-bit 16 colors
|
11
21
|
posterized = resized.posterize(2)
|
12
22
|
#now, as the display expects a file with all pixels set, we need to extend the image to the display size
|
13
23
|
#if it is smaller in either width or height or both
|
14
|
-
if (posterize.columns !=
|
24
|
+
if (posterize.columns != width or posterize.rows != height)
|
15
25
|
# extent fill color
|
16
26
|
posterized.background_color = "#FFFFFF"
|
17
27
|
# calculate necessary translation to center image on background
|
18
|
-
x = (posterized.columns -
|
19
|
-
y = (posterized.rows -
|
28
|
+
x = (posterized.columns - width) / 2
|
29
|
+
y = (posterized.rows - height) / 2
|
20
30
|
# now, 'extent' the image to the correct size with the image centered
|
21
|
-
posterized = posterized.extent(
|
31
|
+
posterized = posterized.extent(width, height, x, y)
|
22
32
|
end
|
23
33
|
# Now, make grayscale with only 2 colors, b/w, brings it down to 1-bit 2 colors
|
24
|
-
|
25
|
-
|
26
|
-
|
34
|
+
return posterized.quantize(2, Magick::GRAYColorspace)
|
35
|
+
end
|
36
|
+
|
37
|
+
# As the EPD display needs 1-bit per pixel, which get written as a string to the fuse-fs display file
|
38
|
+
# we need to load all the bits together in bytes, and packed those bytes into a string
|
39
|
+
# @param width[integer] width the image should be scaled to
|
40
|
+
# @param height[integer] height the image should be scaled to
|
41
|
+
# @param inverse[boolean] wether the image should be made negative
|
42
|
+
def to_bit_stream(width, height, inverse = false)
|
43
|
+
bytes =[]
|
44
|
+
# First, we convert whatever image we got to a 1-bit 2-color image,
|
45
|
+
# then we traverse over the pixels in byte (8 bits) chucks to create our output bytes
|
46
|
+
to_1_bit_2_color_bw_image(width, height).get_pixels(0, 0, width, height).each_slice(8).map do |pixels|
|
47
|
+
#we create a byte with its bits set to 00000000
|
48
|
+
byte = 0
|
49
|
+
0.upto(7) do |bit|
|
50
|
+
#and switch the bit to 1 (or 0 if not inverse) for each pixel if it was white
|
51
|
+
#we have to check pixels[7-bit] as the order is right to left
|
52
|
+
byte |= 1 << bit if (inverse && pixels[7-bit].blue == 65535) || (!inverse && pixels[7-bit].blue == 0)
|
53
|
+
end
|
54
|
+
#and add it to the output byte stream
|
55
|
+
bytes.push(byte)
|
56
|
+
end
|
57
|
+
#now we just need to pack all bytes into a file writable string
|
58
|
+
bytes.pack('C*')
|
27
59
|
end
|
28
60
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: papirus
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mischa Molhoek
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-10-
|
11
|
+
date: 2017-10-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: shoulda
|