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