条形码或称条码(barcode)是将宽度不等的多个黑条和空白,按照一定的编码规则排列,用以表达一组信息的图形标识符。条形码技术主要原理是利用了光的反射,白色物体能反射各种波长的可见光,黑色物体则吸收各种波长的可见光,所以当条形码扫描器光源发出的光在条形码上反射后,反射光照射到条码扫描器内部的光电转换器上,光电转换器根据强弱不同的反射光信号,转换成相应的电信号。

第一个条形码是与食品有关的,1949年美国人诺曼·伍德兰和伯尼·西尔法(Berny Silver)申请了用于食品自动识别领域的环形条形码。

常用的一维条形码标准包括三九码、二五码、EAN 128码等等,本文只讨论一维码的生成和打印编程,二维码等不再说明。

常用的条码生成和打印编程方式包括以下三种:

一、条码字体。

使用条码字体来生成和打印条码是最简单的,因为只要直接调用字体就好了,但是使用字体生成的条码打印后分辨率十分低。此种技术一般使用39码来编码,因为39码的条形比较宽,相对于其他编码格式的条形码,识别率比较高。但是过宽的因素又会导致打印出来的条码很大,以吵吵的实验为例,用39码字体打印出来12位数的条码,长度达到5厘米左右,手持的扫描枪才比较容易识别。

所以该种方式只适合足够大的页面打印,而且识别率不是很高。

二、Excel控件调用方式。

Excel中有一个控件叫做Microsoft BarCode 控件9.0,该控件属于ActiveX控件,这意味着你可以在其它应用程序中调用该控件来生成条码。

使用该控件可以方便的生成条码,但是这个控件并不是那么好用。它是一个有界面的控件,大小比较难以调整,吵吵用的时候,还出现了一个问题是,当条码生成之后,我去读它的图片,由于控件还没刷新,结果读到张空白图片。

三、BCEncode.dll。

如果要打印识别率十分高的条码,条码一定是一个像素一个像素点画的,但是由于规则的复杂等原因,我们就不再去自己慢慢画了,那么有什么好一点库和类封装好了么?

BCEncode.dll是一个是我找到的一个比较好用的动态库,该库可以通过API的调用方式生成我们需要的条码,然后返回Windows的位图句柄HBitmap,有了这张位图,我们就可以任意去绘制条码了。

通过吵吵的实验,使用25码编码,12位的数字编码后的条码宽度只有1.5厘米的时候,识别率还特别的高,基本扫描无障碍。用于吵吵试剂管理系统的条码就是用这个生成的25码,12位数字,条码大概2.5厘米左右,识别率100%。





delphi实现条码生成与打印实现

代码


 

以下是用dlephi写的一个条码打印类,用于打印试剂的条码、名称、过期日期和批号:
 unit FMBarCode;
 interface
 uses
 Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
 Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls,Vcl.Printers,System.StrUtils;
 type
 BarPrintInfo=record
 Bar:string[20];
 RegentName:string[50];
 Lot:string[20];
 ExpireDate:string[30];
 end; type
 TFMBarCode = class(TObject)
 constructor Create(APrinterIndex:Integer);
 destructor Destroy();
 function MakeBarCode(ABar:string):HBITMAP;
 function AddBar(ABarPrint:BarPrintInfo):Boolean;
 procedure Print();
 private
 { Private declarations }
 FHDLL:THandle;
 FaryBar:array of BarPrintInfo;
 FPrinterIndex:Integer;
 public
 { Public declarations }
 end;
 TMakeBarcodeBmpFile=Function (lpszFileName:AnsiString; lDpi:DWORD;nBType:Integer;lpszText:AnsiString; nNarrow:
 integer;nWide:integer;nHeight:Integer;nRotate:Integer;
 nReadable:Integer; err:DWORD):DWORD;stdcall;
 TMakeBarCode=function (nBtype:Integer;lpszText: AnsiString;nNarrow:Integer;nWide:integer;
 nHeight:Integer;nRotate:Integer;nReadable:Integer; err:DWORD):HBITMAP;stdcall;
 implementation
 constructor TFMBarCode.Create(APrinterIndex:Integer);
 begin
 FPrinterIndex:=APrinterIndex;
 Printer.PrinterIndex:=FPrinterIndex;
 FHDLL:= LoadLibrary('BCEncode.dll');
 SetLength(FaryBar,0); end;
 destructor TFMBarCode.Destroy();
 begin
 FreeLibrary(FHDLL);
 end;
 function TFMBarCode.MakeBarCode(ABar:string):HBITMAP;
 var
 funcMakeBarCode:TMakeBarCode;
 begin
 funcMakeBarCode:=GetProcAddress(FHDLL, 'MakeBarCode');
 result:=funcMakeBarCode(5,ABar,2,4,60,0,3,0);
 end; function TFMBarCode.AddBar(ABarPrint:BarPrintInfo):Boolean;
 var
 iCount:Integer;
 begin
 iCount:=length(FaryBar);
 SetLength(FaryBar,icount+1);
 FaryBar[iCount].Bar:=ABarPrint.Bar;
 FaryBar[iCount].RegentName:=ABarPrint.RegentName;
 FaryBar[iCount].Lot:=ABarPrint.Lot;
 FaryBar[iCount].ExpireDate:=ABarPrint.ExpireDate; Result:=True;
 end; procedure TFMBarCode.Print();
 var
 iTotal:Integer;
 iRow:Integer;
 iCol:Integer;
 iCurrent:Integer;
 j,k:Integer;
 i: Integer;
 bmpBar:TBitmap;
 begin
 bmpBar:=TBitmap.Create;
 iTotal:=Length(FaryBar);
 iRow:=(iTotal div 3)+1;
 if (iTotal mod 3)=0 then iRow:=iRow-1; iCol:=3;
 iCurrent:=0;
 Printer.BeginDoc;
 for j := 0 to irow-1 do
 begin
 for k := 0 to icol-1 do
 begin
 if iCurrent=iTotal then Break;
 bmpBar.Handle:=MakeBarCode(FaryBar[iCurrent].Bar);
 Printer.Canvas.Draw(10+k*290,0,bmpBar);
 Printer.Canvas.TextOut(10+k*290,70,leftstr(FaryBar[iCurrent].RegentName,20));
 //Printer.Canvas.TextOut(10+k*290,100,leftstr(12,24,FaryBar[iCurrent].RegentName));
 Printer.Canvas.TextOut(10+k*290,150,'Lot:'+FaryBar[iCurrent].Lot);
 Printer.Canvas.TextOut(10+k*290,180,'Exp:'+FaryBar[iCurrent].ExpireDate);
 iCurrent:=iCurrent+1; end;
 if j<>(iRow-1) then Printer.NewPage;
 end;
 Printer.EndDoc; end;
 end.