//Copyright (c) 2019 by Jason Southwell // //Permission is hereby granted, free of charge, to any person obtaining a copy //of this software and associated documentation files (the "Software"), to deal //in the Software without restriction, including without limitation the rights //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell //copies of the Software, and to permit persons to whom the Software is //furnished to do so, subject to the following conditions: // //The above copyright notice and this permission notice shall be included in all //copies or substantial portions of the Software. // //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE //SOFTWARE. unit qr.code; interface uses System.SysUtils, System.Classes, System.Generics.Collections, System.Types; {$SCOPEDENUMS ON} type TQRMode = (Numeric, AlphaNumeric, Byte, Kanji); TErrorCorrectionLevel = (Auto, Low, Medium, Quartile, High); TVersion = ( Auto, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40); TMask = (m0, m1, m2, m3, m4, m5, m6, m7, Auto); TPaintHandler = reference to procedure(Width, Height : integer; BlackRects : TArray); TOnStatusHandler = reference to procedure(const Msg : String); EQREncodeException = Exception; TQRCode = class(TPersistent) strict private type TBlock = TArray; TGroup = TArray; TFinderPosition = (TopLeft, TopRight, BottomLeft); TCodeWordField = (DataCodewordCount, ECCodewordsPerBlock, BlocksInGroup1Count, DataCodewordsInGroup1BlockCount, BlocksInGroup2Count, DataCodewordsInGroup2BlockCount); TCodeWordFields = Array[TCodeWordField] of integer; TCodeWordRequirements = record Low : TCodeWordFields; Medium : TCodeWordFields; Quartile : TCodeWordFields; High : TCodeWordFields; end; TCapacities = record Low : Array[TQRMode.Numeric..TQRMode.Kanji] of Integer; Medium : Array[TQRMode.Numeric..TQRMode.Kanji] of Integer; Quartile : Array[TQRMode.Numeric..TQRMode.Kanji] of Integer; High : Array[TQRMode.Numeric..TQRMode.Kanji] of Integer; end; TRectHelper = record helper for TRect function IntersectsWithRect(const R : TRect) : boolean; function IntersectsWithPoint(const pt : TPoint) : boolean; end; TArrayHelper = class strict private class procedure NextCombo(Prefix, Source: TArray; Count: Cardinal; Result: TArray>; var ResultIdx: Cardinal); static; public class function AdvanceArray(Source: TArray; idx: integer): TArray; class function Combination(SourceArray : TArray; SubsetSize : Cardinal) : TArray>; end; strict private class var FVerCapacities : Array[TVersion.v1..TVersion.v40] of TCapacities; class var FCodeWordRequirements : Array[TVersion.v1..TVersion.v40] of TCodeWordRequirements; strict private FOnStatus: TOnStatusHandler; FPenaltyScores: TArray>; FMaskInUse: TMask; FVersion: TVersion; FVersionInUse : TVersion; FMode: TQRMode; FECL: TErrorCorrectionLevel; FECLInUse : TErrorCorrectionLevel; FData: TArray; FUpdateDepth : integer; FCodeWords : TArray; FReservedAreas : TList; FBitsLen : integer; FBitsPos : integer; FBits : TArray; FLogTable : TArray; FAntilogTable : TArray; FModules : TArray>; FPixelsPerModule: Integer; FDataBits : string; FMask : TMask; FRenderSize: integer; FOnPaint: TPaintHandler; procedure SetOnPaint(const Value: TPaintHandler); procedure SetPixelsPerModule(const Value: integer); procedure SetRenderSize(const Value: integer); function GetText: string; procedure SetData(const Value: TArray); procedure SetECL(const Value: TErrorCorrectionLevel); procedure SetText(const Value: string); procedure SetVersion(const Value: TVersion); procedure SetMask(const Value: TMask); function Pow(i, k: Integer): Integer; function BinaryToDecimal(Str: string): Integer; function DecimalToBinary(value, digits: integer): string; function DataCodewordCount : integer; function GetSize : integer; function FinderLocation(pos : TFinderPosition) : TPoint; procedure CheckBitsPos; function DetermineQRMode : TQRMode; procedure WriteMode; procedure WriteLength; function MinVersion : TVersion; function MaxECL : TErrorCorrectionLevel; procedure WriteBits(const s : string); procedure WriteBit(b : boolean); procedure CalculateModules; procedure EncodeNumeric; procedure EncodeAlphaNumeric; procedure EncodeByte; procedure EncodeKanji; function ReadCodeword(var Pos : integer) : Byte; function CodewordCount : integer; function OutputAsString : string; procedure DrawModules; procedure PaintQRCode; procedure AddReservedArea(rect : TRect); protected procedure UpdateCode; virtual; procedure SetStatus(const Msg : string); virtual; public destructor Destroy; override; constructor Create; virtual; class constructor Create; property OnPaint : TPaintHandler read FOnPaint write SetOnPaint; property OnStatus : TOnStatusHandler read FOnStatus write FOnStatus; property Mode : TQRMode read FMode; property VersionInUse : TVersion read FVersionInUse; property Data : TArray read FData write SetData; property ECLInUse : TErrorCorrectionLEvel read FECLInUse; property DataBits : string read FDataBits; property MaskInUse : TMask read FMaskInUse; property Size : integer read GetSize; property PenaltyScores : TArray> Read FPenaltyScores; procedure BeginUpdate; procedure EndUpdate; procedure Redraw; property Codewords : TArray read FCodeWords; published property Version : TVersion read FVersion write SetVersion; property Text : string read GetText write SetText; property ECL : TErrorCorrectionLevel read FECL write SetECL; property Mask : TMask read FMask write SetMask; property RenderSize : integer read FRenderSize write SetRenderSize; property PixelsPerModule : integer read FPixelsPerModule write SetPixelsPerModule; end; implementation uses System.Math, qr.rs; const RemainderBits : Array[TVersion.v1..TVersion.v40] of Byte = ( 0, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0 ); AlphaEncoding : Array[0..44] of char = ( '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ' ', '$', '%', '*', '+', '-', '.', '/', ':' ); { TQRCode } procedure TQRCode.AddReservedArea(rect: TRect); begin FReservedAreas.Add(rect); end; procedure TQRCode.BeginUpdate; begin inc(FUpdateDepth); end; function TQRCode.BinaryToDecimal(Str: string): Integer; var Len, i: Integer; begin Len := Length(Str); Result := 0; for i:=1 to Len do if (Str[i]='0') or (Str[i]='1') then Result := Result + Pow(2, Len-i) * StrToInt(Str[i]) else raise EQREncodeException.Create('"'+str+'" is not a binary number'); end; procedure TQRCode.CheckBitsPos; begin if FBitsLen-FBitsPos < 1024 then begin inc(FBitsLen, 4096); SetLength(FBits, FBitsLen); end; end; function TQRCode.CodewordCount: integer; begin Result := FBitsPos div 8; end; class constructor TQRCode.Create; procedure AssignCodeWords(Elim : integer; Level : TErrorCorrectionLevel; DCC, ECCPerBlock, BG1, DG1C, BG2, DG2C : integer); overload; begin case Level of TErrorCorrectionLevel.Low: begin FCodeWordRequirements[TVersion(Elim)].Low[TCodeWordField.DataCodewordCount] := DCC; FCodeWordRequirements[TVersion(Elim)].Low[TCodeWordField.ECCodewordsPerBlock] := ECCPerBlock; FCodeWordRequirements[TVersion(Elim)].Low[TCodeWordField.BlocksInGroup1Count] := BG1; FCodeWordRequirements[TVersion(Elim)].Low[TCodeWordField.DataCodewordsInGroup1BlockCount] := DG1C; FCodeWordRequirements[TVersion(Elim)].Low[TCodeWordField.BlocksInGroup2Count] := BG2; FCodeWordRequirements[TVersion(Elim)].Low[TCodeWordField.DataCodewordsInGroup2BlockCount] := DG2C; end; TErrorCorrectionLevel.Medium: begin FCodeWordRequirements[TVersion(Elim)].Medium[TCodeWordField.DataCodewordCount] := DCC; FCodeWordRequirements[TVersion(Elim)].Medium[TCodeWordField.ECCodewordsPerBlock] := ECCPerBlock; FCodeWordRequirements[TVersion(Elim)].Medium[TCodeWordField.BlocksInGroup1Count] := BG1; FCodeWordRequirements[TVersion(Elim)].Medium[TCodeWordField.DataCodewordsInGroup1BlockCount] := DG1C; FCodeWordRequirements[TVersion(Elim)].Medium[TCodeWordField.BlocksInGroup2Count] := BG2; FCodeWordRequirements[TVersion(Elim)].Medium[TCodeWordField.DataCodewordsInGroup2BlockCount] := DG2C; end; TErrorCorrectionLevel.Quartile: begin FCodeWordRequirements[TVersion(Elim)].Quartile[TCodeWordField.DataCodewordCount] := DCC; FCodeWordRequirements[TVersion(Elim)].Quartile[TCodeWordField.ECCodewordsPerBlock] := ECCPerBlock; FCodeWordRequirements[TVersion(Elim)].Quartile[TCodeWordField.BlocksInGroup1Count] := BG1; FCodeWordRequirements[TVersion(Elim)].Quartile[TCodeWordField.DataCodewordsInGroup1BlockCount] := DG1C; FCodeWordRequirements[TVersion(Elim)].Quartile[TCodeWordField.BlocksInGroup2Count] := BG2; FCodeWordRequirements[TVersion(Elim)].Quartile[TCodeWordField.DataCodewordsInGroup2BlockCount] := DG2C; end; TErrorCorrectionLevel.High: begin FCodeWordRequirements[TVersion(Elim)].High[TCodeWordField.DataCodewordCount] := DCC; FCodeWordRequirements[TVersion(Elim)].High[TCodeWordField.ECCodewordsPerBlock] := ECCPerBlock; FCodeWordRequirements[TVersion(Elim)].High[TCodeWordField.BlocksInGroup1Count] := BG1; FCodeWordRequirements[TVersion(Elim)].High[TCodeWordField.DataCodewordsInGroup1BlockCount] := DG1C; FCodeWordRequirements[TVersion(Elim)].High[TCodeWordField.BlocksInGroup2Count] := BG2; FCodeWordRequirements[TVersion(Elim)].High[TCodeWordField.DataCodewordsInGroup2BlockCount] := DG2C; end; end; end; procedure AssignCodeWords(Elim : integer; Level : TErrorCorrectionLevel; DCC, ECCPerBlock, BG1, DG1C : integer); overload; begin AssignCodeWords(Elim, Level, DCC, ECCPerBlock, BG1, DG1C, 0, 0); end; procedure AssignVerCapacity(Elim : integer; Level : TErrorCorrectionLevel; Num, Alph, Byt, Kanj : integer); begin case Level of TErrorCorrectionLevel.Low: begin FVerCapacities[TVersion(Elim)].Low[TQRMode.Numeric] := Num; FVerCapacities[TVersion(Elim)].Low[TQRMode.AlphaNumeric] := Alph; FVerCapacities[TVersion(Elim)].Low[TQRMode.Byte] := Byt; FVerCapacities[TVersion(Elim)].Low[TQRMode.Kanji] := Kanj; end; TErrorCorrectionLevel.Medium: begin FVerCapacities[TVersion(Elim)].Medium[TQRMode.Numeric] := Num; FVerCapacities[TVersion(Elim)].Medium[TQRMode.AlphaNumeric] := Alph; FVerCapacities[TVersion(Elim)].Medium[TQRMode.Byte] := Byt; FVerCapacities[TVersion(Elim)].Medium[TQRMode.Kanji] := Kanj; end; TErrorCorrectionLevel.Quartile: begin FVerCapacities[TVersion(Elim)].Quartile[TQRMode.Numeric] := Num; FVerCapacities[TVersion(Elim)].Quartile[TQRMode.AlphaNumeric] := Alph; FVerCapacities[TVersion(Elim)].Quartile[TQRMode.Byte] := Byt; FVerCapacities[TVersion(Elim)].Quartile[TQRMode.Kanji] := Kanj; end; TErrorCorrectionLevel.High: begin FVerCapacities[TVersion(Elim)].High[TQRMode.Numeric] := Num; FVerCapacities[TVersion(Elim)].High[TQRMode.AlphaNumeric] := Alph; FVerCapacities[TVersion(Elim)].High[TQRMode.Byte] := Byt; FVerCapacities[TVersion(Elim)].High[TQRMode.Kanji] := Kanj; end; end; end; begin AssignVerCapacity(1 ,TErrorCorrectionLevel.Low ,41 ,25 ,17 ,10); AssignVerCapacity(1 ,TErrorCorrectionLevel.Medium, 34 , 20 , 14 , 8); AssignVerCapacity(1 ,TErrorCorrectionLevel.Quartile, 27 , 16 , 11 , 7); AssignVerCapacity(1 ,TErrorCorrectionLevel.High, 17 , 10 , 7, 4); AssignVerCapacity(2 ,TErrorCorrectionLevel.Low ,77 ,47 ,32 ,20); AssignVerCapacity(2 ,TErrorCorrectionLevel.Medium, 63 , 38 , 26 , 16); AssignVerCapacity(2 ,TErrorCorrectionLevel.Quartile, 48 , 29 , 20 , 12); AssignVerCapacity(2 ,TErrorCorrectionLevel.High, 34 , 20 , 14 , 8); AssignVerCapacity(3 ,TErrorCorrectionLevel.Low ,127 ,77 ,53 ,32); AssignVerCapacity(3 ,TErrorCorrectionLevel.Medium, 101, 61 , 42 , 26); AssignVerCapacity(3 ,TErrorCorrectionLevel.Quartile, 77 , 47 , 32 , 20); AssignVerCapacity(3 ,TErrorCorrectionLevel.High, 58 , 35 , 24 , 15); AssignVerCapacity(4 ,TErrorCorrectionLevel.Low ,187 ,114 ,78 ,48); AssignVerCapacity(4 ,TErrorCorrectionLevel.Medium, 149, 90 , 62 , 38); AssignVerCapacity(4 ,TErrorCorrectionLevel.Quartile, 111, 67 , 46 , 28); AssignVerCapacity(4 ,TErrorCorrectionLevel.High, 82 , 50 , 34 , 21); AssignVerCapacity(5 ,TErrorCorrectionLevel.Low ,255 ,154 ,106 ,65); AssignVerCapacity(5 ,TErrorCorrectionLevel.Medium, 202, 122, 84 , 52); AssignVerCapacity(5 ,TErrorCorrectionLevel.Quartile, 144, 87 , 60 , 37); AssignVerCapacity(5 ,TErrorCorrectionLevel.High, 106, 64 , 44 , 27); AssignVerCapacity(6 ,TErrorCorrectionLevel.Low ,322 ,195 ,134 ,82); AssignVerCapacity(6 ,TErrorCorrectionLevel.Medium, 255, 154, 106, 65); AssignVerCapacity(6 ,TErrorCorrectionLevel.Quartile, 178, 108, 74 , 45); AssignVerCapacity(6 ,TErrorCorrectionLevel.High, 139, 84 , 58 , 36); AssignVerCapacity(7 ,TErrorCorrectionLevel.Low ,370 ,224 ,154 ,95); AssignVerCapacity(7 ,TErrorCorrectionLevel.Medium, 293, 178, 122, 75); AssignVerCapacity(7 ,TErrorCorrectionLevel.Quartile, 207, 125, 86 , 53); AssignVerCapacity(7 ,TErrorCorrectionLevel.High, 154, 93 , 64 , 39); AssignVerCapacity(8 ,TErrorCorrectionLevel.Low ,461 ,279 ,192 ,118); AssignVerCapacity(8 ,TErrorCorrectionLevel.Medium, 365, 221, 152, 93); AssignVerCapacity(8 ,TErrorCorrectionLevel.Quartile, 259, 157, 108, 66); AssignVerCapacity(8 ,TErrorCorrectionLevel.High, 202, 122, 84 , 52); AssignVerCapacity(9 ,TErrorCorrectionLevel.Low ,552 ,335 ,230 ,141); AssignVerCapacity(9 ,TErrorCorrectionLevel.Medium, 432, 262, 180, 111); AssignVerCapacity(9 ,TErrorCorrectionLevel.Quartile, 312, 189, 130, 80); AssignVerCapacity(9 ,TErrorCorrectionLevel.High, 235, 143, 98 , 60); AssignVerCapacity(10 ,TErrorCorrectionLevel.Low ,652 ,395 ,271 ,167); AssignVerCapacity(10 ,TErrorCorrectionLevel.Medium, 513, 311, 213, 131); AssignVerCapacity(10 ,TErrorCorrectionLevel.Quartile, 364, 221, 151, 93); AssignVerCapacity(10 ,TErrorCorrectionLevel.High, 288, 174, 119, 74); AssignVerCapacity(11 ,TErrorCorrectionLevel.Low ,772 ,468 ,321 ,198); AssignVerCapacity(11 ,TErrorCorrectionLevel.Medium, 604, 366, 251, 155); AssignVerCapacity(11 ,TErrorCorrectionLevel.Quartile, 427, 259, 177, 109); AssignVerCapacity(11 ,TErrorCorrectionLevel.High, 331, 200, 137, 85); AssignVerCapacity(12 ,TErrorCorrectionLevel.Low ,883 ,535 ,367 ,226); AssignVerCapacity(12 ,TErrorCorrectionLevel.Medium, 691, 419, 287, 177); AssignVerCapacity(12 ,TErrorCorrectionLevel.Quartile, 489, 296, 203, 125); AssignVerCapacity(12 ,TErrorCorrectionLevel.High, 374, 227, 155, 96); AssignVerCapacity(13 ,TErrorCorrectionLevel.Low ,1022 ,619 ,425 ,262); AssignVerCapacity(13 ,TErrorCorrectionLevel.Medium, 796, 483, 331, 204); AssignVerCapacity(13 ,TErrorCorrectionLevel.Quartile, 580, 352, 241, 149); AssignVerCapacity(13 ,TErrorCorrectionLevel.High, 427, 259, 177, 109); AssignVerCapacity(14 ,TErrorCorrectionLevel.Low ,1101 ,667 ,458 ,282); AssignVerCapacity(14 ,TErrorCorrectionLevel.Medium, 871, 528, 362, 223); AssignVerCapacity(14 ,TErrorCorrectionLevel.Quartile, 621, 376, 258, 159); AssignVerCapacity(14 ,TErrorCorrectionLevel.High, 468, 283, 194, 120); AssignVerCapacity(15 ,TErrorCorrectionLevel.Low ,1250 ,758 ,520 ,320); AssignVerCapacity(15 ,TErrorCorrectionLevel.Medium, 991, 600, 412, 254); AssignVerCapacity(15 ,TErrorCorrectionLevel.Quartile, 703, 426, 292, 180); AssignVerCapacity(15 ,TErrorCorrectionLevel.High, 530, 321, 220, 136); AssignVerCapacity(16 ,TErrorCorrectionLevel.Low ,1408 ,854 ,586 ,361); AssignVerCapacity(16 ,TErrorCorrectionLevel.Medium, 1082 , 656, 450, 277); AssignVerCapacity(16 ,TErrorCorrectionLevel.Quartile, 775, 470, 322, 198); AssignVerCapacity(16 ,TErrorCorrectionLevel.High, 602, 365, 250, 154); AssignVerCapacity(17 ,TErrorCorrectionLevel.Low ,1548 ,938 ,644 ,397); AssignVerCapacity(17 ,TErrorCorrectionLevel.Medium, 1212 , 734, 504, 310); AssignVerCapacity(17 ,TErrorCorrectionLevel.Quartile, 876, 531, 364, 224); AssignVerCapacity(17 ,TErrorCorrectionLevel.High, 674, 408, 280, 173); AssignVerCapacity(18 ,TErrorCorrectionLevel.Low ,1725 ,1046 ,718 ,442); AssignVerCapacity(18 ,TErrorCorrectionLevel.Medium, 1346 , 816, 560, 345); AssignVerCapacity(18 ,TErrorCorrectionLevel.Quartile, 948, 574, 394, 243); AssignVerCapacity(18 ,TErrorCorrectionLevel.High, 746, 452, 310, 191); AssignVerCapacity(19 ,TErrorCorrectionLevel.Low ,1903 ,1153 ,792 ,488); AssignVerCapacity(19 ,TErrorCorrectionLevel.Medium, 1500 , 909, 624, 384); AssignVerCapacity(19 ,TErrorCorrectionLevel.Quartile, 1063 , 644, 442, 272); AssignVerCapacity(19 ,TErrorCorrectionLevel.High, 813, 493, 338, 208); AssignVerCapacity(20 ,TErrorCorrectionLevel.Low ,2061 ,1249 ,858 ,528); AssignVerCapacity(20 ,TErrorCorrectionLevel.Medium, 1600 , 970, 666, 410); AssignVerCapacity(20 ,TErrorCorrectionLevel.Quartile, 1159 , 702, 482, 297); AssignVerCapacity(20 ,TErrorCorrectionLevel.High, 919, 557, 382, 235); AssignVerCapacity(21 ,TErrorCorrectionLevel.Low ,2232 ,1352 ,929 ,572); AssignVerCapacity(21 ,TErrorCorrectionLevel.Medium, 1708 , 1035 , 711, 438); AssignVerCapacity(21 ,TErrorCorrectionLevel.Quartile, 1224 , 742, 509, 314); AssignVerCapacity(21 ,TErrorCorrectionLevel.High, 969, 587, 403, 248); AssignVerCapacity(22 ,TErrorCorrectionLevel.Low ,2409 ,1460 ,1003 ,618); AssignVerCapacity(22 ,TErrorCorrectionLevel.Medium, 1872 , 1134 , 779, 480); AssignVerCapacity(22 ,TErrorCorrectionLevel.Quartile, 1358 , 823, 565, 348); AssignVerCapacity(22 ,TErrorCorrectionLevel.High, 1056 , 640, 439, 270); AssignVerCapacity(23 ,TErrorCorrectionLevel.Low ,2620 ,1588 ,1091 ,672); AssignVerCapacity(23 ,TErrorCorrectionLevel.Medium, 2059 , 1248 , 857, 528); AssignVerCapacity(23 ,TErrorCorrectionLevel.Quartile, 1468 , 890, 611, 376); AssignVerCapacity(23 ,TErrorCorrectionLevel.High, 1108 , 672, 461, 284); AssignVerCapacity(24 ,TErrorCorrectionLevel.Low ,2812 ,1704 ,1171 ,721); AssignVerCapacity(24 ,TErrorCorrectionLevel.Medium, 2188 , 1326 , 911, 561); AssignVerCapacity(24 ,TErrorCorrectionLevel.Quartile, 1588 , 963, 661, 407); AssignVerCapacity(24 ,TErrorCorrectionLevel.High, 1228 , 744, 511, 315); AssignVerCapacity(25 ,TErrorCorrectionLevel.Low ,3057 ,1853 ,1273 ,784); AssignVerCapacity(25 ,TErrorCorrectionLevel.Medium, 2395 , 1451 , 997, 614); AssignVerCapacity(25 ,TErrorCorrectionLevel.Quartile, 1718 , 1041 , 715, 440); AssignVerCapacity(25 ,TErrorCorrectionLevel.High, 1286 , 779, 535, 330); AssignVerCapacity(26 ,TErrorCorrectionLevel.Low ,3283 ,1990 ,1367 ,842); AssignVerCapacity(26 ,TErrorCorrectionLevel.Medium, 2544 , 1542 , 1059 , 652); AssignVerCapacity(26 ,TErrorCorrectionLevel.Quartile, 1804 , 1094 , 751, 462); AssignVerCapacity(26 ,TErrorCorrectionLevel.High, 1425 , 864, 593, 365); AssignVerCapacity(27 ,TErrorCorrectionLevel.Low ,3517 ,2132 ,1465 ,902); AssignVerCapacity(27 ,TErrorCorrectionLevel.Medium, 2701 , 1637 , 1125 , 692); AssignVerCapacity(27 ,TErrorCorrectionLevel.Quartile, 1933 , 1172 , 805, 496); AssignVerCapacity(27 ,TErrorCorrectionLevel.High, 1501 , 910, 625, 385); AssignVerCapacity(28 ,TErrorCorrectionLevel.Low ,3669 ,2223 ,1528 ,940); AssignVerCapacity(28 ,TErrorCorrectionLevel.Medium, 2857 , 1732 , 1190 , 732); AssignVerCapacity(28 ,TErrorCorrectionLevel.Quartile, 2085 , 1263 , 868, 534); AssignVerCapacity(28 ,TErrorCorrectionLevel.High, 1581 , 958, 658, 405); AssignVerCapacity(29 ,TErrorCorrectionLevel.Low ,3909 ,2369 ,1628 ,1002); AssignVerCapacity(29 ,TErrorCorrectionLevel.Medium, 3035 , 1839 , 1264 , 778); AssignVerCapacity(29 ,TErrorCorrectionLevel.Quartile, 2181 , 1322 , 908, 559); AssignVerCapacity(29 ,TErrorCorrectionLevel.High, 1677 , 1016 , 698, 430); AssignVerCapacity(30 ,TErrorCorrectionLevel.Low ,4158 ,2520 ,1732 ,1066); AssignVerCapacity(30 ,TErrorCorrectionLevel.Medium, 3289 , 1994 , 1370 , 843); AssignVerCapacity(30 ,TErrorCorrectionLevel.Quartile, 2358 , 1429 , 982, 604); AssignVerCapacity(30 ,TErrorCorrectionLevel.High, 1782 , 1080 , 742, 457); AssignVerCapacity(31 ,TErrorCorrectionLevel.Low ,4417 ,2677 ,1840 ,1132); AssignVerCapacity(31 ,TErrorCorrectionLevel.Medium, 3486 , 2113 , 1452 , 894); AssignVerCapacity(31 ,TErrorCorrectionLevel.Quartile, 2473 , 1499 , 1030 , 634); AssignVerCapacity(31 ,TErrorCorrectionLevel.High, 1897 , 1150 , 790, 486); AssignVerCapacity(32 ,TErrorCorrectionLevel.Low ,4686 ,2840 ,1952 ,1201); AssignVerCapacity(32 ,TErrorCorrectionLevel.Medium, 3693 , 2238 , 1538 , 947); AssignVerCapacity(32 ,TErrorCorrectionLevel.Quartile, 2670 , 1618 , 1112 , 684); AssignVerCapacity(32 ,TErrorCorrectionLevel.High, 2022 , 1226 , 842, 518); AssignVerCapacity(33 ,TErrorCorrectionLevel.Low ,4965 ,3009 ,2068 ,1273); AssignVerCapacity(33 ,TErrorCorrectionLevel.Medium, 3909 , 2369 , 1628 , 1002); AssignVerCapacity(33 ,TErrorCorrectionLevel.Quartile, 2805 , 1700 , 1168 , 719); AssignVerCapacity(33 ,TErrorCorrectionLevel.High, 2157 , 1307 , 898, 553); AssignVerCapacity(34 ,TErrorCorrectionLevel.Low ,5253 ,3183 ,2188 ,1347); AssignVerCapacity(34 ,TErrorCorrectionLevel.Medium, 4134 , 2506 , 1722 , 1060); AssignVerCapacity(34 ,TErrorCorrectionLevel.Quartile, 2949 , 1787 , 1228 , 756); AssignVerCapacity(34 ,TErrorCorrectionLevel.High, 2301 , 1394 , 958, 590); AssignVerCapacity(35 ,TErrorCorrectionLevel.Low ,5529 ,3351 ,2303 ,1417); AssignVerCapacity(35 ,TErrorCorrectionLevel.Medium, 4343 , 2632 , 1809 , 1113); AssignVerCapacity(35 ,TErrorCorrectionLevel.Quartile, 3081 , 1867 , 1283 , 790); AssignVerCapacity(35 ,TErrorCorrectionLevel.High, 2361 , 1431 , 983, 605); AssignVerCapacity(36 ,TErrorCorrectionLevel.Low ,5836 ,3537 ,2431 ,1496); AssignVerCapacity(36 ,TErrorCorrectionLevel.Medium, 4588 , 2780 , 1911 , 1176); AssignVerCapacity(36 ,TErrorCorrectionLevel.Quartile, 3244 , 1966 , 1351 , 832); AssignVerCapacity(36 ,TErrorCorrectionLevel.High, 2524 , 1530 , 1051 , 647); AssignVerCapacity(37 ,TErrorCorrectionLevel.Low ,6153 ,3729 ,2563 ,1577); AssignVerCapacity(37 ,TErrorCorrectionLevel.Medium, 4775 , 2894 , 1989 , 1224); AssignVerCapacity(37 ,TErrorCorrectionLevel.Quartile, 3417 , 2071 , 1423 , 876); AssignVerCapacity(37 ,TErrorCorrectionLevel.High, 2625 , 1591 , 1093 , 673); AssignVerCapacity(38 ,TErrorCorrectionLevel.Low ,6479 ,3927 ,2699 ,1661); AssignVerCapacity(38 ,TErrorCorrectionLevel.Medium, 5039 , 3054 , 2099 , 1292); AssignVerCapacity(38 ,TErrorCorrectionLevel.Quartile, 3599 , 2181 , 1499 , 923); AssignVerCapacity(38 ,TErrorCorrectionLevel.High, 2735 , 1658 , 1139 , 701); AssignVerCapacity(39 ,TErrorCorrectionLevel.Low ,6743 ,4087 ,2809 ,1729); AssignVerCapacity(39 ,TErrorCorrectionLevel.Medium, 5313 , 3220 , 2213 , 1362); AssignVerCapacity(39 ,TErrorCorrectionLevel.Quartile, 3791 , 2298 , 1579 , 972); AssignVerCapacity(39 ,TErrorCorrectionLevel.High, 2927 , 1774 , 1219 , 750); AssignVerCapacity(40 ,TErrorCorrectionLevel.Low ,7089 ,4296 ,2953 ,1817); AssignVerCapacity(40 ,TErrorCorrectionLevel.Medium, 5596 , 3391 , 2331 , 1435); AssignVerCapacity(40 ,TErrorCorrectionLevel.Quartile, 3993 , 2420 , 1663 , 1024); AssignVerCapacity(40 ,TErrorCorrectionLevel.High, 3057 , 1852 , 1273 , 784); AssignCodeWords(1, TErrorCorrectionLevel.Low, 19 ,7 ,1 ,19 ); AssignCodeWords(1, TErrorCorrectionLevel.Medium, 16 ,10 ,1 ,16 ); AssignCodeWords(1, TErrorCorrectionLevel.Quartile, 13 ,13 ,1 ,13 ); AssignCodeWords(1, TErrorCorrectionLevel.High, 9 ,17 ,1 ,9 ); AssignCodeWords(2, TErrorCorrectionLevel.Low, 34 ,10 ,1 ,34 ); AssignCodeWords(2, TErrorCorrectionLevel.Medium, 28 ,16 ,1 ,28 ); AssignCodeWords(2, TErrorCorrectionLevel.Quartile, 22 ,22 ,1 ,22 ); AssignCodeWords(2, TErrorCorrectionLevel.High, 16 ,28 ,1 ,16 ); AssignCodeWords(3, TErrorCorrectionLevel.Low, 55 ,15 ,1 ,55 ); AssignCodeWords(3, TErrorCorrectionLevel.Medium, 44 ,26 ,1 ,44 ); AssignCodeWords(3, TErrorCorrectionLevel.Quartile, 34 ,18 ,2 ,17 ); AssignCodeWords(3, TErrorCorrectionLevel.High, 26 ,22 ,2 ,13 ); AssignCodeWords(4, TErrorCorrectionLevel.Low, 80 ,20 ,1 ,80 ); AssignCodeWords(4, TErrorCorrectionLevel.Medium, 64 ,18 ,2 ,32 ); AssignCodeWords(4, TErrorCorrectionLevel.Quartile, 48 ,26 ,2 ,24 ); AssignCodeWords(4, TErrorCorrectionLevel.High, 36 ,16 ,4 ,9 ); AssignCodeWords(5, TErrorCorrectionLevel.Low, 108 ,26 ,1 ,108 ); AssignCodeWords(5, TErrorCorrectionLevel.Medium, 86 ,24 ,2 ,43 ); AssignCodeWords(5, TErrorCorrectionLevel.Quartile, 62 ,18 ,2 ,15 ,2 ,16 ); AssignCodeWords(5, TErrorCorrectionLevel.High, 46 ,22 ,2 ,11 ,2 ,12 ); AssignCodeWords(6, TErrorCorrectionLevel.Low, 136 ,18 ,2 ,68 ); AssignCodeWords(6, TErrorCorrectionLevel.Medium, 108 ,16 ,4 ,27 ); AssignCodeWords(6, TErrorCorrectionLevel.Quartile, 76 ,24 ,4 ,19 ); AssignCodeWords(6, TErrorCorrectionLevel.High, 60 ,28 ,4 ,15 ); AssignCodeWords(7, TErrorCorrectionLevel.Low, 156 ,20 ,2 ,78 ); AssignCodeWords(7, TErrorCorrectionLevel.Medium, 124 ,18 ,4 ,31 ); AssignCodeWords(7, TErrorCorrectionLevel.Quartile, 88 ,18 ,2 ,14 ,4 ,15 ); AssignCodeWords(7, TErrorCorrectionLevel.High, 66 ,26 ,4 ,13 ,1 ,14 ); AssignCodeWords(8, TErrorCorrectionLevel.Low, 194 ,24 ,2 ,97 ); AssignCodeWords(8, TErrorCorrectionLevel.Medium, 154 ,22 ,2 ,38 ,2 ,39 ); AssignCodeWords(8, TErrorCorrectionLevel.Quartile, 110 ,22 ,4 ,18 ,2 ,19 ); AssignCodeWords(8, TErrorCorrectionLevel.High, 86 ,26 ,4 ,14 ,2 ,15 ); AssignCodeWords(9, TErrorCorrectionLevel.Low, 232 ,30 ,2 ,116 ); AssignCodeWords(9, TErrorCorrectionLevel.Medium, 182 ,22 ,3 ,36 ,2 ,37 ); AssignCodeWords(9, TErrorCorrectionLevel.Quartile, 132 ,20 ,4 ,16 ,4 ,17 ); AssignCodeWords(9, TErrorCorrectionLevel.High, 100 ,24 ,4 ,12 ,4 ,13 ); AssignCodeWords(10, TErrorCorrectionLevel.Low, 274 ,18 ,2 ,68 ,2 ,69 ); AssignCodeWords(10, TErrorCorrectionLevel.Medium, 216 ,26 ,4 ,43 ,1 ,44 ); AssignCodeWords(10, TErrorCorrectionLevel.Quartile, 154 ,24 ,6 ,19 ,2 ,20 ); AssignCodeWords(10, TErrorCorrectionLevel.High, 122 ,28 ,6 ,15 ,2 ,16 ); AssignCodeWords(11, TErrorCorrectionLevel.Low, 324 ,20 ,4 ,81 ); AssignCodeWords(11, TErrorCorrectionLevel.Medium, 254 ,30 ,1 ,50 ,4 ,51 ); AssignCodeWords(11, TErrorCorrectionLevel.Quartile, 180 ,28 ,4 ,22 ,4 ,23 ); AssignCodeWords(11, TErrorCorrectionLevel.High, 140 ,24 ,3 ,12 ,8 ,13 ); AssignCodeWords(12, TErrorCorrectionLevel.Low, 370 ,24 ,2 ,92 ,2 ,93 ); AssignCodeWords(12, TErrorCorrectionLevel.Medium, 290 ,22 ,6 ,36 ,2 ,37 ); AssignCodeWords(12, TErrorCorrectionLevel.Quartile, 206 ,26 ,4 ,20 ,6 ,21 ); AssignCodeWords(12, TErrorCorrectionLevel.High, 158 ,28 ,7 ,14 ,4 ,15 ); AssignCodeWords(13, TErrorCorrectionLevel.Low, 428 ,26 ,4 ,107); AssignCodeWords(13, TErrorCorrectionLevel.Medium, 334 ,22 ,8 ,37 ,1 ,38 ); AssignCodeWords(13, TErrorCorrectionLevel.Quartile, 244 ,24 ,8 ,20 ,4 ,21 ); AssignCodeWords(13, TErrorCorrectionLevel.High, 180 ,22 ,12 ,11 ,4 ,12 ); AssignCodeWords(14, TErrorCorrectionLevel.Low, 461 ,30 ,3 ,115 ,1 ,116 ); AssignCodeWords(14, TErrorCorrectionLevel.Medium, 365 ,24 ,4 ,40 ,5 ,41 ); AssignCodeWords(14, TErrorCorrectionLevel.Quartile, 261 ,20 ,11 ,16 ,5 ,17 ); AssignCodeWords(14, TErrorCorrectionLevel.High, 197 ,24 ,11 ,12 ,5 ,13 ); AssignCodeWords(15, TErrorCorrectionLevel.Low, 523 ,22 ,5 ,87 ,1 ,88 ); AssignCodeWords(15, TErrorCorrectionLevel.Medium, 415 ,24 ,5 ,41 ,5 ,42 ); AssignCodeWords(15, TErrorCorrectionLevel.Quartile, 295 ,30 ,5 ,24 ,7 ,25 ); AssignCodeWords(15, TErrorCorrectionLevel.High, 223 ,24 ,11 ,12 ,7 ,13 ); AssignCodeWords(16, TErrorCorrectionLevel.Low, 589 ,24 ,5 ,98 ,1 ,99 ); AssignCodeWords(16, TErrorCorrectionLevel.Medium, 453 ,28 ,7 ,45 ,3 ,46 ); AssignCodeWords(16, TErrorCorrectionLevel.Quartile, 325 ,24 ,15 ,19 ,2 ,20 ); AssignCodeWords(16, TErrorCorrectionLevel.High, 253 ,30 ,3 ,15 ,13 ,16 ); AssignCodeWords(17, TErrorCorrectionLevel.Low, 647 ,28 ,1 ,107 ,5 ,108 ); AssignCodeWords(17, TErrorCorrectionLevel.Medium, 507 ,28 ,10 ,46 ,1 ,47 ); AssignCodeWords(17, TErrorCorrectionLevel.Quartile, 367 ,28 ,1 ,22 ,15 ,23 ); AssignCodeWords(17, TErrorCorrectionLevel.High, 283 ,28 ,2 ,14 ,17 ,15 ); AssignCodeWords(18, TErrorCorrectionLevel.Low, 721 ,30 ,5 ,120 ,1 ,121 ); AssignCodeWords(18, TErrorCorrectionLevel.Medium, 563 ,26 ,9 ,43 ,4 ,44 ); AssignCodeWords(18, TErrorCorrectionLevel.Quartile, 397 ,28 ,17 ,22 ,1 ,23 ); AssignCodeWords(18, TErrorCorrectionLevel.High, 313 ,28 ,2 ,14 ,19 ,15 ); AssignCodeWords(19, TErrorCorrectionLevel.Low, 795 ,28 ,3 ,113 ,4 ,114 ); AssignCodeWords(19, TErrorCorrectionLevel.Medium, 627 ,26 ,3 ,44 ,11 ,45 ); AssignCodeWords(19, TErrorCorrectionLevel.Quartile, 445 ,26 ,17 ,21 ,4 ,22 ); AssignCodeWords(19, TErrorCorrectionLevel.High, 341 ,26 ,9 ,13 ,16 ,14 ); AssignCodeWords(20, TErrorCorrectionLevel.Low, 861 ,28 ,3 ,107 ,5 ,108 ); AssignCodeWords(20, TErrorCorrectionLevel.Medium, 669 ,26 ,3 ,41 ,13 ,42 ); AssignCodeWords(20, TErrorCorrectionLevel.Quartile, 485 ,30 ,15 ,24 ,5 ,25 ); AssignCodeWords(20, TErrorCorrectionLevel.High, 385 ,28 ,15 ,15 ,10 ,16 ); AssignCodeWords(21, TErrorCorrectionLevel.Low, 932 ,28 ,4 ,116 ,4 ,117 ); AssignCodeWords(21, TErrorCorrectionLevel.Medium, 714 ,26 ,17 ,42 ); AssignCodeWords(21, TErrorCorrectionLevel.Quartile, 512 ,28 ,17 ,22 ,6 ,23 ); AssignCodeWords(21, TErrorCorrectionLevel.High, 406 ,30 ,19 ,16 ,6 ,17 ); AssignCodeWords(22, TErrorCorrectionLevel.Low, 1006 ,28 ,2 ,111 ,7 ,112 ); AssignCodeWords(22, TErrorCorrectionLevel.Medium, 782 ,28 ,17 ,46 ); AssignCodeWords(22, TErrorCorrectionLevel.Quartile, 568 ,30 ,7 ,24 ,16 ,25 ); AssignCodeWords(22, TErrorCorrectionLevel.High, 442 ,24 ,34 ,13 ); AssignCodeWords(23, TErrorCorrectionLevel.Low, 1094 ,30 ,4 ,121 ,5 ,122 ); AssignCodeWords(23, TErrorCorrectionLevel.Medium, 860 ,28 ,4 ,47 ,14 ,48 ); AssignCodeWords(23, TErrorCorrectionLevel.Quartile, 614 ,30 ,11 ,24 ,14 ,25 ); AssignCodeWords(23, TErrorCorrectionLevel.High, 464 ,30 ,16 ,15 ,14 ,16 ); AssignCodeWords(24, TErrorCorrectionLevel.Low, 1174 ,30 ,6 ,117 ,4 ,118 ); AssignCodeWords(24, TErrorCorrectionLevel.Medium, 914 ,28 ,6 ,45 ,14 ,46 ); AssignCodeWords(24, TErrorCorrectionLevel.Quartile, 664 ,30 ,11 ,24 ,16 ,25 ); AssignCodeWords(24, TErrorCorrectionLevel.High, 514 ,30 ,30 ,16 ,2 ,17 ); AssignCodeWords(25, TErrorCorrectionLevel.Low, 1276 ,26 ,8 ,106 ,4 ,107 ); AssignCodeWords(25, TErrorCorrectionLevel.Medium, 1000 ,28 ,8 ,47 ,13 ,48 ); AssignCodeWords(25, TErrorCorrectionLevel.Quartile, 718 ,30 ,7 ,24 ,22 ,25 ); AssignCodeWords(25, TErrorCorrectionLevel.High, 538 ,30 ,22 ,15 ,13 ,16 ); AssignCodeWords(26, TErrorCorrectionLevel.Low, 1370 ,28 ,10 ,114 ,2 ,115 ); AssignCodeWords(26, TErrorCorrectionLevel.Medium, 1062 ,28 ,19 ,46 ,4 ,47 ); AssignCodeWords(26, TErrorCorrectionLevel.Quartile, 754 ,28 ,28 ,22 ,6 ,23 ); AssignCodeWords(26, TErrorCorrectionLevel.High, 596 ,30 ,33 ,16 ,4 ,17 ); AssignCodeWords(27, TErrorCorrectionLevel.Low, 1468 ,30 ,8 ,122 ,4 ,123 ); AssignCodeWords(27, TErrorCorrectionLevel.Medium, 1128 ,28 ,22 ,45 ,3 ,46 ); AssignCodeWords(27, TErrorCorrectionLevel.Quartile, 808 ,30 ,8 ,23 ,26 ,24 ); AssignCodeWords(27, TErrorCorrectionLevel.High, 628 ,30 ,12 ,15 ,28 ,16 ); AssignCodeWords(28, TErrorCorrectionLevel.Low, 1531 ,30 ,3 ,117 ,10 ,118 ); AssignCodeWords(28, TErrorCorrectionLevel.Medium, 1193 ,28 ,3 ,45 ,23 ,46 ); AssignCodeWords(28, TErrorCorrectionLevel.Quartile, 871 ,30 ,4 ,24 ,31 ,25 ); AssignCodeWords(28, TErrorCorrectionLevel.High, 661 ,30 ,11 ,15 ,31 ,16 ); AssignCodeWords(29, TErrorCorrectionLevel.Low, 1631 ,30 ,7 ,116 ,7 ,117 ); AssignCodeWords(29, TErrorCorrectionLevel.Medium, 1267 ,28 ,21 ,45 ,7 ,46 ); AssignCodeWords(29, TErrorCorrectionLevel.Quartile, 911 ,30 ,1 ,23 ,37 ,24 ); AssignCodeWords(29, TErrorCorrectionLevel.High, 701 ,30 ,19 ,15 ,26 ,16 ); AssignCodeWords(30, TErrorCorrectionLevel.Low, 1735 ,30 ,5 ,115 ,10 ,116 ); AssignCodeWords(30, TErrorCorrectionLevel.Medium, 1373 ,28 ,19 ,47 ,10 ,48 ); AssignCodeWords(30, TErrorCorrectionLevel.Quartile, 985 ,30 ,15 ,24 ,25 ,25 ); AssignCodeWords(30, TErrorCorrectionLevel.High, 745 ,30 ,23 ,15 ,25 ,16 ); AssignCodeWords(31, TErrorCorrectionLevel.Low, 1843 ,30 ,13 ,115 ,3 ,116 ); AssignCodeWords(31, TErrorCorrectionLevel.Medium, 1455 ,28 ,2 ,46 ,29 ,47 ); AssignCodeWords(31, TErrorCorrectionLevel.Quartile, 1033 ,30 ,42 ,24 ,1 ,25 ); AssignCodeWords(31, TErrorCorrectionLevel.High, 793 ,30 ,23 ,15 ,28 ,16 ); AssignCodeWords(32, TErrorCorrectionLevel.Low, 1955, 30, 17 , 115); AssignCodeWords(32, TErrorCorrectionLevel.Medium, 1541 ,28 ,10 ,46 ,23 ,47 ); AssignCodeWords(32, TErrorCorrectionLevel.Quartile, 1115 ,30 ,10 ,24 ,35 ,25 ); AssignCodeWords(32, TErrorCorrectionLevel.High, 845 ,30 ,19 ,15 ,35 ,16 ); AssignCodeWords(33, TErrorCorrectionLevel.Low, 2071 ,30 ,17 ,115 ,1 ,116 ); AssignCodeWords(33, TErrorCorrectionLevel.Medium, 1631 ,28 ,14 ,46 ,21 ,47 ); AssignCodeWords(33, TErrorCorrectionLevel.Quartile, 1171 ,30 ,29 ,24 ,19 ,25 ); AssignCodeWords(33, TErrorCorrectionLevel.High, 901 ,30 ,11 ,15 ,46 ,16 ); AssignCodeWords(34, TErrorCorrectionLevel.Low, 2191 ,30 ,13 ,115 ,6 ,116 ); AssignCodeWords(34, TErrorCorrectionLevel.Medium, 1725 ,28 ,14 ,46 ,23 ,47 ); AssignCodeWords(34, TErrorCorrectionLevel.Quartile, 1231 ,30 ,44 ,24 ,7 ,25 ); AssignCodeWords(34, TErrorCorrectionLevel.High, 961 ,30 ,59 ,16 ,1 ,17 ); AssignCodeWords(35, TErrorCorrectionLevel.Low, 2306 ,30 ,12 ,121 ,7 ,122 ); AssignCodeWords(35, TErrorCorrectionLevel.Medium, 1812 ,28 ,12 ,47 ,26 ,48 ); AssignCodeWords(35, TErrorCorrectionLevel.Quartile, 1286 ,30 ,39 ,24 ,14 ,25 ); AssignCodeWords(35, TErrorCorrectionLevel.High, 986 ,30 ,22 ,15 ,41 ,16 ); AssignCodeWords(36, TErrorCorrectionLevel.Low, 2434 ,30 ,6 ,121 ,14 ,122 ); AssignCodeWords(36, TErrorCorrectionLevel.Medium, 1914 ,28 ,6 ,47 ,34 ,48 ); AssignCodeWords(36, TErrorCorrectionLevel.Quartile, 1354 ,30 ,46 ,24 ,10 ,25 ); AssignCodeWords(36, TErrorCorrectionLevel.High, 1054 ,30 ,2 ,15 ,64 ,16 ); AssignCodeWords(37, TErrorCorrectionLevel.Low, 2566 ,30 ,17 ,122 ,4 ,123 ); AssignCodeWords(37, TErrorCorrectionLevel.Medium, 1992 ,28 ,29 ,46 ,14 ,47 ); AssignCodeWords(37, TErrorCorrectionLevel.Quartile, 1426 ,30 ,49 ,24 ,10 ,25 ); AssignCodeWords(37, TErrorCorrectionLevel.High, 1096 ,30 ,24 ,15 ,46 ,16 ); AssignCodeWords(38, TErrorCorrectionLevel.Low, 2702 ,30 ,4 ,122 ,18 ,123 ); AssignCodeWords(38, TErrorCorrectionLevel.Medium, 2102 ,28 ,13 ,46 ,32 ,47 ); AssignCodeWords(38, TErrorCorrectionLevel.Quartile, 1502 ,30 ,48 ,24 ,14 ,25 ); AssignCodeWords(38, TErrorCorrectionLevel.High, 1142 ,30 ,42 ,15 ,32 ,16 ); AssignCodeWords(39, TErrorCorrectionLevel.Low, 2812 ,30 ,20 ,117 ,4 ,118 ); AssignCodeWords(39, TErrorCorrectionLevel.Medium, 2216 ,28 ,40 ,47 ,7 ,48 ); AssignCodeWords(39, TErrorCorrectionLevel.Quartile, 1582 ,30 ,43 ,24 ,22 ,25 ); AssignCodeWords(39, TErrorCorrectionLevel.High, 1222 ,30 ,10 ,15 ,67 ,16 ); AssignCodeWords(40, TErrorCorrectionLevel.Low, 2956 ,30 ,19 ,118 ,6 ,119 ); AssignCodeWords(40, TErrorCorrectionLevel.Medium, 2334 ,28 ,18 ,47 ,31 ,48 ); AssignCodeWords(40, TErrorCorrectionLevel.Quartile, 1666 ,30 ,34 ,24 ,34 ,25 ); AssignCodeWords(40, TErrorCorrectionLevel.High, 1276 ,30 ,20 ,15 ,61 ,16 ); end; constructor TQRCode.Create; var i: Integer; begin inherited Create; FUpdateDepth := 0; FReservedAreas := TList.Create; SetLength(FPenaltyScores,8); for i := 0 to 7 do SetLength(FPenaltyScores[i],4); FMaskInUse := TMask.m0; FMask := TMask.Auto; FVersion := TVersion.Auto; FVersionInUse := TVersion.v1; FMode := TQRMode.Numeric; FECL := TErrorCorrectionLevel.Auto; FECLInUse := TErrorCorrectionLevel.Low; SetLength(FData,0); SetLength(FCodeWords, 0); FBitsLen := 0; FBitsPos := 0; SetLength(FBits,0); SetLength(FModules,0); FDataBits := ''; FOnPaint := nil; SetLength(FLogTable, 256); FLogTable[0] := 1; FLogTable[1] := 2; FLogTable[2] := 4; FLogTable[3] := 8; FLogTable[4] := 16; FLogTable[5] := 32; FLogTable[6] := 64; FLogTable[7] := 128; FLogTable[8] := 29; FLogTable[9] := 58; FLogTable[10] := 116; FLogTable[11] := 232; FLogTable[12] := 205; FLogTable[13] := 135; FLogTable[14] := 19; FLogTable[15] := 38; FLogTable[16] := 76; FLogTable[17] := 152; FLogTable[18] := 45; FLogTable[19] := 90; FLogTable[20] := 180; FLogTable[21] := 117; FLogTable[22] := 234; FLogTable[23] := 201; FLogTable[24] := 143; FLogTable[25] := 3; FLogTable[26] := 6; FLogTable[27] := 12; FLogTable[28] := 24; FLogTable[29] := 48; FLogTable[30] := 96; FLogTable[31] := 192; FLogTable[32] := 157; FLogTable[33] := 39; FLogTable[34] := 78; FLogTable[35] := 156; FLogTable[36] := 37; FLogTable[37] := 74; FLogTable[38] := 148; FLogTable[39] := 53; FLogTable[40] := 106; FLogTable[41] := 212; FLogTable[42] := 181; FLogTable[43] := 119; FLogTable[44] := 238; FLogTable[45] := 193; FLogTable[46] := 159; FLogTable[47] := 35; FLogTable[48] := 70; FLogTable[49] := 140; FLogTable[50] := 5; FLogTable[51] := 10; FLogTable[52] := 20; FLogTable[53] := 40; FLogTable[54] := 80; FLogTable[55] := 160; FLogTable[56] := 93; FLogTable[57] := 186; FLogTable[58] := 105; FLogTable[59] := 210; FLogTable[60] := 185; FLogTable[61] := 111; FLogTable[62] := 222; FLogTable[63] := 161; FLogTable[64] := 95; FLogTable[65] := 190; FLogTable[66] := 97; FLogTable[67] := 194; FLogTable[68] := 153; FLogTable[69] := 47; FLogTable[70] := 94; FLogTable[71] := 188; FLogTable[72] := 101; FLogTable[73] := 202; FLogTable[74] := 137; FLogTable[75] := 15; FLogTable[76] := 30; FLogTable[77] := 60; FLogTable[78] := 120; FLogTable[79] := 240; FLogTable[80] := 253; FLogTable[81] := 231; FLogTable[82] := 211; FLogTable[83] := 187; FLogTable[84] := 107; FLogTable[85] := 214; FLogTable[86] := 177; FLogTable[87] := 127; FLogTable[88] := 254; FLogTable[89] := 225; FLogTable[90] := 223; FLogTable[91] := 163; FLogTable[92] := 91; FLogTable[93] := 182; FLogTable[94] := 113; FLogTable[95] := 226; FLogTable[96] := 217; FLogTable[97] := 175; FLogTable[98] := 67; FLogTable[99] := 134; FLogTable[100] := 17; FLogTable[101] := 34; FLogTable[102] := 68; FLogTable[103] := 136; FLogTable[104] := 13; FLogTable[105] := 26; FLogTable[106] := 52; FLogTable[107] := 104; FLogTable[108] := 208; FLogTable[109] := 189; FLogTable[110] := 103; FLogTable[111] := 206; FLogTable[112] := 129; FLogTable[113] := 31; FLogTable[114] := 62; FLogTable[115] := 124; FLogTable[116] := 248; FLogTable[117] := 237; FLogTable[118] := 199; FLogTable[119] := 147; FLogTable[120] := 59; FLogTable[121] := 118; FLogTable[122] := 236; FLogTable[123] := 197; FLogTable[124] := 151; FLogTable[125] := 51; FLogTable[126] := 102; FLogTable[127] := 204; FLogTable[128] := 133; FLogTable[129] := 23; FLogTable[130] := 46; FLogTable[131] := 92; FLogTable[132] := 184; FLogTable[133] := 109; FLogTable[134] := 218; FLogTable[135] := 169; FLogTable[136] := 79; FLogTable[137] := 158; FLogTable[138] := 33; FLogTable[139] := 66; FLogTable[140] := 132; FLogTable[141] := 21; FLogTable[142] := 42; FLogTable[143] := 84; FLogTable[144] := 168; FLogTable[145] := 77; FLogTable[146] := 154; FLogTable[147] := 41; FLogTable[148] := 82; FLogTable[149] := 164; FLogTable[150] := 85; FLogTable[151] := 170; FLogTable[152] := 73; FLogTable[153] := 146; FLogTable[154] := 57; FLogTable[155] := 114; FLogTable[156] := 228; FLogTable[157] := 213; FLogTable[158] := 183; FLogTable[159] := 115; FLogTable[160] := 230; FLogTable[161] := 209; FLogTable[162] := 191; FLogTable[163] := 99; FLogTable[164] := 198; FLogTable[165] := 145; FLogTable[166] := 63; FLogTable[167] := 126; FLogTable[168] := 252; FLogTable[169] := 229; FLogTable[170] := 215; FLogTable[171] := 179; FLogTable[172] := 123; FLogTable[173] := 246; FLogTable[174] := 241; FLogTable[175] := 255; FLogTable[176] := 227; FLogTable[177] := 219; FLogTable[178] := 171; FLogTable[179] := 75; FLogTable[180] := 150; FLogTable[181] := 49; FLogTable[182] := 98; FLogTable[183] := 196; FLogTable[184] := 149; FLogTable[185] := 55; FLogTable[186] := 110; FLogTable[187] := 220; FLogTable[188] := 165; FLogTable[189] := 87; FLogTable[190] := 174; FLogTable[191] := 65; FLogTable[192] := 130; FLogTable[193] := 25; FLogTable[194] := 50; FLogTable[195] := 100; FLogTable[196] := 200; FLogTable[197] := 141; FLogTable[198] := 7; FLogTable[199] := 14; FLogTable[200] := 28; FLogTable[201] := 56; FLogTable[202] := 112; FLogTable[203] := 224; FLogTable[204] := 221; FLogTable[205] := 167; FLogTable[206] := 83; FLogTable[207] := 166; FLogTable[208] := 81; FLogTable[209] := 162; FLogTable[210] := 89; FLogTable[211] := 178; FLogTable[212] := 121; FLogTable[213] := 242; FLogTable[214] := 249; FLogTable[215] := 239; FLogTable[216] := 195; FLogTable[217] := 155; FLogTable[218] := 43; FLogTable[219] := 86; FLogTable[220] := 172; FLogTable[221] := 69; FLogTable[222] := 138; FLogTable[223] := 9; FLogTable[224] := 18; FLogTable[225] := 36; FLogTable[226] := 72; FLogTable[227] := 144; FLogTable[228] := 61; FLogTable[229] := 122; FLogTable[230] := 244; FLogTable[231] := 245; FLogTable[232] := 247; FLogTable[233] := 243; FLogTable[234] := 251; FLogTable[235] := 235; FLogTable[236] := 203; FLogTable[237] := 139; FLogTable[238] := 11; FLogTable[239] := 22; FLogTable[240] := 44; FLogTable[241] := 88; FLogTable[242] := 176; FLogTable[243] := 125; FLogTable[244] := 250; FLogTable[245] := 233; FLogTable[246] := 207; FLogTable[247] := 131; FLogTable[248] := 27; FLogTable[249] := 54; FLogTable[250] := 108; FLogTable[251] := 216; FLogTable[252] := 173; FLogTable[253] := 71; FLogTable[254] := 142; FLogTable[255] := 1; SetLength(FAntilogTable, 256); FAntilogTable[1] := 0; FAntilogTable[2] := 1; FAntilogTable[3] := 25; FAntilogTable[4] := 2; FAntilogTable[5] := 50; FAntilogTable[6] := 26; FAntilogTable[7] := 198; FAntilogTable[8] := 3; FAntilogTable[9] := 223; FAntilogTable[10] := 51; FAntilogTable[11] := 238; FAntilogTable[12] := 27; FAntilogTable[13] := 104; FAntilogTable[14] := 199; FAntilogTable[15] := 75; FAntilogTable[16] := 4; FAntilogTable[17] := 100; FAntilogTable[18] := 224; FAntilogTable[19] := 14; FAntilogTable[20] := 52; FAntilogTable[21] := 141; FAntilogTable[22] := 239; FAntilogTable[23] := 129; FAntilogTable[24] := 28; FAntilogTable[25] := 193; FAntilogTable[26] := 105; FAntilogTable[27] := 248; FAntilogTable[28] := 200; FAntilogTable[29] := 8; FAntilogTable[30] := 76; FAntilogTable[31] := 113; FAntilogTable[32] := 5; FAntilogTable[33] := 138; FAntilogTable[34] := 101; FAntilogTable[35] := 47; FAntilogTable[36] := 225; FAntilogTable[37] := 36; FAntilogTable[38] := 15; FAntilogTable[39] := 33; FAntilogTable[40] := 53; FAntilogTable[41] := 147; FAntilogTable[42] := 142; FAntilogTable[43] := 218; FAntilogTable[44] := 240; FAntilogTable[45] := 18; FAntilogTable[46] := 130; FAntilogTable[47] := 69; FAntilogTable[48] := 29; FAntilogTable[49] := 181; FAntilogTable[50] := 194; FAntilogTable[51] := 125; FAntilogTable[52] := 106; FAntilogTable[53] := 39; FAntilogTable[54] := 249; FAntilogTable[55] := 185; FAntilogTable[56] := 201; FAntilogTable[57] := 154; FAntilogTable[58] := 9; FAntilogTable[59] := 120; FAntilogTable[60] := 77; FAntilogTable[61] := 228; FAntilogTable[62] := 114; FAntilogTable[63] := 166; FAntilogTable[64] := 6; FAntilogTable[65] := 191; FAntilogTable[66] := 139; FAntilogTable[67] := 98; FAntilogTable[68] := 102; FAntilogTable[69] := 221; FAntilogTable[70] := 48; FAntilogTable[71] := 253; FAntilogTable[72] := 226; FAntilogTable[73] := 152; FAntilogTable[74] := 37; FAntilogTable[75] := 179; FAntilogTable[76] := 16; FAntilogTable[77] := 145; FAntilogTable[78] := 34; FAntilogTable[79] := 136; FAntilogTable[80] := 54; FAntilogTable[81] := 208; FAntilogTable[82] := 148; FAntilogTable[83] := 206; FAntilogTable[84] := 143; FAntilogTable[85] := 150; FAntilogTable[86] := 219; FAntilogTable[87] := 189; FAntilogTable[88] := 241; FAntilogTable[89] := 210; FAntilogTable[90] := 19; FAntilogTable[91] := 92; FAntilogTable[92] := 131; FAntilogTable[93] := 56; FAntilogTable[94] := 70; FAntilogTable[95] := 64; FAntilogTable[96] := 30; FAntilogTable[97] := 66; FAntilogTable[98] := 182; FAntilogTable[99] := 163; FAntilogTable[100] := 195; FAntilogTable[101] := 72; FAntilogTable[102] := 126; FAntilogTable[103] := 110; FAntilogTable[104] := 107; FAntilogTable[105] := 58; FAntilogTable[106] := 40; FAntilogTable[107] := 84; FAntilogTable[108] := 250; FAntilogTable[109] := 133; FAntilogTable[110] := 186; FAntilogTable[111] := 61; FAntilogTable[112] := 202; FAntilogTable[113] := 94; FAntilogTable[114] := 155; FAntilogTable[115] := 159; FAntilogTable[116] := 10; FAntilogTable[117] := 21; FAntilogTable[118] := 121; FAntilogTable[119] := 43; FAntilogTable[120] := 78; FAntilogTable[121] := 212; FAntilogTable[122] := 229; FAntilogTable[123] := 172; FAntilogTable[124] := 115; FAntilogTable[125] := 243; FAntilogTable[126] := 167; FAntilogTable[127] := 87; FAntilogTable[128] := 7; FAntilogTable[129] := 112; FAntilogTable[130] := 192; FAntilogTable[131] := 247; FAntilogTable[132] := 140; FAntilogTable[133] := 128; FAntilogTable[134] := 99; FAntilogTable[135] := 13; FAntilogTable[136] := 103; FAntilogTable[137] := 74; FAntilogTable[138] := 222; FAntilogTable[139] := 237; FAntilogTable[140] := 49; FAntilogTable[141] := 197; FAntilogTable[142] := 254; FAntilogTable[143] := 24; FAntilogTable[144] := 227; FAntilogTable[145] := 165; FAntilogTable[146] := 153; FAntilogTable[147] := 119; FAntilogTable[148] := 38; FAntilogTable[149] := 184; FAntilogTable[150] := 180; FAntilogTable[151] := 124; FAntilogTable[152] := 17; FAntilogTable[153] := 68; FAntilogTable[154] := 146; FAntilogTable[155] := 217; FAntilogTable[156] := 35; FAntilogTable[157] := 32; FAntilogTable[158] := 137; FAntilogTable[159] := 46; FAntilogTable[160] := 55; FAntilogTable[161] := 63; FAntilogTable[162] := 209; FAntilogTable[163] := 91; FAntilogTable[164] := 149; FAntilogTable[165] := 188; FAntilogTable[166] := 207; FAntilogTable[167] := 205; FAntilogTable[168] := 144; FAntilogTable[169] := 135; FAntilogTable[170] := 151; FAntilogTable[171] := 178; FAntilogTable[172] := 220; FAntilogTable[173] := 252; FAntilogTable[174] := 190; FAntilogTable[175] := 97; FAntilogTable[176] := 242; FAntilogTable[177] := 86; FAntilogTable[178] := 211; FAntilogTable[179] := 171; FAntilogTable[180] := 20; FAntilogTable[181] := 42; FAntilogTable[182] := 93; FAntilogTable[183] := 158; FAntilogTable[184] := 132; FAntilogTable[185] := 60; FAntilogTable[186] := 57; FAntilogTable[187] := 83; FAntilogTable[188] := 71; FAntilogTable[189] := 109; FAntilogTable[190] := 65; FAntilogTable[191] := 162; FAntilogTable[192] := 31; FAntilogTable[193] := 45; FAntilogTable[194] := 67; FAntilogTable[195] := 216; FAntilogTable[196] := 183; FAntilogTable[197] := 123; FAntilogTable[198] := 164; FAntilogTable[199] := 118; FAntilogTable[200] := 196; FAntilogTable[201] := 23; FAntilogTable[202] := 73; FAntilogTable[203] := 236; FAntilogTable[204] := 127; FAntilogTable[205] := 12; FAntilogTable[206] := 111; FAntilogTable[207] := 246; FAntilogTable[208] := 108; FAntilogTable[209] := 161; FAntilogTable[210] := 59; FAntilogTable[211] := 82; FAntilogTable[212] := 41; FAntilogTable[213] := 157; FAntilogTable[214] := 85; FAntilogTable[215] := 170; FAntilogTable[216] := 251; FAntilogTable[217] := 96; FAntilogTable[218] := 134; FAntilogTable[219] := 177; FAntilogTable[220] := 187; FAntilogTable[221] := 204; FAntilogTable[222] := 62; FAntilogTable[223] := 90; FAntilogTable[224] := 203; FAntilogTable[225] := 89; FAntilogTable[226] := 95; FAntilogTable[227] := 176; FAntilogTable[228] := 156; FAntilogTable[229] := 169; FAntilogTable[230] := 160; FAntilogTable[231] := 81; FAntilogTable[232] := 11; FAntilogTable[233] := 245; FAntilogTable[234] := 22; FAntilogTable[235] := 235; FAntilogTable[236] := 122; FAntilogTable[237] := 117; FAntilogTable[238] := 44; FAntilogTable[239] := 215; FAntilogTable[240] := 79; FAntilogTable[241] := 174; FAntilogTable[242] := 213; FAntilogTable[243] := 233; FAntilogTable[244] := 230; FAntilogTable[245] := 231; FAntilogTable[246] := 173; FAntilogTable[247] := 232; FAntilogTable[248] := 116; FAntilogTable[249] := 214; FAntilogTable[250] := 244; FAntilogTable[251] := 234; FAntilogTable[252] := 168; FAntilogTable[253] := 80; FAntilogTable[254] := 88; FAntilogTable[255] := 175; PixelsPerModule := 15; end; function TQRCode.DecimalToBinary(value, digits: integer): string; var i: integer; begin if digits > 32 then digits := 32; Result := ''; i := 0; while i < digits do begin if ((1 shl i) and value) > 0 then Result := '1' + Result else Result := '0' + Result; inc(i); end; end; destructor TQRCode.Destroy; begin FReservedAreas.Free; inherited; end; function TQRCode.DetermineQRMode : TQRMode; var i: Integer; begin Result := TQRMode.Numeric; if length(FData) = 0 then exit; for i := 0 to Length(FData)-1 do if (not CharInSet(Char(FData[i]), ['0'..'9'])) then begin if (not CharInSet(Char(FData[i]),['0'..'9', 'A'..'Z', ' ', '$', '%', '*', '+', '-', '.', '/', ':'])) then begin (*if {(Ord(s.Chars[i]) > 256) or }(TEncoding.UTF8.GetString(FData) <> TEncoding.Unicode.GetString(FData)) then begin Result := TQRMode.Kanji; end else if (Result < TQRMode.Byte) then*) Result := TQRMode.Byte; end else if (Result < TQRMode.AlphaNumeric) then Result := TQRMode.AlphaNumeric; end; end; procedure TQRCode.DrawModules; procedure DrawFinder(fp : TFinderPosition); var pt : TPoint; x, y: Integer; begin pt := FinderLocation(fp); for x := 0 to 6 do for y := 0 to 6 do begin FModules[x + pt.x][y + pt.y] := (x = 0) or (x = 6) or (y = 0) or (y = 6) or ((x >= 2) and (x <= 4) and (y >= 2) and (y <= 4)) // center end; case fp of TFinderPosition.TopLeft: ; TFinderPosition.TopRight: pt.Offset(-1,0); TFinderPosition.BottomLeft: pt.Offset(0,-1); end; AddReservedArea(TRect.Create(pt,8,8)); end; procedure DrawAlignmentPatterns; procedure DrawAlignmentPatternAt(pt : TPoint); var i: Integer; fp : TFinderPosition; ptfp : TPoint; rectAP : TRect; rectFinder : TRect; x: Integer; y: Integer; begin pt.Offset(-2,-2); rectAP := TRect.Create(pt,5,5); for i := 0 to 2 do begin fp := TFinderPosition(i); ptfp := FinderLocation(fp); case fp of TFinderPosition.TopRight: ptfp.SetLocation(ptfp.X, ptfp.Y); TFinderPosition.BottomLeft: ptfp.SetLocation(ptfp.X, ptfp.Y); end; rectFinder := TRect.Create(ptfp,8,8); if rectAP.IntersectsWithRect(rectFinder) then exit; end; for x := 0 to 4 do for y := 0 to 4 do FModules[x + pt.x][y + pt.Y] := (x = 0) or (x = 4) or (y = 0) or (y = 4) or ((x = 2) and (y = 2)); AddReservedArea(TRect.Create(pt, 4,4)); end; var Locs : TArray; Points : TArray>; i: Integer; idx : integer; begin case FVersionInUse of TVersion.v1: SetLength(Locs,0); TVersion.v2: begin SetLength(Locs,2); Locs[0] := 6; Locs[1] := 18; end; TVersion.v3: begin SetLength(Locs,2); Locs[0] := 6; Locs[1] := 22; end; TVersion.v4: begin SetLength(Locs,2); Locs[0] := 6; Locs[1] := 26; end; TVersion.v5: begin SetLength(Locs,2); Locs[0] := 6; Locs[1] := 30; end; TVersion.v6: begin SetLength(Locs,2); Locs[0] := 6; Locs[1] := 34; end; TVersion.v7: begin SetLength(Locs,3); Locs[0] := 6; Locs[1] := 22; Locs[2] := 38; end; TVersion.v8: begin SetLength(Locs,3); Locs[0] := 6; Locs[1] := 24; Locs[2] := 42; end; TVersion.v9: begin SetLength(Locs,3); Locs[0] := 6; Locs[1] := 26; Locs[2] := 46; end; TVersion.v10: begin SetLength(Locs,3); Locs[0] := 6; Locs[1] := 28; Locs[2] := 50; end; TVersion.v11: begin SetLength(Locs,3); Locs[0] := 6; Locs[1] := 30; Locs[2] := 54; end; TVersion.v12: begin SetLength(Locs,3); Locs[0] := 6; Locs[1] := 32; Locs[2] := 58; end; TVersion.v13: begin SetLength(Locs,3); Locs[0] := 6; Locs[1] := 34; Locs[2] := 62; end; TVersion.v14: begin SetLength(Locs,4); Locs[0] := 6; Locs[1] := 26; Locs[2] := 46; Locs[3] := 66; end; TVersion.v15: begin SetLength(Locs,4); Locs[0] := 6; Locs[1] := 26; Locs[2] := 48; Locs[3] := 70; end; TVersion.v16: begin SetLength(Locs,4); Locs[0] := 6; Locs[1] := 26; Locs[2] := 50; Locs[3] := 74; end; TVersion.v17: begin SetLength(Locs,4); Locs[0] := 6; Locs[1] := 30; Locs[2] := 54; Locs[3] := 78; end; TVersion.v18: begin SetLength(Locs,4); Locs[0] := 6; Locs[1] := 30; Locs[2] := 56; Locs[3] := 82; end; TVersion.v19: begin SetLength(Locs,4); Locs[0] := 6; Locs[1] := 30; Locs[2] := 58; Locs[3] := 86; end; TVersion.v20: begin SetLength(Locs,4); Locs[0] := 6; Locs[1] := 34; Locs[2] := 62; Locs[3] := 90; end; TVersion.v21: begin SetLength(Locs,5); Locs[0] := 6; Locs[1] := 28; Locs[2] := 50; Locs[3] := 72; Locs[4] := 94; end; TVersion.v22: begin SetLength(Locs,5); Locs[0] := 6; Locs[1] := 26; Locs[2] := 50; Locs[3] := 74; Locs[4] := 98; end; TVersion.v23: begin SetLength(Locs,5); Locs[0] := 6; Locs[1] := 30; Locs[2] := 54; Locs[3] := 78; Locs[4] := 102; end; TVersion.v24: begin SetLength(Locs,5); Locs[0] := 6; Locs[1] := 28; Locs[2] := 54; Locs[3] := 80; Locs[4] := 106; end; TVersion.v25: begin SetLength(Locs,5); Locs[0] := 6; Locs[1] := 32; Locs[2] := 58; Locs[3] := 84; Locs[4] := 110; end; TVersion.v26: begin SetLength(Locs,5); Locs[0] := 6; Locs[1] := 30; Locs[2] := 58; Locs[3] := 86; Locs[4] := 114; end; TVersion.v27: begin SetLength(Locs,5); Locs[0] := 6; Locs[1] := 34; Locs[2] := 62; Locs[3] := 90; Locs[4] := 118; end; TVersion.v28: begin SetLength(Locs,6); Locs[0] := 6; Locs[1] := 26; Locs[2] := 50; Locs[3] := 74; Locs[4] := 98; Locs[5] := 122; end; TVersion.v29: begin SetLength(Locs,6); Locs[0] := 6; Locs[1] := 30; Locs[2] := 54; Locs[3] := 78; Locs[4] := 102; Locs[5] := 126; end; TVersion.v30: begin SetLength(Locs,6); Locs[0] := 6; Locs[1] := 26; Locs[2] := 52; Locs[3] := 78; Locs[4] := 104; Locs[5] := 130; end; TVersion.v31: begin SetLength(Locs,6); Locs[0] := 6; Locs[1] := 30; Locs[2] := 56; Locs[3] := 82; Locs[4] := 108; Locs[5] := 134; end; TVersion.v32: begin SetLength(Locs,6); Locs[0] := 6; Locs[1] := 34; Locs[2] := 60; Locs[3] := 86; Locs[4] := 112; Locs[5] := 138; end; TVersion.v33: begin SetLength(Locs,6); Locs[0] := 6; Locs[1] := 30; Locs[2] := 58; Locs[3] := 86; Locs[4] := 114; Locs[5] := 142; end; TVersion.v34: begin SetLength(Locs,6); Locs[0] := 6; Locs[1] := 34; Locs[2] := 62; Locs[3] := 90; Locs[4] := 118; Locs[5] := 146; end; TVersion.v35: begin SetLength(Locs,7); Locs[0] := 6; Locs[1] := 30; Locs[2] := 54; Locs[3] := 78; Locs[4] := 102; Locs[5] := 126; Locs[6] := 150; end; TVersion.v36: begin SetLength(Locs,7); Locs[0] := 6; Locs[1] := 24; Locs[2] := 50; Locs[3] := 76; Locs[4] := 102; Locs[5] := 128; Locs[6] := 154; end; TVersion.v37: begin SetLength(Locs,7); Locs[0] := 6; Locs[1] := 28; Locs[2] := 54; Locs[3] := 80; Locs[4] := 106; Locs[5] := 132; Locs[6] := 158; end; TVersion.v38: begin SetLength(Locs,7); Locs[0] := 6; Locs[1] := 32; Locs[2] := 58; Locs[3] := 84; Locs[4] := 110; Locs[5] := 136; Locs[6] := 162; end; TVersion.v39: begin SetLength(Locs,7); Locs[0] := 6; Locs[1] := 26; Locs[2] := 54; Locs[3] := 82; Locs[4] := 110; Locs[5] := 138; Locs[6] := 166; end; TVersion.v40: begin SetLength(Locs,7); Locs[0] := 6; Locs[1] := 30; Locs[2] := 58; Locs[3] := 86; Locs[4] := 114; Locs[5] := 142; Locs[6] := 170; end; end; if Length(Locs) > 0 then begin Points := TArrayHelper.Combination(Locs, 2); SetLength(Points, Length(Points)+Length(Locs)); for i := Length(Locs)-1 downto 0 do begin setLength(Points[Length(Points)-i-1],2); Points[Length(Points)-i-1][0] := Locs[i]; Points[Length(Points)-i-1][1] := Locs[i]; end; for i := Length(Points)-1 downto 0 do begin if Points[i][0] <> Points[i][1] then begin SetLength(Points, length(Points)+1); idx := length(Points)-1; SetLength(Points[idx],2); Points[idx][0] := Points[i][1]; Points[idx][1] := Points[i][0]; end; end; for i := 0 to length(Points)-1 do begin DrawAlignmentPatternAt(TPoint.Create(Points[i][0], Points[i][1])); end; end; end; procedure DrawTimingPatterns; var x, y: Integer; begin y := 6; for x := 8 to Size-9 do begin FModules[x][y] := (x+1) mod 2 <> 0; FModules[y][x] := (x+1) mod 2 <> 0; end; end; procedure DrawDarkModule; var pt : TPoint; begin pt := FinderLocation(TFinderPosition.BottomLeft); pt.Offset(8,-1); FModules[pt.X][pt.Y] := True; AddReservedArea(TRect.Create(pt,0,0)); end; procedure ReserveFormatArea; begin AddReservedArea(TRect.Create(0,8, 8, 8)); AddReservedArea(TRect.Create(8,0, 8, 8)); AddReservedArea(TRect.Create(8,FinderLocation(TFinderPosition.BottomLeft).Y,8,FinderLocation(TFinderPosition.BottomLeft).Y+8)); AddReservedArea(TRect.Create(FinderLocation(TFinderPosition.TopRight).X-1,8, FinderLocation(TFinderPosition.TopRight).X+7,8)); end; procedure ReserveVersionArea; begin if FVersionInUse >= TVersion.v7 then begin AddReservedArea(TRect.Create(FinderLocation(TFinderPosition.TopRight).X-4,0,FinderLocation(TFinderPosition.TopRight).X-2,5)); AddReservedArea(TRect.Create(0, FinderLocation(TFinderPosition.BottomLeft).Y-4,5,FinderLocation(TFinderPosition.BottomLeft).Y-2)); end; end; function IsPointReserved(pt : TPoint) : Boolean; var i: Integer; begin Result := (pt.x = 6) or (pt.y = 6); if not Result then for i := 0 to FReservedAreas.Count-1 do if FReservedAreas[i].IntersectsWithPoint(pt) then begin Result := True; exit; end; end; procedure DrawDataBits; var x, y, idx : integer; begin x := Size-1; idx := 0; repeat y := Size-1; repeat if y = 6 then begin dec(y); continue; end; if idx < DataBits.Length then begin if not IsPointReserved(TPoint.Create(x,y)) then begin FModules[x,y] := DataBits.Chars[idx] = '1'; inc(idx); end; end; if idx < DataBits.Length then begin if not IsPointReserved(TPoint.Create(x-1,y)) then begin FModules[x-1,y] := DataBits.Chars[idx] = '1'; inc(idx); end; end; dec(y); until y<0; dec(x,2); if x = 6 then dec(x); y := 0; repeat if y = 6 then begin inc(y); continue; end; if idx < DataBits.Length then begin if not IsPointReserved(TPoint.Create(x,y)) then begin FModules[x,y] := DataBits.Chars[idx] = '1'; inc(idx); end; end; if idx < DataBits.Length then begin if not IsPointReserved(TPoint.Create(x-1,y)) then begin FModules[x-1,y] := DataBits.Chars[idx] = '1'; inc(idx); end; end; inc(y); until y >= Size; dec(x,2); if x = 6 then dec(x); until (x<0); end; procedure DrawMaskPattern; procedure ApplyMask(Pattern : TMask; var ary : TArray>); var x: Integer; y: Integer; pt : TPoint; begin if Pattern = TMask.Auto then raise EQREncodeException.Create('Cannot apply invalid mask.'); for y := 0 to Size-1 do for x := 0 to Size-1 do begin pt := TPoint.Create(x, y);; if not IsPointReserved(pt) then begin case Integer(Pattern) of 0: if (y + x) mod 2 = 0 then ary[x][y] := not ary[x][y]; 1: if (y) mod 2 = 0 then ary[x][y] := not ary[x][y]; 2: if (x) mod 3 = 0 then ary[x][y] := not ary[x][y]; 3: if (y + x) mod 3 = 0 then ary[x][y] := not ary[x][y]; 4: if ( floor(y / 2) + floor(x / 3) ) mod 2 = 0 then ary[x][y] := not ary[x][y]; 5: if ( floor(y / 2) + floor(x / 3) ) mod 2 = 0 then ary[x][y] := not ary[x][y]; 6: if ( floor(y / 2) + floor(x / 3) ) mod 2 = 0 then ary[x][y] := not ary[x][y]; 7: if ( floor(y / 2) + floor(x / 3) ) mod 2 = 0 then ary[x][y] := not ary[x][y]; end; end; end; FMaskInUse := Pattern; end; function PenaltyScore(Mask : integer; ary : TArray>) : integer; function PenaltyTest1 : integer; var y, x: Integer; iColorCnt : integer; bLastColor : boolean; begin Result := 0; for y := 0 to Size-1 do begin iColorCnt := 1; bLastColor := ary[0][y]; for x := 1 to Size-1 do begin if ary[x][y] = bLastColor then begin inc(iColorCnt); if iColorCnt = 5 then inc(Result,3) else if iColorCnt > 5 then inc(Result,1); end else begin iColorCnt := 1; bLastColor := not bLastColor; end; end; end; for x := 0 to Size-1 do begin iColorCnt := 1; bLastColor := ary[x][0]; for y := 1 to Size-1 do begin if ary[x][y] = bLastColor then begin inc(iColorCnt); if iColorCnt = 5 then inc(Result,3) else if iColorCnt > 5 then inc(Result,1); end else begin iColorCnt := 1; bLastColor := not bLastColor; end; end; end; end; function PenaltyTest2 : integer; var y, x: Integer; begin Result := 0; for x := 0 to Size-2 do for y := 0 to Size-2 do begin if (ary[x][y] = ary[x+1][y]) and (ary[x][y] = ary[x][y+1]) and (ary[x][y] = ary[x+1][y+1]) then inc(Result,3); end; end; function PenaltyTest3 : integer; var y, x: Integer; begin Result := 0; for y := 0 to Size-1 do for x := 0 to Size-12 do begin if (ary[x][y] and (not ary[x+1][y]) and ary[x+2][y] and ary[x+3][y] and ary[x+4][y] and (not ary[x+5][y]) and ary[x+6][y] and (not ary[x+7][y]) and (not ary[x+8][y]) and (not ary[x+9][y]) and (not ary[x+10][y])) or ((not ary[x][y]) and (not ary[x+1][y]) and (not ary[x+2][y]) and (not ary[x+3][y]) and ary[x+4][y] and (not ary[x+5][y]) and ary[x+6][y] and ary[x+7][y] and ary[x+8][y] and (not ary[x+9][y]) and ary[x+10][y]) then inc(Result,40); end; for x := 0 to Size-1 do for y := 0 to Size-12 do begin if (ary[x][y] and (not ary[x][y+1]) and ary[x][y+2] and ary[x][y+3] and ary[x][y+4] and (not ary[x][y+5]) and ary[x][y+6] and (not ary[x][y+7]) and (not ary[x][y+8]) and (not ary[x][y+9]) and (not ary[x][y+10])) or ((not ary[x][y]) and (not ary[x][y+1]) and (not ary[x][y+2]) and (not ary[x][y+3]) and ary[x][y+4] and (not ary[x][y+5]) and ary[x][y+6] and ary[x][y+7] and ary[x][y+8] and (not ary[x][y+9]) and ary[x][y+10]) then inc(Result,40); end; end; function PenaltyTest4 : integer; var x: Integer; y: Integer; iCnt, iColor : integer; iPercent, iLow, iHigh : integer; begin iCnt := 0; iColor := 0; for x := 0 to Size-1 do for y := 0 to Size-1 do begin inc(iCnt); if ary[x][y] then inc(iColor); end; if iCnt = 0 then begin result := 0; exit; end; iPercent := Trunc((iColor / iCnt) * 100); iLow := iPercent -1; iHigh := iPercent +1; while iLow mod 5 <> 0 do dec(iLow); while iHigh mod 5 <> 0 do inc(iHigh); Result := Min(Abs(iLow-50), Abs(iHigh-50))*10; end; begin FPenaltyScores[Mask][0] := PenaltyTest1; FPenaltyScores[Mask][1] := PenaltyTest2; FPenaltyScores[Mask][2] := PenaltyTest3; FPenaltyScores[Mask][3] := PenaltyTest4; Result := FPenaltyScores[Mask][0] + FPenaltyScores[Mask][1] + FPenaltyScores[Mask][2] + FPenaltyScores[Mask][3] ; end; var ary : TArray>; iScore, iLowScore, iSelected : integer; i, x, y: Integer; begin iSelected := 0; iLowScore := High(Integer); for i := 0 to 7 do begin SetLength(ary, Length(FModules)); for y := 0 to Length(FModules)-1 do begin SetLength(ary[y], Length(FModules[y])); end; for y := 0 to Length(FModules)-1 do begin for x := 0 to length(FModules[y])-1 do ary[x][y] := FModules[x][y]; end; ApplyMask(TMask(i), ary); iScore := PenaltyScore(i, ary); if iScore < iLowScore then begin iLowScore := iScore; iSelected := i; end; end; if FMask = TMask.Auto then ApplyMask(TMask(iSelected), FModules) else ApplyMask(FMask, FModules); end; procedure DrawFormat; function FormatString : string; begin case FECLInUse of TErrorCorrectionLevel.Low: case Integer(FMaskInUse) of 0: Result := '111011111000100'; 1: Result := '111001011110011'; 2: Result := '111110110101010'; 3: Result := '111100010011101'; 4: Result := '110011000101111'; 5: Result := '110001100011000'; 6: Result := '110110001000001'; 7: Result := '110100101110110'; end; TErrorCorrectionLevel.Medium: case Integer(FMaskInUse) of 0: Result := '101010000010010'; 1: Result := '101000100100101'; 2: Result := '101111001111100'; 3: Result := '101101101001011'; 4: Result := '100010111111001'; 5: Result := '100000011001110'; 6: Result := '100111110010111'; 7: Result := '100101010100000'; end; TErrorCorrectionLevel.Quartile: case Integer(FMaskInUse) of 0: Result := '011010101011111'; 1: Result := '011000001101000'; 2: Result := '011111100110001'; 3: Result := '011101000000110'; 4: Result := '010010010110100'; 5: Result := '010000110000011'; 6: Result := '010111011011010'; 7: Result := '010101111101101'; end; TErrorCorrectionLevel.High: case Integer(FMaskInUse) of 0: Result := '001011010001001'; 1: Result := '001001110111110'; 2: Result := '001110011100111'; 3: Result := '001100111010000'; 4: Result := '000011101100010'; 5: Result := '000001001010101'; 6: Result := '000110100001100'; 7: Result := '000100000111011'; end; end; end; var s : string; sFmt : string; x, y : integer; y2 : integer; x2 : integer; begin sFmt := FormatString; x := 0; y := 8; y2 := Size-1; x2 := 8; for s in sFmt do begin FModules[x][y] := s = '1'; if x < 8 then inc(x) else dec(y); if x = 6 then inc(x); if y = 6 then dec(y); FModules[x2][y2] := s = '1'; if y2 <= Size-7 then begin if y2 = Size-7 then begin y2 := 8; x2 := Size-8; end else inc(x2); end else dec(y2) end; end; procedure DrawVersion; var sVer : string; s: string; x, y, x2, y2 : integer; i: Integer; begin if FVersionInUse >= TVersion.v7 then begin case FVersionInUse of TVersion.v7 : sVer := '000111110010010100'; TVersion.v8 : sVer := '001000010110111100'; TVersion.v9 : sVer := '001001101010011001'; TVersion.v10 : sVer := '001010010011010011'; TVersion.v11 : sVer := '001011101111110110'; TVersion.v12 : sVer := '001100011101100010'; TVersion.v13 : sVer := '001101100001000111'; TVersion.v14 : sVer := '001110011000001101'; TVersion.v15 : sVer := '001111100100101000'; TVersion.v16 : sVer := '010000101101111000'; TVersion.v17 : sVer := '010001010001011101'; TVersion.v18 : sVer := '010010101000010111'; TVersion.v19 : sVer := '010011010100110010'; TVersion.v20 : sVer := '010100100110100110'; TVersion.v21 : sVer := '010101011010000011'; TVersion.v22 : sVer := '010110100011001001'; TVersion.v23 : sVer := '010111011111101100'; TVersion.v24 : sVer := '011000111011000100'; TVersion.v25 : sVer := '011001000111100001'; TVersion.v26 : sVer := '011010111110101011'; TVersion.v27 : sVer := '011011000010001110'; TVersion.v28 : sVer := '011100110000011010'; TVersion.v29 : sVer := '011101001100111111'; TVersion.v30 : sVer := '011110110101110101'; TVersion.v31 : sVer := '011111001001010000'; TVersion.v32 : sVer := '100000100111010101'; TVersion.v33 : sVer := '100001011011110000'; TVersion.v34 : sVer := '100010100010111010'; TVersion.v35 : sVer := '100011011110011111'; TVersion.v36 : sVer := '100100101100001011'; TVersion.v37 : sVer := '100101010000101110'; TVersion.v38 : sVer := '100110101001100100'; TVersion.v39 : sVer := '100111010101000001'; TVersion.v40 : sVer := '101000110001101001'; end; s := sVer; for i := 1 to Length(sVer) do begin s[length(sVer)-i+1] := sVer[i]; end; sVer := s; x := 0; y := FinderLocation(TFinderPosition.BottomLeft).Y-4; x2 := FinderLocation(TFinderPosition.TopRight).X-4; y2 := 0; for s in sVer do begin FModules[x][y] := s = '1'; inc(y); if y >= FinderLocation(TFinderPosition.BottomLeft).Y-1 then begin inc(x); y := FinderLocation(TFinderPosition.BottomLeft).Y-4; end; FModules[x2][y2] := s = '1'; inc(x2); if x2 >= FinderLocation(TFinderPosition.TopRight).X-1 then begin inc(y2); x2 := FinderLocation(TFinderPosition.TopRight).X-4; end; end; end; end; var i: Integer; fp: TFinderPosition; j: Integer; begin SetLength(FModules, Size); for i := 0 to Length(FModules) - 1 do begin SetLength(FModules[i], Size); for j := 0 to Length(FModules[i])-1 do FModules[i][j] := False; end; for i := 0 to 2 do begin fp := TFinderPosition(i); DrawFinder(fp); end; DrawAlignmentPatterns; DrawTimingPatterns; DrawDarkModule; ReserveFormatArea; ReserveVersionArea; DrawDataBits; DrawMaskPattern; DrawFormat; DrawVersion; end; procedure TQRCode.EncodeAlphaNumeric; function LookupAlphaVal(c : char) : integer; var i: Integer; begin Result := 0; for i := 0 to 44 do if AlphaEncoding[i] = c then begin Result := i; break; end; end; var sSeg : string; s: String; iVal : integer; begin s := TEncoding.UTF8.GetString(FData); while s.Length > 0 do begin sSeg := s.Substring(0,2); Delete(s,1,2); if sSeg.Length = 2 then begin iVal := (LookupAlphaVal(sSeg.Chars[0]) * 45)+LookupAlphaVal(sSeg.Chars[1]) ; WriteBits(DecimalToBinary(iVal,11)); end else begin iVal := LookupAlphaVal(sSeg.Chars[0]); WriteBits(DecimalToBinary(iVal,6)); end; end; end; procedure TQRCode.EncodeByte; var i: Integer; begin for i := 0 to Length(FData)-1 do WriteBits(DecimalToBinary(FData[i],8)); end; procedure TQRCode.EncodeKanji; begin raise EQREncodeException.Create('Kanji is not currently supported.'); end; procedure TQRCode.EncodeNumeric; var sSeg : string; s : string; begin s := TEncoding.UTF8.GetString(FData); while s.Length > 0 do begin sSeg := s.Substring(0,3); Delete(s,1,3); if (sSeg <> '') and sSeg.StartsWith('0') then Delete(sSeg,1,1); if (sSeg <> '') and sSeg.StartsWith('0') then Delete(sSeg,1,1); if sSeg = '' then sSeg := '0'; case sSeg.Length of 1: WriteBits(DecimalToBinary(sSeg.ToInteger,4)); 2: WriteBits(DecimalToBinary(sSeg.ToInteger,7)); 3: WriteBits(DecimalToBinary(sSeg.ToInteger,10)); end; end; end; procedure TQRCode.EndUpdate; begin dec(FUpdateDepth); if FUpdateDepth < 0 then FUpdateDepth := 0; if FUpdateDepth = 0 then UpdateCode; end; function TQRCode.DataCodewordCount: integer; begin case FECLInUse of TErrorCorrectionLevel.Low: Result := FCodeWordRequirements[FVersionInUse].Low[TCodeWordField.DataCodewordCount]; TErrorCorrectionLevel.Medium: Result := FCodeWordRequirements[FVersionInUse].Medium[TCodeWordField.DataCodewordCount]; TErrorCorrectionLevel.Quartile: Result := FCodeWordRequirements[FVersionInUse].Quartile[TCodeWordField.DataCodewordCount]; TErrorCorrectionLevel.High: Result := FCodeWordRequirements[FVersionInUse].High[TCodeWordField.DataCodewordCount]; else Result := 0; end; end; function TQRCode.FinderLocation(pos: TFinderPosition): TPoint; begin case pos of TFinderPosition.TopLeft: Result := TPoint.Create(0,0); TFinderPosition.TopRight: Result := TPoint.Create((((Integer(FVersionInUse)-1)*4)+21) - 7, 0); TFinderPosition.BottomLeft: Result := TPoint.Create(0,(((Integer(FVersionInUse)-1)*4)+21) - 7); end; end; procedure TQRCode.CalculateModules; var g1, g2, gECC1, gECC2 : TGroup; blk : TBlock; cw : Byte; i, iBlock, iPos, iOutPos: integer; cwf : TCodeWordFields; iECCSize : integer; rs : TReedSolomonGenerator; begin case FECLInUse of TErrorCorrectionLevel.Low: cwf := FCodeWordRequirements[FVersionInUse].Low; TErrorCorrectionLevel.Medium: cwf := FCodeWordRequirements[FVersionInUse].Medium; TErrorCorrectionLevel.Quartile: cwf := FCodeWordRequirements[FVersionInUse].Quartile; TErrorCorrectionLevel.High: cwf := FCodeWordRequirements[FVersionInUse].High; end; iPos := 0; iECCSize := 0; SetStatus('Collecting Data Codewords'); setLength(g1, cwf[TCodeWordField.BlocksInGroup1Count]); for iBlock := 0 to Length(g1)-1 do begin setLength(blk, cwf[TCodeWordField.DataCodewordsInGroup1BlockCount]); for i := 0 to cwf[TCodeWordField.DataCodewordsInGroup1BlockCount]-1 do begin cw := ReadCodeword(iPos); blk[i] := cw; end; g1[iBlock] := blk; end; setLength(g2, cwf[TCodeWordField.BlocksInGroup2Count]); for iBlock := 0 to Length(g2)-1 do begin setLength(blk, cwf[TCodeWordField.DataCodewordsInGroup2BlockCount]); for i := 0 to cwf[TCodeWordField.DataCodewordsInGroup2BlockCount]-1 do begin cw := ReadCodeword(iPos); blk[i] := cw; end; g2[iBlock] := blk; end; setLength(gECC1, length(g1)); for iBlock := 0 to length(g1)-1 do begin SetStatus('Calculating ECC Codewords Group 1 Block '+(iBlock+1).ToString); blk := g1[iBlock]; inc(iECCSize, cwf[TCodeWordField.ECCodewordsPerBlock]); rs := TReedSolomonGenerator.Create(cwf[TCodeWordField.ECCodewordsPerBlock]); try gECC1[iBlock] := rs.GetRemaineder(blk); finally rs.Free; end; end; setLength(gECC2, length(g2)); for iBlock := 0 to length(g2)-1 do begin SetStatus('Calculating ECC Codewords Group 2 Block '+(iBlock+1).ToString); blk := g2[iBlock]; inc(iECCSize, cwf[TCodeWordField.ECCodewordsPerBlock]); rs := TReedSolomonGenerator.Create(cwf[TCodeWordField.ECCodewordsPerBlock]); try gECC2[iBlock] := rs.GetRemaineder(blk); finally rs.Free; end; end; SetStatus('Interleaving Data Codewords'); SetLength(FCodeWords, CodewordCount+iECCSize); iPos := 0; iOutPos := 0; repeat if length(g1) > 0 then begin if iPos < cwf[TCodeWordField.DataCodewordsInGroup1BlockCount] then for iBlock := 0 to length(g1)-1 do begin if iPos < length(g1[iBlock]) then begin FCodeWords[iOutPos] := g1[iBlock][iPos]; inc(iOutPos); end; end; end; if length(g2) > 0 then begin if iPos < cwf[TCodeWordField.DataCodewordsInGroup2BlockCount] then for iBlock := 0 to length(g2)-1 do begin if iPos < length(g2[iBlock]) then begin FCodeWords[iOutPos] := g2[iBlock][iPos]; inc(iOutPos); end; end; end; inc(iPos); until iOutPos >= (Length(FCodeWords)-iECCSize); SetStatus('Interleaving ECC Codewords'); iPos := 0; repeat if length(gECC1) > 0 then begin if iPos < cwf[TCodeWordField.ECCodewordsPerBlock] then for iBlock := 0 to length(gECC1)-1 do begin if iPos < length(gECC1[iBlock]) then begin FCodeWords[iOutPos] := gECC1[iBlock][iPos]; inc(iOutPos); end; end; end; if length(gECC2) > 0 then begin if iPos < cwf[TCodeWordField.ECCodewordsPerBlock] then for iBlock := 0 to length(gECC2)-1 do begin if iPos < length(gECC2[iBlock]) then begin FCodeWords[iOutPos] := gECC2[iBlock][iPos]; inc(iOutPos); end; end; end; inc(iPos); until iOutPos >= Length(FCodeWords); FDataBits := OutputAsString; for i := 1 to RemainderBits[FVersionInUse] do begin FDataBits := FDataBits + '0'; end; SetStatus('Drawing Modules'); DrawModules; end; function TQRCode.GetText: string; begin Result := TEncoding.UTF8.GetString(FData); end; function TQRCode.MaxECL: TErrorCorrectionLevel; begin if Length(FData) < FVerCapacities[FVersionInUse].High[FMode] then Exit(TErrorCorrectionLevel.High) else if Length(FData) < FVerCapacities[FVersionInUse].Quartile[FMode] then Exit(TErrorCorrectionLevel.Quartile) else if Length(FData) < FVerCapacities[FVersionInUse].Medium[FMode] then Exit(TErrorCorrectionLevel.Medium) else if length(FData) < FVerCapacities[FVersionInUse].Low[FMode] then Exit(TErrorCorrectionLevel.Low) else raise Exception.Create('The data supplied will not fit in the requested qr version.'); end; function TQRCode.MinVersion : TVersion; var iLen : integer; i : TVersion; s : string; begin s := TEncoding.UTF8.GetString(FData); iLen := Length(S); for i := TVersion.v1 to TVersion.v40 do begin Result := i; case FECLInUse of TErrorCorrectionLevel.Low: if iLen <= FVerCapacities[i].Low[Mode] then break; TErrorCorrectionLevel.Medium: if iLen <= FVerCapacities[i].Medium[Mode] then break; TErrorCorrectionLevel.Quartile: if iLen <= FVerCapacities[i].Quartile[Mode] then break; TErrorCorrectionLevel.High: if iLen <= FVerCapacities[i].High[Mode] then break; end; end; end; function TQRCode.OutputAsString: string; var i: Integer; begin Result := ''; for i := 0 to Length(FCodeWords)-1 do begin Result := Result+DecimalToBinary(FCodeWords[i],8); end; end; procedure TQRCode.PaintQRCode; var x, y, width : integer; Offset : integer; FilledRects : TArray; iCnt : integer; begin if not Assigned(FOnPaint) then exit; width := (Length(FModules) * FPixelsPerModule) + (8 * FPixelsPerModule) + 2; Offset := (4 * FPixelsPerModule)+1; // Quiet Zone x := 0; y := 0; iCnt := 0; setLength(FilledRects, Size * Size); repeat repeat if FModules[x][y] then begin FilledRects[iCnt] := TRect.Create( (x*FPixelsPerModule)+Offset, (y*FPixelsPerModule)+Offset, (x*FPixelsPerModule)+FPixelsPerModule+Offset, (y*FPixelsPerModule)+FPixelsPerModule+Offset ); inc(iCnt); end; inc(y); until y = Length(FModules[x]); y := 0; inc(x); until x = Length(FModules); SetLength(FilledRects, iCnt); FOnPaint(width, width, FilledRects); end; function TQRCode.Pow(i, k: Integer): Integer; var j, Count: Integer; begin if k>0 then j:=2 else j:=1; for Count:=1 to k-1 do j:=j*i; Result:=j; end; function TQRCode.GetSize: integer; begin Result := (((Integer(FVersionInUse)-1)*4)+21); end; function TQRCode.ReadCodeword(var Pos: integer): Byte; var s : string; iCnt : integer; begin iCnt := 0; s := ''; repeat if FBits[Pos] then s := s+'1' else s := s+'0'; inc(iCnt); inc(Pos); until (Pos > FBitsPos) or (iCnt >= 8); Result := BinaryToDecimal(s); end; procedure TQRCode.Redraw; begin UpdateCode; end; procedure TQRCode.SetData(const Value: TArray); begin FData := Value; UpdateCode; end; procedure TQRCode.SetECL(const Value: TErrorCorrectionLevel); begin FECL := Value; if FECL <> TErrorCorrectionLevel.Auto then FECLInUse := Value; UpdateCode; end; procedure TQRCode.SetMask(const Value: TMask); begin FMask := Value; UpdateCode; end; procedure TQRCode.SetOnPaint(const Value: TPaintHandler); begin FOnPaint := Value; UpdateCode; end; procedure TQRCode.SetPixelsPerModule(const Value: integer); begin if Value <= 0 then raise Exception.Create('PixelsPerModule cannot be sero or less.'); FPixelsPerModule := Value; FRenderSize := FPixelsPerModule * Size; UpdateCode; end; procedure TQRCode.SetRenderSize(const Value: integer); begin PixelsPerModule := Value div (Size+8); end; procedure TQRCode.SetStatus(const Msg: string); begin if Assigned(FOnStatus) then FOnStatus(Msg); end; procedure TQRCode.SetText(const Value: string); begin FData := TEncoding.UTF8.GetBytes(Value); UpdateCode; end; procedure TQRCode.SetVersion(const Value: TVersion); begin FVersion := Value; if FVersion <> TVersion.Auto then FVersionInUse := Value; UpdateCode; end; procedure TQRCode.UpdateCode; var iReqBits : integer; i: Integer; begin if FUpdateDepth > 0 then exit; SetLength(FBits, 0); SetLength(FBits, 4096); FBitsLen := 4096; FBitsPos := 0; FReservedAreas.Clear; FMode := DetermineQRMode; if FVersion = TVersion.Auto then FVersionInUse := MinVersion else while (FVersionInUse < MinVersion) do if (FECLInUse > TErrorCorrectionLevel.Low) and (FECL = TErrorCorrectionLevel.Auto) then begin Dec(FECLInUse); end else raise EQREncodeException.Create('Specified Version is too low for size of data to encode.'); if FECL = TErrorCorrectionLevel.Auto then FECLInUse := MaxECL else while FECL > MaxECL do begin if (FVersionInUse < TVersion.v40) and (FVersion = TVersion.Auto) then inc(FVersionInUse) else raise EQREncodeException.Create('Specified Error Correction Level is too high for this qr code version and data size.'); end; SetStatus('Initializing Bits'); WriteMode; WriteLength; SetStatus('Encoding Data'); case FMode of TQRMode.Numeric: EncodeNumeric; TQRMode.AlphaNumeric: EncodeAlphaNumeric; TQRMode.Byte: EncodeByte; TQRMode.Kanji: EncodeKanji; end; iReqBits := DataCodewordCount * 8; for i := 1 to 4 do begin if FBitsPos < iReqBits then WriteBit(False); end; while (FBitsPos mod 8) <> 0 do WriteBit(False); while FBitsPos < iReqBits do begin WriteBits('11101100'); if FBitsPos < iReqBits then WriteBits('00010001'); end; SetStatus('Calculating Modules'); CalculateModules; SetStatus('Painting Code'); PaintQRCode; end; procedure TQRCode.WriteBit(b: boolean); begin FBits[FBitsPos] := b ; inc(FBitsPos); CheckBitsPos; end; procedure TQRCode.WriteBits(const s: string); var c: Char; begin for c in s do begin if c = '0' then WriteBit(False) else if c = '1' then WriteBit(True) else raise Exception.Create('Bad Bit'); end; end; procedure TQRCode.WriteLength; var s : string; iBits : integer; begin case FVersionInUse of TVersion.v1..TVersion.v9: case FMode of TQRMode.Numeric: iBits := 10; TQRMode.AlphaNumeric: iBits := 9; TQRMode.Byte: iBits := 8; TQRMode.Kanji: iBits := 8; else iBits := 0; end; TVersion.v10..TVersion.v26: case FMode of TQRMode.Numeric: iBits := 12; TQRMode.AlphaNumeric: iBits := 11; TQRMode.Byte: iBits := 16; TQRMode.Kanji: iBits := 10; else iBits := 0; end; TVersion.v27..TVersion.v40: case FMode of TQRMode.Numeric: iBits := 14; TQRMode.AlphaNumeric: iBits := 13; TQRMode.Byte: iBits := 16; TQRMode.Kanji: iBits := 12; else iBits := 0; end; else iBits := 0; end; s := DecimalToBinary(length(FData), iBits); while length(s) < iBits do s := '0'+s; WriteBits(s); end; procedure TQRCode.WriteMode; begin case FMode of TQRMode.Numeric: WriteBits('0001'); TQRMode.AlphaNumeric: WriteBits('0010'); TQRMode.Byte: WriteBits('0100'); TQRMode.Kanji: WriteBits('1000'); end; end; { TQRCode.TArrayHelper } class function TQRCode.TArrayHelper.AdvanceArray(Source: TArray; idx: integer): TArray; var i: Integer; begin SetLength(Result,Length(Source)-idx); for i := 0 to Length(Result)-1 do Result[i] := Source[i+idx]; end; class function TQRCode.TArrayHelper.Combination(SourceArray: TArray; SubsetSize: Cardinal): TArray>; var i, iResultSize, iNum, iDenom : Cardinal; idx: Cardinal; ary : TArray; begin iNum := 1; iDenom := 1; for i := Length(SourceArray) downto Length(SourceArray)-SubsetSize+1 do iNum := iNum*i; for i := SubsetSize downto 1 do iDenom := iDenom*i; iResultSize := iNum div iDenom; SetLength(Result, iResultSize); SetLength(ary,0); idx := 0; NextCombo(ary, SourceArray, SubsetSize, Result, idx); end; class procedure TQRCode.TArrayHelper.NextCombo(Prefix, Source: TArray; Count: Cardinal; Result: TArray>; var ResultIdx: Cardinal); var i : integer; a: T; ary : TArray; begin if Count = 0 then begin Result[ResultIdx] := Prefix; inc(ResultIdx); exit; end; for i := 0 to length(Source)-1 do begin a := Source[i]; ary := Prefix; SetLength(ary,Length(ary)+1); ary[Length(ary)-1] := a; NextCombo(ary, AdvanceArray(Source,i+1), Count-1,Result,ResultIdx); end; end; { TQRCode.TRectHelper } function TQRCode.TRectHelper.IntersectsWithPoint(const pt: TPoint): boolean; begin Result := IntersectsWithRect(TRect.Create(pt.X, pt.Y, pt.X, pt.Y)); end; function TQRCode.TRectHelper.IntersectsWithRect(const R: TRect): boolean; begin Result := (Self.Left <= R.Right) and (Self.Right >= R.Left) and (Self.Top <= R.Bottom) and (Self.Bottom >= R.Top); end; end.