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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2e4a81e5d2a007320dd5fe508cfd8f28e0136265
4
- data.tar.gz: dcedbd0e7fee34467acf974839bf0cd715a1cf6b
3
+ metadata.gz: 7922a759efaac058b340469a65cb2ae523805fc3
4
+ data.tar.gz: 8b47d280f358a191fdc2682f1a5eeccb1daa2694
5
5
  SHA512:
6
- metadata.gz: e5e46eda4b6c84f40fd1f7183a2ebafd5ec1cdc4c454366c73e6228f5af17975e4e79a5e438cd46a2c39cc710b0af903f289a388b3eb0a4c50934496e48aa658
7
- data.tar.gz: 91e93335743a1d73742d3ad98101ffa0dfd8a00e5db9a00f593d5e53df69b018308c82b04f533bae1d433e22a5888cb6e003c847e1d8f58cede0c038578488b6
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 setup
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](here)
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 year, yes that is possible)
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
- The, start an irb session to play around
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
- ## there are multiple screen commands ['F', 'P', 'U', 'C']
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 work (now output is black)
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
@@ -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'])
@@ -1,25 +1,39 @@
1
1
  require 'chunky_png'
2
2
 
3
3
  module ChunkyPNG::Canvas::StreamExporting
4
- def inspect_bitstream
5
- #create a simple map of the image of '0's and '1's
6
- #for debugging purpuses
7
- pixels.each_slice(@width).map{|row| row.each_slice(8).map{|pixels|pixels.map{|pixel| pixel == ChunkyPNG::Color::WHITE ? '0' : '1'}.join}.join(' ')}
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
- def to_bit_stream(inverse = false)
11
- #as the ChunkyPNG library works with 4 bytes data per pixel (1 byte for R, G, B and transparancy)
12
- #and the EDP needs 1 bit per pixel (on or off), we need some way to traverse over all pixels
13
- #and add a bit to a byte stream for each pixel. so
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
- pixels.each_slice(8).map do |pixels|
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] == ChunkyPNG::Color::WHITE) || (!inverse && pixels[7-bit] != ChunkyPNG::Color::WHITE)
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)
@@ -1,28 +1,60 @@
1
1
  require 'rmagick'
2
2
 
3
3
  class Magick::Image
4
- # Send's any image to the PAPiRus display, if it is found
5
- # image is rescaled to fit the display (positioning it mid center)
6
- # @param display[PaPiRus::Display] The {PaPiRus::Display} object
7
- def to_papirus(display)
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(display.width, display.height)
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 != display.width or posterize.rows != display.height)
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 - display.width) / 2
19
- y = (posterized.rows - display.height) / 2
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(display.width, display.height, x, y)
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
- quantized = posterized.quantize(2, Magick::GRAYColorspace)
25
- #return the raw image data
26
- quantized.write(display.display_path){self.format='DIB'} #DIB=Device Independant Binary, as in , no headers, just raw data
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.0
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 00:00:00.000000000 Z
11
+ date: 2017-10-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: shoulda