// ---------------------------------------------------------------------
//
// Barcode Component
//
// Copyright (c) 2014-2022 WINSOFT
//
// ---------------------------------------------------------------------

//{$define TRIAL} // trial version, comment this line for full version

{$WARN SYMBOL_DEPRECATED OFF}

unit FBarcode;

{$if CompilerVersion >= 24} // Delphi XE3 or higher
  {$LEGACYIFEND ON}
{$ifend}

{$if CompilerVersion = 23} // Delphi XE2
  {$define DXE2}
{$ifend}

{$if CompilerVersion >= 26} // Delphi XE5 or higher
  {$define DXE5PLUS}
{$ifend}

{$if CompilerVersion >= 29} // Delphi XE8 or higher
  {$define DXE8PLUS}
{$ifend}

{$if CompilerVersion >= 33} // Delphi 10.3 or higher
  {$define D103PLUS}
{$ifend}

{$if CompilerVersion >= 35} // Delphi 11 or higher
  {$define D11PLUS}
{$ifend}

{$ifdef IOS}
  {$ifdef CPUARM}
    {$define IOS_DEVICE}
  {$else}
    {$define IOS_SIMULATOR}
  {$endif CPUARM}
{$endif IOS}

{$ifdef WIN32}
{$HPPEMIT '#pragma link "FBarcodeP.lib"'}
{$endif WIN32}

{$ifdef WIN64}
{$HPPEMIT '#pragma link "FBarcodeP.a"'}
{$endif WIN64}

interface

uses {$ifdef MSWINDOWS} Winapi.Windows, {$endif MSWINDOWS}
  FZint, System.UITypes, System.Classes,
  {$ifdef DXE5PLUS} FMX.Graphics, {$endif DXE5PLUS}
  FMX.Types, System.SysUtils;

type
  EBarcodeError = class(Exception);

type
  TSymbology =
  (
    syCode11,
    syStandardCode2Of5,
    syInterleaved2Of5,
    syCode2Of5IATA,
    syCode2Of5DataLogic,
    syCode2Of5Industrial,
    syCode3Of9,
    syExtendedCode3Of9,
    syEAN,
    syEAN_Check,
    syGS1_128,
    syCodabar,
    syCode128,
    syDeutschePostLeitcode,
    syDeutschePostIdentcode,
    syCode16K,
    syCode49,
    syCode93,
    syFlattermarken,
    syGS1_DataBarOmni,
    syGS1_DataBarLimited,
    syGS1_DataBarExpanded,
    syTelepenAlpha,
    syUPCA,
    syUPCA_Check,
    syUPCE,
    syUPCE_Check,
    syPostNet,
    syMsiPlessey,
    syFIM,
    syLOGMARS,
    syPharmacodeOneTrack,
    syPZN,
    syPharmacodeTwoTrack,
    syPDF417,
    syPDF417Compact,
    syMaxicode,
    syQRCode,
    syCode128SubsetB,
    syAustraliaPostStandardCustomer,
    syAustraliaPostReplyPaid,
    syAustraliaPostRouting,
    syAustraliaPostRedirection,
    syISBN,
    syRoyalMail4State,
    syDataMatrix,
    syEAN14,
    syVIN,
    syCodaBlockF,
    syNVE18,
    syJapanesePost,
    syKoreaPost,
    syGS1_DataBarStacked,
    syGS1_DataBarOmniStacked,
    syGS1_DataBarExpandedStacked,
    syPLANET,
    syMicroPDF417,
    syUSPSIntelligentMail,
    syPlesseyCode,
    syTelepenNumeric,
    syITF14,
    syDutchPostKIXCode,
    syAztecCode,
    syDAFTCode,
    syDPD,
    syMicroQRCode,
    syHIBC_Code128,
    syHIBC_Code39,
    syHIBC_DataMatrix,
    syHIBC_QRCode,
    syHIBC_PDF417,
    syHIBC_MicroPDF417,
    syHIBC_BlockF,
    syHIBC_AztecCode,
    syDotCode,
    syHanXin,
    syMailmark,
    syAztecRunes,
    syCode32,
    syCompositeEAN,
    syCompositeGS1_128,
    syCompositeGS1_DataBarOmni,
    syCompositeGS1_DataBarLimited,
    syCompositeGS1_DataBarExpanded,
    syCompositeUPCA,
    syCompositeUPCE,
    syCompositeGS1_DataBarStacked,
    syCompositeGS1_DataBarOmniStacked,
    syCompositeGS1_DataBarExpandedStacked,
    syChannelCode,
    syCodeOne,
    syGridMatrix,
    syUPNQR,
    syUltracode,
    syRMQR
  );

  TInputMode = (imData, imUnicode, imGs1);

  TOutputOption = (opBars, opBoldText, opBox, opBpp1, opCmyk, opDotty,
    opGsSeparator, opReaderInit, opSmallText, opStdout, opCompliantHeight);

  TOutputOptions = set of TOutputOption;

  TSecurityLevel = (slDefault, sl1, sl2, sl3, sl4, sl5, sl6, sl7, sl8);

  TEncodingMode = (emDefault, em0, em1, em2, em3, em4, em5, em6);

  TEciEncoding =
  (
    enDefault,
    enLatin1,          // ISO 8859-1 Latin alphabet No. 1
    enLatin2,          // ISO 8859-2 Latin alphabet No. 2
    enLatin3,          // ISO 8859-3 Latin alphabet No. 3
    enLatin4,          // ISO 8859-4 Latin alphabet No. 4
    enLatin5,          // ISO 8859-9 Latin alphabet No. 5
    enLatin6,          // ISO 8859-10 Latin alphabet No. 6
    enLatin7,          // ISO 8859-13 Latin alphabet No. 7 (Baltic Rim)
    enLatin8,          // ISO 8859-14 Latin alphabet No. 8 (Celtic)
    enLatin9,          // ISO 8859-15 Latin alphabet No. 9
    enLatin10,         // ISO 8859-16 Latin alphabet No. 10
    enLatinArabic,     // ISO 8859-6 Latin/Arabic alphabet
    enLatinCyrilic,    // ISO 8859-5 Latin/Cyrillic alphabet
    enLatinGreek,      // ISO 8859-7 Latin/Greek alphabet
    enLatinHebrew,     // ISO 8859-8 Latin/Hebrew alphabet
    enLatinThai,       // ISO 8859-11 Latin/Thai alphabet
    enWindowsCyrillic, // Windows 1251 Cyrillic
    enWindowsLatin1,   // Windows 1252 Latin 1
    enWindowsLatin2,   // Windows 1250 Latin 2 (Central Europe)
    enWindowsArabic,   // Windows 1256 Arabic
    enUtf8             // ISO 10646 UTF-8
  );

  TDataMatrix = (dmDefault, dmSquare, dmExtended);

  TUltracode = (ucDefault, ucCompress);

  TWarningLevel = (waDefault, waError);

  TCapability = (caHumanReadable, caStackable, caExtendable, caComposite,
    caECI, caGS1, caDotty, caQuietZones, caFixedRatio, caReaderInit,
    caMultiByte, caMask, caStructuredAppend, caCompliantHeight);

  TCapabilities = set of TCapability;

  TQuietZones = (qzDefault, qzCompliant, qzDisabled);

  [ComponentPlatformsAttribute(pidWin32 or pidWin64 {$ifdef D103PLUS} or pidOSX64 or pidAndroid32Arm or pidAndroid64Arm {$else} {$ifndef DXE2} or pidAndroid {$endif DXE2} {$endif D103PLUS} {$ifdef DXE8PLUS} or pidiOSDevice64 {$endif DXE8PLUS})]
  TFBarcode = class(TComponent)
  private
    FBackColor: TAlphaColor;
    FBitmap: TBitmap;
    FBorderWidth: Integer;
    FChanged: Boolean;
    FColumns: Integer;
    FDataMatrix: TDataMatrix;
    FDotSize: Single;
    FEciEncoding: TEciEncoding;
    FEncodingMode: TEncodingMode;
    FFastMode: Boolean;
    FFontSize: Integer;
    FForeColor: TAlphaColor;
    FGuardDescent: Single;
    FHeight: Single;
    FHeightPerRow: Boolean;
    FInputCheck: Boolean;
    FInputEscape: Boolean;
    FInputMode: TInputMode;
    FInputParentheses: Boolean;
    FInputText: string;
    FMask: Integer;
    FMultiByte: Boolean;
    FOutputOptions: TOutputOptions;
    FOutputText: string;
    FPrimaryMessage: string;
    FQuietZones: TQuietZones;
    FRotation: Integer;
    FRowCount: Integer;
    FRows: Integer;
    FScale: Single;
    FSecurityLevel: TSecurityLevel;
    FSeparatorHeight: Integer;
    FShowText: Boolean;
    FSymbology: TSymbology;
    FSymbolVersion: Integer;
    FUltracode: TUltracode;
    FWarningLevel: TWarningLevel;
    FWhiteSpaceHeight: Integer;
    FWhiteSpaceWidth: Integer;
    FWidth: Integer;
    function GetAbout: string;
    function GetBarcodeName: string;
    function GetBarcodeNames(Index: TSymbology): string;
    function GetBitmap: TBitmap;
    function GetCapabilities: TCapabilities;
    function GetOutputText: string;
    function GetRowCount: Integer;
    function GetSymbologyName: string;
    function GetSymbologyNames(Index: TSymbology): string;
    function GetVersion: Integer;
    function GetWidth: Integer;
    procedure ProcessBarcode(const FileName: string);
    procedure SetBackColor(Value: TAlphaColor);
    procedure SetBorderWidth(Value: Integer);
    procedure SetColumns(Value: Integer);
    procedure SetDataMatrix(Value: TDataMatrix);
    procedure SetDotSize(Value: Single);
    procedure SetEmpty(const Value: string);
    procedure SetEncodingMode(Value: TEncodingMode);
    procedure SetFastMode(Value: Boolean);
    procedure SetFontSize(Value: Integer);
    procedure SetForeColor(Value: TAlphaColor);
    procedure SetGuardDescent(Value: Single);
    procedure SetHeight(Value: Single);
    procedure SetHeightPerRow(Value: Boolean);
    procedure SetInputCheck(Value: Boolean);
    procedure SetInputEscape(Value: Boolean);
    procedure SetInputMode(Value: TInputMode);
    procedure SetInputParentheses(Value: Boolean);
    procedure SetInputText(const Value: string);
    procedure SetMask(Value: Integer);
    procedure SetOutputOptions(Value: TOutputOptions);
    procedure SetPrimaryMessage(const Value: string);
    procedure SetQuietZones(Value: TQuietZones);
    procedure SetRotation(Value: Integer);
    procedure SetRows(Value: Integer);
    procedure SetScale(Value: Single);
    procedure SetSecurityLevel(Value: TSecurityLevel);
    procedure SetSeparatorHeight(Value: Integer);
    procedure SetShowText(Value: Boolean);
    procedure SetSymbology(Value: TSymbology);
    procedure SetSymbologyName(const Value: string);
    procedure SetSymbolVersion(Value: Integer);
    procedure SetWhiteSpaceHeight(Value: Integer);
    procedure SetWhiteSpaceWidth(Value: Integer);
    function StoreDotSize: Boolean;
    function StoreGuardDescent: Boolean;
    function StoreHeight: Boolean;
    function StoreScale: Boolean;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure Save(const FileName: string = 'barcode.svg');
    property BarcodeName: string read GetBarcodeName;
    property BarcodeNames[Index: TSymbology]: string read GetBarcodeNames;
    property Bitmap: TBitmap read GetBitmap;
    property Capabilities: TCapabilities read GetCapabilities;
    property OutputText: string read GetOutputText;
    property RowCount: Integer read GetRowCount;
    property SymbologyNames[Index: TSymbology]: string read GetSymbologyNames;
    property Version: Integer read GetVersion;
    property Width: Integer read GetWidth;
  published
    property About: string read GetAbout write SetEmpty stored False;
    property BackColor: TAlphaColor read FBackColor write SetBackColor default TAlphaColorRec.White;
    property BorderWidth: Integer read FBorderWidth write SetBorderWidth default 0;
    property Columns: Integer read FColumns write SetColumns default 0;
    property DataMatrix: TDataMatrix read FDataMatrix write SetDataMatrix default dmDefault;
    property DotSize: Single read FDotSize write SetDotSize stored StoreDotSize;
    property EciEncoding: TEciEncoding read FEciEncoding write FEciEncoding default enDefault;
    property EncodingMode: TEncodingMode read FEncodingMode write SetEncodingMode default emDefault;
    property FastMode: Boolean read FFastMode write SetFastMode default False;
    property FontSize: Integer read FFontSize write SetFontSize default 8;
    property ForeColor: TAlphaColor read FForeColor write SetForeColor default TAlphaColorRec.Black;
    property GuardDescent: Single read FGuardDescent write SetGuardDescent stored StoreGuardDescent;
    property Height: Single read FHeight write SetHeight stored StoreHeight;
    property HeightPerRow: Boolean read FHeightPerRow write SetHeightPerRow default False;
    property InputCheck: Boolean read FInputCheck write SetInputCheck default True;
    property InputEscape: Boolean read FInputEscape write SetInputEscape default False;
    property InputMode: TInputMode read FInputMode write SetInputMode default imData;
    property InputParentheses: Boolean read FInputParentheses write SetInputParentheses default False;
    property InputText: string read FInputText write SetInputText;
    property Mask: Integer read FMask write SetMask default -1;
    property MultiByte: Boolean read FMultiByte write FMultiByte default False;
    property OutputOptions: TOutputOptions read FOutputOptions write SetOutputOptions default [];
    property PrimaryMessage: string read FPrimaryMessage write SetPrimaryMessage;
    property QuietZones: TQuietZones read FQuietZones write SetQuietZones default qzDefault;
    property Rotation: Integer read FRotation write SetRotation default 0;
    property Rows: Integer read FRows write SetRows default 0;
    property Scale: Single read FScale write SetScale stored StoreScale;
    property SecurityLevel: TSecurityLevel read FSecurityLevel write SetSecurityLevel default slDefault;
    property SeparatorHeight: Integer read FSeparatorHeight write SetSeparatorHeight default 1;
    property ShowText: Boolean read FShowText write SetShowText default True;
    property Symbology: TSymbology read FSymbology write SetSymbology default syQRCode;
    property SymbologyName: string read GetSymbologyName write SetSymbologyName stored False;
    property SymbolVersion: Integer read FSymbolVersion write SetSymbolVersion default 0;
    property Ultracode: TUltracode read FUltracode write FUltracode default ucDefault;
    property WarningLevel: TWarningLevel read FWarningLevel write FWarningLevel default waDefault;
    property WhiteSpaceHeight: Integer read FWhiteSpaceHeight write SetWhiteSpaceHeight default 0;
    property WhiteSpaceWidth: Integer read FWhiteSpaceWidth write SetWhiteSpaceWidth default 0;
  end;

{$ifdef IOS_DEVICE}
{$define STATIC_LIBRARY}
{$endif IOS_DEVICE}

{$ifdef ANDROID}
{$define STATIC_LIBRARY}
{$endif ANDROID}

{$ifdef STATIC_LIBRARY}
const
  LibZint = 'libzint.a';

function ZintCreate: zint_symbol_ptr; cdecl; external LibZint name 'ZBarcode_Create';
procedure ZintClear(symbol: zint_symbol_ptr); cdecl; external LibZint name 'ZBarcode_Clear';
procedure ZintDelete(symbol: zint_symbol_ptr); cdecl; external LibZint name 'ZBarcode_Delete';
function ZintEncode(symbol: zint_symbol_ptr; source: PByte; length: Integer): Integer; cdecl; external LibZint name 'ZBarcode_Encode';
function ZintEncode_File(symbol: zint_symbol_ptr; filename: PByte): Integer; cdecl; external LibZint name 'ZBarcode_Encode_File';
function ZintPrint(symbol: zint_symbol_ptr; rotate_angle: Integer): Integer; cdecl; external LibZint name 'ZBarcode_Print';
function ZintEncodeAndPrint(symbol: zint_symbol_ptr; source: PByte; length, rotate_angle: Integer): Integer; cdecl; external LibZint name 'ZBarcode_Encode_and_Print';
function ZintEncodeFileAndPrint(symbol: zint_symbol_ptr; filename: PByte; rotate_angle: Integer): Integer; cdecl; external LibZint name 'ZBarcode_Encode_File_and_Print';
function ZintBuffer(symbol: zint_symbol_ptr; rotate_angle: Integer): Integer; cdecl; external LibZint name 'ZBarcode_Buffer';
function ZintEncodeAndBuffer(symbol: zint_symbol_ptr; source: PByte; length, rotate_angle: Integer): Integer; cdecl; external LibZint name 'ZBarcode_Encode_and_Buffer';
function ZintEncodeFileAndBuffer(symbol: zint_symbol_ptr; filename: PByte; rotate_angle: Integer): Integer; cdecl; external LibZint name 'ZBarcode_Encode_File_and_Buffer';
function ZintBufferVector(symbol: zint_symbol_ptr; rotate_angle: Integer): Integer; cdecl; external LibZint name 'ZBarcode_Buffer_Vector';
function ZintEncodeAndBufferVector(symbol: zint_symbol_ptr; source: PByte; length, rotate_angle: Integer): Integer; cdecl; external LibZint name 'ZBarcode_Encode_and_Buffer_Vector';
function ZintEncodeFileAndBufferVector(symbol: zint_symbol_ptr; filename: PByte; rotate_angle: Integer): Integer; cdecl; external LibZint name 'ZBarcode_Encode_File_and_Buffer_Vector';
function ZintValidID(symbol_id: Integer): Integer; cdecl; external LibZint name 'ZBarcode_ValidID';
function ZintBarcodeName(symbol_id: Integer; out name: TBarcodeName): Integer; cdecl; external LibZint name 'ZBarcode_BarcodeName';
function ZintCap(symbol_id: Integer; cap_flag: Cardinal): Cardinal; cdecl; external LibZint name 'ZBarcode_Cap';
function ZintVersion: Integer; cdecl; external LibZint name 'ZBarcode_Version';
{$else}

var
  ZintLibraryName: string = '';
  ZintLibrary: HMODULE;

  ZintCreate: ZBarcode_Create;
  ZintClear: ZBarcode_Clear;
  ZintDelete: ZBarcode_Delete;
  ZintEncode: ZBarcode_Encode;
  ZintEncodeFile: ZBarcode_Encode_File;
  ZintPrint: ZBarcode_Print;
  ZintEncodeAndPrint: ZBarcode_Encode_and_Print;
  ZintEncodeFileAndPrint: ZBarcode_Encode_File_and_Print;
  ZintBuffer: ZBarcode_Buffer;
  ZintEncodeAndBuffer: ZBarcode_Encode_and_Buffer;
  ZintEncodeFileAndBuffer: ZBarcode_Encode_File_and_Buffer;
  ZintBufferVector: ZBarcode_Buffer_Vector;
  ZintEncodeAndBufferVector: ZBarcode_Encode_and_Buffer_Vector;
  ZintEncodeFileAndBufferVector: ZBarcode_Encode_File_and_Buffer_Vector;
  ZintValidID: ZBarcode_ValidID;
  ZintBarcodeName: ZBarcode_BarcodeName;
  ZintCap: ZBarcode_Cap;
  ZintVersion: ZBarcode_Version;
{$endif STATIC_LIBRARY}

function LoadedLibrary: Boolean;
procedure LoadLibrary;
procedure UnloadLibrary;

implementation

uses FMX.Consts, System.IOUtils {$ifdef TRIAL}, FMX.Dialogs {$endif TRIAL};

resourcestring
  SSymbologyNotFound = 'Symbology not found';
{$ifdef DXE2}
  SPropertyOutOfRange = '%s property out of range';
{$endif DXE2}

const
  SymbologyNames: array[TSymbology] of string =
  (
    'Code 11',
    'Standard Code 2 of 5',
    'Interleaved 2 of 5',
    'Code 2 of 5 IATA',
    'Code 2 of 5 Data Logic',
    'Code 2 of 5 Industrial',
    'Code 3 of 9 (Code 39)',
    'Extended Code 3 of 9 (Code 39+)',
    'EAN (including EAN-8 and EAN-13)',
    'EAN + Check Digit',
    'GS1-128 (UCC.EAN-128)',
    'Codabar',
    'Code 128 (automatic subset switching)',
    'Deutsche Post Leitcode',
    'Deutsche Post Identcode',
    'Code 16K',
    'Code 49',
    'Code 93',
    'Flattermarken',
    'GS1 DataBar Omnidirectional (including GS1 DataBar Truncated)',
    'GS1 DataBar Limited',
    'GS1 DataBar Expanded',
    'Telepen Alpha',
    'UPC-A',
    'UPC-A + Check Digit',
    'UPC-E',
    'UPC-E + Check Digit',
    'POSTNET',
    'MSI Plessey',
    'FIM',
    'LOGMARS',
    'Pharmacode One-Track',
    'PZN',
    'Pharmacode Two-Track',
    'PDF417',
    'Compact PDF417 (Truncated PDF417)',
    'MaxiCode',
    'QR Code',
    'Code 128 (Subset B)',
    'Australia Post Standard Customer',
    'Australia Post Reply Paid',
    'Australia Post Routing',
    'Australia Post Redirection',
    'ISBN (EAN-13 with verification stage)',
    'Royal Mail 4 State (RM4SCC)',
    'Data Matrix (ECC200)',
    'EAN-14',
    'Vehicle Identification Number',
    'Codablock-F',
    'NVE-18 (SSCC-18)',
    'Japanese Postal Code',
    'Korea Post',
    'GS1 DataBar Stacked (stacked version of GS1 DataBar Truncated)',
    'GS1 DataBar Stacked Omnidirectional',
    'GS1 DataBar Expanded Stacked',
    'PLANET',
    'MicroPDF417',
    'USPS Intelligent Mail (OneCode)',
    'Plessey Code',
    'Telepen Numeric',
    'ITF-14',
    'Dutch Post KIX Code',
    'Aztec Code',
    'DAFT Code',
    'DPD Code',
    'Micro QR Code',
    'HIBC (Health Industry Barcode) Code 128',
    'HIBC Code 39',
    'HIBC Data Matrix ECC200',
    'HIBC QR Code',
    'HIBC PDF417',
    'HIBC MicroPDF417',
    'HIBC Codablock-F',
    'HIBC Aztec Code',
    'DotCode',
    'Han Xin (Chinese Sensible) Code',
    'Royal Mail 4-state Mailmark',
    'Aztec Runes',
    'Code 32',
    'Composite Symbol with EAN linear component',
    'Composite Symbol with GS1-128 linear component',
    'Composite Symbol with GS1 DataBar Omnidirectional linear component',
    'Composite Symbol with GS1 DataBar Limited linear component',
    'Composite Symbol with GS1 DataBar Expanded linear component',
    'Composite Symbol with UPC-A linear component',
    'Composite Symbol with UPC-E linear component',
    'Composite Symbol with GS1 DataBar Stacked component',
    'Composite Symbol with GS1 DataBar Stacked Omnidirectional component',
    'Composite Symbol with GS1 DataBar Expanded Stacked component',
    'Channel Code',
    'Code One',
    'Grid Matrix',
    'UPNQR (Univerzalnega Plačilnega Naloga QR)',
    'Ultracode',
    'Rectangular Micro QR Code (rMQR)'
  );

  SymbologyCode: array[TSymbology] of Integer =
  (
    // Tbarcode 7 codes
    BARCODE_CODE11,
    BARCODE_C25STANDARD,
    BARCODE_C25INTER,
    BARCODE_C25IATA,
    BARCODE_C25LOGIC,
    BARCODE_C25IND,
    BARCODE_CODE39,
    BARCODE_EXCODE39,
    BARCODE_EANX,
    BARCODE_EANX_CHK,
    BARCODE_GS1_128,
    BARCODE_CODABAR,
    BARCODE_CODE128,
    BARCODE_DPLEIT,
    BARCODE_DPIDENT,
    BARCODE_CODE16K,
    BARCODE_CODE49,
    BARCODE_CODE93,
    BARCODE_FLAT,
    BARCODE_DBAR_OMN,
    BARCODE_DBAR_LTD,
    BARCODE_DBAR_EXP,
    BARCODE_TELEPEN,
    BARCODE_UPCA,
    BARCODE_UPCA_CHK,
    BARCODE_UPCE,
    BARCODE_UPCE_CHK,
    BARCODE_POSTNET,
    BARCODE_MSI_PLESSEY,
    BARCODE_FIM,
    BARCODE_LOGMARS,
    BARCODE_PHARMA,
    BARCODE_PZN,
    BARCODE_PHARMA_TWO,
    BARCODE_PDF417,
    BARCODE_PDF417COMP,
    BARCODE_MAXICODE,
    BARCODE_QRCODE,
    BARCODE_CODE128B,
    BARCODE_AUSPOST,
    BARCODE_AUSREPLY,
    BARCODE_AUSROUTE,
    BARCODE_AUSREDIRECT,
    BARCODE_ISBNX,
    BARCODE_RM4SCC,
    BARCODE_DATAMATRIX,
    BARCODE_EAN14,
    BARCODE_VIN,
    BARCODE_CODABLOCKF,
    BARCODE_NVE18,
    BARCODE_JAPANPOST,
    BARCODE_KOREAPOST,
    BARCODE_DBAR_STK,
    BARCODE_DBAR_OMNSTK,
    BARCODE_DBAR_EXPSTK,
    BARCODE_PLANET,
    BARCODE_MICROPDF417,
    BARCODE_USPS_IMAIL,
    BARCODE_PLESSEY,

    // Tbarcode 8 codes
    BARCODE_TELEPEN_NUM,
    BARCODE_ITF14,
    BARCODE_KIX,
    BARCODE_AZTEC,
    BARCODE_DAFT,
    BARCODE_DPD,
    BARCODE_MICROQR,

    // Tbarcode 9 codes
    BARCODE_HIBC_128,
    BARCODE_HIBC_39,
    BARCODE_HIBC_DM,
    BARCODE_HIBC_QR,
    BARCODE_HIBC_PDF,
    BARCODE_HIBC_MICPDF,
    BARCODE_HIBC_BLOCKF,
    BARCODE_HIBC_AZTEC,

    // Tbarcode 10 codes
    BARCODE_DOTCODE,
    BARCODE_HANXIN,

    // Tbarcode 11 codes
    BARCODE_MAILMARK,

    // Zint specific
    BARCODE_AZRUNE,
    BARCODE_CODE32,
    BARCODE_EANX_CC,
    BARCODE_GS1_128_CC,
    BARCODE_DBAR_OMN_CC,
    BARCODE_DBAR_LTD_CC,
    BARCODE_DBAR_EXP_CC,
    BARCODE_UPCA_CC,
    BARCODE_UPCE_CC,
    BARCODE_DBAR_STK_CC,
    BARCODE_DBAR_OMNSTK_CC,
    BARCODE_DBAR_EXPSTK_CC,
    BARCODE_CHANNEL,
    BARCODE_CODEONE,
    BARCODE_GRIDMATRIX,
    BARCODE_UPNQR,
    BARCODE_ULTRA,
    BARCODE_RMQR
  );

  InputModeCode: array[TInputMode] of Integer =
  (
    DATA_MODE,
    UNICODE_MODE,
    GS1_MODE
  );

  EciCode: array [TEciEncoding] of Integer =
  (
    0, // enDefault
    3, // enLatin1
    4, // enLatin2
    5, // enLatin3
    6, // enLatin4
    11, // enLatin5
    12, // enLatin6
    15, // enLatin7
    16, // enLatin8
    17, // enLatin9
    18, // enLatin10
    8, // enLatinArabic
    7, // enLatinCyrilic
    9, // enLatinGreek
    10, // enLatinHebrew
    13, // enLatinThai
    22, // enWindowsCyrillic 1251
    23, // enWindowsLatin1 1252
    21, // enWindowsLatin2 1250
    24, // enWindowsArabic 1256
    26 // enUtf8
  );

  WarningLevelCode: array [TWarningLevel] of Integer =
  (
    WARN_DEFAULT,
    WARN_FAIL_ALL
  );

function ToBytes(Pointer: PByte): TBytes;
var
  Length: Integer;
  Ptr: PByte;
begin
  if Pointer = nil then
    Result := nil
  else
  begin
    Ptr := Pointer;
    while Ptr^ <> 0 do
      Inc(Ptr);
    Length := Ptr - Pointer;
    SetLength(Result, Length);
    Move(Pointer^, Result[0], Length);
  end;
end;

function ToUtf8(const Text: string): TBytes;
begin
  Result := TEncoding.UTF8.GetBytes(Text);
end;

function FromUtf8(const Data: TBytes): string;
begin
  Result := TEncoding.UTF8.GetString(Data);
end;

procedure Check(Value: Boolean; const ErrorMessage: string);
begin
  if not Value then
    raise EBarcodeError.Create(ErrorMessage);
end;

function EncodeSymbology(Symbology: TSymbology): Integer;
begin
  Result := SymbologyCode[Symbology];
end;

function EncodeInputMode(InputMode: TInputMode): Integer;
begin
  Result := InputModeCode[InputMode];
end;

function EncodeWarningLevel(WarningLevel: TWarningLevel): Integer;
begin
  Result := WarningLevelCode[WarningLevel];
end;

function FindSymbology(const SymbologyName: string; var Symbology: TSymbology): Boolean;
var Sym: TSymbology;
begin
  Result := True;
  for Sym := Low(Symbology) to High(Symbology) do
    if SymbologyNames[Sym] = SymbologyName then
    begin
      Symbology := Sym;
      Exit;
    end;

  Result := False;
end;

function HexDigit(Value: Integer): Byte;
begin
  if Value < 10 then
    Result := Value + Ord('0')
  else
    Result := Value - 10 + Ord('A');
end;

procedure EncodeColor(Color: TAlphaColor; Output: PByte);
begin
  Output[0] := HexDigit((Ord(Color) shr 20) and $F);
  Output[1] := HexDigit((Ord(Color) shr 16) and $F);
  Output[2] := HexDigit((Ord(Color) shr 12) and $F);
  Output[3] := HexDigit((Ord(Color) shr 8) and $F);
  Output[4] := HexDigit((Ord(Color) shr 4) and $F);
  Output[5] := HexDigit((Ord(Color) shr 0) and $F);
  Output[6] := 0;
  Output[7] := 0;
  Output[8] := 0;
  Output[9] := 0;
end;

// TFBarcode

constructor TFBarcode.Create(AOwner: TComponent);
begin
  inherited;
  FBackColor := TAlphaColorRec.White;
  FChanged := True;
  FDotSize := 0.0; // 0.8
  FFontSize := 8;
  FForeColor := TAlphaColorRec.Black;
  FHeight := 50.0;
  FGuardDescent := 5.0;
  FInputCheck := True;
  FInputMode := imData;
  FMask := -1;
  FQuietZones := qzDefault;
  FScale := 1.0;
  FSeparatorHeight := 1;
  FShowText := True;
  FSymbology := syQRCode;
  FWarningLevel := waDefault;
end;

destructor TFBarcode.Destroy;
begin
  FBitmap.Free;
  inherited Destroy;
end;

function TFBarcode.GetAbout: string;
begin
  Result := 'Version 6.8, Copyright (c) 2014-2022 WINSOFT, https://www.winsoft.sk';
end;

function TFBarcode.StoreDotSize: Boolean;
begin
  Result := FDotSize <> 0.0;
end;

function TFBarcode.StoreGuardDescent: Boolean;
begin
  Result := FGuardDescent <> 5.0;
end;

function TFBarcode.StoreHeight: Boolean;
begin
  Result := FHeight <> 50.0;
end;

function TFBarcode.StoreScale: Boolean;
begin
  Result := FScale <> 1.0;
end;

function TFBarcode.GetBitmap: TBitmap;
begin
  ProcessBarcode('');
  Result := FBitmap;
end;

function TFBarcode.GetBarcodeNames(Index: TSymbology): string;
var Buffer: TBarcodeName;
begin
  if ZintBarcodeName(EncodeSymbology(Symbology), Buffer) = 0 then
  {$ifdef NEXTGEN}
    Result := FromUtf8(ToBytes(@Buffer[0]))
  {$else}
    Result := string(PAnsiChar(@Buffer[0]))
  {$endif NEXTGEN}
  else
    Result := '';
end;

function TFBarcode.GetBarcodeName: string;
begin
  Result := BarcodeNames[FSymbology];
end;

function TFBarcode.GetSymbologyNames(Index: TSymbology): string;
begin
  Result := FBarcode.SymbologyNames[Index];
end;

function TFBarcode.GetSymbologyName: string;
begin
  Result := SymbologyNames[FSymbology];
end;

function TFBarcode.GetOutputText: string;
begin
  ProcessBarcode('');
  Result := FOutputText;
end;

function TFBarcode.GetRowCount: Integer;
begin
  ProcessBarcode('');
  Result := FRowCount;
end;

function TFBarcode.GetWidth: Integer;
begin
  ProcessBarcode('');
  Result := FWidth;
end;

procedure TFBarcode.Save(const FileName: string);
begin
  FChanged := True;
  ProcessBarcode(FileName);
end;

procedure TFBarcode.ProcessBarcode(const FileName: string);
var
  Symbol: zint_symbol_ptr;
  I, J, InputLength, PrimaryLength: Integer;
  SourcePtr: PByte;
{$ifndef DXE2}
  Data: TBitmapData;
{$endif DXE2}
  Color: TAlphaColor;
{$ifdef NEXTGEN}
  ZintResult: Integer;
  Input, Output, Primary: TBytes;
{$else}
  Input, Output, Primary: AnsiString;
{$endif NEXTGEN}
  AllCapabilities: TCapabilities;
begin
  if FChanged then
  begin
    LoadLibrary;
    Check(ZintVersion = 21009, 'Incorrect Zint library version');
    Symbol := ZIntCreate;
    if Symbol <> nil then
      try
        ZIntClear(Symbol);
        Symbol.symbology := EncodeSymbology(Symbology);
        Symbol.guard_descent := GuardDescent;
        Symbol.height := Height;
        Symbol.whitespace_width := WhiteSpaceWidth;
        Symbol.whitespace_height := WhiteSpaceHeight;
        Symbol.border_width := BorderWidth;
        Symbol.warn_level := EncodeWarningLevel(WarningLevel);

        if FileName <> '' then
        begin
        {$ifdef NEXTGEN}
          Output := ToUtf8(FileName);
        {$else}
          Output := UTF8Encode(FileName);
        {$endif NEXTGEN}

          Check(Length(Output) < 256, 'FileName size has to be less than 256 characters');
        {$ifdef NEXTGEN}
          Move(Output[0], Symbol.outfile[0], Length(Output));
        {$else}
          Move(Output[1], Symbol.outfile[0], Length(Output));
        {$endif NEXTGEN}
        end;

        Symbol.output_options := 0;
        if opBars in OutputOptions then
          Symbol.output_options := Symbol.output_options or BARCODE_BIND;
        if opBox in OutputOptions then
          Symbol.output_options := Symbol.output_options or BARCODE_BOX;
        if opStdout in OutputOptions then
          Symbol.output_options := Symbol.output_options or BARCODE_STDOUT;
        if opReaderInit in OutputOptions then
          Symbol.output_options := Symbol.output_options or READER_INIT;
        if opSmallText in OutputOptions then
          Symbol.output_options := Symbol.output_options or SMALL_TEXT;
        if opBoldText in OutputOptions then
          Symbol.output_options := Symbol.output_options or BOLD_TEXT;
        if opCmyk in OutputOptions then
          Symbol.output_options := Symbol.output_options or CMYK_COLOUR;
        if opDotty in OutputOptions then
          Symbol.output_options := Symbol.output_options or BARCODE_DOTTY_MODE;
        if opGsSeparator in OutputOptions then
          Symbol.output_options := Symbol.output_options or GS1_GS_SEPARATOR;
        if opCompliantHeight in OutputOptions then
          Symbol.output_options := Symbol.output_options or COMPLIANT_HEIGHT;
        if opBpp1 in OutputOptions then
        begin
          Check(Symbology <> syUltracode, 'Ultracode symbology doesn''t support opBpp1 output option');
          Symbol.output_options := Symbol.output_options or OUT_BUFFER_INTERMEDIATE;
        end;

        case QuietZones of
          qzCompliant: Symbol.output_options := Symbol.output_options or BARCODE_QUIET_ZONES;
          qzDisabled:  Symbol.output_options := Symbol.output_options or BARCODE_NO_QUIET_ZONES;
        end;

        Symbol.fontsize := FontSize;
        EncodeColor(ForeColor, @Symbol.fgcolour[0]);
        EncodeColor(BackColor, @Symbol.bgcolour[0]);
        Symbol.scale := Scale;
        Symbol.show_hrt := Ord(ShowText);
        Symbol.input_mode := EncodeInputMode(InputMode);
        if not InputCheck then
          Symbol.input_mode := Symbol.input_mode or GS1NOCHECK_MODE;
        if InputEscape then
          Symbol.input_mode := Symbol.input_mode or ESCAPE_MODE;
        if InputParentheses then
          Symbol.input_mode := Symbol.input_mode or GS1PARENS_MODE;
        if HeightPerRow then
          Symbol.input_mode := Symbol.input_mode or HEIGHTPERROW_MODE;
        if FastMode then
          Symbol.input_mode := Symbol.input_mode or FAST_MODE;

        if EciEncoding <> enDefault then
          Symbol.eci := EciCode[EciEncoding];

        if DotSize > 0.0 then
          Symbol.dot_size := DotSize;

        if Symbology in [syAztecCode, syPDF417, syPDF417Compact, syMicroPDF417, syHIBC_PDF417,
          syHIBC_MicroPDF417, syQRCode, syMicroQRCode, syHIBC_QRCode] then
        begin
          if SecurityLevel <> slDefault then
            Symbol.option_1 := Ord(SecurityLevel);
        end
        else if Symbology in [syMaxicode, syCompositeEAN, syCompositeGS1_128, syCompositeGS1_DataBarOmni,
          syCompositeGS1_DataBarLimited, syCompositeGS1_DataBarExpanded, syCompositeUPCA,
          syCompositeUPCE, syCompositeGS1_DataBarStacked, syCompositeGS1_DataBarOmniStacked,
          syCompositeGS1_DataBarExpandedStacked] then
        begin
          if EncodingMode <> emDefault then
            Symbol.option_1 := Ord(EncodingMode) - 1;
        end
        else
        begin
          if Rows <> 0 then
            Symbol.option_1 := Rows;
        end;

        if Symbology in [syCode11, syMsiPlessey, syCode3Of9, syExtendedCode3Of9,
          syLOGMARS, syVIN, syCodabar, syChannelCode, syDataMatrix, syQRCode,
          syMicroQRCode, syRMQR, syAztecCode, syCodeOne, syGridMatrix, syHanXin,
          syHIBC_Code39, syHIBC_DataMatrix, syHIBC_QRCode, syHIBC_AztecCode] then
        begin
          if SymbolVersion <> 0 then
            Symbol.option_2 := SymbolVersion;
        end
        else
        begin
          if Columns <> 0 then
            Symbol.option_2 := Columns;
        end;

        AllCapabilities := Capabilities;
        if Symbology = syUltracode then
        begin
          if Ultracode = ucCompress then
            Symbol.option_3 := ULTRA_COMPRESSION;
        end
        else if Symbology in [syDataMatrix, syHIBC_DataMatrix] then
          case DataMatrix of
            dmSquare: Symbol.option_3 := DM_SQUARE;
            dmExtended: Symbol.option_3 := DM_DMRE;
          end
        else if caStackable in AllCapabilities then
          Symbol.option_3 := SeparatorHeight
        else
        begin
          if MultiByte then
            if caMultiByte in AllCapabilities then
              Symbol.option_3 := ZINT_FULL_MULTIBYTE;

          if Mask <> -1 then
            if caMask in AllCapabilities then
              Symbol.option_3 := Symbol.option_3 or ((Mask + 1) shl 8);
        end;

{$ifdef NEXTGEN}
        Primary := ToUtf8(PrimaryMessage);
{$else}
        Primary := UTF8Encode(PrimaryMessage);
{$endif NEXTGEN}
        PrimaryLength := Length(Primary);
        if PrimaryLength > 127 then
          PrimaryLength := 127;
{$ifdef NEXTGEN}
        Move(Primary[0], Symbol.Primary[0], PrimaryLength);
{$else}
        Move(Primary[1], Symbol.Primary[0], PrimaryLength);
{$endif NEXTGEN}

{$ifdef NEXTGEN}
        Input := ToUtf8(InputText);
{$else}
        Input := UTF8Encode(InputText);
{$endif NEXTGEN}

        InputLength := Length(Input);
        if InputLength = 0 then
          SetLength(Input, 1);
{$ifdef NEXTGEN}
        ZintResult := ZintEncode(Symbol, @Input[0], InputLength); // this call cannot be directly placed inside Check
        Check(ZintResult = 0, FromUtf8(ToBytes(@Symbol.errtxt[0])));
{$else}
        Check(ZintEncode(Symbol, @Input[1], InputLength) = 0, string(AnsiString(PAnsiChar(@Symbol.errtxt[0]))));
{$endif NEXTGEN}

        FRowCount := Symbol.rows;
        FWidth := Symbol.width;
        FOutputText := UTF8ToString(@Symbol.text[0]);

        if FileName <> '' then
        begin
        {$ifdef NEXTGEN}
          ZintResult := ZintPrint(Symbol, Rotation); // this call cannot be directly placed inside Check
          Check(ZintResult = 0, FromUtf8(ToBytes(@Symbol.errtxt[0])));
        {$else}
          Check(ZintPrint(Symbol, Rotation) = 0, string(AnsiString(PAnsiChar(@Symbol.errtxt[0]))));
        {$endif NEXTGEN}
          FChanged := True;
        end
        else
        begin
        {$ifdef NEXTGEN}
          ZintResult := ZintBuffer(Symbol, Rotation); // this call cannot be directly placed inside Check
          Check(ZintResult = 0, FromUtf8(ToBytes(@Symbol.errtxt[0])));
        {$else}
          Check(ZintBuffer(Symbol, Rotation) = 0, string(AnsiString(PAnsiChar(@Symbol.errtxt[0]))));
        {$endif NEXTGEN}

          if FBitmap = nil then
            FBitmap := TBitmap.Create(Symbol.bitmap_width, Symbol.bitmap_height)
          else
          begin
            FBitmap.Width := Symbol.bitmap_width;
            FBitmap.Height := Symbol.bitmap_height;
          end;

          SourcePtr := Symbol.bitmap;
        {$ifndef DXE2}
          {$ifdef D11PLUS}
          FBitmap.Map(TMapAccess.Write, Data);
          {$else}
          FBitmap.Map(TMapAccess.maWrite, Data);
          {$endif D11PLUS}
          try
        {$endif DXE2}
            if opBpp1 in OutputOptions then
            begin
              for I := 0 to FBitmap.Height - 1 do
                for J := 0 to FBitmap.Width - 1 do
                begin
                  if True then
                  if SourcePtr^ = Ord('0') then
                    Color := BackColor
                  else
                    Color := ForeColor;
                  Inc(SourcePtr);

          {$ifndef DXE2}
                  Data.SetPixel(J, I, Color);
          {$else}
                  FBitmap.Pixels[J, I] := Color;
          {$endif DXE2}
                end;
            end
            else
            begin
              for I := 0 to FBitmap.Height - 1 do
                for J := 0 to FBitmap.Width - 1 do
                begin
                  TAlphaColorRec(Color).R := SourcePtr^;
                  Inc(SourcePtr);
                  TAlphaColorRec(Color).G := SourcePtr^;
                  Inc(SourcePtr);
                  TAlphaColorRec(Color).B := SourcePtr^;
                  Inc(SourcePtr);
                  TAlphaColorRec(Color).A := $ff;
          {$ifndef DXE2}
                  Data.SetPixel(J, I, Color);
          {$else}
                  FBitmap.Pixels[J, I] := Color;
          {$endif DXE2}
                end;
            end;
        {$ifndef DXE2}
          finally
            FBitmap.Unmap(Data);
          end;
        {$endif DXE2}
          FChanged := False;
        end;
      finally
        ZintDelete(Symbol);
      end;
  end;
end;

procedure TFBarcode.SetEmpty(const Value: string);
begin
end;

procedure TFBarcode.SetBackColor(Value: TAlphaColor);
begin
  if Value <> FBackColor then
  begin
    FBackColor := Value;
    FChanged := True;
  end;
end;

procedure TFBarcode.SetEncodingMode(Value: TEncodingMode);
begin
  if Value <> FEncodingMode then
  begin
    FEncodingMode := Value;
    FChanged := True;
  end;
end;

procedure TFBarcode.SetForeColor(Value: TAlphaColor);
begin
  if Value <> FForeColor then
  begin
    FForeColor := Value;
    FChanged := True;
  end;
end;

procedure TFBarcode.SetFontSize(Value: Integer);
begin
  if Value <> FFontSize then
  begin
    if (Value < 0) or (Value > 100) then
      raise EInvalidOperation.CreateFmt(SPropertyOutOfRange, [Self.Classname]);

    FFontSize := Value;
    FChanged := True;
  end;
end;

procedure TFBarcode.SetHeight(Value: Single);
begin
  if Value <> FHeight then
  begin
//    if (Value < 0.0) or (Value > 2000.0) then
//      raise EInvalidOperation.CreateFmt(SPropertyOutOfRange, [Self.Classname]);

    FHeight := Value;
    FChanged := True;
  end;
end;

procedure TFBarcode.SetHeightPerRow(Value: Boolean);
begin
  if Value <> FHeightPerRow then
  begin
    FHeightPerRow := Value;
    FChanged := True;
  end;
end;

procedure TFBarcode.SetFastMode(Value: Boolean);
begin
  if Value <> FFastMode then
  begin
    FFastMode := Value;
    FChanged := True;
  end;
end;

procedure TFBarcode.SetInputCheck(Value: Boolean);
begin
  if Value <> FInputCheck then
  begin
    FInputCheck := Value;
    FChanged := True;
  end;
end;

procedure TFBarcode.SetInputEscape(Value: Boolean);
begin
  if Value <> FInputEscape then
  begin
    FInputEscape := Value;
    FChanged := True;
  end;
end;

procedure TFBarcode.SetInputParentheses(Value: Boolean);
begin
  if Value <> FInputParentheses then
  begin
    FInputParentheses := Value;
    FChanged := True;
  end;
end;

procedure TFBarcode.SetInputMode(Value: TInputMode);
begin
  if Value <> FInputMode then
  begin
    FInputMode := Value;
    FChanged := True;
  end;
end;

procedure TFBarcode.SetColumns(Value: Integer);
begin
  if Value <> FColumns then
  begin
    if (Value < 0) or (Value > 200) then
      raise EInvalidOperation.CreateFmt(SPropertyOutOfRange, [Self.Classname]);

    FColumns := Value;
    FChanged := True;
  end;
end;

procedure TFBarcode.SetMask(Value: Integer);
begin
  if Value <> FMask then
  begin
    if (Value < -1) or (Value > 7) then
      raise EInvalidOperation.CreateFmt(SPropertyOutOfRange, [Self.Classname]);

    FMask := Value;
    FChanged := True;
  end;
end;

procedure TFBarcode.SetSeparatorHeight(Value: Integer);
begin
  if Value <> FSeparatorHeight then
  begin
//    if (Value < 0) or (Value > 4) then
//      raise EInvalidOperation.CreateFmt(SPropertyOutOfRange, [Self.Classname]);

    FSeparatorHeight := Value;
    FChanged := True;
  end;
end;

procedure TFBarcode.SetSymbolVersion(Value: Integer);
begin
  if Value <> FSymbolVersion then
  begin
    if (Value < 0) or (Value > 84) then
      raise EInvalidOperation.CreateFmt(SPropertyOutOfRange, [Self.Classname]);

    FSymbolVersion := Value;
    FChanged := True;
  end;
end;

procedure TfBarcode.SetQuietZones(Value: TQuietZones);
begin
  if Value <> FQuietZones then
  begin
    FQuietZones := Value;
    FChanged := True;
  end;
end;

procedure TFBarcode.SetRotation(Value: Integer);
begin
  if Value <> FRotation then
  begin
    FRotation := Value;
    FChanged := True;
  end;
end;

procedure TFBarcode.SetRows(Value: Integer);
begin
  if Value <> FRows then
  begin
//    if (Value < 0) or (Value >= 200) then
//      raise EInvalidOperation.CreateFmt(SPropertyOutOfRange, [Self.Classname]);

    FRows := Value;
    FChanged := True;
  end;
end;

procedure TfBarcode.SetGuardDescent(Value: Single);
begin
  if Value <> FGuardDescent then
  begin
//    if (Value < 0.0) or (Value > 50.0) then
//      raise EInvalidOperation.CreateFmt(SPropertyOutOfRange, [Self.Classname]);

    FGuardDescent := Value;
    FChanged := True;
  end;
end;

procedure TFBarcode.SetScale(Value: Single);
begin
  if Value <> FScale then
  begin
//    if (Value <= 0.0) or (Value > 100.0) then
//      raise EInvalidOperation.CreateFmt(SPropertyOutOfRange, [Self.Classname]);

    FScale := Value;
    FChanged := True;
  end;
end;

procedure TFBarcode.SetSecurityLevel(Value: TSecurityLevel);
begin
  if Value <> FSecurityLevel then
  begin
    FSecurityLevel := Value;
    FChanged := True;
  end;
end;

procedure TFBarcode.SetShowText(Value: Boolean);
begin
  if Value <> FShowText then
  begin
    FShowText := Value;
    FChanged := True;
  end;
end;

procedure TFBarcode.SetSymbology(Value: TSymbology);
begin
  if Value <> FSymbology then
  begin
    FSymbology := Value;
    FChanged := True;
  end;
end;

procedure TFBarcode.SetSymbologyName(const Value: string);
var NewSymbology: TSymbology;
begin
  if Value <> SymbologyName then
  begin
    Check(FindSymbology(Value, NewSymbology), SSymbologyNotFound);
    Symbology := NewSymbology;
  end;
end;

procedure TFBarcode.SetInputText(const Value: string);
begin
  if Value <> FInputText then
  begin
    FInputText := Value;
    FChanged := True;
  end;
end;

procedure TFBarcode.SetPrimaryMessage(const Value: string);
begin
  if Value <> FPrimaryMessage then
  begin
    FPrimaryMessage := Value;
    FChanged := True;
  end;
end;

procedure TFBarcode.SetOutputOptions(Value: TOutputOptions);
begin
  if Value <> FOutputOptions then
  begin
    FOutputOptions := Value;
    FChanged := True;
  end;
end;

procedure TFBarcode.SetBorderWidth(Value: Integer);
begin
  if Value <> FBorderWidth then
  begin
//    if (Value < 0) or (Value > 100) then
//      raise EInvalidOperation.CreateFmt(SPropertyOutOfRange, [Self.Classname]);

    FBorderWidth := Value;
    FChanged := True;
  end;
end;

procedure TFBarcode.SetDataMatrix(Value: TDataMatrix);
begin
  if Value <> FDataMatrix then
  begin
    FDataMatrix := Value;
    FChanged := True;
  end;
end;

procedure TFBarcode.SetDotSize(Value: Single);
begin
  if Value <> FDotSize then
  begin
//    if (Value < 0.0) or (Value > 20.0) then
//      raise EInvalidOperation.CreateFmt(SPropertyOutOfRange, [Self.Classname]);

    FDotSize := Value;
    FChanged := True;
  end;
end;

procedure TFBarcode.SetWhiteSpaceHeight(Value: Integer);
begin
  if Value <> FWhiteSpaceHeight then
  begin
//    if (Value < 0) or (Value > 100) then
//      raise EInvalidOperation.CreateFmt(SPropertyOutOfRange, [Self.Classname]);

    FWhiteSpaceHeight := Value;
    FChanged := True;
  end;
end;

procedure TFBarcode.SetWhiteSpaceWidth(Value: Integer);
begin
  if Value <> FWhiteSpaceWidth then
  begin
//    if (Value < 0) or (Value > 100) then
//      raise EInvalidOperation.CreateFmt(SPropertyOutOfRange, [Self.Classname]);

    FWhiteSpaceWidth := Value;
    FChanged := True;
  end;
end;

function TFBarcode.GetVersion: Integer;
begin
  LoadLibrary;
  Result := ZintVersion;
end;

function TFBarcode.GetCapabilities: TCapabilities;
var Cap: Integer;
begin
  LoadLibrary;
  Cap := ZintCap(EncodeSymbology(Symbology),
    ZINT_CAP_HRT or
    ZINT_CAP_STACKABLE or
    ZINT_CAP_EXTENDABLE or
    ZINT_CAP_COMPOSITE or
    ZINT_CAP_ECI or
    ZINT_CAP_GS1 or
    ZINT_CAP_DOTTY or
    ZINT_CAP_QUIET_ZONES or
    ZINT_CAP_FIXED_RATIO or
    ZINT_CAP_READER_INIT or
    ZINT_CAP_FULL_MULTIBYTE or
    ZINT_CAP_MASK or
    ZINT_CAP_STRUCTAPP or
    ZINT_CAP_COMPLIANT_HEIGHT);

  Result := [];
  if (Cap and ZINT_CAP_HRT) <> 0 then
    Result := Result + [caHumanReadable];
  if (Cap and ZINT_CAP_STACKABLE) <> 0 then
    Result := Result + [caStackable];
  if (Cap and ZINT_CAP_EXTENDABLE) <> 0 then
    Result := Result + [caExtendable];
  if (Cap and ZINT_CAP_COMPOSITE) <> 0 then
    Result := Result + [caComposite];
  if (Cap and ZINT_CAP_ECI) <> 0 then
    Result := Result + [caECI];
  if (Cap and ZINT_CAP_GS1) <> 0 then
    Result := Result + [caGS1];
  if (Cap and ZINT_CAP_DOTTY) <> 0 then
    Result := Result + [caDotty];
  if (Cap and ZINT_CAP_QUIET_ZONES) <> 0 then
    Result := Result + [caQuietZones];
  if (Cap and ZINT_CAP_FIXED_RATIO) <> 0 then
    Result := Result + [caFixedRatio];
  if (Cap and ZINT_CAP_READER_INIT) <> 0 then
    Result := Result + [caReaderInit];
  if (Cap and ZINT_CAP_FULL_MULTIBYTE) <> 0 then
    Result := Result + [caMultiByte];
  if (Cap and ZINT_CAP_MASK) <> 0 then
    Result := Result + [caMask];
  if (Cap and ZINT_CAP_STRUCTAPP) <> 0 then
    Result := Result + [caStructuredAppend];
  if (Cap and ZINT_CAP_COMPLIANT_HEIGHT) <> 0 then
    Result := Result + [caCompliantHeight];
end;

// Zint library

function LoadedLibrary: Boolean;
begin
{$ifdef STATIC_LIBRARY}
  Result := True;
{$else}
  Result := ZintLibrary <> 0;
{$endif STATIC_LIBRARY}
end;

procedure UnloadLibrary;
begin
{$ifndef STATIC_LIBRARY}
  if LoadedLibrary then
  begin
    FreeLibrary(ZintLibrary);
    ZintLibrary := 0;
  end;
{$endif STATIC_LIBRARY}
end;

{$ifndef STATIC_LIBRARY}
procedure CheckLoadLibrary(const Name: string; var Handle: HMODULE);
begin
  Handle := SafeLoadLibrary(PChar(Name));
  if Handle = 0 then
    raise EBarcodeError.Create(SysErrorMessage(GetLastError) + ': ' + Name);
end;

function CheckGetProcAddress(const Name: string): Pointer;
var ErrorMessage: string;
begin
  Result := GetProcAddress(ZintLibrary, PChar(Name));
  if Result = nil then
  begin
    ErrorMessage := SysErrorMessage(GetLastError) + ': ' + Name;
    UnloadLibrary;
    raise EBarcodeError.Create(ErrorMessage);
  end;
end;

function GetLibraryExtension: string;
begin
{$ifdef MSWINDOWS}
   Result := 'dll';
{$endif MSWINDOWS}

{$ifdef MACOS} // includes IOS
   Result := 'dylib';
{$endif MACOS}
end;

function GetLibraryPath(const Name: string): string;
begin
  Result := Name + '.' + GetLibraryExtension;
end;
{$endif STATIC_LIBRARY}

{$IFDEF TRIAL}
var WasTrial: Boolean;
{$ENDIF TRIAL}

procedure LoadLibrary;
begin
{$ifndef STATIC_LIBRARY}
  if not LoadedLibrary then
  begin
{$endif STATIC_LIBRARY}

    {$IFDEF TRIAL}
    if not WasTrial then
    begin
      WasTrial := True;
      ShowMessage(
        'Barcode for FireMonkey, Copyright (c) 2014-2022 WINSOFT' + #13#10#13#10 +
        'A trial version of Barcode component started.' + #13#10#13#10 +
        'Please note that trial version is supposed to be used for evaluation only. ' +
        'If you wish to distribute Barcode component as part of your application, ' +
        'you must register from website at https://www.winsoft.sk.' + #13#10#13#10 +
        'Thank you for trialing Barcode component.');
    end;
    {$ENDIF TRIAL}

{$ifndef STATIC_LIBRARY}
    if ZintLibraryName = '' then
      ZintLibraryName := GetLibraryPath({$ifdef MSWINDOWS} 'zint' {$else} 'libzint' {$endif MSWINDOWS});
    CheckLoadLibrary(ZintLibraryName, ZintLibrary);

    ZintCreate := CheckGetProcAddress('ZBarcode_Create');
    ZintClear := CheckGetProcAddress('ZBarcode_Clear');
    ZintDelete := CheckGetProcAddress('ZBarcode_Delete');
    ZintEncode := CheckGetProcAddress('ZBarcode_Encode');
    ZintEncodeFile := CheckGetProcAddress('ZBarcode_Encode_File');
    ZintPrint := CheckGetProcAddress('ZBarcode_Print');
    ZintEncodeAndPrint := CheckGetProcAddress('ZBarcode_Encode_and_Print');
    ZintEncodeFileAndPrint := CheckGetProcAddress('ZBarcode_Encode_File_and_Print');
    ZintBuffer := CheckGetProcAddress('ZBarcode_Buffer');
    ZintEncodeAndBuffer := CheckGetProcAddress('ZBarcode_Encode_and_Buffer');
    ZintEncodeFileAndBuffer := CheckGetProcAddress('ZBarcode_Encode_File_and_Buffer');
    ZintBufferVector := CheckGetProcAddress('ZBarcode_Buffer_Vector');
    ZintEncodeAndBufferVector := CheckGetProcAddress('ZBarcode_Encode_and_Buffer_Vector');
    ZintEncodeFileAndBufferVector := CheckGetProcAddress('ZBarcode_Encode_File_and_Buffer_Vector');
    ZintValidID := CheckGetProcAddress('ZBarcode_ValidID');
    ZintBarcodeName := CheckGetProcAddress('ZBarcode_BarcodeName');
    ZintCap := CheckGetProcAddress('ZBarcode_Cap');
    ZintVersion := CheckGetProcAddress('ZBarcode_Version');
  end;
{$endif STATIC_LIBRARY}
end;

end.