class ImageWriter
Constants
- HORIZ_DPI_CODE
Send Esc + this letter to change horizontal DPI
- LINE_FEEDS
Send x1F then this letter to send N line feeds
Public Class Methods
new(argv)
click to toggle source
# File bin/imagewriter, line 17 def initialize(argv) parse_argv!(argv.clone) @img = ChunkyPNG::Image.from_file(@filename) STDERR.puts "#{@filename}: height #{@img.height}, width #{@img.width}" printable_width = @hdpi * 8 if @img.width > printable_width STDERR.puts "Warning: image exceeds printable width of #{printable_width} pixels; printout will be clipped" end end
Public Instance Methods
b1(x, y)
click to toggle source
Returns data byte for first-pass lines
# File bin/imagewriter, line 164 def b1(x, y) 0 + 0b00000001 * get(x, y) + 0b00000010 * get(x, y+2) + 0b00000100 * get(x, y+4) + 0b00001000 * get(x, y+6) + 0b00010000 * get(x, y+8) + 0b00100000 * get(x, y+10) + 0b01000000 * get(x, y+12) + 0b10000000 * get(x, y+14) end
b2(x, y)
click to toggle source
Returns data byte for second-pass lines
# File bin/imagewriter, line 177 def b2(x, y) 0 + 0b00000001 * get(x, y+1) + 0b00000010 * get(x, y+3) + 0b00000100 * get(x, y+5) + 0b00001000 * get(x, y+7) + 0b00010000 * get(x, y+9) + 0b00100000 * get(x, y+11) + 0b01000000 * get(x, y+13) + 0b10000000 * get(x, y+15) end
get(x, y)
click to toggle source
Returns 1 for black pixels that exist, 0 otherwise
# File bin/imagewriter, line 190 def get(x, y) x = @img[x, y] & 0xffffff00 # strip alpha channel return 0 if x > 0 1 rescue 0 end
init_printer!()
click to toggle source
# File bin/imagewriter, line 198 def init_printer! print "\eT01" # set line feed to 1/144 inch printf "\e%s", HORIZ_DPI_CODE[@hdpi] end
parse_argv!(argv)
click to toggle source
# File bin/imagewriter, line 102 def parse_argv!(argv) options = { hdpi: 144, quality: 1, sleep: 0.75 } help = nil OptionParser.new do |parser| parser.banner = <<-EOT Usage: imagewriter [options] filename.png Vertical resolution is 144 dpi; horizontal resolution is adjustable. Max printable width is 8 inches, or 8 * horizontal DPI pixels. Options: EOT dpis = HORIZ_DPI_CODE.keys.join(", ") parser.on('-H', '--horizontal DPI', Integer, "Horizontal DPI. One of: #{dpis}; default #{options[:hdpi]}") do |n| if HORIZ_DPI_CODE[n] options[:hdpi] = n else STDERR.puts "Bad horizontal DPI setting #{n} (must be one of: #{dpis})\n" STDERR.puts parser.to_s exit 1 end end parser.on("-q", "--quality QUALITY", Integer, "Print quality. 1 (fastest) to 7 (best); default #{options[:quality]}") do |n| if n > 0 && n < 8 options[:quality] = n else STDERR.puts "Bad quality setting #{n} (must be 1-7)" STDERR.puts parser exit 1 end end parser.on("-s", "--sleep SECONDS", Float, "Sleep this many seconds between passes. Default #{options[:sleep]}") do |n| options[:sleep] = n end parser.on("-h", "--help", "Print this help message to STDERR") do STDERR.puts parser exit end help = parser.to_s end.parse!(argv) @hdpi = options[:hdpi] @quality = options[:quality] @sleep = options[:sleep] @filename = argv.shift if !@filename STDERR.puts "Missing filename\n" STDERR.puts help exit 1 end end
print!()
click to toggle source
Prints an image at double vertical resolution (144 dpi) by writing interleaved rows in a back-and-forth “double pass”.
# File bin/imagewriter, line 31 def print! init_printer! ## Higher quality is achieved by printing fewer lines at a time, ## and dovetailing these lines with the adjacent double-passes dovetail = 2 * (@quality-1) lines_per_double_pass = 16 - dovetail ## Make bitmasks for first- and second-pass bytes half_dovetail = (dovetail / 2).to_i dovemask1 = 0xff >> half_dovetail dovemask2 = 0xff << half_dovetail width = [@hdpi * 8, @img.width].min y = -16 # start here to provide any necessary margin for dovetailing while (y <= @img.height) do bytes1 = 0.upto(width-1).map{|x| b1(x, y) & dovemask1} bytes2 = 0.upto(width-1).map{|x| b2(x, y) & dovemask2} printf "\eG%.4d", bytes1.length bytes1.each{|b| print b.chr} print "\r" print "\x1F1" # one line feed printf "\eG%.4d", bytes2.length bytes2.each{|b| print b.chr} print "\r" printf "\x1F%s", LINE_FEEDS[lines_per_double_pass - 1] sleep @sleep y += lines_per_double_pass end end