Created
April 3, 2018 13:37
-
-
Save Miouyouyou/a3083b6b51ebfcccaf64ccf38b0cf355 to your computer and use it in GitHub Desktop.
Generate EPL code allowing you to print a QRCode with a Zebra 2746e (European and American versions)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
; !! IF YOU'RE OPENING THIS FILE ON UNIX/LINUX SYSTEMS, KEEP THE CRLF !! | |
; !! USE unix2dos IF YOUR EDITOR IS TOO DUMB TO KEEP THEM !! | |
; This is a comment (Assembly-like comments) | |
; Set the form length (Distance between each print ??) | |
Q0001,0 | |
; The label width in dots | |
q831 | |
; Set the double buffer mode (For what purpose, I have no idea) | |
rN | |
; Print speed : [2-6] = [level_selected*25] mm/s -> (2 == 2*25 mm/s) -> 50 mm/s | |
S2 | |
; Print density (quality. 5 = draft, 10 = normal, 15 = HQ) | |
D10 | |
; Print from top or bottom (T = TOP - B = BOTTOM) | |
ZT | |
; Disable Top of Form Backup (???) | |
JB | |
; Disable all options | |
O | |
; Move the reference point (offset). Values in points. | |
R671,0 | |
; Cut position (???) | |
f100 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This requires the rqrcode GEM | |
# This does not use the internal QR code generation command | |
# since this command only exists in Japanese versions of the | |
# printer. | |
# Instead, it generates a graphic representing the QR code, | |
# using the GW command, and prints it. | |
# To actually print the QR code, you'll need to add the printer | |
# using CUPS, then use the following command : | |
# lpr -P TheCUPSPrinterName -o raw test.qr | |
# This uses a header file provided below. The header file must | |
# keep the CRLF line endings. | |
require 'rqrcode' # gem install rqrcode | |
# In this documentation : pixel and dot are the same thing. | |
# | |
# First, in EPL (Eltron Programming Language), every dot (pixel) in a | |
# picture is encoded on one *bit*. | |
# Not an octet. A single bit. | |
# This means that 0xff -> 0b11111111 = 8 dots ! | |
# Obviously pictures are printed in monochrome. | |
# | |
# 0 means black, 1 means white. | |
# | |
# Now, after instigating how Zebra Designer generated QR-Code pictures, | |
# it seems that the QR Code is scaled 4 times. | |
# | |
# We'll use the same scale here. | |
# That means that each dot is printed 4 times in width and height. | |
# So basically, each dot will take half of an octet (0b0000) and each line | |
# will be printed 4 times. | |
# Padding will consist of one more pixel when the width is odd. | |
# 1 byte = 8 dots. Each scaled dot equals 4 dots. Meaning that a | |
# byte contains 2 scaled dots. | |
# (odd-number-of-dots / 2 scaled dots per byte -> n + half a byte | |
# (odd-number-of-dots + 1 dot of padding) / 2 scaled dots per byte -> n bytes) | |
# Remember that the print support width is tiny, so you cannot scale too | |
# much. | |
black = 0 | |
white = 1 | |
gw_data = [] | |
scaling = 4 | |
# QR Codes limits are defined by the level of security applied | |
# and their initial size. | |
# Security repeats the pattern more times, making the QR code more | |
# resilient to time. | |
# Obviously, repeating the pattern diminishes the available space | |
# in a given size. | |
# The different levels are : | |
# :l => 7% of code can be restored | |
# :m => 15% of code can be restored | |
# :q => 25% of code can be restored | |
# :h => 30% of code can be restored | |
qr = RQRCode::QRCode.new('My hamster knows kung-fu !', :size => 2, :level => :l) | |
# "modules" are pixels rows. | |
pixels_rows = qr.modules | |
# The width and height of the QR code. | |
height = pixels_rows.length | |
# All lines of a QR code have the same width, so | |
# the first column width == QR code width | |
width = pixels_rows.first.length | |
# Padding that will be added to each row in order to deal with | |
# unused space inside a byte at the end of a row. | |
# There's other ways to deal with this, but this way is hassle free | |
dots_per_byte = (8/scaling) | |
padding = [false] * (width%dots_per_byte) | |
current_byte = 0 # Current byte value. | |
current_i = 7 # Current bit inside the current byte value | |
# Each pixel row contains boolean values. | |
# True for a pixel, False for no pixel. | |
pixels_rows.each {|row| | |
# Add the necessary padding | |
row.push(*padding) | |
# p row # This just prints the current padded row, for debugging | |
current_byte = 0 # Start with an all-black byte | |
# We draw left to right, so we start from the higher bit in a byte | |
current_i = 7 | |
# Print each line x times, where x is the scaling | |
scaling.times { | |
# Start a line | |
row.each {|pixel| | |
# Printing with black ink on white. | |
pixel_value = (pixel ? black : white) | |
# Print each pixel x times, where x is the scaling | |
scaling.times { | |
# If pixel_value is white, this set the dot to white | |
# Black pixels are already set up, so this has no effect | |
# when pixel_value is black. | |
current_byte |= (pixel_value << current_i) | |
if (current_i != 0) | |
# We're still inside a byte. | |
current_i -= 1 # Let's move to the next bit | |
else | |
# We have a full byte, store it. | |
gw_data << current_byte | |
# In order to DRY this, refactoring everything into a | |
# Module or Class is needed. | |
current_byte = 0 | |
current_i = 7 | |
end | |
} | |
} | |
} | |
} | |
# The width and height stored in the printing listing are used | |
# by the printer to determine the number of bytes to parse. | |
# Example 13,100 tells the printer that the next 13 * 100 bytes | |
# are graphics data. | |
# | |
# We need to compute the width in bytes, based on the number of | |
# dots stored inside a byte, and round up to the next value | |
# since in-byte padding is automatically added when the width isn't | |
# aligned on byte boundaries. | |
stored_width = (width * scaling / 8.0).ceil | |
# Height values is just the number of rows to draw. | |
stored_height = height * scaling | |
puts "#{width} x #{height} (#{stored_width} x #{stored_height})" | |
# Arbitrary start position of the printed graphic | |
x = 18 | |
y = 9 | |
# Add the header. This header tells the printer to print with good | |
# quality. The default being "garbage quality". | |
header = File.read("zebra_print_header.txt") | |
# The command to draw graphics is GW | |
# The syntax is : | |
# GWx,y,bytes_per_row,rows,graphics_data | |
# | |
# N just tells the printer to start a new print buffer (New) | |
# P1 prints the data stored inside the buffer (written by GW) | |
File.write("test.qr", "#{header}N\r\nGW#{x},#{y},#{stored_width},#{stored_height},#{gw_data.pack("C*")}\r\nP1\r\n") | |
# The GW data are stored inside qr.raw for examination. | |
File.write("qr.raw", gw_data.pack("C*")) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment