Click here if you wish to know more about QR Codes and how they can help you automate logistical processes in your company.
About a month ago (on november 2014) a major third-party system update in my company required us to change label barcodes from 1D to 2D due to limited label dimensions and increased data string size. So i was required to create a QR generator capable of encoding strings of 32 numbers.
Four days later i already had a fixed version 2-H (the number is the QR Code version, and refers to the size and capacity, while the letter stands for the Error Correction Level in the code - 30% in this case) numeric strings QR Code generator fully coded in AutoHotkey. The increase in reading speed of the printed labels was so good that i promptly adopted the task of creating a full QR Code library as a side project. Later on, i also decided to drop in 1D barcode creation as a plus.
So here it is:
Barcode Generator Library v1.02 by Giordanno Sperotto (BARCODER.ahk) : Download
Main Fuctions (simply call these functions to retrieve a 1D (CODE39/CODE ITF/CODE 128B) or 2D (QR CODE) array/table object that contains the indexed monochrome pixel values of a barcode image - Object[Column] for 1D, Object[Row,Column] for 2D barcodes):
BARCODER_GENERATE_CODE_39(MESSAGE_TO_ENCODE) - Retrieve a 1D object representing a CODE39 row.
BARCODER_GENERATE_CODE_ITF(MESSAGE_TO_ENCODE) - Retrieve a 1D object representing an interleaved 2 of 5 row.
BARCODER_GENERATE_CODE_128B(MESSAGE_TO_ENCODE) - Retrieve a 1D object representing a CODE128B row.
BARCODER_GENERATE_QR_CODE(MESSAGE_TO_ENCODE) - Retrieve a 2D object representing a QR Code matrix.
Creating an image with the output objects in AutoHotkey should be quite easy thanks to Tic's GDIP Library (http://www.autohotkey.com/forum/viewtopic.php?t=32238). See the examples below the Library code.
Example 1: Generating a 1D Code39 Barcode (Requires BARCODER.ahk - Link above - and GDIP.ahk - Link above - to be present in the same directory as the script).
If you are using Unicode64 versions of AutoHotkey use the file GDIP_All.ahk in place of GDIP.ahk and adjust the #Include lines accordingly. Download link is in the same topic.
Code: Select all
#SingleInstance, Force
SetBatchLines, -1
START:
inputbox, Test,, Type in a message and a corresponding CODE39 Barcode image will be generated and saved in the scripts directory.
MATRIX_TO_PRINT := BARCODER_GENERATE_CODE_39(test)
if (MATRIX_TO_PRINT = 1)
{
Msgbox, 0x10, Error, The input message is either blank or contains characters that cannot be encoded in CODE_39. You can only encode the following characters in CODE39: UPPERCASE letters, Digits (0-9) and symbols `$, `%, `+, `-, `. and `/. Please adjust the input message accordingly.
Goto START
}
; Start gdi+
If !pToken := Gdip_Startup()
{
MsgBox, 48, gdiplus error!, Gdiplus failed to start. Please ensure you have gdiplus on your system
ExitApp
}
HEIGHT_OF_IMAGE := 20 ; 20 is the arbitrary height of the Barcode image for this example. You can chage it to any number to increase/decrease the height of the image. Since a scanner must get an accurate vision of a full line, a taller image may offer a higher chance that a physically damaged print will have at least 1 fully readable line (This should not be confused with QR Codes Error Correction Level protection though).
pBitmap := Gdip_CreateBitmap(MATRIX_TO_PRINT.MaxIndex() + 8, HEIGHT_OF_IMAGE) ; Adding 8 pixels to the width here as a "quiet zone" for the image. This serves to improve the printed code readability.
G := Gdip_GraphicsFromImage(pBitmap)
Gdip_SetSmoothingMode(pBitmap, 3)
pBrush := Gdip_BrushCreateSolid(0xFFFFFFFF)
Gdip_FillRectangle(G, pBrush, 0, 0, MATRIX_TO_PRINT.MaxIndex() + 8, HEIGHT_OF_IMAGE) ; Same as above
Gdip_DeleteBrush(pBrush)
Loop % HEIGHT_OF_IMAGE
{
CURRENT_ROW := A_Index
Loop % MATRIX_TO_PRINT.MaxIndex()
{
CURRENT_COLUMN := A_Index
If (MATRIX_TO_PRINT[A_Index] = 1)
{
Gdip_SetPixel(pBitmap, CURRENT_COLUMN + 3, CURRENT_ROW, 0xFF000000) ; Adding 3 to the current column and the current row to skip the quiet zones.
}
}
}
CURRENT_ROW := "", CURRENT_COLUMN := ""
StringReplace, FILE_NAME_TO_USE, test, `" ; We can't use all the characters that byte mode can encode in the name of the file. So we are replacing them here (if they exist).
FILE_PATH_AND_NAME := A_ScriptDir . "\" . SubStr(RegExReplace(FILE_NAME_TO_USE, "[\t\r\n\\\/\`:\`?\`*\`|\`>\`<]"), 1, 20) . ".png" ; Same as above. We will only use the first 20 characters for the file name in this example.
Gdip_SaveBitmapToFile(pBitmap, FILE_PATH_AND_NAME)
Gdip_DisposeImage(pBitmap)
Gdip_DeleteGraphics(G)
Gdip_Shutdown(pToken)
msgbox, 0, Success, CODE39 image succesfully created!
Goto START
Return
#Include %A_ScriptDir%/BARCODER.ahk
#Include %A_ScriptDir%/GDIP.ahk
If you are using Unicode64 versions of AutoHotkey use the file GDIP_All.ahk in place of GDIP.ahk and adjust the #Include lines accordingly. Download link is in the same topic.
Code: Select all
#SingleInstance, Force
SetBatchLines, -1
START:
inputbox, Test,, Type in a message and a corresponding QR Code image will be generated and saved in the scripts directory.
MATRIX_TO_PRINT := BARCODER_GENERATE_QR_CODE(test)
if (MATRIX_TO_PRINT = 1)
{
Msgbox, 0x10, Error, The input message is blank. Please input a message to succesfully generate a QR Code image.
Goto START
}
If MATRIX_TO_PRINT between 1 and 7
{
Msgbox, 0x10, Error, ERROR CODE: %MATRIX_TO_PRINT% `n`nERROR CODE TABLE:`n`n1 - Input message is blank.`n2 - The Choosen Code Mode cannot encode all the characters in the input message.`n3 - Choosen Code Mode does not correspond to one of the currently indexed code modes (Automatic, numeric, alphanumeric or byte).`n4 - The choosen forced QR Matrix version (size) cannot encode the entire input message using the choosen ECL Code_Mode. Try forcing a higher version or choosing automated version selection (parameter value 0).`n5 - The input message is exceeding the QR Code standards maximum length for the choosen ECL and Code Mode.`n6 - Choosen Error Correction Level does not correspond to one of the standard ECLs (L, M, Q and H).`n7 - Forced version does not correspond to one of the QR Code standards versions.
Goto START
}
; Start gdi+
If !pToken := Gdip_Startup()
{
MsgBox, 48, gdiplus error!, Gdiplus failed to start. Please ensure you have gdiplus on your system
ExitApp
}
pBitmap := Gdip_CreateBitmap(MATRIX_TO_PRINT.MaxIndex() + 8, MATRIX_TO_PRINT.MaxIndex() + 8) ; Adding 8 pixels to the width and height here as a "quiet zone" for the image. This serves to improve the printed code readability. QR Code specs require the quiet zones to surround the whole image and to be at least 4 modules wide (4 on each side = 8 total width added to the image). Don't forget to increase this number accordingly if you plan to change the pixel size of each module.
G := Gdip_GraphicsFromImage(pBitmap)
Gdip_SetSmoothingMode(pBitmap, 3)
pBrush := Gdip_BrushCreateSolid(0xFFFFFFFF)
Gdip_FillRectangle(G, pBrush, 0, 0, MATRIX_TO_PRINT.MaxIndex() + 8, MATRIX_TO_PRINT.MaxIndex() + 8) ; Same as above.
Gdip_DeleteBrush(pBrush)
Loop % MATRIX_TO_PRINT.MaxIndex() ; Acess the Rows of the Matrix
{
CURRENT_ROW := A_Index
Loop % MATRIX_TO_PRINT[1].MaxIndex() ; Access the modules (Columns of the Rows).
{
If (MATRIX_TO_PRINT[CURRENT_ROW, A_Index] = 1)
{
Gdip_SetPixel(pBitmap, A_Index + 3, CURRENT_ROW + 3, 0xFF000000) ; Adding 3 to the current column and row to skip the quiet zones.
}
}
}
StringReplace, FILE_NAME_TO_USE, test, `" ; We can't use all the characters that byte mode can encode in the name of the file. So we are replacing them here (if they exist).
FILE_PATH_AND_NAME := A_ScriptDir . "\" . SubStr(RegExReplace(FILE_NAME_TO_USE, "[\t\r\n\\\/\`:\`?\`*\`|\`>\`<]"), 1, 20) . ".png" ; Same as above. We will only use the first 20 characters for the file name in this example.
Gdip_SaveBitmapToFile(pBitmap, FILE_PATH_AND_NAME)
Gdip_DisposeImage(pBitmap)
Gdip_DeleteGraphics(G)
Gdip_Shutdown(pToken)
MsgBox,0,Success,Created QR Code in file`n%FILE_PATH_AND_NAME%
Goto START
Return
#Include %A_ScriptDir%/BARCODER.ahk
#Include %A_ScriptDir%/GDIP.ahk
If you are using Unicode64 versions of AutoHotkey use the file GDIP_All.ahk in place of GDIP.ahk and adjust the #Include lines accordingly. Download link is in the same topic.
Code: Select all
#SingleInstance, Force
SetBatchLines, -1
START:
inputbox, Test,, Type in a message and a corresponding CODE INTERLEAVED 2 OF 5 Barcode image will be generated and saved in the scripts directory.
If (Test = "")
{
msgbox, 0x10, Error, The input message is blank. Please insert a message to succesfully generate a CODE_ITF image.
Goto START
}
MATRIX_TO_PRINT := BARCODER_GENERATE_CODE_ITF(test)
if (MATRIX_TO_PRINT = 1)
{
msgbox, 0x10, Error, The input string contains characters that cannot be encoded in an INTERLEAVED 2 OF 5 Barcode. Please correct the message or choose another type of barcode. `n`nYou can only encode numeric strings (0-9) in an INTERLEAVED 2 OF 5 Barcode.
Goto START
}
; Start gdi+
If !pToken := Gdip_Startup()
{
MsgBox, 48, gdiplus error!, Gdiplus failed to start. Please ensure you have gdiplus on your system
ExitApp
}
HEIGHT_OF_IMAGE := 20 ; 20 is the arbitrary height of the Barcode image for this example. You can chage it to any number to increase/decrease the height of the image. Since a scanner must get an accurate vision of a full line, a taller image may offer a higher chance that a physically damaged print will have at least 1 fully readable line (This should not be confused with QR Codes Error Correction Level protection though).
pBitmap := Gdip_CreateBitmap(MATRIX_TO_PRINT.MaxIndex() + 8, HEIGHT_OF_IMAGE) ; Adding 8 pixels here as a "quiet zone" for the image. This serves to improve the printed code readability.
G := Gdip_GraphicsFromImage(pBitmap)
Gdip_SetSmoothingMode(pBitmap, 3)
pBrush := Gdip_BrushCreateSolid(0xFFFFFFFF)
Gdip_FillRectangle(G, pBrush, 0, 0, MATRIX_TO_PRINT.MaxIndex() + 8, HEIGHT_OF_IMAGE)
Gdip_DeleteBrush(pBrush)
Loop % HEIGHT_OF_IMAGE
{
CURRENT_ROW := A_Index
Loop % MATRIX_TO_PRINT.MaxIndex()
{
CURRENT_COLUMN := A_Index
If (MATRIX_TO_PRINT[A_Index] = 1)
{
Gdip_SetPixel(pBitmap, CURRENT_COLUMN + 3, CURRENT_ROW, 0xFF000000) ; Adding 3 to the current column to skip the quiet zone.
}
}
}
CURRENT_ROW := "", CURRENT_COLUMN := ""
StringReplace, FILE_NAME_TO_USE, test, `" ; We can't use all the characters that byte mode can encode in the name of the file. So we are replacing them here (if they exist).
FILE_PATH_AND_NAME := A_ScriptDir . "\" . SubStr(RegExReplace(FILE_NAME_TO_USE, "[\t\r\n\\\/\`:\`?\`*\`|\`>\`<]"), 1, 20) . ".png" ; Same as above. We will only use the first 20 characters for the file name in this example.
Gdip_SaveBitmapToFile(pBitmap, FILE_PATH_AND_NAME)
Gdip_DisposeImage(pBitmap)
Gdip_DeleteGraphics(G)
Gdip_Shutdown(pToken)
msgbox, 0, Success, CODE2OF5 image succesfully created!
Goto START
Return
#Include %A_ScriptDir%/BARCODER.ahk
#Include %A_ScriptDir%/GDIP.ahk
If you are using Unicode64 versions of AutoHotkey use the file GDIP_All.ahk in place of GDIP.ahk and adjust the #Include lines accordingly. Download link is in the same topic.
Code: Select all
#SingleInstance, Force
SetBatchLines, -1
START:
inputbox, Test,, Type in a message and a corresponding CODE128 Barcode image will be generated and saved in the scripts directory.
MATRIX_TO_PRINT := BARCODER_GENERATE_CODE_128B(test)
if (MATRIX_TO_PRINT = 1)
{
Msgbox, 0x10, Error, The input message is either blank or contains characters that cannot be encoded in CODE_128B.
Goto START
}
; Start gdi+
If !pToken := Gdip_Startup()
{
MsgBox, 48, gdiplus error!, Gdiplus failed to start. Please ensure you have gdiplus on your system
ExitApp
}
HEIGHT_OF_IMAGE := 20 ; 20 is the arbitrary height of the Barcode image for this example. You can chage it to any number to increase/decrease the height of the image. Since a scanner must get an accurate vision of a full line, a taller image may offer a higher chance that a physically damaged print will have at least 1 fully readable line (This should not be confused with QR Codes Error Correction Level protection though).
pBitmap := Gdip_CreateBitmap(MATRIX_TO_PRINT.MaxIndex() + 8, HEIGHT_OF_IMAGE) ; Adding 8 pixels to the width here as a "quiet zone" for the image. This serves to improve the printed code readability.
G := Gdip_GraphicsFromImage(pBitmap)
Gdip_SetSmoothingMode(pBitmap, 3)
pBrush := Gdip_BrushCreateSolid(0xFFFFFFFF)
Gdip_FillRectangle(G, pBrush, 0, 0, MATRIX_TO_PRINT.MaxIndex() + 8, HEIGHT_OF_IMAGE) ; Same as above
Gdip_DeleteBrush(pBrush)
Loop % HEIGHT_OF_IMAGE
{
CURRENT_ROW := A_Index
Loop % MATRIX_TO_PRINT.MaxIndex()
{
CURRENT_COLUMN := A_Index
If (MATRIX_TO_PRINT[A_Index] = 1)
{
Gdip_SetPixel(pBitmap, CURRENT_COLUMN + 3, CURRENT_ROW, 0xFF000000) ; Adding 3 to the current column and the current row to skip the quiet zones.
}
}
}
CURRENT_ROW := "", CURRENT_COLUMN := ""
StringReplace, FILE_NAME_TO_USE, test, `" ; We can't use all the characters that byte mode can encode in the name of the file. So we are replacing them here (if they exist).
FILE_PATH_AND_NAME := A_ScriptDir . "\" . SubStr(RegExReplace(FILE_NAME_TO_USE, "[\t\r\n\\\/\`:\`?\`*\`|\`>\`<]"), 1, 20) . ".png" ; Same as above. We will only use the first 20 characters for the file name in this example.
Gdip_SaveBitmapToFile(pBitmap, FILE_PATH_AND_NAME)
Gdip_DisposeImage(pBitmap)
Gdip_DeleteGraphics(G)
Gdip_Shutdown(pToken)
msgbox, 0, Success, CODE128B image succesfully created!
Goto START
Return
#Include %A_ScriptDir%/BARCODER.ahk
#Include %A_ScriptDir%/GDIP.ahk
1 - This library is fully coded in AutoHotkey (no external dependencies).
2 - QR Codes can encode up to: 7089 characters long numeric strings (0-9), 4296 characters long AlphaNumeric strings or 2953 Bytes. (The later is interpreted through the full ASCII list of characters if a text reader is used.)
3 - You can force the Version (size) of the QR matrix in the fourth parameter of the GENERATE_QR_CODE() function if the choosen version is big enougth to encode all the data you have entered (this may be usefull if you are looking for a standard size output regardless of string length). Be careful though: If a forced version has no capacity to fully encode the input message, no QR Matrix will be generated at all. Available QR Code versions and corresponding parameter values: 1 to 40.
4 - The standard Error Correction Level (ECL) for the GENERATE_QR_CODE() function is set to M (15%). You can force another ECL level in the third parameter of the function if you wish more ECL (though this may end up generating a bigger matrix) or less (outputing a smaller matrix). Available ECLs for the QR Codes standard are L (7%), M (15%), Q (25%) and H (30%). Parameter values are 1 for L, 2 for M, 3 for Q and 4 for H.
5 - The examples above output QR Code images whose modules (individual "points") are 1 pixel wide. It is possible, however, to use loops to generate an image with modules 2 pixels wide, 3 pixels wide, or any other dimensions you like. Check this post for an example on how to change module sizes.
6 - You can force an encoding mode in the second parameter of the GENERATE_QR_CODE() function if that mode is capable of encoding all the data you have entered. That is not recomended, however, as the function already uses the best option for each case and if a forced encoding mode is unable to encode all the characters in the input message, no QR Matrix will be generated at all.
7 - If you wish to implement a QR Code routine, there is usually no need to worry about coding a QR Code reader function since the 2D scanners available in the market usually ship bundled with reading and auto-typing softwares.
8 - If your routine absolutely needs to have your PC decoding the QR Codes without a scanner though, there are some freeware tools that will do the job for you. ZBar, in example (and as mentioned by JoeWinograd), decodes QR Codes in image files or straight from your PCs webcam, and is able to output the decoded messages to the CMD (which can than be retrieved by AutoHotkey using CMDRet()). You can check an example here.
Known limitations of this version:
Kanji (Japanese/Korean/Chinese Characters) Encoding in QR Codes is currently NOT supported natively. HOWEVER, you can still encode Kanji in QR Codes using BARCODER and this funcion by Zhang.
Aditional credits:
1 - Infogulch, for Bin() and Dec() - http://www.autohotkey.com/board/topic/49990-binary-and-decimal-conversion/
2 - Tic for the Gdip Library (used in the examples and recomended as the choice AHK image editor tool) - http://www.autohotkey.com/forum/viewtopic.php?t=32238
3 - AlphaBravo, for the Interleaved 2 of 5 and Code128 barcode functions.
4 - JoeWinograd, for suggestions and examples regarding reading QR Codes without a scanner.
5 - Zhang, for a function and an example on how to encode Kanji in QR Codes using this library.
Feel free to drop in any questions.
Best wishes
CHANGELOG:
11 December 2014:
First version is up. Supports CODE39 and QR Code barcode generation. Examples added to the post.
23 December 2014:
1 - Added Interleaved 2 of 5 Functions by AlphaBravo.
2 - Changed the lib and function names to allow MyLib_MyFunc syntax compatibility.
25 December 2014:
Fixed a typo in the code generating incorrect version 11-M matrixes.
27 December 2014:
1 - Ran a test on each of the 40 QR Code versions, using each of the 4 ECLs for every version. All 160 matrixes generated were found to be perfectly readable.
2 - Changed Library Version to 1.02 to avoid confusion with 1.0, which was generating non-working QR Code version 11 Matrixes.
3 - The Messageboxes warning errors in the QR Code function have been commented out (so that the function can operate silently). The function now returns all errors as values 1 to 7. Check the notes above the function code if you wish to see/manage these errors in your code.
23 June 2016:
Added Code128B functions by AlphaBravo.