imagewriter 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. checksums.yaml +7 -0
  2. data/bin/imagewriter +244 -0
  3. metadata +46 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f9cc11fca615fa5553ed388686b6d88150bb7385
4
+ data.tar.gz: ea380b30ae49e7238c6e20bc1dcd880d938858b9
5
+ SHA512:
6
+ metadata.gz: 59a6e33c951000f9be772c61b06f00c6c5da4dbba5af5ad36e0c0033f15031d757b530748b1146c296b0f443801c64dda94bf0688ab3d6758d0bfa85459e9039
7
+ data.tar.gz: e1622a9dbb2032360d73b63b79df3d5b1b901ab0b1df512d2e25ab02217902d360405910af5cb4caf1012c8707092db1c70f9689fd5496e87d1ef3ee38b0dc06
@@ -0,0 +1,244 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # imagewriter
4
+ #
5
+ # writes a black and white PNG image onto a piece of paper,
6
+ # using an Apple Imagewriter or ImageWriter II printer
7
+ #
8
+ # run `./imagewriter -h` to see options.
9
+ #
10
+ # , 2020 pete gamache pete@gamache.org
11
+ # (k) all rights reversed
12
+
13
+ require 'chunky_png'
14
+ require 'optparse'
15
+
16
+ class ImageWriter
17
+ def initialize(argv)
18
+ parse_argv!(argv.clone)
19
+
20
+ @img = ChunkyPNG::Image.from_file(@filename)
21
+ STDERR.puts "#{@filename}: height #{@img.height}, width #{@img.width}"
22
+
23
+ printable_width = @hdpi * 8
24
+ if @img.width > printable_width
25
+ STDERR.puts "Warning: image exceeds printable width of #{printable_width} pixels; printout will be clipped"
26
+ end
27
+ end
28
+
29
+ def print!
30
+ init_printer!
31
+
32
+ if @quality == "regular"
33
+ do_print!(16, 0, :b1_v144_regular, :b2_v144_regular, 1, 15)
34
+ elsif @quality == "enhanced"
35
+ do_print!(12, -4, :b1_v144_enhanced, :b2_v144_enhanced, 1, 11)
36
+ elsif @quality == "best"
37
+ do_print!(4, 0, :b1_v144_best, :b2_v144_best, 1, 3)
38
+ end
39
+ end
40
+
41
+ @private
42
+
43
+ ## Send Esc + this letter to change horizontal DPI
44
+ HORIZ_DPI_CODE = {
45
+ 72 => "n",
46
+ 80 => "N",
47
+ 96 => "E",
48
+ 107 => "e",
49
+ 120 => "q",
50
+ 136 => "Q",
51
+ 144 => "p",
52
+ 160 => "P"
53
+ }
54
+
55
+ ## Send \x1F then this letter to send N line feeds
56
+ LINE_FEEDS = {
57
+ 1 => "1",
58
+ 2 => "2",
59
+ 3 => "3",
60
+ 4 => "4",
61
+ 5 => "5",
62
+ 6 => "6",
63
+ 7 => "7",
64
+ 8 => "8",
65
+ 9 => "9",
66
+ 10 => ":",
67
+ 11 => ";",
68
+ 12 => "<",
69
+ 13 => "=",
70
+ 14 => ">",
71
+ 15 => "?"
72
+ }
73
+
74
+ QUALITY = ["regular", "enhanced", "best"]
75
+
76
+ def parse_argv!(argv)
77
+ options = {
78
+ hdpi: 144,
79
+ quality: "regular",
80
+ sleep: 0.75
81
+ }
82
+
83
+ help = nil
84
+ OptionParser.new do |parser|
85
+ parser.banner = <<-EOT
86
+ Usage: imagewriter [options] filename.png"
87
+ Vertical resolution is 144 dpi; horizontal resolution is adjustable.
88
+ Max printable width is 8 inches, or 8 * horizontal DPI pixels.
89
+ Options:
90
+ EOT
91
+
92
+ dpis = HORIZ_DPI_CODE.keys.join(", ")
93
+ parser.on('-H', '--horizontal DPI', Integer, "Horizontal DPI (one of: #{dpis}; default #{options[:hdpi]})") do |n|
94
+ if HORIZ_DPI_CODE[n]
95
+ options[:hdpi] = n
96
+ else
97
+ STDERR.puts "Bad horizontal DPI setting #{n} (must be one of: #{dpis})\n"
98
+ STDERR.puts parser.to_s
99
+ exit 1
100
+ end
101
+ end
102
+
103
+ parser.on("-q", "--quality QUALITY", "Print quality (one of: #{QUALITY.join(", ")}; default #{options[:quality]})") do |n|
104
+ if QUALITY.include?(n)
105
+ options[:quality] = n
106
+ else
107
+ STDERR.puts "Bad quality setting #{n} (must be one of: #{QUALITY.join(", ")})\n"
108
+ STDERR.puts parser
109
+ exit 1
110
+ end
111
+ end
112
+
113
+ parser.on("-s", "--sleep", Float, "Sleep this many seconds between passes (default #{options[:sleep]})") do |n|
114
+ options[:sleep] = n
115
+ end
116
+
117
+ parser.on("-h", "--help", "Print this help message to STDERR") do
118
+ STDERR.puts parser
119
+ exit
120
+ end
121
+
122
+ help = parser.to_s
123
+ end.parse!(argv)
124
+
125
+ @hdpi = options[:hdpi]
126
+ @quality = options[:quality]
127
+ @sleep = options[:sleep]
128
+
129
+ @filename = argv.shift
130
+ if !@filename
131
+ STDERR.puts "Missing filename\n"
132
+ STDERR.puts help
133
+ exit 1
134
+ end
135
+ end
136
+
137
+ def do_print!(lines_per_double_pass, y0, b1_fun, b2_fun, lf1, lf2)
138
+ double_passes = (@img.height / lines_per_double_pass).ceil + 1
139
+ y = y0
140
+ width = [@hdpi * 8, @img.width].min
141
+
142
+ 0.upto(double_passes) do
143
+ bytes1 = 0.upto(width).map{|x| self.send(b1_fun, x, y)}
144
+ bytes2 = 0.upto(width).map{|x| self.send(b2_fun, x, y)}
145
+
146
+ printf "\eG%.4d", width
147
+ bytes1.each{|b| print b.chr}
148
+ printf "\r"
149
+
150
+ printf "\x1F%s", LINE_FEEDS[lf1]
151
+
152
+ printf "\eG%.4d", width
153
+ bytes2.each{|b| print b.chr}
154
+ printf "\r"
155
+
156
+ printf "\x1F%s", LINE_FEEDS[lf2]
157
+
158
+ sleep @sleep
159
+ y += lines_per_double_pass
160
+ end
161
+ end
162
+
163
+ ### Regular quality: 16 lines per double-pass
164
+ def b1_v144_regular(x, y)
165
+ 0 +
166
+ 0b00000001 * get(x, y) +
167
+ 0b00000010 * get(x, y+2) +
168
+ 0b00000100 * get(x, y+4) +
169
+ 0b00001000 * get(x, y+6) +
170
+ 0b00010000 * get(x, y+8) +
171
+ 0b00100000 * get(x, y+10) +
172
+ 0b01000000 * get(x, y+12) +
173
+ 0b10000000 * get(x, y+14)
174
+ end
175
+
176
+ def b2_v144_regular(x, y)
177
+ 0 +
178
+ 0b00000001 * get(x, y+1) +
179
+ 0b00000010 * get(x, y+3) +
180
+ 0b00000100 * get(x, y+5) +
181
+ 0b00001000 * get(x, y+7) +
182
+ 0b00010000 * get(x, y+9) +
183
+ 0b00100000 * get(x, y+11) +
184
+ 0b01000000 * get(x, y+13) +
185
+ 0b10000000 * get(x, y+15)
186
+ end
187
+
188
+ ### Enhanced quality: 12 lines per double-pass, 4 dots dovetailed
189
+ def b1_v144_enhanced(x, y)
190
+ 0 +
191
+ 0b00000001 * get(x, y) +
192
+ 0b00000010 * get(x, y+2) +
193
+ 0b00000100 * get(x, y+4) +
194
+ 0b00001000 * get(x, y+6) +
195
+ 0b00010000 * get(x, y+8) +
196
+ 0b00100000 * get(x, y+10)
197
+ #0b01000000 * get(x, y+12) +
198
+ #0b10000000 * get(x, y+14)
199
+ end
200
+
201
+ def b2_v144_enhanced(x, y)
202
+ 0 +
203
+ #0b00000001 * get(x, y+1) +
204
+ #0b00000010 * get(x, y+3) +
205
+ 0b00000100 * get(x, y+5) +
206
+ 0b00001000 * get(x, y+7) +
207
+ 0b00010000 * get(x, y+9) +
208
+ 0b00100000 * get(x, y+11) +
209
+ 0b01000000 * get(x, y+13) +
210
+ 0b10000000 * get(x, y+15)
211
+ end
212
+
213
+ ### Best quality: 4 lines per double-pass
214
+ def b1_v144_best(x, y)
215
+ 0 +
216
+ 0b00000001 * get(x, y) +
217
+ 0b00000010 * get(x, y+2)
218
+ end
219
+
220
+ def b2_v144_best(x, y)
221
+ 0 +
222
+ 0b00000001 * get(x, y+1) +
223
+ 0b00000010 * get(x, y+3)
224
+ end
225
+
226
+ ## Returns 0 for black pixels that exist, 1 otherwise
227
+ def get(x, y)
228
+ x = @img[x, y] & 0xffffff00
229
+ return 0 if x > 0
230
+ 1
231
+ rescue
232
+ 1
233
+ end
234
+
235
+ def init_printer!
236
+ printf "\ef" # forward line feeds
237
+ printf "\e\x6C1" # do not insert carriage return before LF and FF
238
+ printf "\eZ\x80\x00" # no line feed added after CR
239
+ printf "\eT01" # set line feed to 1/144 inch
240
+ printf "\e%s", HORIZ_DPI_CODE[@hdpi]
241
+ end
242
+ end
243
+
244
+ ImageWriter.new(ARGV).print!
metadata ADDED
@@ -0,0 +1,46 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: imagewriter
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - pete gamache
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-11-29 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description:
14
+ email: pete@gamache.org
15
+ executables:
16
+ - imagewriter
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - bin/imagewriter
21
+ homepage: https://github.com/gamache/imagewriter
22
+ licenses:
23
+ - CC-PDDC
24
+ metadata: {}
25
+ post_install_message:
26
+ rdoc_options: []
27
+ require_paths:
28
+ - lib
29
+ required_ruby_version: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ required_rubygems_version: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - ">="
37
+ - !ruby/object:Gem::Version
38
+ version: '0'
39
+ requirements: []
40
+ rubyforge_project:
41
+ rubygems_version: 2.5.2.3
42
+ signing_key:
43
+ specification_version: 4
44
+ summary: writes PNG images onto paper using an Apple Imagewriter or ImageWriter II
45
+ printer
46
+ test_files: []