• Welcome to PlanetSquires Forums.
 

C# Headers and functions

Started by Petrus Vorster, November 04, 2022, 06:40:56 AM

Previous topic - Next topic

Petrus Vorster

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
-Regards
Peter

Paul Squires

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.

Paul Squires
PlanetSquires Software
WinFBE Editor and Visual Designer

Paul Squires

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

Paul Squires
PlanetSquires Software
WinFBE Editor and Visual Designer

Petrus Vorster

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
-Regards
Peter

Petrus Vorster

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
-Regards
Peter

Paul Squires

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.

Paul Squires
PlanetSquires Software
WinFBE Editor and Visual Designer

Paul Squires

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.



Paul Squires
PlanetSquires Software
WinFBE Editor and Visual Designer

Paul Squires

Quote from: Petrus Vorster on November 04, 2022, 01:28: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.

Paul Squires
PlanetSquires Software
WinFBE Editor and Visual Designer

Petrus Vorster

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
-Regards
Peter

Paul Squires

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.
Paul Squires
PlanetSquires Software
WinFBE Editor and Visual Designer

Eros Olmi

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

Petrus Vorster

#11
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
-Regards
Peter

Eros Olmi

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


Petrus Vorster

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
-Regards
Peter