Online
Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.068 Beiträge
Delphi 12 Athens
|
AW: Barcode aus Bild auslesen
30. Jun 2011, 14:21
So, hat mich etwas nerven gekostet, aber jetzt geht's
Delphi-Quellcode:
uses
ZBar;
type
TZbarSymbolTypes = set of zbar_symbol_type_e;
procedure ReadBarcode(Codes: TStrings; Source: TGraphic; AddBarType: Boolean = False;
BarTypes: TZbarSymbolTypes = []; CheckDigit: Boolean = True; Density: Integer = 1);
var
bmp: TBitmap;
bytesPerLine, count, i: Integer;
p, pg: PByte;
//processor: zbar_processor_t;
scanner: zbar_image_scanner_t;
image: zbar_image_t;
stype: zbar_symbol_type_e;
symbol: zbar_symbol_t;
symboltype: zbar_symbol_type_t;
begin
if BarTypes = [] then BarTypes := [ZBAR_EAN8, ZBAR_UPCE, ZBAR_ISBN10, ZBAR_UPCA, ZBAR_EAN13, ZBAR_ISBN13, ZBAR_I25, ZBAR_CODE39, ZBAR_CODE128];
bmp := TBitmap.Create;
bmp.PixelFormat := pf32bit;;
try
bmp.Width := Source.Width;
bmp.Height := Source.Height;
bmp.Canvas.Draw(0, 0, Source);
//processor := zbar_processor_create(0);
//Assert(Assigned(processor), 'zbar-processor');
//try
// if zbar_processor_init(processor, nil, Ord(False)) <> 0 then begin
// zbar_processor_error_spew(processor, 0);
// Assert(False, 'zbar-processor_init');
// end;
// zbar_processor_set_visible(processor, 0);
scanner := zbar_image_scanner_create;
Assert(Assigned(scanner), 'zbar-scanner');
try
zbar_image_scanner_set_config(scanner, ZBAR_NONE, ZBAR_CFG_ENABLE, 0);
i := zbar_image_scanner_set_config(scanner, ZBAR_NONE, ZBAR_CFG_X_DENSITY, Density);
Assert(i = 0, 'zbar-set_config');
i := zbar_image_scanner_set_config(scanner, ZBAR_NONE, ZBAR_CFG_Y_DENSITY, Density);
Assert(i = 0, 'zbar-set_config');
for stype in BarTypes do begin
i := zbar_image_scanner_set_config(scanner, stype, ZBAR_CFG_ENABLE, 1);
Assert(i = 0, 'zbar-set_config');
if CheckDigit then
zbar_image_scanner_set_config(scanner, stype, ZBAR_CFG_ADD_CHECK, 1);
end;
image := zbar_image_create;
Assert(Assigned(image), 'zbar-image');
try
bytesPerLine := bmp.Width;
p := bmp.ScanLine[bmp.Height - 1]; // die Bildzeilen gehen von unten nach oben
pg := GetMemory(bmp.Height * bytesPerLine);
try
for i := bmp.Height * bytesPerLine downto 0 do
pg[i] := Round(p[i*4]*0.3 + p[i*4+1]*0.59 + p[i*4+2]*0.11);
zbar_image_set_format(image, 'Y800');
zbar_image_set_size(image, bmp.Width, bmp.Height);
zbar_image_set_data(image, pg, bmp.Height * bytesPerLine, nil);
count := zbar_scan_image(scanner, image);
//zbar_process_image(processor, image); count := 1;
finally
FreeMemory(pg);
end;
if count > 0 then begin
symbol := zbar_image_first_symbol(image);
while Assigned(symbol) do begin
symboltype := zbar_symbol_get_type(symbol);
if AddBarType then
Codes.Add(String(AnsiString(zbar_get_symbol_name(symboltype)) + AnsiString(zbar_get_addon_name(symboltype)))
+ Codes.NameValueSeparator + String(AnsiString(zbar_symbol_get_data(symbol))))
else
Codes.Add(String(AnsiString(zbar_symbol_get_data(symbol))));
symbol := zbar_symbol_next(symbol);
end;
end;
finally
zbar_image_destroy(image);
end;
finally
zbar_image_scanner_destroy(scanner);
end;
//finally
// zbar_processor_destroy(processor);
//end;
finally
bmp.Free;
end;
end;
Wer schräge Barcodes einscännen will/muß, der braucht einfach nur das Bild zu drehen, denn die ZBar-Barcode-Komponente scännt nur in 90°-Winkeln (wagerecht und senkrecht).
z.B. von 0° bis <90° in 10°-Schritten
oder einfach nur noch einmal 45°
oder 0°, 22°, 45° und 68°
Da könnte man z.B. direkt in den Block nach image := zbar_image_create;
eine entsprechende Schleife einbauen.
Eventuell dann auch noch die StringListe mit .Sort:=True und .Duplicates:=dupIgnore .
Delphi-Quellcode:
procedure RotateBitmap(Dest, Source: TBitmap; Winkel: Double; Hintergrund: TColor = clWhite; GroesseAnpassen: Boolean = True);
type
//TArray = array[0..0] of Byte; {pf8bit}
//TArray = array[0..0] of array[0..1] of Byte; {pf16bit}
//TArray = array[0..0] of array[0..2] of Byte; {pf24bit}
TArray = array[0..0] of array[0..3] of Byte; {pf32bit}
PArray = ^TArray;
var
rw: Boolean;
CT, ST: Double;
I, J, X, Y, SrcW, SrcH, SrcWD, SrcHD, SrcWD2, SrcHD2: Integer;
ScanS, ScanD: array of PArray;
XCT, XST: Integer;
YCT, YST: array of Integer;
begin
//Source.PixelFormat := pf8bit;
//Source.PixelFormat := pf16bit;
//Source.PixelFormat := pf24bit;
Source.PixelFormat := pf32bit;
Dest.PixelFormat := Source.PixelFormat;
Winkel := 360 - Winkel;
while Winkel > 360 do Winkel := Winkel - 360;
while Winkel < 0 do Winkel := Winkel + 360;
Winkel := Winkel * PI / 180;
ST := Sin(Winkel);
CT := Cos(Winkel);
rw := Frac(Winkel / 90) = 0;
if not GroesseAnpassen then begin
Dest.Width := Source.Width;
Dest.Height := Source.Height;
end else if ST * CT < 0 then begin
Dest.Width := Round(Abs(Source.Width * CT - Source.Height * ST));
Dest.Height := Round(Abs(Source.Width * ST - Source.Height * CT));
end else begin
Dest.Width := Round(Abs(Source.Width * CT + Source.Height * ST));
Dest.Height := Round(Abs(Source.Width * ST + Source.Height * CT));
end;
with Dest.Canvas do begin
Brush.Style := bsSolid;
Brush.Color := Hintergrund;
FillRect(ClipRect);
end;
SrcWD := Source.Width;
SrcHD := Source.Height;
SrcWD2 := Source.Width div 2;
SrcHD2 := Source.Height div 2;
if CT < 0 then Dec(SrcWD2);
if ST < 0 then Dec(SrcHD2);
SetLength(ScanS, Source.Height);
SetLength(ScanD, Dest.Height);
for I := Source.Height - 1 downto 0 do ScanS[I] := Source.ScanLine[I];
for I := Dest.Height - 1 downto 0 do ScanD[I] := Dest.ScanLine[I];
SetLength(YCT, Dest.Height);
SetLength(YST, Dest.Height);
for J := 0 to Dest.Height - 1 do begin
if rw then
Y := Trunc(J - Dest.Height / 2 + 0.5)
else
Y := J - Dest.Height div 2;
YCT[J] := Round(Y * CT * 4 + 2);
YST[J] := Round(Y * ST * 4 + 2);
end;
for I := 0 to Dest.Width - 1 do begin
if rw then
X := Trunc(I - Dest.Width / 2)
else
X := I - Dest.Width div 2;
XCT := Round((X * CT + SrcWD2) * 4);
XST := Round((X * ST + SrcHD2) * 4);
for J := 0 to Dest.Height - 1 do begin
SrcW := (XCT - YST[J]) shr 2; {... div 4}
SrcH := (XST + YCT[J]) shr 2;
if (SrcH >= 0) and (SrcH < SrcHD) and (SrcW >= 0) and (SrcW < SrcWD) then
ScanD[J][I] := ScanS[SrcH][SrcW];
end;
end;
end;
Benötigt wird nur die angehängte Zbar.pas und die libzbar-0.dll von zbar.sourceforge.net, bzw. aus dem Anhang.
Das die Zbar.pas wurde natürlich auch gleich mit auf Unicode angepaßt ... läuft aber weiterhin auch mit ANSI.
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PoSex im Delphi viel seltener praktiziert.
Geändert von himitsu (30. Jun 2011 um 16:45 Uhr)
|