ZPL - How to embed GS1 application identifiers into GS1 QR code - qr-code

I'm trying to code a GS1 compliant QR code in ZPL which will inlcude a number of application identifiers. I don't understand how to embed the FNC1 character within the ^FD string when using ^BQ to create a 2d code.
Below is my first attempt. When creating a GS1-128 barcode, I would use the >8 character to denote variable length fields.
^FX Test^FS
^XA^MCY^XZ
^XA^LH0,65
^LH0,0^FS
^BQN,2,10^FD>;>83018099999>82411184174>810MFATA00001>891EA^FS
^PQ1,0,0,N
^XZ
This creates a 2d barcode that returns the following string when scanned, but is not recoginised as GS1 compliant.
11611193018099999>82411184174>810MFATA00001>891EA
How do I configure the ^FD field to enable the FNC1 character?

QR ZPL Issues
See a recent answer I had for QR codes here:
Print ZPLII QR to open url
You are missing some of the parameters for the ^BQ and ^FD commands.
GS1 QR Issues
Research I've done indicates that the GS1 QR code is quite proprietary, and does not seem to be easily generated with ZPL. However, you can use a Data Matrix barcode quite easily.
Looks like you are trying to create a code with the following Application Identifiers and values:
30: Variable Count of Items: 18099999
241: Variable Customer Part Number: 1184174
10: Variable Batch/Lot Number: MFATA00001
91: Variable Company Internal: EA
GTIN 01 seems to be required and is missing. I've added a temporary GTIN string. Customer part number 241 seems to be local only, and may not validate in some applications which validate global requirements.
Full Barcode String.
^FD_10112345678901234_110MFATA00001_13018099999_12411184174_191EA^FS
Full ZPL for sample label
^XA
^FO10,10
^BXN,9,200,40,40,,_
^FD_10112345678901234_110MFATA00001_13018099999_12411184174_191EA^FS
^XZ
Hope that helps.
https://www.gs1.org/docs/barcodes/GSCN_16_477_FNC1.pdf
https://www.zebra.com/us/en/support-downloads/knowledge-articles/creating-gs1-barcodes-with-zebra-printers-for-data-matrix-and-code-128-using-zpl.html

EdHayes3's answer is just great.
As specified by Zebra in a ^BX the escape character is the underscore and the subsequent number defines what kind of FNC is used.
_1 - > FNC1
_2 - > FNC2
_3 - > FNC3
FNC4 is not supported according to how I understand the Zebra documentation.
The only thing I do not entirely agree with is escaping every GS1 AI since the most common ones except Lot/Batch number have a fixed length.
In other words, I do not think that it is necessary to escape for example the GTIN. Though, you probably have to keep in mind to pad it up with leading zeros in case of GTIN-12 or GTIN-13.

Related

Why does contents of ^FN1 in ZPL not show all content when used in ^BQ command with ^FD?

I am looking for some direction here, as I seem to be missing something. I have the following ZPL that is loaded into a ZD620:
^XA
^LH0,0^LRN^FT100,50,0^A0N,30,30^FN1^FDCORELIMS.BARCODE^FS
^FO471,27^BQN,1,3^FDQA,^FN1^FS
^FT381,188^A0N,50,68^FD^FN1^FS
^XZ
I use an off-the-shelf software that turns CORELIMS.BARCODE into the entity's barcode value to be encoded. That works fine. What is not happening, when the Generated QR Code is scanned, the output is always missing the first 3 characters. What should show up is something like: 5BX10, what I get is: 10.
During my troubleshooting I used the following code and I receive the full string:
^XA
^LH0,0^LRN^FT100,50,0^A0N,30,30^FN1^FDCORELIMS.BARCODE^FS
^FO471,27^BQN,1,3^FDQA,5BX10^FS
^FT381,188^A0N,50,68^FD^FN1^FS
^XZ
All other fields using the ^FN1 command (including this one: ^FT381,188^A0N,50,68^FD^FN1^FS) output the correct value, just not the generated QR code.
I found similar questions, however, none of which are using a ^FN command, and their suggestions do not work for my situation. Those links are listed here:
Print ZPLII QR to open url
ZPL QR code not printing what is in the string
Thanks for help and I would really like to learn what I am doing wrong.
The ^FNx commands are used with stored formats; they cannot be used in a "one-off" label format like you are showing. I am traveling and don't have a zebra printer to test this but basically you need to define the label format "template" using ^DF like:
^XA
^DFR:MYFORMAT.ZPL^FS
^LH0,0^LRN^FT100,50,0^A0N,30,30
^FO471,27^BQN,1,3^FN1^FS
^FT381,188^A0N,50,68^FN1^FS
^XZ
That stores the format as R:MYFORMAT.ZPL. Then you use ^XF to recall the format and provide the values for the ^FNx:
^XA
^XFR:MYFORMAT.ZPL^FS
^FN1^FDQA,CORELIMS.BARCODE^FS
^XZ
Note that you include the extra data params required by ^BQ in the ^FD string.
Hope that helps.

How concat multiple fields for a GS1 Data-matrix (BXN) in Zebra Programming Lang (ZPL)

I'm trying to show some data in a GS1 Datamatrix which has field separators (FNC1,GS) pass within the variable to a zpl template.
Originally, in ZebraDesigner I couldn't get zpl to allow me to pass the separators within the parameter/variable. The separators would only show as text within the data, not as control characters for the scanner. (I was able to pass the separators as Fix Data, however it needs to work with a parameter).
Alternatively, I was hoping to edit the zpl and concatenate the control characters and QR values into one printed data for the Datamatrix.
This is zpl using one variable QRCode: (This works but not with passed separators)
^BY208,208^FT448,1123^BXN,8,200,0,0,1,~
^FH\^FN18^FDQRCode^FS
This is using fixed data where FNC1 is \7E and GS is \1D: (This works but doesn't use variables/parameters)
^BY208,208^FT448,1123^BXN,8,200,0,0,1,~
^FH\^FD\7E188text234567890\1Dmoretext^FS
This is my attempt to concat the separators and variables QRData1...:
^BY208,208^FT448,1123^BXN,8,200,0,0,1,~
^FH\^FD\7E^FN18^FDQRData1^FN22^FD\1D^FDQRData2^FD\1D^FN23^FDQRData3^FS
Unfortunately, the QR code only shows the value for the last var QRData3
Escape your field seperator hex codes with an _ (underscore), not with a backslash.
And use only one ^FD command like in your second example.
For reference see the pages of the commands ^FD, ^FH and ^BX in the Zebra ZPL II Programming Giude
As the OP found out, the field seperator _d029 worked for him! This is the hex value (0xD029) for the control character.
More information can be found here:
Encode GS,RS, and EOT for Code 128 and PDF417
GS is ~029
RS is ~030
EOT is ~004
Example:
[)><RS>06<GS>13V12GG7<GS>1P029-102489-157<GS>NC-411-661478-1<RS><EOT>
Enter the data as:
[)>~03006~d02913V12GG7~0291P029-102489-157~029NC-411-661478-1~030~004
Encode GS,RS, and EOT for Data Matrix, Aztec, and QR Code
GS is ~d029
RS is ~d030
EOT is ~d004
Example:
[)><RS>06<GS>13V12GG7<GS>1P029-102489-157<GS>NC-411-661478-1<RS><EOT>
Enter the data as:
[)>~d03006~d02913V12GG7~d0291P029-102489-157~d029NC-411-661478-1~d030~d004

convert comment string to an ASCII character list in sicstus-prolog

currently I am working on comparison between SICStus3 and SICStus4 but I got one issue that is SICStus4 will not consult any cases where the comment string has carriage controls or tab characters etc as given below.
Example case as given below.It has 3 arguments with comma delimiter.
case('pr_ua_sfochi',"
Response:
answer(amount(2370.09,usd),[[01AUG06SFO UA CHI Q9.30 1085.58FUA2SFS UA SFO Q9.30 1085.58FUA2SFS NUC2189.76END ROE1.0 XT USD 180.33 ZPSFOCHI 164.23US6.60ZP5.00AY XF4.50SFO4.5]],amount(2189.76,usd),amount(2189.76,usd),amount(180.33,usd),[[fua2sfs,fua2sfs]],amount(6.6,usd),amount(4.5,usd),amount(0.0,usd),amount(18.6,usd),lasttktdate([20061002]),lastdateafterres(200712282]),[[fic_ticketinfo(fare(fua2sfs),fic([]),nvb([]),nva([]),tktiss([]),penalty([]),tktendorsement([]),tourinfo([]),infomsgs([])),fic_ticketinfo(fare(fua2sfs),fic([]),nvb([]),nva([]),tktiss([]),penalty([]),tktendorsement([]),tourinfo([]),infomsgs([]))]],<>,<>,cat35(cat35info([])))
.
02/20/2006 17:05:10 Transaction 35 served by static.static.server1 (usclsefat002:7551) running E*Fare version $Name: build-2006-02-19-1900 $
",price(pnr(
user('atl','1y',<>,<>,dept(<>,'0005300'),<>,<>,<>),
[
passenger(adt,1,[ptconly(n)])
],
[
segment(1,sfo,chi,'ua','<>','100',20140901,0800,f,20140901,2100,'737',res(20140628,1316),hk,pf2(n,[],[],n),<>,flags(no,no,no,no,no,no,no,no,no)),
segment(2,chi,sfo,'ua','<>','101',20140906,1000,f,20140906,1400,'737',res(20140628,1316),hk,pf2(n,[],[],n),<>,flags(no,no,no,no,no,no,no,no,no))
]),[
rebook(n),
ticket(20140301,131659),
dbaccess(20140301,131659),
platingcarrier('ua'),
tax_exempt([]),
trapparm("trap:ffil"),
city(y)
])).
The below predicate will remove comment section in above case.
flatten-cases :-
getmessage(M1),
write_flattened_case(M1),
flatten-cases.
flatten-cases.
write_flattened_case(M1):-
M1 = case(Case,_Comment,Entry),!,
M2 = case(Case,Entry),
writeq(M2),write('.'),nl.
getmessage(M) :-
read(M),
!,
M \== end_of_file.
:- flatten-cases.
Now my requirement is to convert the comment string to an ASCII character list.
Layout characters other than a regular space cannot occur literally in a quoted atom or a double quoted list. This is a requirement of the ISO standard and is fully implemented in SICStus since 3.9.0 invoking SICStus 3 with the option --iso. Since SICStus 4 only ISO syntax is supported.
You need to insert \n and \t accordingly. So instead of
log('Response:
yes'). % BAD!
Now write
log('Response:\n\tyes').
Or, to make it better readable use a continuation escape sequence:
log('Response:\n\
\tyes').
Note that using literal tabs and literal newlines is highly problematic. On a printout you do not see them! Think of 'A \nB' which would not show the trailing spaces nor trailing tabs.
But there are also many other situations like: Making a screenshot of program text, making a photo of program text, using a 3270 terminal emulator and copying the output. In the past, punched cards. The text-mode when reading files (which was originally motivated by punched cards). Similar arguments hold for the tabulator which comes from typewriters with their manually settable tab stops.
And then on SO it is quite difficult to type in a TAB. The browser refuses to type it (very wisely), and if you copy it in, you get it rendered as spaces.
If I am at it, there is also another problem. The name flatten-case should rather be written flatten_case.

GS1 support in a QR encoder/decoder?

Very few QR encoders/decoders have (explicit) support for so-called GS1 encoding. Zint is one of the exceptions (under QR select GS-1 Data Mode), but its license prevents me from using it. Commercial offers, mainly from Tec-It, are costly, especially because I'm not interested in all other kinds of barcodes they support.
Is there a way to add GS1 support to any QR encoder/decoder without changing its source? For example, could I apply some algorithm to transform textual GTIN AI data into compatible binary? I think it should be possible, because after all, it's still QR. Please note that I am not a data coding expert - I'm just looking for a way to deal with this standard without paying a small fortune. So far, I found postscriptbarcode which does have support for it, and seems to use its own QR engine, but output quality is so-so and my PostScript skills are far too limited to figure out the algorithm.
As long as the library supports decoding of the FNC1 special character, it can be used to read GS1 codes. The FNC1 character is not a byte in the data-stream, but more of a formatting symbol.
The specification says that a leading FNC1-character is used to identify GS1 barcodes, and should be decoded as "]d2" (GS1 DataMatrix), "]C1" (GS1-128), "]e0" (GS1 DataBar Omnidirectional) or "]Q3" (GS1 QR Code). Any other FNC1-characters should be decoded as ASCII GS-characters (byte value 29).
Depending on the library, the leading FNC1 might be missing, or decoded as GS (not critical), or the embedded FNC1-characters might be missing (critical). The embedded FNC1-characters are used to delimit variable-length fields.
You can read the full specification here (pdf). The algorithm for decoding the data can be found under heading 7.9 Processing of Data from a GS1 Symbology using GS1 Application Identifiers (page 426).
The algorithm goes something like this:
Peek at the first character.
If it is ']',
If string does not start with ']C1' or ']e0' or ']d2' or ']Q3',
Not a GS1 barcode.
Stop.
Consume the caracters.
Else if it is <GS>,
Consume character.
Else,
No symbology identifier, assume GS1.
While not end of input,
Read the first two digits.
If they are in the table of valid codes,
Look up the length of the AI-code.
Read the rest of the code.
Look up the length of the field.
If it is variable-length,
Read until the next <FNC1> or <GS>.
Else,
Read the rest if the field.
Peek at the next character.
If it is <FNC1> or <GS>, consume it.
Save the read field.
Else,
Error: Invalid AI
The binary data in the QR Code is encoded as 4-bit tokens, with embedded data.
0111 -> Start Extended Channel Interpretation (ECI) Mode (special encodings).
0001, 0010, 0100, 1000 -> start numeric, alphanumeric, raw 8-bit, kanji encoded data.
0011 -> structured append (combine two or more QR Codes to one data-stream).
0101 -> FNC1 initial position.
1001 -> FNC1 other positions.
0000 -> End of stream (can be omitted if not enough space).
After an encoding specification comes the data-length, followed by the actual data. The meanings of the data bits depends on the encoding used. In between the data-blocks, you can squeeze FNC1 characters.
The QR Code specification (ISO/IEC 18004) unfortunately costs money (210 Franc). You might find some pirate version online though.
To create GS1 QR Codes, you need to be able to specify the FNC1-characters in the data. The library should either recognize the "]Q3" prefix and GS-characters, or allow you to write FNC1 tokens via some other method.
If you have some way to write the FNC1-characters, you can encode GS1 data as follows:
Write initial FNC1.
For each field,
Write the AI-code as decimal digits.
Write field data.
If the code is a variable-length field,
If not the last field,
Write FNC1 to terminate the field.
If possible, you should order the fields such that a variable-length field comes last.
As noted by Terry Burton in the comments; The FNC1 symbol in a GS1 QR Code can be encoded as % in alphanumeric data, and as GS in byte mode. To encode an actual percent symbol, you write it as %%.
To encode (01) 04912345123459 (15) 970331 (30) 128 (10) ABC123, you first combine it into the data string 01049123451234591597033130128%10ABC123 (% indicator is the encoded FNC1 symbol). This string is then written as
0101 - Initial FNC1, GS1 mode indicator
0001 - QR numeric mode
0000011101 - Data length (29)
<data bits for "01049123451234591597033130128">
0010 - QR alphanumeric mode
000001001 - Data length (9)
<data bits for "%10ABC123">
(Example from the ISO 18004:2006 specification)

Please help identify multi-byte character encoding scheme on ASP Classic page

I'm working with a 3rd party (Commidea.com) payment processing system and one of the parameters being sent along with the processing result is a "signature" field. This is used to provide a SHA1 hash of the result message wrapped in an RSA encrypted envelope to provide both integrity and authenticity control. I have the API from Commidea but it doesn't give details of encoding and uses artificially created signatures derived from Base64 strings to illustrate the examples.
I'm struggling to work out what encoding is being used on this parameter and hoped someone might recognise the quite distinctive pattern. I initially thought it was UTF8 but having looked at the individual characters I am less sure.
Here is a short sample of the content which was created by the following code where I am looping through each "byte" in the string:
sig = Request.Form("signature")
For x = 1 To LenB(sig)
s = s & AscB(MidB(sig,x,1)) & ","
Next
' Print s to a debug log file
When I look in the log I get something like this:
129,0,144,0,187,0,67,0,234,0,71,0,197,0,208,0,191,0,9,0,43,0,230,0,19,32,195,0,248,0,102,0,183,0,73,0,192,0,73,0,175,0,34,0,163,0,174,0,218,0,230,0,157,0,229,0,234,0,182,0,26,32,42,0,123,0,217,0,143,0,65,0,42,0,239,0,90,0,92,0,57,0,111,0,218,0,31,0,216,0,57,32,117,0,160,0,244,0,29,0,58,32,56,0,36,0,48,0,160,0,233,0,173,0,2,0,34,32,204,0,221,0,246,0,68,0,238,0,28,0,4,0,92,0,29,32,5,0,102,0,98,0,33,0,5,0,53,0,192,0,64,0,212,0,111,0,31,0,219,0,48,32,29,32,89,0,187,0,48,0,28,0,57,32,213,0,206,0,45,0,46,0,88,0,96,0,34,0,235,0,184,0,16,0,187,0,122,0,33,32,50,0,69,0,160,0,11,0,39,0,172,0,176,0,113,0,39,0,218,0,13,0,239,0,30,32,96,0,41,0,233,0,214,0,34,0,191,0,173,0,235,0,126,0,62,0,249,0,87,0,24,0,119,0,82,0
Note that every other value is a zero except occasionally where it is 32 (0x20). I'm familiar with UTF8 where it represents characters above 127 by using two bytes but if this was UTF8 encoding then I would expect the "32" value to be more like 194 (0xC2) or (0xC3) and the other value would be greater than 0x80.
Ultimately what I'm trying to do is convert this signature parameter into a hex encoded string (eg. "12ab0528...") which is then used by the RSA/SHA1 function to verify the message is intact. This part is already working but I can't for the life of me figure out how to get the signature parameter decoded.
For historical reasons we are having to use classic ASP and the SHA1/RSA functions are javascript based.
Any help would be much appreciated.
Regards,
Craig.
Update: Tried looking into UTF-16 encoding on Wikipedia and other sites. Can't find anything to explain why I am seeing only 0x20 or 0x00 in the (assumed) high order byte positions. I don't think this is relevant any more as the example below shows other values in this high order position.
Tried adding some code to log the values using Asc instead of AscB (Len,Mid instead of LenB,MidB too). Got some surprising results. Here is a new stream of byte-wise characters followed by the equivalent stream of word-wise (if you know what I mean) characters.
21,0,83,1,214,0,201,0,88,0,172,0,98,0,182,0,43,0,103,0,88,0,103,0,34,33,88,0,254,0,173,0,188,0,44,0,66,0,120,1,246,0,64,0,47,0,110,0,160,0,84,0,4,0,201,0,176,0,251,0,166,0,211,0,67,0,115,0,209,0,53,0,12,0,243,0,6,0,78,0,106,0,250,0,19,0,204,0,235,0,28,0,243,0,165,0,94,0,60,0,82,0,82,0,172,32,248,0,220,2,176,0,141,0,239,0,34,33,47,0,61,0,72,0,248,0,230,0,191,0,219,0,61,0,105,0,246,0,3,0,57,32,54,0,34,33,127,0,224,0,17,0,224,0,76,0,51,0,91,0,210,0,35,0,89,0,178,0,235,0,161,0,114,0,195,0,119,0,69,0,32,32,188,0,82,0,237,0,183,0,220,0,83,1,10,0,94,0,239,0,187,0,178,0,19,0,168,0,211,0,110,0,101,0,233,0,83,0,75,0,218,0,4,0,241,0,58,0,170,0,168,0,82,0,61,0,35,0,184,0,240,0,117,0,76,0,32,0,247,0,74,0,64,0,163,0
And now the word-wise data stream:
21,156,214,201,88,172,98,182,43,103,88,103,153,88,254,173,188,44,66,159,246,64,47,110,160,84,4,201,176,251,166,211,67,115,209,53,12,243,6,78,106,250,19,204,235,28,243,165,94,60,82,82,128,248,152,176,141,239,153,47,61,72,248,230,191,219,61,105,246,3,139,54,153,127,224,17,224,76,51,91,210,35,89,178,235,161,114,195,119,69,134,188,82,237,183,220,156,10,94,239,187,178,19,168,211,110,101,233,83,75,218,4,241,58,170,168,82,61,35,184,240,117,76,32,247,74,64,163
Note the second pair of byte-wise characters (83,1) seem to be interpreted as 156 in the word-wise stream. We also see (34,33) as 153 and (120,1) as 159 and (220,2) as 152. Does this give any clues as the encoding? Why are these 15[2369] values apparently being treated differently from other values?
What I'm trying to figure out is whether I should use the byte-wise data and carry out some post-processing to get back to the intended values or if I should trust the word-wise data with whatever implicit decoding it is apparently performing. At the moment, neither seem to give me a match between data content and signature so I need to change something.
Thanks.
Quick observation tells me that you are likely dealing with UTF-16. Start from there.

Resources