Files
labelprint/tools/build_test_label.rb
T

116 lines
3.7 KiB
Ruby

require 'tmpdir'
require 'rqrcode'
DPI = 203
SRC_PDF = ARGV[0] || '/home/randy/EPH266757312_adresne_stitky_a6.pdf'
OUT_PS = ARGV[1] || '/tmp/test-label-v2.ps'
# barcode crop region in the source label, in native pixels at 203dpi
BARCODE_BOX = { x0: 388, y0: 222, x1: 772, y1: 322 }
def read_pbm(path)
bytes = File.binread(path)
header = /\AP4\s+(?:#[^\n]*\n\s*)*(\d+)\s+(\d+)\s/.match(bytes)
raise "bad pbm #{path}" unless header
width, height = header[1].to_i, header[2].to_i
bytes_per_row = (width + 7) / 8
body = bytes.byteslice(header.end(0), bytes_per_row * height)
{ width: width, height: height, bytes_per_row: bytes_per_row, body: body }
end
def pbm_bit(pbm, x, y)
byte = pbm[:body].getbyte(y * pbm[:bytes_per_row] + (x / 8))
(byte >> (7 - (x % 8))) & 1
end
# Packs a [x,y] => 0/1 (1 = black) pixel getter into row-padded, bit-inverted
# (PostScript DeviceGray 1bpc: 0=black) bytes ready for the `image` operator.
def pack_for_ps_image(width, height)
bytes_per_row = (width + 7) / 8
rows = Array.new(height) { "\x00".b * bytes_per_row }
height.times do |y|
row = rows[y].dup.b
width.times do |x|
next unless yield(x, y) == 1
byte_index = x / 8
bit = 0x80 >> (x % 8)
row.setbyte(byte_index, row.getbyte(byte_index) | bit)
end
rows[y] = row
end
packed = rows.join
inverted = packed.bytes.map { |b| (~b) & 0xFF }.pack('C*')
{ width: width, height: height, hex: inverted.unpack1('H*').upcase }
end
def ps_image_block(x_pt, y_pt, w_pt, h_pt, img)
<<~PS
gsave
#{x_pt} #{y_pt} translate
#{w_pt} #{h_pt} scale
#{img[:width]} #{img[:height]} 1
[#{img[:width]} 0 0 -#{img[:height]} 0 #{img[:height]}]
{ <#{img[:hex]}> } image
grestore
PS
end
Dir.mktmpdir do |dir|
pbm_path = File.join(dir, 'label.pbm')
system('gs', '-q', '-dNOPAUSE', '-dBATCH', '-dSAFER',
'-sDEVICE=pbmraw', "-r#{DPI}", '-dFirstPage=1', '-dLastPage=1',
"-sOutputFile=#{pbm_path}", SRC_PDF) or raise 'gs failed'
pbm = read_pbm(pbm_path)
bw = BARCODE_BOX[:x1] - BARCODE_BOX[:x0]
bh = BARCODE_BOX[:y1] - BARCODE_BOX[:y0]
barcode_img = pack_for_ps_image(bw, bh) do |x, y|
pbm_bit(pbm, BARCODE_BOX[:x0] + x, BARCODE_BOX[:y0] + y)
end
qr = RQRCode::QRCode.new('TEST-LABEL-PRINTSERVER')
modules = qr.modules
quiet = 4
qsize = modules.size + quiet * 2
qr_img = pack_for_ps_image(qsize, qsize) do |x, y|
mx, my = x - quiet, y - quiet
next 0 if mx.negative? || my.negative? || mx >= modules.size || my >= modules.size
modules[my][mx] ? 1 : 0
end
# physical sizes on the A6 (298x420pt) page
barcode_pt_w = 220
barcode_pt_h = barcode_pt_w * bh / bw
qr_pt = 100
ps = <<~PS
%!PS
<< /PageSize [298 420] >> setpagedevice
1 setlinewidth
10 10 278 400 rectstroke
/Helvetica-Bold findfont 24 scalefont setfont
30 380 moveto (TEST LABEL) show
/Helvetica findfont 9 scalefont setfont
30 362 moveto (Generic print-quality test page - safe to reprint anytime) show
/Helvetica-Bold findfont 13 scalefont setfont
30 330 moveto (Odosielatel: Test Sender, BA) show
30 312 moveto (Adresat: Test Recipient, KE) show
/Helvetica findfont 8 scalefont setfont
30 292 moveto (Fine print 8pt: quick brown fox 0123456789) show
#{ps_image_block(30, 210, barcode_pt_w, barcode_pt_h, barcode_img)}
/Helvetica findfont 8 scalefont setfont
30 198 moveto (1D: reused known-good Code128 from a real courier label) show
#{ps_image_block(30, 60, qr_pt, qr_pt, qr_img)}
/Helvetica findfont 8 scalefont setfont
140 100 moveto (QR: TEST-LABEL-PRINTSERVER) show
140 88 moveto (rendered natively via rqrcode) show
showpage
PS
File.write(OUT_PS, ps)
puts "wrote #{OUT_PS}"
end