papirus 0.3.0 → 0.3.1
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 +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
|
-

|
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
|