Hi All
It seems that C++ and C# forums has a lot of headers and tools.
Since I am always busy with barcodes, and those needs to be in international accepted standards, I am wondering if one can get a c header for those functions, how it can be used in Freebasic, especially the WINFBE designer.
My old powerbasic barcode creator DPI's does not meet the standards.
I need to up this to work on a reasonable label printer and be placed on documents or in-house products.
Some ideas would be great.
-Peter
Hi Peter,
I've seen that you asked similar questions in the past about barcodes and SVG and printer output, etc. Let's get you settled away with some solutions. :)
Give me a little bit of time to read up on EAN128 barcodes and I will see if I can convert some existing code or find a good "C" library. It is not feasible to use C++ or C# because they do not integrate easily into FB.
Hi Peter,
Here is my conversion of the EAN128 barcode code. Please check it to ensure that it generates the correct sequence of "1" and "0"'s. I modified Nathan Durland's old PB code and converted it to use lookup table arrays and a couple of other optimizations. I assume that Nathan's code was correct.
Once you are confident that the code produced by my code is correct, then we can move on to using the output to generate some type of image file (SVG, metafile, PNG, etc). After that then we can tackle the printing.
' Based on code by Nathan Durland
' https://www.planetsquires.com/protect/forum/index.php?msg=27564
' Converted by Paul Squires to use lookup table arrays
' and other optimizations.
dim shared EAN128Pattern(32 to 95) as string * 11 => _
{ "11011001100","11001101100","11001100110","10010011000","10010001100","10001001100", _
"10011001000","10011000100","10001100100","11001001000","11001000100","11000100100", _
"10110011100","10011011100","10011001110","10111001100","10011101100","10011100110", _
"11001110010","11001011100","11001001110","11011100100","11001110100","11101101110", _
"11101001100","11100101100","11100100110","11101100100","11100110100","11100110010", _
"11011011000","11011000110","11000110110","10100011000","10001011000","10001000110", _
"10110001000","10001101000","10001100010","11010001000","11000101000","11000100010", _
"10110111000","10110001110","10001101110","10111011000","10111000110","10001110110", _
"11101110110","11010001110","11000101110","11011101000","11011100010","11011101110", _
"11101011000","11101000110","11100010110","11101101000","11101100010","11100011010", _
"11101111010","11001000010","11110001010","10100110000" }
dim shared EAN128CheckSum(0 to 104) as string * 11 => _
{ "11011001100","11001101100","11001100110","10010011000","10010001100","10001001100", _
"10011001000","10011000100","10001100100","11001001000","11001000100","11000100100", _
"10110011100","10011011100","10011001110","10111001100","10011101100","10011100110", _
"11001110010","11001011100","11001001110","11011100100","11001110100","11101101110", _
"11101001100","11100101100","11100100110","11101100100","11100110100","11100110010", _
"11011011000","11011000110","11000110110","10100011000","10001011000","10001000110", _
"10110001000","10001101000","10001100010","11010001000","11000101000","11000100010", _
"10110111000","10110001110","10001101110","10111011000","10111000110","10001110110", _
"11101110110","11010001110","11000101110","11011101000","11011100010","11011101110", _
"11101011000","11101000110","11100010110","11101101000","11101100010","11100011010", _
"11101111010","11001000010","11110001010","10100110000","10100001100","10010110000", _
"10010000110","10000101100","10000100110","10110010000","10110000100","10011010000", _
"10011000010","10000110100","10000110010","11000010010","11001010000","11110111010", _
"11000010100","10001111010","10100111100","10010111100","10010011110","10111100100", _
"10011110100","10011110010","11110100100","11110010100","11110010010","11011011110", _
"11011110110","11110110110","10101111000","10100011110","10001011110","10111101000", _
"10111100010","11110101000","11110100010","10111011110","10100001000","11101011110", _
"11110101110","11010000100","11010010000" }
'//
'//
function CreateEAN128( byval src as string ) as string
'-------------------------------------------------------
' This function encodes the given string into a string
' of 1's and 0's; this is the pattern for the bars in
' the bar code
'-------------------------------------------------------
dim as long checksum = 103 ' checksum modulus
dim as string z ' output string used to construct the barcode
dim as long ch ' individual character in the src string
dim as long chcheck ' individual character checksum
' Convert the incoming src source string to all uppercase and
' ensure no leading or trailing spaces.
src = ucase(trim(src))
z = "0000000000" & _ ' leading quiet zone
"11010000100" ' 2 1 1 4 1 2 Start Class A
for i as long = 0 to len(src) - 1
ch = src[i]
if (ch >= 32) andalso (ch <= 95) then
z = z & EAN128Pattern(ch)
chcheck = (ch - 32)
checksum = checksum + (chcheck * i)
else
? "invalid character: "; chr(ch)
end if
next
checksum = (checksum mod 103)
z = z & EAN128CheckSum(checksum)
z = z & "1100011101011" & _ ' 2 3 3 1 1 1 2 Stop (7 patts.)
"0000000000" ' trailing quiet zone
function = z
end function
'------------------------------------------------------------------------------------------------------------------------
' MAIN ENTRY POINT - TEST CODE
dim as string teststring = "Paul Squires"
? "teststring: "; teststring
? "EAN128 barcode: "; CreateEAN128(teststring)
sleep
Hi Paul
This is amazing.
Some barcodes are easy like 3 of 9. Simple.
The 128C is quite something else. (and then there is QR!)
I got it to work perfectly in Powerbasic with the help of many people.
You create the encoded string with the check digit, then use a font to create PNG.
But for some reason, my font did not scale up correctly.
And every good font you need to pay for!
I will check tonight at home.
Someone else on the forum once asked me about this too privately some time ago. I think he has one of those Toshiba sorting robots and wanted to print these on the fly so the bot could move the heavy stuff automatically on a conveyor belt.
My barcoder worked, but it was not up to EU standards.
in .NET its a simple as Encodedstring$ = EAN128barcode(Originalstring$).
I never checked how they draw the lines though in .net. (Too much stuff going on there)
The only way to really and quickly test it, is having a good quality scanner on hand that can scan straight of the screen.
You create the test-string, print to PNG on-screen and scan it.
I appreciate it that you went out of your way with all your workload.
Regards,
Peter
Hi Paul
This looks perfectly fine.
Now to convert that into an actual Barcode....
Nathan is quite the expert on barcodes.
This is also MUCH different than how we did it in Powerbasic.
We build a string with ASCII characters, leading and ending character + Check digit.
It looked weird, but it worked once you turn that into barcode font.
The binary string , I am afraid I am completely lost. :o
Regards, Peter
Hi Peter,
I will research more into this. I am thinking that I could output the string to an EMF raster image that I should be able to load into WinFBE's image control which uses Jose's image control behind the scenes using GDI+. From there, it is just a hopefully simple jump to printing it.
I think that I will also research for any "C" DLL's that already do all of this stuff. Creating barcode, creating image file, etc... Might be easier than creating everything from scratch. I'd only then have to compile the DLL for 32/64 bit and create the header file.
Hi Peter,
I did a bit more internet searching tonight and rather than re-invent everything from scratch, why not just distribute a standalone EXE with your app that generates the barcode image for you!
Here is the best one that I could find that allows you to create the barcode from a command line program.
https://zint.org.uk/manual/chapter/4
I have attached that zint.exe command line program to this email.
In your application, you would simply need to shell to the zint program and feed it your data via the command line. The zint program will then generate the barcode image which you could then display in your program. The end user would never know that your program is shelling to the barcode exe because you can suppress the "DOS" like command window that would flash on the screen.
Seems to be the easiest, low effort, high reward way of doing accomplishing your barcode needs.
Quote from: Petrus Vorster on November 04, 2022, 01:58:58 PMNow to convert that into an actual Barcode....
We build a string with ASCII characters, leading and ending character + Check digit.
It looked weird, but it worked once you turn that into barcode font.
The binary string , I am afraid I am completely lost.
Pretty simple. You would loop through the string and for every "1" you would draw a line in your image. For a "0" you would just leave the space blank. The hard part would be setting up the image and outputting the commands that actually draw the lines. Depending on the image format (PNG, EMF, etc) then it could involve a little bit of work. Once you have the image generated then the rest is easy.... just load it into your image control.
Hi Paul
The old VB6 examples I had also went this way of drawing the barcode yourself.
Then some bright guy came up with a font which made it much easier.
I have never done any form of line drawing in Freebasic yet.
That would be an interesting journey.
Regards,
Peter
The reason I suggest using the external program to generate the barcode and image is that the source code that I posted does not handle CODE A, CODE B, CODE C stuff in Code128 format? Not that I know much about that stuff but I have seen it in all of the source code that I have reviewed related to Code128/EAN128 format. I think it is just a way of creating a more efficient barcode and/or handling special character.
If interested I've a thinBasic source code using ZINT.DLL to generate any barcode supported by ZINT library.
Script show barcode on screen inside a window control and save it as BMP on the fly.
Let me know and I will post here
Hi Eros
Zint works perfectly in WinFBE.
I have managed with the great help of the good people on this forum to make perfect barcodes on the fly.
But please do share your example.
Regards, Peter
Sure, here it is attached.
program is "zint_DirectDllHandling.exe"
It is a thinBasic stand alone executable.
Nothing special if you already are using zint.
It was a test I made some years ago translating some C structures to thinBasic.
The minimum to call zint dll functions.
Program creates barcode image at every window size using timer to generate random barcode text
Image is saved on disk and loaded into the window every time you resize the window
thinBasic programming language source code is in "zint_DirectDllHandling.tbasic" and here below.
You need to install thinBasic interpreter in order to test it from source and change barcode type.
Ciao
Eros
'----------------------------------------------------------------------------
' Generating barcode interacting directly to ZINT.DLL library
' Maybe a specific module will be developed
'----------------------------------------------------------------------------
' References: http://www.zint.org.uk/Manual.aspx?type=p&page=5
'----------------------------------------------------------------------------
Type zint_render_line
x as single
y as single
length as single
width as single
pNext as DWord
end type
Type zint_render_string
x as single
y as single
fsize as single
width as single
length as Long
pText as Byte
pNext as DWord
end type
Type zint_render_ring
x as single
y as single
radius as single
line_width as single
pNext as DWord
end type
Type zint_render_hexagon
x as single
y as single
height as single
pNext as DWord
end type
Type zint_render
width as DWord
height as DWord
pLines as DWord 'struct zint_render_line *lines; /* Pointer to first line */
pStrings as dword 'struct zint_render_string *strings; /* Pointer to first string */
pRings as DWord 'struct zint_render_ring *rings; /* Pointer to first ring */
phexagons as DWord 'struct zint_render_hexagon *hexagons; /* Pointer to first hexagon */
end type
' struct zint_symbol {
' int symbology;
' int height;
' int whitespace_width;
' int border_width;
' int output_options;
' char fgcolour[10];
' char bgcolour[10];
' char outfile[256];
' float scale;
' int option_1;
' int option_2;
' int option_3;
' int show_hrt;
' int input_mode;
' int eci;
' unsigned char text[128];
' int rows;
' int width;
' char primary[128];
' unsigned char encoded_data[200][143];
' int row_height[200]; /* Largest symbol is 189 x 189 Han Xin */
' char errtxt[100];
' char *bitmap;
' int bitmap_width;
' int bitmap_height;
' unsigned int bitmap_byte_length;
' float dot_size;
' struct zint_render *rendered;
' int debug;
' };
'
Type zint_symbol
symbology as Long
height as Long
whitespace_width as Long
border_width as Long
output_options as long
fgcolour(10) as Byte
bgcolour(10) as byte
outfile as string * 256
scale as float32 'single
option_1 as Long
option_2 as Long
option_3 as Long
show_hrt as Long
input_mode as Long
eci as Long
stext as string * 128
rows as Long
width as Long
primary as string * 128
encoded_data(200,143) as Byte
row_height(200) as Long
errtxt as string * 100
pbitmap as dword
bitmap_width as Long
bitmap_height as Long
bitmap_byte_length as Long
dot_size as single
pRendered as dword 'struct zint_render *rendered;
debug as Long
end type
'ZINT_EXTERN struct zint_symbol *ZBarcode_Create(void);
DECLARE FUNCTION ZBarcode_Create LIB "zint.dll" ALIAS "ZBarcode_Create" () AS DWord
'ZINT_EXTERN void ZBarcode_Clear(struct zint_symbol *symbol);
DECLARE sub ZBarcode_Clear LIB "zint.dll" ALIAS "ZBarcode_Clear" (byval lSymbol as DWord)
'ZINT_EXTERN void ZBarcode_Delete(struct zint_symbol *symbol);
DECLARE sub ZBarcode_Delete LIB "zint.dll" ALIAS "ZBarcode_Delete" (byval lSymbol as DWord)
'
'ZINT_EXTERN int ZBarcode_Encode(struct zint_symbol *symbol, const unsigned char *source, int in_length);
DECLARE FUNCTION ZBarcode_Encode LIB "zint.dll" ALIAS "ZBarcode_Encode" (byval lSymbol as DWord, byval zSource as asciiz ptr, byval in_length as Long) AS long
'ZINT_EXTERN int ZBarcode_Encode_File(struct zint_symbol *symbol, char *filename);
DECLARE FUNCTION ZBarcode_Encode_File LIB "zint.dll" ALIAS "ZBarcode_Encode_File" (byval lSymbol as DWord, byval zFileName as asciiz ptr) AS Long
'ZINT_EXTERN int ZBarcode_Print(struct zint_symbol *symbol, int rotate_angle);
DECLARE FUNCTION ZBarcode_Print LIB "zint.dll" ALIAS "ZBarcode_Print" (byval lSymbol as DWord, byval rotate_angle as Long) AS Long
'ZINT_EXTERN int ZBarcode_Encode_and_Print(struct zint_symbol *symbol, unsigned char *input, int length, int rotate_angle);
'ZINT_EXTERN int ZBarcode_Encode_File_and_Print(struct zint_symbol *symbol, char *filename, int rotate_angle);
'
'ZINT_EXTERN int ZBarcode_Render(struct zint_symbol *symbol, const float width, const float height);
'
'ZINT_EXTERN int ZBarcode_Buffer(struct zint_symbol *symbol, int rotate_angle);
DECLARE FUNCTION ZBarcode_Buffer LIB "zint.dll" ALIAS "ZBarcode_Buffer" (byval lSymbol as DWord, byval rotate_angle as Long) AS Long
'ZINT_EXTERN int ZBarcode_Encode_and_Buffer(struct zint_symbol *symbol, unsigned char *input, int length, int rotate_angle);
'ZINT_EXTERN int ZBarcode_Encode_File_and_Buffer(struct zint_symbol *symbol, char *filename, int rotate_angle);
'
'ZINT_EXTERN int ZBarcode_ValidID(int symbol_id);
DECLARE FUNCTION ZBarcode_ValidID LIB "zint.dll" ALIAS "ZBarcode_ValidID" (ByVal SymbolID as Long) AS Long
'ZINT_EXTERN int ZBarcode_Version();
DECLARE FUNCTION ZBarcode_Version LIB "zint.dll" ALIAS "ZBarcode_Version" () AS long
' http://zint.org.uk/Manual.aspx?type=p&page=5
Uses "UI"
uses "console"
' -- ID numbers of controls
Begin ControlID
%cCanvasDB
%bBarCode
%bClose
End ControlID
' -- Create dialog here
FUNCTION TBMAIN()
Dialog NEW Pixels, Name MainWindow, 0, "thinBasic and zint lib",-1,-1, 800, 400,
%WS_DLGFRAME |
%DS_CENTER |
%WS_CAPTION |
%WS_SYSMENU |
%WS_OVERLAPPEDWINDOW |
%WS_CLIPSIBLINGS |
%WS_CLIPCHILDREN
' -- Place controls here
Control ADD CANVAS, Name canBarcode, MainWindow.Handle, %cCanvasDB, "", 5, 5, 640, 200, %WS_BORDER
Control ADD BUTTON, Name btnBarCode , MainWindow.Handle, %bBarCode , "Redraw" , 10, 250, 50, 25
Control ADD BUTTON, Name btnClose , MainWindow.Handle, %bClose , "Close" , 100, 250, 50, 25
DIALOG SHOW MODAL MainWindow.Handle
END FUNCTION
' -- Callback for dialog
CALLBACK FUNCTION MainWindow_OnCallback()
'printl function_name, cbmsg
END FUNCTION
' -- Callback for dialog
CALLBACK FUNCTION MainWindow_OnInit()
DIALOG SET MINSIZE CBHNDL, 300, 200
printl "zint Version:", ZBarcode_Version
END FUNCTION
' -- Callback for dialog
CALLBACK FUNCTION MainWindow_OnSize()
canBarcode.W = MainWindow.W - 25
canBarcode.H = MainWindow.H - 100
btnBarCode.Y = MainWindow.H - 75
btnClose.Y = MainWindow.H - 75
DrawBarCode(CBHNDL)
END FUNCTION
' -- Callback for close button
CallBack Function btnClose_OnClick()
MainWindow.END
End Function
CallBack Function btnBarCode_OnClick()
DrawBarCode(CBHNDL)
End Function
function DrawBarCode(byval hWnd as Long) as Long
dim pSymbol as zint_symbol ptr
static lSymbol as DWord
if lSymbol <> 0 Then
'---We should delete but GPF for some reason
'ZBarcode_Delete(lSymbol)
end If
string sText = "thinBASIC & zint " & timer & $NUL
printl "----------------------------------------------------------"
lSymbol = ZBarcode_Create
PrintL "Symbol:", lSymbol
pSymbol = lSymbol
'---Select barcode
pSymbol.symbology = 20 'Code 128
'pSymbol.symbology = 58 'QR Code
'pSymbol.symbology = 71 'Data MATRIX
pSymbol.whitespace_width = 10
pSymbol.height = 50
'pSymbol.border_width = 10
pSymbol.outfile = app_sourcepath & "BarCode.BMP" & $nul '---$Nul is need because library check it
pSymbol.input_mode = 0 'DATA_MODE
'printl "BARCODE_CODE128 :", ZBarcode_ValidID(20)
printl "Current pSymbol.symbology", pSymbol.symbology
printl "ZBarcode_Encode :", ZBarcode_Encode(lSymbol, sText, 0)
printl "TEXT :", sText
printl "ZBarcode_Buffer :", ZBarcode_Buffer(lSymbol, 0)
printl "Printing to file", pSymbol.outfile
printl "ZBarcode_Print :", ZBarcode_Print(lSymbol, 0)
printl "Canvas X:", CanBarcode.X
printl "Canvas Y:", CanBarcode.Y
printl "Canvas W:", CanBarcode.W
printl "Canvas H:", CanBarcode.H
printl "pSymbol.bitmap_width", pSymbol.bitmap_width
printl "pSymbol.bitmap_height", pSymbol.bitmap_height
Double ScaleX = CanBarcode.W / pSymbol.bitmap_width
Double ScaleY = CanBarcode.H / pSymbol.bitmap_height
'---Scale to Canvas
if CanBarcode.W < pSymbol.bitmap_width or CanBarcode.H < pSymbol.bitmap_height Then
if ScaleY < ScaleX Then
pSymbol.scale = (CanBarcode.H / pSymbol.bitmap_height)
Else
pSymbol.scale = (CanBarcode.W / pSymbol.bitmap_width)
end If
end if
printl "Scale:", pSymbol.scale
'---Buffer again after scaling
printl "ZBarcode_Buffer :", ZBarcode_Buffer(lSymbol, 0)
printl "ZBarcode_Print :", ZBarcode_Print(lSymbol, 0)
'---Center Barcode in Canvas Long StartX
long StartX
long StartY
StartX = (CanBarcode.W - pSymbol.bitmap_width)/2
StartY = (CanBarcode.H - pSymbol.bitmap_height)/2
if StartX < 0 then StartX = 1
if StartY < 0 then StartY = 1
printl "StartX:", StartX
printl "StartY:", StartY
CANVAS_Attach(hWnd, %cCanvasDB, %TRUE)
canvas_Clear(rgb(255, 255, 255))
CANVAS_Redraw
Canvas_BitmapRender(app_sourcepath & "BarCode.BMP", StartX, StartY)', X2, Y2)
CANVAS_Redraw
end Function
Thank you for the example Eros.
Something i have NOT been able to do in WINFBE(and also did not spend much time on!) is what I did in Powerbasic:
Create an entire list of scannable barcodes on an A4 paper.
I have not touched PDF in WINFBE. I used Richard's PDF class in Powerbasic and that was as easy as 123, to make sheets of barcodes.
If anyone here has and example how to make PDF documents with columns of barcodes that I will be most grateful!
Ragard, Peter