{
* Copyright 2007 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Original Authors: Sean Owen and dswitkin@google.com (Daniel Switkin)
* Ported from ZXING Java Source: www.Redivivus.in (suraj.supekar@redivivus.in)
* Delphi Implementation by E. Spelt and K. Gossens
}
unit ZXing.MultiFormatReader;
interface
uses
System.SysUtils,
System.Rtti,
System.Generics.Collections,
System.RegularExpressions,
ZXing.ReadResult,
ZXing.Reader,
ZXing.DecodeHintType,
ZXing.BinaryBitmap,
ZXing.BarcodeFormat,
ZXing.ResultPoint,
// 1D Barcodes
ZXing.OneD.OneDReader,
ZXing.OneD.Code128Reader,
ZXing.OneD.Code93Reader,
ZXing.OneD.ITFReader,
ZXing.OneD.EAN13Reader,
ZXing.OneD.EAN8Reader,
ZXing.OneD.UPCAReader,
ZXing.OneD.UPCEReader,
ZXing.OneD.Code39Reader,
// 2D Codes
ZXing.QrCode.QRCodeReader,
ZXing.Datamatrix.DataMatrixReader;
///
/// MultiFormatReader is a convenience class and the main entry point into the library for most uses.
/// By default it attempts to decode all barcode formats that the library supports. Optionally, you
/// can provide a hints object to request different behavior, for example only decoding QR codes.
///
/// Sean Owen
/// dswitkin@google.com (Daniel Switkin)
/// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source
type
TMultiFormatReader = class(TInterfacedObject, IReader)
private
FHints: TDictionary;
readers: TList;
function DecodeInternal(image: TBinaryBitmap): TReadResult;
procedure Set_Hints(const Value: TDictionary);
function Get_Hints: TDictionary;
/// This version of decode honors the intent of Reader.decode(BinaryBitmap) in that it
/// passes null as a hint to the decoders. However, that makes it inefficient to call repeatedly.
/// Use setHints() followed by decodeWithState() for continuous scan applications.
///
///
/// The pixel data to decode
///
/// The contents of the image
///
/// ReaderException Any errors which occurred
public
function decode(const image: TBinaryBitmap): TReadResult; overload;
function decode(const image: TBinaryBitmap; WithHints: Boolean)
: TReadResult; overload;
/// Decode an image using the hints provided. Does not honor existing state.
///
///
/// The pixel data to decode
///
/// The hints to use, clearing the previous state.
///
/// The contents of the image
///
/// ReaderException Any errors which occurred
function decode(const image: TBinaryBitmap;
hints: TDictionary): TReadResult; overload;
/// Decode an image using the state set up by calling setHints() previously. Continuous scan
/// clients will get a large speed increase by using this instead of decode().
///
///
/// The pixel data to decode
///
/// The contents of the image
///
/// ReaderException Any errors which occurred
function DecodeWithState(image: TBinaryBitmap): TReadResult;
destructor Destroy; override;
/// This method adds state to the MultiFormatReader. By setting the hints once, subsequent calls
/// to decodeWithState(image) can reuse the same set of readers without reallocating memory. This
/// is important for performance in continuous scan clients.
///
///
/// The set of hints to use for subsequent calls to decode(image)
///
property hints: TDictionary read Get_Hints
write Set_Hints;
procedure Reset;
procedure FreeReaders();
end;
implementation
function TMultiFormatReader.decode(const image: TBinaryBitmap): TReadResult;
begin
hints := nil;
result := DecodeInternal(image)
end;
function TMultiFormatReader.decode(const image: TBinaryBitmap;
WithHints: Boolean): TReadResult;
begin
result := DecodeInternal(image)
end;
function TMultiFormatReader.decode(const image: TBinaryBitmap;
hints: TDictionary): TReadResult;
begin
FHints := hints;
result := DecodeInternal(image)
end;
function TMultiFormatReader.DecodeWithState(image: TBinaryBitmap): TReadResult;
begin
// Make sure to set up the default state so we don't crash
if readers = nil then
begin
hints := nil
end;
result := DecodeInternal(image);
end;
destructor TMultiFormatReader.Destroy;
begin
FreeReaders;
inherited;
end;
procedure TMultiFormatReader.FreeReaders;
begin
if readers <> nil then
readers.Clear();
readers.Free;
readers := nil;
end;
function TMultiFormatReader.Get_Hints: TDictionary;
begin
result := FHints;
end;
procedure TMultiFormatReader.Set_Hints(const Value: TDictionary);
var
useCode39CheckDigit, useCode39ExtendedMode: Boolean;
formats: TList;
begin
FHints := Value;
// tryHarder := (Value <> nil) and
// (Value.ContainsKey(ZXing.DecodeHintType.TRY_HARDER));
if ((Value = nil) or
(not Value.ContainsKey(ZXing.DecodeHintType.POSSIBLE_FORMATS))) then
begin
formats := nil;
end
else
begin
formats := Value[ZXing.DecodeHintType.POSSIBLE_FORMATS]
as TList
end;
// add readers from the hints
readers := TList.Create;
if formats <> nil then
begin
// 1D readers
if (formats.Contains(TBarcodeFormat.CODE_128)) then
begin
readers.Add(TCode128Reader.Create())
end;
if (formats.Contains(TBarcodeFormat.CODE_93)) then
begin
readers.Add(TCode93Reader.Create())
end;
if (formats.Contains(TBarcodeFormat.ITF)) then
begin
readers.Add(TITFReader.Create())
end;
// 2D readers
if (formats.Contains(TBarcodeFormat.QR_CODE)) then
begin
readers.Add(TQRCodeReader.Create())
end;
if formats.Contains(TBarcodeFormat.DATA_MATRIX) then
readers.Add(TDataMatrixReader.Create);
if (formats.Contains(TBarcodeFormat.EAN_13)) then
readers.Add(TEAN13Reader.Create());
if (formats.Contains(TBarcodeFormat.EAN_8)) then
readers.Add(TEAN8Reader.Create());
if (formats.Contains(TBarcodeFormat.UPC_A)) then
readers.Add(TUPCAReader.Create());
if (formats.Contains(TBarcodeFormat.UPC_E)) then
readers.Add(TUPCEReader.Create());
if (formats.Contains(TBarcodeFormat.CODE_39)) then
begin
useCode39CheckDigit := hints.ContainsKey
(TDecodeHintType.ASSUME_CODE_39_CHECK_DIGIT) and
hints.ContainsKey(TDecodeHintType.ASSUME_CODE_39_CHECK_DIGIT);
useCode39ExtendedMode := hints.ContainsKey
(TDecodeHintType.USE_CODE_39_EXTENDED_MODE) and
hints.ContainsKey(TDecodeHintType.USE_CODE_39_EXTENDED_MODE);
readers.Add(TCode39Reader.Create(useCode39CheckDigit,
useCode39ExtendedMode));
end;
end;
if (readers.Count = 0) then // must be auto, add them all
begin
// 1D readers
readers.Add(TCode128Reader.Create());
readers.Add(TUPCAReader.Create());
readers.Add(TUPCEReader.Create());
readers.Add(TEAN13Reader.Create());
readers.Add(TEAN8Reader.Create());
readers.Add(TCode93Reader.Create());
readers.Add(TITFReader.Create());
useCode39CheckDigit := hints.ContainsKey
(TDecodeHintType.ASSUME_CODE_39_CHECK_DIGIT) and hints.ContainsKey
(TDecodeHintType.ASSUME_CODE_39_CHECK_DIGIT);
useCode39ExtendedMode := hints.ContainsKey
(TDecodeHintType.USE_CODE_39_EXTENDED_MODE) and hints.ContainsKey
(TDecodeHintType.USE_CODE_39_EXTENDED_MODE);
readers.Add(TCode39Reader.Create(useCode39CheckDigit,
useCode39ExtendedMode));
// 2D readers
readers.Add(TQRCodeReader.Create());
readers.Add(TDataMatrixReader.Create)
end;
end;
procedure TMultiFormatReader.Reset;
var
Reader: IReader;
begin
if readers <> nil then
begin
for Reader in readers do
begin
Reader.Reset();
end
end
end;
function TMultiFormatReader.DecodeInternal(image: TBinaryBitmap): TReadResult;
var
rpCallBack: TResultPointCallback;
i: integer;
Reader: IReader;
begin
result := nil;
if (readers = nil) then
begin
Exit;
end;
rpCallBack := nil;
if ((FHints <> nil) and
(FHints.ContainsKey(ZXing.DecodeHintType.NEED_RESULT_POINT_CALLBACK))) then
begin
// rpCallBack := FHints[DecodeHintType.NEED_RESULT_POINT_CALLBACK]
// as TResultPointCallback(nil);
end;
for i := 0 to readers.Count - 1 do
begin
Reader := readers[i];
Reader.Reset();
result := Reader.decode(image, FHints);
if result <> nil then
begin
// found a barcode, pushing the successful reader up front
// I assume that the same type of barcode is read multiple times
// so the reordering of the readers list should speed up the next reading
// a little bit
readers.Delete(i);
readers.Insert(0, Reader);
Exit;
end;
// if rpCallBack <> nil then
// rpCallBack(nil)
end;
end;
end.