Feature Request - ZPL Format
Posted: 2012-08-10T22:41:21-07:00
Hi guys, today i convert images to ZPL format (Zebra label printer) using a PHP script
i want a solution in imagemagick, since some times i don´t have PHP to execute this job
i was reading corders/mono.c at source code, and zpl image representation is very near
instead of a binary string, we need string representation of hexdecimal bytes and rounded widths of image (rounded in 8 pixels -> zpl width = ceil(image width/8)*8)
for example
a image of 4x3 pixel (3=height) MUST be changed to 8x3 pixel and new pixels will be white (in binary = 0), image start from TOP LEFT and run to RIGHT each line, after line end, it jump one line down, and get back to left like a "\n\r" (new line, carrier return), as a standard each line end with a "\n" (newline) character (can be removed or use "\r\n" or "\n\r")
for example... a binary image of 4x3 black/white:
will be resized and converted to hexadecimal string
ZPL will interpret "C0" as black (1),black (1),white (0),white (0),white (0),white (0),white (0),white (0)
check that it ALWAYS need 2 bytes of hexadecimal information
in manual it say that each char is one niblle of pixel (4pixels), but using printer (ZEBRA S600, S4M, S400, Z4M) i checked that for each line we need one full byte information, in others words, we reaaalllyyyy need 8pixels, a line of 4 pixel don´t work
example, an image of 4x3: "C\nC\nC\n", MUST be converted to 8x3: "C0\nC0\nC0\n"
---
after convert to a hexadecimal string, we must set some info to send this image to printer, we can call this as ZPL Image HEADER... it tell what the name of file inside printer memory, image format (ascii,png,others) and tell the width/height of image, from my PHP script we have:
now we can have the file:
any doubt? could anyone implement this?
there´s some compression that we can implement but as a first version this works for 90% of zpl files
compressions:
":" string in ZPL picture = repeat last line
if we repeat one line for example:
"CO\nCO\n60\n30\n"
we can rewrite it as:
"CO\n:\n60\n30\n"
this is good for very big lines of white or black pixels (normally a label have many white line, and just some black+white line, and more many white lines)
"," put 0 from current position to end of line
"!" put 1 from current position to end of line
for example
"!!!" = 3 lines of 1111111111111111111111111111111111111111111... (black)
",,," = 3 lines of 0000000000000000000000000000000000000000000... (white)
"12341!\n" = 12341+1111111111111111111111111111...
"FF," = FF+000000000000000...
some others compressions exists, for example a big line of "0000000000000" can be rewrite in another string using some algorithm like RLE, but i never used and never tested, i know it exists but i don´t know if anyone use it...
MORE ABOUT THIS TYPE OF COMPERSSION CAN BE FOUNDED IN MANUAL... (CHECK END OF POST)
---------------
some more information can be founded here:
http://www.ptshome.com/kb/Manuals/ZPL_Vol2.pdf
at page 38: ~DG COMMAND OPTIONS (CHECK THAT WE CAN USE ~DY OR ~DG, ANYONE WORKS, but DY have more parameters - allow png,ascii compressed and others options, but not all ZPL printers support compression and PNG...)
at page 39: explanation about ASCII image parameter of ~DG command
The data string defines the image and is an ASCII hexadecimal representation of the image. Each character represents a horizontal nibble of four dots.
more about image format can be founded here:
http://www.omnihost.us/files/Zebra/1390 ... Stripe.pdf
at page 105 (DG COMMAND)
more about compression can be founded here, but it uses ~DG and not ~DY
http://www.ptshome.com/kb/Manuals/ZPL_Vol2.pdf
page 71
----------------
now... how to read from a GRF file to write a picture...
first... find ~DY or ~DG string....
after founded...
if ~DY the format is: ~DY[FILENAME],[FORMAT],[EXTENSION],[BYTES IN FILE],[BYTES PER ROW],[DATA]
so first find format.. it must be = "a"
find EXTENSION.. it must be = "G"
find bytes in file.. it must be a unsigned interger, zebra memory have about 32MB of ram, we could use a unsigned int of 32 bits to handle any kind of image...
find bytes per row... it must be multiple of bytes in file, for example...
bytes in file = 10, 10/bytes per row must be a integer, in other words...
10/1 = 10 (integer => 10 lines, 1*8 pixels per line)
10/2 = 5 (integer => 5 lines, 2*8 pixels per line)
10/3 = 3.333 ( not a integer, invalid information, don´t convert image)
10/4 = 2.5 (not a integer, invalid information, don´t convert image)
10/5 = 2 (integer => 2 lines, 5*8 pixels per line)
....
10/10 = 1 (integer => 1 lines, 10*8pixels per line)
for ~DG command-> format is: ~DG[FILENAME],[BYTES IN FILE],[BYTES PER ROW],[DATA]
check that ~DY and ~DG can have "\n" (new line) and "\r" (carrier return) after last "," (comma) for example
~DGABC.GRF,10,2,
ADAD
ADAD
ADAD
ADAD
ADAD
-- end of file
that´s because [DATA] when interpreted by print will only accept some characters... (we will not implement cancel commands: "~JA", "~JP", "~JX", "~DN")
the characters accepted as pixel informations are [0-9][a-z][A-Y][:][!][,]
--
well now to convert data to pixels...
we have bytes per line... start painting pixel per pixel, start from top left, go to right on first line, end of line, go to next line return to first pixel of left, starting painting again... i don´t know if exists a function to paint without 2d (x,y) information... some thinking like: 5 pixels per line... paint(black,20) it will paint black on y=5 x=0, if it exists well paint will be more more easy... just read pixel information and write, doesn´t matter line... the file is a continous string of each pixel in image....
ok... start reading file... allow caracters: [0-9][A-F][:][!][,] i never used [a-f] but i think it should work like [A-F]...
for others compressions [G-Y][g-z]
check that for compression [G-Y] != [g-y]
image will be always BLACK AND WHITE
--------------------
if you want more help please contact me, i have a IMAGE to GRF, and a GRF to IMAGE PHP script, my email: rspadim at gmail dot com
but please only contact if you want to develop it to imagemagick code
thanks guys!
i want a solution in imagemagick, since some times i don´t have PHP to execute this job
i was reading corders/mono.c at source code, and zpl image representation is very near
instead of a binary string, we need string representation of hexdecimal bytes and rounded widths of image (rounded in 8 pixels -> zpl width = ceil(image width/8)*8)
for example
a image of 4x3 pixel (3=height) MUST be changed to 8x3 pixel and new pixels will be white (in binary = 0), image start from TOP LEFT and run to RIGHT each line, after line end, it jump one line down, and get back to left like a "\n\r" (new line, carrier return), as a standard each line end with a "\n" (newline) character (can be removed or use "\r\n" or "\n\r")
for example... a binary image of 4x3 black/white:
Code: Select all
1100 (black,black,white,white)
0110 (white,black,black,white)
0011 (white,white,black,black)
Code: Select all
binary => hexadecimal string
11000000 => "C0\n"
01100000 => "60\n"
00110000 => "30\n"
check that it ALWAYS need 2 bytes of hexadecimal information
in manual it say that each char is one niblle of pixel (4pixels), but using printer (ZEBRA S600, S4M, S400, Z4M) i checked that for each line we need one full byte information, in others words, we reaaalllyyyy need 8pixels, a line of 4 pixel don´t work
example, an image of 4x3: "C\nC\nC\n", MUST be converted to 8x3: "C0\nC0\nC0\n"
---
after convert to a hexadecimal string, we must set some info to send this image to printer, we can call this as ZPL Image HEADER... it tell what the name of file inside printer memory, image format (ascii,png,others) and tell the width/height of image, from my PHP script we have:
Code: Select all
"~DY$name,a,G,$bytes,$bytes_per_row,\n$zebra_image\n"
$name = name of file, 8 bytes + ".GRF", like FAT16 filesystem names, example: "ABCDEFGH.GRF"
as default (in manual) if we don´t know the name we could use: "UNKNOWN.GRF", since we have some problem with image names, we could put it to always use UNKNOWN.GRF or as a optional especific ZPL parameter at "convert" program, for example: "convert -format ZPL -zplname ABC.GRF image.png image.grf"
$bytes_per_row = ceil(width of image / 8)
"CO" = 8 bits = 1 byte, if we have a image of 3x4, we should resize to 8x4, and divide 8pixels of 'width' to 1byte of 'size'
$bytes = total number of bytes in image, in our example:
"C06030" => 8bits+8bits+8bits = 24bits = 24/8 = 3 bytes
$zebra_image = ASCII representation of image pixels from top left to right, after one line jump to next bottom line and get back to left, like a "\n\r" in bash terminal
Code: Select all
"~DYUNKNOWN.GRF,a,G,3,1,\n"
"CO\n"
"60\n"
"30\n"
there´s some compression that we can implement but as a first version this works for 90% of zpl files
compressions:
":" string in ZPL picture = repeat last line
if we repeat one line for example:
"CO\nCO\n60\n30\n"
we can rewrite it as:
"CO\n:\n60\n30\n"
this is good for very big lines of white or black pixels (normally a label have many white line, and just some black+white line, and more many white lines)
"," put 0 from current position to end of line
"!" put 1 from current position to end of line
for example
"!!!" = 3 lines of 1111111111111111111111111111111111111111111... (black)
",,," = 3 lines of 0000000000000000000000000000000000000000000... (white)
"12341!\n" = 12341+1111111111111111111111111111...
"FF," = FF+000000000000000...
some others compressions exists, for example a big line of "0000000000000" can be rewrite in another string using some algorithm like RLE, but i never used and never tested, i know it exists but i don´t know if anyone use it...
MORE ABOUT THIS TYPE OF COMPERSSION CAN BE FOUNDED IN MANUAL... (CHECK END OF POST)
---------------
some more information can be founded here:
http://www.ptshome.com/kb/Manuals/ZPL_Vol2.pdf
at page 38: ~DG COMMAND OPTIONS (CHECK THAT WE CAN USE ~DY OR ~DG, ANYONE WORKS, but DY have more parameters - allow png,ascii compressed and others options, but not all ZPL printers support compression and PNG...)
at page 39: explanation about ASCII image parameter of ~DG command
The data string defines the image and is an ASCII hexadecimal representation of the image. Each character represents a horizontal nibble of four dots.
more about image format can be founded here:
http://www.omnihost.us/files/Zebra/1390 ... Stripe.pdf
at page 105 (DG COMMAND)
more about compression can be founded here, but it uses ~DG and not ~DY
http://www.ptshome.com/kb/Manuals/ZPL_Vol2.pdf
page 71
----------------
now... how to read from a GRF file to write a picture...
first... find ~DY or ~DG string....
after founded...
if ~DY the format is: ~DY[FILENAME],[FORMAT],[EXTENSION],[BYTES IN FILE],[BYTES PER ROW],[DATA]
so first find format.. it must be = "a"
find EXTENSION.. it must be = "G"
find bytes in file.. it must be a unsigned interger, zebra memory have about 32MB of ram, we could use a unsigned int of 32 bits to handle any kind of image...
find bytes per row... it must be multiple of bytes in file, for example...
bytes in file = 10, 10/bytes per row must be a integer, in other words...
10/1 = 10 (integer => 10 lines, 1*8 pixels per line)
10/2 = 5 (integer => 5 lines, 2*8 pixels per line)
10/3 = 3.333 ( not a integer, invalid information, don´t convert image)
10/4 = 2.5 (not a integer, invalid information, don´t convert image)
10/5 = 2 (integer => 2 lines, 5*8 pixels per line)
....
10/10 = 1 (integer => 1 lines, 10*8pixels per line)
for ~DG command-> format is: ~DG[FILENAME],[BYTES IN FILE],[BYTES PER ROW],[DATA]
check that ~DY and ~DG can have "\n" (new line) and "\r" (carrier return) after last "," (comma) for example
~DGABC.GRF,10,2,
ADAD
ADAD
ADAD
ADAD
ADAD
-- end of file
that´s because [DATA] when interpreted by print will only accept some characters... (we will not implement cancel commands: "~JA", "~JP", "~JX", "~DN")
the characters accepted as pixel informations are [0-9][a-z][A-Y][:][!][,]
--
well now to convert data to pixels...
we have bytes per line... start painting pixel per pixel, start from top left, go to right on first line, end of line, go to next line return to first pixel of left, starting painting again... i don´t know if exists a function to paint without 2d (x,y) information... some thinking like: 5 pixels per line... paint(black,20) it will paint black on y=5 x=0, if it exists well paint will be more more easy... just read pixel information and write, doesn´t matter line... the file is a continous string of each pixel in image....
ok... start reading file... allow caracters: [0-9][A-F][:][!][,] i never used [a-f] but i think it should work like [A-F]...
for others compressions [G-Y][g-z]
check that for compression [G-Y] != [g-y]
image will be always BLACK AND WHITE
--------------------
if you want more help please contact me, i have a IMAGE to GRF, and a GRF to IMAGE PHP script, my email: rspadim at gmail dot com
but please only contact if you want to develop it to imagemagick code
thanks guys!