这个实例在windows、OS X、IOS和Android等平台运行正常。
本文参考这个网站提供的方法:http://zarko-gajic.iz.hr/firemonkey-mobile-android-ios-qr-code-generation-using-delphi-xe-5-delphizxingqrcode/

代码中用到的DelphiZXingQRCode.Pas点这下载

  1. 1 unit Unit3;
  2. 2
  3. 3 interface
  4. 4
  5. 5 uses
  6. 6 System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  7. 7 FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Objects,
  8. 8 FMX.Controls.Presentation, FMX.Edit, FMX.StdCtrls,DelphiZXingQRCode,
  9. 9 FMX.ListBox,system.math;
  10. 10
  11. 11 type
  12. 12 TForm3 = class(TForm)
  13. 13 Button1: TButton;
  14. 14 edtText: TEdit;
  15. 15 imgQRCode: TImage;
  16. 16 cmbEncoding: TComboBox;
  17. 17 edtQuietZone: TEdit;
  18. 18 procedure Button1Click(Sender: TObject);
  19. 19 private
  20. 20 { Private declarations }
  21. 21 BMP: TBitmap;
  22. 22 public
  23. 23 { Public declarations }
  24. 24 end;
  25. 25
  26. 26 var
  27. 27 Form3: TForm3;
  28. 28
  29. 29 implementation
  30. 30
  31. 31 {$R *.fmx}
  32. 32
  33. 33 procedure TForm3.Button1Click(Sender: TObject);
  34. 34 const
  35. 35 downsizeQuality: Integer = 2; // bigger value, better quality, slower rendering
  36. 36 var
  37. 37 QRCode: TDelphiZXingQRCode;
  38. 38 Row, Column: Integer;
  39. 39 pixelColor : TAlphaColor;
  40. 40 vBitMapData : TBitmapData;
  41. 41 pixelCount, y, x: Integer;
  42. 42 columnPixel, rowPixel: Integer;
  43. 43 function GetPixelCount(AWidth, AHeight: Single): Integer;
  44. 44 begin
  45. 45 if QRCode.Rows > 0 then
  46. 46 Result := Trunc(Min(AWidth, AHeight)) div QRCode.Rows
  47. 47 else
  48. 48 Result := 0;
  49. 49 end;
  50. 50 begin
  51. 51 QRCode := TDelphiZXingQRCode.Create;
  52. 52 try
  53. 53 QRCode.Data := edtText.Text;
  54. 54 QRCode.Encoding := TQRCodeEncoding(cmbEncoding.ItemIndex);
  55. 55 QRCode.QuietZone := StrToIntDef(edtQuietZone.Text, 4);
  56. 56 pixelCount := GetPixelCount(imgQRCode.Width, imgQRCode.Height);
  57. 57 case imgQRCode.WrapMode of
  58. 58 TImageWrapMode.iwOriginal,TImageWrapMode.iwTile,TImageWrapMode.iwCenter:
  59. 59 begin
  60. 60 if pixelCount > 0 then
  61. 61 imgQRCode.Bitmap.SetSize(QRCode.Columns * pixelCount,
  62. 62 QRCode.Rows * pixelCount);
  63. 63 end;
  64. 64 TImageWrapMode.iwFit:
  65. 65 begin
  66. 66 if pixelCount > 0 then
  67. 67 begin
  68. 68 imgQRCode.Bitmap.SetSize(QRCode.Columns * pixelCount * downsizeQuality,
  69. 69 QRCode.Rows * pixelCount * downsizeQuality);
  70. 70 pixelCount := pixelCount * downsizeQuality;
  71. 71 end;
  72. 72 end;
  73. 73 TImageWrapMode.iwStretch:
  74. 74 raise Exception.Create('Not a good idea to stretch the QR Code');
  75. 75 end;
  76. 76// if imgQRCode.Bitmap.Canvas.BeginScene then
  77. 77// begin
  78. 78 try
  79. 79 imgQRCode.Bitmap.Canvas.Clear(TAlphaColors.White);
  80. 80 if pixelCount > 0 then
  81. 81 begin
  82. 82 if imgQRCode.Bitmap.Map(TMapAccess.maWrite, vBitMapData) then
  83. 83 begin
  84. 84 try
  85. 85 for Row := 0 to QRCode.Rows - 1 do
  86. 86 begin
  87. 87 for Column := 0 to QRCode.Columns - 1 do
  88. 88 begin
  89. 89 if (QRCode.IsBlack[Row, Column]) then
  90. 90 pixelColor := TAlphaColors.Black
  91. 91 else
  92. 92 pixelColor := TAlphaColors.White;
  93. 93 columnPixel := Column * pixelCount;
  94. 94 rowPixel := Row * pixelCount;
  95. 95 for x := 0 to pixelCount - 1 do
  96. 96 for y := 0 to pixelCount - 1 do
  97. 97 vBitMapData.SetPixel(columnPixel + x,
  98. 98 rowPixel + y, pixelColor);
  99. 99 end;
  100. 100 end;
  101. 101 finally
  102. 102 imgQRCode.Bitmap.Unmap(vBitMapData);
  103. 103 end;
  104. 104 end;
  105. 105 end;
  106. 106 finally
  107. 107// imgQRCode.Bitmap.Canvas.EndScene;
  108. 108// end;
  109. 109 end;
  110. 110 finally
  111. 111 QRCode.Free;
  112. 112 end;
  113. 113 end;
  114. 114
  115. 115 end.

FMX:

  1. 1 object Form3: TForm3
  2. 2 Left = 0
  3. 3 Top = 0
  4. 4 Caption = 'Form3'
  5. 5 ClientHeight = 487
  6. 6 ClientWidth = 328
  7. 7 FormFactor.Width = 320
  8. 8 FormFactor.Height = 480
  9. 9 FormFactor.Devices = [Desktop]
  10. 10 DesignerMasterStyle = 3
  11. 11 object Button1: TButton
  12. 12 Position.X = 32.000000000000000000
  13. 13 Position.Y = 104.000000000000000000
  14. 14 Size.Width = 89.000000000000000000
  15. 15 Size.Height = 44.000000000000000000
  16. 16 Size.PlatformDefault = False
  17. 17 TabOrder = 0
  18. 18 Text = 'Button1'
  19. 19 OnClick = Button1Click
  20. 20 end
  21. 21 object edtText: TEdit
  22. 22 Touch.InteractiveGestures = [LongTap, DoubleTap]
  23. 23 TabOrder = 1
  24. 24 Position.X = 32.000000000000000000
  25. 25 Position.Y = 56.000000000000000000
  26. 26 Size.Width = 233.000000000000000000
  27. 27 Size.Height = 32.000000000000000000
  28. 28 Size.PlatformDefault = False
  29. 29 end
  30. 30 object imgQRCode: TImage
  31. 31 MultiResBitmap = <
  32. 32 item
  33. 33 end>
  34. 34 Anchors = [akLeft, akTop, akRight, akBottom]
  35. 35 MarginWrapMode = Center
  36. 36 Position.X = 32.000000000000000000
  37. 37 Position.Y = 192.000000000000000000
  38. 38 Size.Width = 250.000000000000000000
  39. 39 Size.Height = 250.000000000000000000
  40. 40 Size.PlatformDefault = False
  41. 41 end
  42. 42 object cmbEncoding: TComboBox
  43. 43 Items.Strings = (
  44. 44 'Auto'
  45. 45 'Numeric'
  46. 46 'Alphanumeric'
  47. 47 'ISO-8859-1'
  48. 48 'UTF-8 without BOM'
  49. 49 'UTF-8 with BOM')
  50. 50 ItemIndex = 0
  51. 51 Position.X = 136.000000000000000000
  52. 52 Position.Y = 112.000000000000000000
  53. 53 Size.Width = 145.000000000000000000
  54. 54 Size.Height = 32.000000000000000000
  55. 55 Size.PlatformDefault = False
  56. 56 TabOrder = 3
  57. 57 end
  58. 58 object edtQuietZone: TEdit
  59. 59 Touch.InteractiveGestures = [LongTap, DoubleTap]
  60. 60 TabOrder = 4
  61. 61 Text = '4'
  62. 62 Position.X = 32.000000000000000000
  63. 63 Position.Y = 152.000000000000000000
  64. 64 Size.Width = 100.000000000000000000
  65. 65 Size.Height = 32.000000000000000000
  66. 66 Size.PlatformDefault = False
  67. 67 end
  68. 68 end

2015-02-13 新的demo,简化调用方式,要配合下面的DelphiZXIngQRCode.pas

 

新的DelphiZXIngQRCode.pas

  1. unit DelphiZXIngQRCode;
  2.  
  3. // ZXing QRCode port to Delphi, by Debenu Pty Ltd
  4. // www.debenu.com
  5.  
  6. // Original copyright notice
  7. (*
  8. * Copyright 2008 ZXing authors
  9. *
  10. * Licensed under the Apache License, Version 2.0 (the "License");
  11. * you may not use this file except in compliance with the License.
  12. * You may obtain a copy of the License at
  13. *
  14. * http://www.apache.org/licenses/LICENSE-2.0
  15. *
  16. * Unless required by applicable law or agreed to in writing, software
  17. * distributed under the License is distributed on an "AS IS" BASIS,
  18. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  19. * See the License for the specific language governing permissions and
  20. * limitations under the License.
  21. *)
  22.  
  23. interface
  24.  
  25. uses
  26. System.UITypes,
  27. FMX.Graphics,
  28. FMX.Objects,
  29. FMX.Types;
  30.  
  31. type
  32. TQRCodeEncoding = (qrAuto, qrNumeric, qrAlphanumeric, qrISO88591, qrUTF8NoBOM,
  33. qrUTF8BOM);
  34. T2DBooleanArray = array of array of Boolean;
  35.  
  36. TDelphiZXingQRCode = class
  37. protected
  38. FData: String;
  39. FRows: Integer;
  40. FColumns: Integer;
  41. FEncoding: TQRCodeEncoding;
  42. FQuietZone: Integer;
  43. FElements: T2DBooleanArray;
  44. procedure SetEncoding(NewEncoding: TQRCodeEncoding);
  45. procedure SetData(const NewData: string);
  46. procedure SetQuietZone(NewQuietZone: Integer);
  47. function GetIsBlack(Row, Column: Integer): Boolean;
  48. procedure Update;
  49. public
  50. constructor Create;
  51. procedure DrawQrcode(imgQRCode: TImage; QRCode: TDelphiZXingQRCode);
  52. property Data: string read FData write SetData;
  53. property Encoding: TQRCodeEncoding read FEncoding write SetEncoding;
  54. property QuietZone: Integer read FQuietZone write SetQuietZone;
  55. property Rows: Integer read FRows;
  56. property Columns: Integer read FColumns;
  57. property IsBlack[Row, Column: Integer]: Boolean read GetIsBlack;
  58. end;
  59.  
  60. implementation
  61.  
  62. uses
  63. System.Generics.Collections, Math, Classes, System.SysUtils;
  64.  
  65. type
  66. TByteArray = array of Byte;
  67. T2DByteArray = array of array of Byte;
  68. TIntegerArray = array of Integer;
  69.  
  70. const
  71. NUM_MASK_PATTERNS = 8;
  72.  
  73. QUIET_ZONE_SIZE = 4;
  74.  
  75. ALPHANUMERIC_TABLE: array [0 .. 95] of Integer = (-1, -1, -1, -1, -1, -1, -1,
  76. -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x00-0x0f
  77. -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x10-0x1f
  78. 36, -1, -1, -1, 37, 38, -1, -1, -1, -1, 39, 40, -1, 41, 42, 43, // 0x20-0x2f
  79. 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 44, -1, -1, -1, -1, -1, // 0x30-0x3f
  80. -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, // 0x40-0x4f
  81. 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1 // 0x50-0x5f
  82. );
  83.  
  84. DEFAULT_BYTE_MODE_ENCODING = 'ISO-8859-1';
  85.  
  86. POSITION_DETECTION_PATTERN: array [0 .. 6, 0 .. 6] of Integer =
  87. ((1, 1, 1, 1, 1, 1, 1), (1, 0, 0, 0, 0, 0, 1), (1, 0, 1, 1, 1, 0, 1),
  88. (1, 0, 1, 1, 1, 0, 1), (1, 0, 1, 1, 1, 0, 1), (1, 0, 0, 0, 0, 0, 1),
  89. (1, 1, 1, 1, 1, 1, 1));
  90.  
  91. HORIZONTAL_SEPARATION_PATTERN: array [0 .. 0, 0 .. 7] of Integer =
  92. ((0, 0, 0, 0, 0, 0, 0, 0));
  93.  
  94. VERTICAL_SEPARATION_PATTERN: array [0 .. 6, 0 .. 0] of Integer = ((0), (0),
  95. (0), (0), (0), (0), (0));
  96.  
  97. POSITION_ADJUSTMENT_PATTERN: array [0 .. 4, 0 .. 4] of Integer =
  98. ((1, 1, 1, 1, 1), (1, 0, 0, 0, 1), (1, 0, 1, 0, 1), (1, 0, 0, 0, 1),
  99. (1, 1, 1, 1, 1));
  100.  
  101. // From Appendix E. Table 1, JIS0510X:2004 (p 71). The table was double-checked by komatsu.
  102. POSITION_ADJUSTMENT_PATTERN_COORDINATE_TABLE: array [0 .. 39, 0 .. 6]
  103. of Integer = ((-1, -1, -1, -1, -1, -1, -1), // Version 1
  104. (6, 18, -1, -1, -1, -1, -1), // Version 2
  105. (6, 22, -1, -1, -1, -1, -1), // Version 3
  106. (6, 26, -1, -1, -1, -1, -1), // Version 4
  107. (6, 30, -1, -1, -1, -1, -1), // Version 5
  108. (6, 34, -1, -1, -1, -1, -1), // Version 6
  109. (6, 22, 38, -1, -1, -1, -1), // Version 7
  110. (6, 24, 42, -1, -1, -1, -1), // Version 8
  111. (6, 26, 46, -1, -1, -1, -1), // Version 9
  112. (6, 28, 50, -1, -1, -1, -1), // Version 10
  113. (6, 30, 54, -1, -1, -1, -1), // Version 11
  114. (6, 32, 58, -1, -1, -1, -1), // Version 12
  115. (6, 34, 62, -1, -1, -1, -1), // Version 13
  116. (6, 26, 46, 66, -1, -1, -1), // Version 14
  117. (6, 26, 48, 70, -1, -1, -1), // Version 15
  118. (6, 26, 50, 74, -1, -1, -1), // Version 16
  119. (6, 30, 54, 78, -1, -1, -1), // Version 17
  120. (6, 30, 56, 82, -1, -1, -1), // Version 18
  121. (6, 30, 58, 86, -1, -1, -1), // Version 19
  122. (6, 34, 62, 90, -1, -1, -1), // Version 20
  123. (6, 28, 50, 72, 94, -1, -1), // Version 21
  124. (6, 26, 50, 74, 98, -1, -1), // Version 22
  125. (6, 30, 54, 78, 102, -1, -1), // Version 23
  126. (6, 28, 54, 80, 106, -1, -1), // Version 24
  127. (6, 32, 58, 84, 110, -1, -1), // Version 25
  128. (6, 30, 58, 86, 114, -1, -1), // Version 26
  129. (6, 34, 62, 90, 118, -1, -1), // Version 27
  130. (6, 26, 50, 74, 98, 122, -1), // Version 28
  131. (6, 30, 54, 78, 102, 126, -1), // Version 29
  132. (6, 26, 52, 78, 104, 130, -1), // Version 30
  133. (6, 30, 56, 82, 108, 134, -1), // Version 31
  134. (6, 34, 60, 86, 112, 138, -1), // Version 32
  135. (6, 30, 58, 86, 114, 142, -1), // Version 33
  136. (6, 34, 62, 90, 118, 146, -1), // Version 34
  137. (6, 30, 54, 78, 102, 126, 150), // Version 35
  138. (6, 24, 50, 76, 102, 128, 154), // Version 36
  139. (6, 28, 54, 80, 106, 132, 158), // Version 37
  140. (6, 32, 58, 84, 110, 136, 162), // Version 38
  141. (6, 26, 54, 82, 110, 138, 166), // Version 39
  142. (6, 30, 58, 86, 114, 142, 170) // Version 40
  143. );
  144.  
  145. // Type info cells at the left top corner.
  146. TYPE_INFO_COORDINATES: array [0 .. 14, 0 .. 1] of Integer = ((8, 0), (8, 1),
  147. (8, 2), (8, 3), (8, 4), (8, 5), (8, 7), (8, 8), (7, 8), (5, 8), (4, 8),
  148. (3, 8), (2, 8), (1, 8), (0, 8));
  149.  
  150. // From Appendix D in JISX0510:2004 (p. 67)
  151. VERSION_INFO_POLY = $1F25; // 1 1111 0010 0101
  152.  
  153. // From Appendix C in JISX0510:2004 (p.65).
  154. TYPE_INFO_POLY = $537;
  155. TYPE_INFO_MASK_PATTERN = $5412;
  156.  
  157. VERSION_DECODE_INFO: array [0 .. 33] of Integer = (
  158.  
  159. $07C94, $085BC, $09A99, $0A4D3, $0BBF6, $0C762, $0D847, $0E60D, $0F928,
  160. $10B78, $1145D, $12A17, $13532, $149A6, $15683, $168C9, $177EC, $18EC4,
  161. $191E1, $1AFAB, $1B08E, $1CC1A, $1D33F, $1ED75, $1F250, $209D5, $216F0,
  162. $228BA, $2379F, $24B0B, $2542E, $26A64, $27541, $28C69);
  163.  
  164. type
  165. TMode = (qmTerminator, qmNumeric, qmAlphanumeric, qmStructuredAppend, qmByte,
  166. qmECI, qmKanji, qmFNC1FirstPosition, qmFNC1SecondPosition, qmHanzi);
  167.  
  168. const
  169. ModeCharacterCountBits: array [TMode] of array [0 .. 2] of Integer =
  170. ((0, 0, 0), (10, 12, 14), (9, 11, 13), (0, 0, 0), (8, 16, 16), (0, 0, 0),
  171. (8, 10, 12), (0, 0, 0), (0, 0, 0), (8, 10, 12));
  172.  
  173. ModeBits: array [TMode] of Integer = (0, 1, 2, 3, 4, 7, 8, 5, 9, 13);
  174.  
  175. type
  176. TErrorCorrectionLevel = class
  177. private
  178. FBits: Integer;
  179. public
  180. procedure Assign(Source: TErrorCorrectionLevel);
  181. function Ordinal: Integer;
  182. property Bits: Integer read FBits;
  183. end;
  184.  
  185. TECB = class
  186. private
  187. Count: Integer;
  188. DataCodewords: Integer;
  189. public
  190. constructor Create(Count, DataCodewords: Integer);
  191. function GetCount: Integer;
  192. function GetDataCodewords: Integer;
  193. end;
  194.  
  195. TECBArray = array of TECB;
  196.  
  197. TECBlocks = class
  198. private
  199. ECCodewordsPerBlock: Integer;
  200. ECBlocks: TECBArray;
  201. public
  202. constructor Create(ECCodewordsPerBlock: Integer; ECBlocks: TECB); overload;
  203. constructor Create(ECCodewordsPerBlock: Integer;
  204. ECBlocks1, ECBlocks2: TECB); overload;
  205. destructor Destroy; override;
  206. function GetTotalECCodewords: Integer;
  207. function GetNumBlocks: Integer;
  208. function GetECCodewordsPerBlock: Integer;
  209. function GetECBlocks: TECBArray;
  210. end;
  211.  
  212. TByteMatrix = class
  213. protected
  214. Bytes: T2DByteArray;
  215. FWidth: Integer;
  216. FHeight: Integer;
  217. public
  218. constructor Create(Width, Height: Integer);
  219. function Get(X, Y: Integer): Integer;
  220. procedure SetBoolean(X, Y: Integer; Value: Boolean);
  221. procedure SetInteger(X, Y: Integer; Value: Integer);
  222. function GetArray: T2DByteArray;
  223. procedure Assign(Source: TByteMatrix);
  224. procedure Clear(Value: Byte);
  225. function Hash: string;
  226. property Width: Integer read FWidth;
  227. property Height: Integer read FHeight;
  228. end;
  229.  
  230. TBitArray = class
  231. private
  232. Bits: array of Integer;
  233. Size: Integer;
  234. procedure EnsureCapacity(Size: Integer);
  235. public
  236. constructor Create; overload;
  237. constructor Create(Size: Integer); overload;
  238. function GetSizeInBytes: Integer;
  239. function GetSize: Integer;
  240. function Get(I: Integer): Boolean;
  241. procedure SetBit(Index: Integer);
  242. procedure AppendBit(Bit: Boolean);
  243. procedure AppendBits(Value, NumBits: Integer);
  244. procedure AppendBitArray(NewBitArray: TBitArray);
  245. procedure ToBytes(BitOffset: Integer; Source: TByteArray;
  246. Offset, NumBytes: Integer);
  247. procedure XorOperation(Other: TBitArray);
  248. end;
  249.  
  250. TCharacterSetECI = class
  251.  
  252. end;
  253.  
  254. TVersion = class
  255. private
  256. VersionNumber: Integer;
  257. AlignmentPatternCenters: array of Integer;
  258. ECBlocks: array of TECBlocks;
  259. TotalCodewords: Integer;
  260. ECCodewords: Integer;
  261. public
  262. constructor Create(VersionNumber: Integer;
  263. AlignmentPatternCenters: array of Integer;
  264. ECBlocks1, ECBlocks2, ECBlocks3, ECBlocks4: TECBlocks);
  265. destructor Destroy; override;
  266. class function GetVersionForNumber(VersionNum: Integer): TVersion;
  267. class function ChooseVersion(NumInputBits: Integer;
  268. ecLevel: TErrorCorrectionLevel): TVersion;
  269. function GetTotalCodewords: Integer;
  270. function GetECBlocksForLevel(ecLevel: TErrorCorrectionLevel): TECBlocks;
  271. function GetDimensionForVersion: Integer;
  272. end;
  273.  
  274. TMaskUtil = class
  275. public
  276. function GetDataMaskBit(MaskPattern, X, Y: Integer): Boolean;
  277. end;
  278.  
  279. TQRCode = class
  280. private
  281. FMode: TMode;
  282. FECLevel: TErrorCorrectionLevel;
  283. FVersion: Integer;
  284. FMatrixWidth: Integer;
  285. FMaskPattern: Integer;
  286. FNumTotalBytes: Integer;
  287. FNumDataBytes: Integer;
  288. FNumECBytes: Integer;
  289. FNumRSBlocks: Integer;
  290. FMatrix: TByteMatrix;
  291. FQRCodeError: Boolean;
  292. public
  293. constructor Create;
  294. destructor Destroy; override;
  295. function At(X, Y: Integer): Integer;
  296. function IsValid: Boolean;
  297. function IsValidMaskPattern(MaskPattern: Integer): Boolean;
  298. procedure SetMatrix(NewMatrix: TByteMatrix);
  299. procedure SetECLevel(NewECLevel: TErrorCorrectionLevel);
  300. procedure SetAll(VersionNum, NumBytes, NumDataBytes, NumRSBlocks,
  301. NumECBytes, MatrixWidth: Integer);
  302. property QRCodeError: Boolean read FQRCodeError;
  303. property Mode: TMode read FMode write FMode;
  304. property Version: Integer read FVersion write FVersion;
  305. property NumDataBytes: Integer read FNumDataBytes;
  306. property NumTotalBytes: Integer read FNumTotalBytes;
  307. property NumRSBlocks: Integer read FNumRSBlocks;
  308. property MatrixWidth: Integer read FMatrixWidth;
  309. property MaskPattern: Integer read FMaskPattern write FMaskPattern;
  310. property ecLevel: TErrorCorrectionLevel read FECLevel;
  311. end;
  312.  
  313. TMatrixUtil = class
  314.  
  315. private
  316. FMatrixUtilError: Boolean;
  317. procedure ClearMatrix(Matrix: TByteMatrix);
  318.  
  319. procedure EmbedBasicPatterns(Version: Integer; Matrix: TByteMatrix);
  320. procedure EmbedTypeInfo(ecLevel: TErrorCorrectionLevel;
  321. MaskPattern: Integer; Matrix: TByteMatrix);
  322. procedure MaybeEmbedVersionInfo(Version: Integer; Matrix: TByteMatrix);
  323. procedure EmbedDataBits(DataBits: TBitArray; MaskPattern: Integer;
  324. Matrix: TByteMatrix);
  325. function FindMSBSet(Value: Integer): Integer;
  326. function CalculateBCHCode(Value, Poly: Integer): Integer;
  327. procedure MakeTypeInfoBits(ecLevel: TErrorCorrectionLevel;
  328. MaskPattern: Integer; Bits: TBitArray);
  329. procedure MakeVersionInfoBits(Version: Integer; Bits: TBitArray);
  330. function IsEmpty(Value: Integer): Boolean;
  331. procedure EmbedTimingPatterns(Matrix: TByteMatrix);
  332. procedure EmbedDarkDotAtLeftBottomCorner(Matrix: TByteMatrix);
  333. procedure EmbedHorizontalSeparationPattern(XStart, YStart: Integer;
  334. Matrix: TByteMatrix);
  335. procedure EmbedVerticalSeparationPattern(XStart, YStart: Integer;
  336. Matrix: TByteMatrix);
  337. procedure EmbedPositionAdjustmentPattern(XStart, YStart: Integer;
  338. Matrix: TByteMatrix);
  339. procedure EmbedPositionDetectionPattern(XStart, YStart: Integer;
  340. Matrix: TByteMatrix);
  341. procedure EmbedPositionDetectionPatternsAndSeparators(Matrix: TByteMatrix);
  342. procedure MaybeEmbedPositionAdjustmentPatterns(Version: Integer;
  343. Matrix: TByteMatrix);
  344. public
  345. constructor Create;
  346. property MatrixUtilError: Boolean read FMatrixUtilError;
  347. procedure BuildMatrix(DataBits: TBitArray; ecLevel: TErrorCorrectionLevel;
  348. Version, MaskPattern: Integer; Matrix: TByteMatrix);
  349. end;
  350.  
  351. function GetModeBits(Mode: TMode): Integer;
  352. begin
  353. Result := ModeBits[Mode];
  354. end;
  355.  
  356. function GetModeCharacterCountBits(Mode: TMode; Version: TVersion): Integer;
  357. var
  358. Number: Integer;
  359. Offset: Integer;
  360. begin
  361. Number := Version.VersionNumber;
  362.  
  363. if (Number <= 9) then
  364. begin
  365. Offset := 0;
  366. end
  367. else if (Number <= 26) then
  368. begin
  369. Offset := 1;
  370. end
  371. else
  372. begin
  373. Offset := 2;
  374. end;
  375. Result := ModeCharacterCountBits[Mode][Offset];
  376. end;
  377.  
  378. type
  379. TBlockPair = class
  380. private
  381. FDataBytes: TByteArray;
  382. FErrorCorrectionBytes: TByteArray;
  383. public
  384. constructor Create(BA1, BA2: TByteArray);
  385. function GetDataBytes: TByteArray;
  386. function GetErrorCorrectionBytes: TByteArray;
  387. end;
  388.  
  389. TGenericGFPoly = class;
  390.  
  391. TGenericGF = class
  392. private
  393. FExpTable: TIntegerArray;
  394. FLogTable: TIntegerArray;
  395. FZero: TGenericGFPoly;
  396. FOne: TGenericGFPoly;
  397. FSize: Integer;
  398. FPrimitive: Integer;
  399. FGeneratorBase: Integer;
  400. FInitialized: Boolean;
  401. FPolyList: array of TGenericGFPoly;
  402.  
  403. procedure CheckInit;
  404. procedure Initialize;
  405. public
  406. class function CreateQRCodeField256: TGenericGF;
  407. class function AddOrSubtract(A, B: Integer): Integer;
  408. constructor Create(Primitive, Size, B: Integer);
  409. destructor Destroy; override;
  410. function GetZero: TGenericGFPoly;
  411. function Exp(A: Integer): Integer;
  412. function GetGeneratorBase: Integer;
  413. function Inverse(A: Integer): Integer;
  414. function Multiply(A, B: Integer): Integer;
  415. function BuildMonomial(Degree, Coefficient: Integer): TGenericGFPoly;
  416. end;
  417.  
  418. TGenericGFPolyArray = array of TGenericGFPoly;
  419.  
  420. TGenericGFPoly = class
  421. private
  422. FField: TGenericGF;
  423. FCoefficients: TIntegerArray;
  424. public
  425. constructor Create(AField: TGenericGF; ACoefficients: TIntegerArray);
  426. destructor Destroy; override;
  427. function Coefficients: TIntegerArray;
  428. function Multiply(Other: TGenericGFPoly): TGenericGFPoly;
  429. function MultiplyByMonomial(Degree, Coefficient: Integer): TGenericGFPoly;
  430. function Divide(Other: TGenericGFPoly): TGenericGFPolyArray;
  431. function GetCoefficients: TIntegerArray;
  432. function IsZero: Boolean;
  433. function GetCoefficient(Degree: Integer): Integer;
  434. function GetDegree: Integer;
  435. function AddOrSubtract(Other: TGenericGFPoly): TGenericGFPoly;
  436. end;
  437.  
  438. TReedSolomonEncoder = class
  439. private
  440. FField: TGenericGF;
  441. FCachedGenerators: TObjectList<TGenericGFPoly>;
  442. public
  443. constructor Create(AField: TGenericGF);
  444. destructor Destroy; override;
  445. procedure Encode(ToEncode: TIntegerArray; ECBytes: Integer);
  446. function BuildGenerator(Degree: Integer): TGenericGFPoly;
  447. end;
  448.  
  449. TEncoder = class
  450. private
  451. FEncoderError: Boolean;
  452.  
  453. function ApplyMaskPenaltyRule1Internal(Matrix: TByteMatrix;
  454. IsHorizontal: Boolean): Integer;
  455. function ChooseMode(const Content: string; var EncodeOptions: Integer)
  456. : TMode; overload;
  457. function FilterContent(const Content: string; Mode: TMode;
  458. EncodeOptions: Integer): string;
  459. procedure Append8BitBytes(const Content: string; Bits: TBitArray;
  460. EncodeOptions: Integer);
  461.  
  462. procedure AppendAlphanumericBytes(const Content: string; Bits: TBitArray);
  463. procedure AppendBytes(const Content: string; Mode: TMode; Bits: TBitArray;
  464. EncodeOptions: Integer);
  465. procedure AppendKanjiBytes(const Content: string; Bits: TBitArray);
  466. procedure AppendLengthInfo(NumLetters, VersionNum: Integer; Mode: TMode;
  467. Bits: TBitArray);
  468. procedure AppendModeInfo(Mode: TMode; Bits: TBitArray);
  469. procedure AppendNumericBytes(const Content: string; Bits: TBitArray);
  470. function ChooseMaskPattern(Bits: TBitArray; ecLevel: TErrorCorrectionLevel;
  471. Version: Integer; Matrix: TByteMatrix): Integer;
  472. function GenerateECBytes(DataBytes: TByteArray;
  473.  
  474. NumECBytesInBlock: Integer): TByteArray;
  475. function GetAlphanumericCode(Code: Integer): Integer;
  476. procedure GetNumDataBytesAndNumECBytesForBlockID(NumTotalBytes,
  477. NumDataBytes, NumRSBlocks, BlockID: Integer;
  478. var NumDataBytesInBlock: TIntegerArray;
  479. var NumECBytesInBlock: TIntegerArray);
  480. procedure InterleaveWithECBytes(Bits: TBitArray;
  481. NumTotalBytes, NumDataBytes, NumRSBlocks: Integer; var Result: TBitArray);
  482. // function IsOnlyDoubleByteKanji(const Content: string): Boolean;
  483. procedure TerminateBits(NumDataBytes: Integer; var Bits: TBitArray);
  484. function CalculateMaskPenalty(Matrix: TByteMatrix): Integer;
  485. function ApplyMaskPenaltyRule1(Matrix: TByteMatrix): Integer;
  486. function ApplyMaskPenaltyRule2(Matrix: TByteMatrix): Integer;
  487. function ApplyMaskPenaltyRule3(Matrix: TByteMatrix): Integer;
  488. function ApplyMaskPenaltyRule4(Matrix: TByteMatrix): Integer;
  489. // procedure Encode(const Content: string; ECLevel: TErrorCorrectionLevel; QRCode: TQRCode); overload;
  490. procedure Encode(const Content: string; EncodeOptions: Integer;
  491. ecLevel: TErrorCorrectionLevel; QRCode: TQRCode);
  492. public
  493. constructor Create;
  494. property EncoderError: Boolean read FEncoderError;
  495. end;
  496.  
  497. function TEncoder.ApplyMaskPenaltyRule1(Matrix: TByteMatrix): Integer;
  498. begin
  499. Result := ApplyMaskPenaltyRule1Internal(Matrix, True) +
  500. ApplyMaskPenaltyRule1Internal(Matrix, False);
  501. end;
  502.  
  503. // Apply mask penalty rule 2 and return the penalty. Find 2x2 blocks with the same color and give
  504. // penalty to them.
  505. function TEncoder.ApplyMaskPenaltyRule2(Matrix: TByteMatrix): Integer;
  506. var
  507. Penalty: Integer;
  508. TheArray: T2DByteArray;
  509. Width: Integer;
  510. Height: Integer;
  511. X: Integer;
  512. Y: Integer;
  513. Value: Integer;
  514. begin
  515. Penalty := 0;
  516. TheArray := Matrix.GetArray;
  517. Width := Matrix.Width;
  518. Height := Matrix.Height;
  519. for Y := 0 to Height - 2 do
  520. begin
  521. for X := 0 to Width - 2 do
  522. begin
  523. Value := TheArray[Y][X];
  524. if ((Value = TheArray[Y][X + 1]) and (Value = TheArray[Y + 1][X]) and
  525. (Value = TheArray[Y + 1][X + 1])) then
  526. begin
  527. Inc(Penalty, 3);
  528. end;
  529. end;
  530. end;
  531. Result := Penalty;
  532. end;
  533.  
  534. // Apply mask penalty rule 3 and return the penalty. Find consecutive cells of 00001011101 or
  535. // 10111010000, and give penalty to them. If we find patterns like 000010111010000, we give
  536. // penalties twice (i.e. 40 * 2).
  537. function TEncoder.ApplyMaskPenaltyRule3(Matrix: TByteMatrix): Integer;
  538. var
  539. Penalty: Integer;
  540. TheArray: T2DByteArray;
  541. Width: Integer;
  542. Height: Integer;
  543. X: Integer;
  544. Y: Integer;
  545. begin
  546. Penalty := 0;
  547. TheArray := Matrix.GetArray;
  548. Width := Matrix.Width;
  549. Height := Matrix.Height;
  550. for Y := 0 to Height - 1 do
  551. begin
  552. for X := 0 to Width - 1 do
  553. begin
  554. if ((X + 6 < Width) and (TheArray[Y][X] = 1) and (TheArray[Y][X + 1] = 0)
  555. and (TheArray[Y][X + 2] = 1) and (TheArray[Y][X + 3] = 1) and
  556. (TheArray[Y][X + 4] = 1) and (TheArray[Y][X + 5] = 0) and
  557. (TheArray[Y][X + 6] = 1) and
  558. (((X + 10 < Width) and (TheArray[Y][X + 7] = 0) and
  559. (TheArray[Y][X + 8] = 0) and (TheArray[Y][X + 9] = 0) and
  560. (TheArray[Y][X + 10] = 0)) or ((X - 4 >= 0) and (TheArray[Y][X - 1] = 0)
  561. and (TheArray[Y][X - 2] = 0) and (TheArray[Y][X - 3] = 0) and
  562. (TheArray[Y][X - 4] = 0)))) then
  563. begin
  564. Inc(Penalty, 40);
  565. end;
  566. if ((Y + 6 < Height) and (TheArray[Y][X] = 1) and (TheArray[Y + 1][X] = 0)
  567. and (TheArray[Y + 2][X] = 1) and (TheArray[Y + 3][X] = 1) and
  568. (TheArray[Y + 4][X] = 1) and (TheArray[Y + 5][X] = 0) and
  569. (TheArray[Y + 6][X] = 1) and
  570. (((Y + 10 < Height) and (TheArray[Y + 7][X] = 0) and
  571. (TheArray[Y + 8][X] = 0) and (TheArray[Y + 9][X] = 0) and
  572. (TheArray[Y + 10][X] = 0)) or ((Y - 4 >= 0) and (TheArray[Y - 1][X] = 0)
  573. and (TheArray[Y - 2][X] = 0) and (TheArray[Y - 3][X] = 0) and
  574. (TheArray[Y - 4][X] = 0)))) then
  575. begin
  576. Inc(Penalty, 40);
  577. end;
  578. end;
  579. end;
  580. Result := Penalty;
  581. end;
  582.  
  583. // Apply mask penalty rule 4 and return the penalty. Calculate the ratio of dark cells and give
  584. // penalty if the ratio is far from 50%. It gives 10 penalty for 5% distance. Examples:
  585. // - 0% => 100
  586. // - 40% => 20
  587. // - 45% => 10
  588. // - 50% => 0
  589. // - 55% => 10
  590. // - 55% => 20
  591. // - 100% => 100
  592. function TEncoder.ApplyMaskPenaltyRule4(Matrix: TByteMatrix): Integer;
  593. var
  594. NumDarkCells: Integer;
  595. TheArray: T2DByteArray;
  596. Width: Integer;
  597. Height: Integer;
  598. NumTotalCells: Integer;
  599. DarkRatio: Double;
  600. X: Integer;
  601. Y: Integer;
  602. begin
  603. NumDarkCells := 0;
  604. TheArray := Matrix.GetArray;
  605. Width := Matrix.Width;
  606. Height := Matrix.Height;
  607. for Y := 0 to Height - 1 do
  608. begin
  609. for X := 0 to Width - 1 do
  610. begin
  611. if (TheArray[Y][X] = 1) then
  612. begin
  613. Inc(NumDarkCells);
  614. end;
  615. end;
  616. end;
  617. NumTotalCells := Matrix.Height * Matrix.Width;
  618. DarkRatio := NumDarkCells / NumTotalCells;
  619. Result := Round(Abs((DarkRatio * 100 - 50)) / 50);
  620. end;
  621.  
  622. // Helper function for applyMaskPenaltyRule1. We need this for doing this calculation in both
  623. // vertical and horizontal orders respectively.
  624. function TEncoder.ApplyMaskPenaltyRule1Internal(Matrix: TByteMatrix;
  625. IsHorizontal: Boolean): Integer;
  626. var
  627. Penalty: Integer;
  628. NumSameBitCells: Integer;
  629. PrevBit: Integer;
  630. TheArray: T2DByteArray;
  631. I: Integer;
  632. J: Integer;
  633. Bit: Integer;
  634. ILimit: Integer;
  635. JLimit: Integer;
  636. begin
  637. Penalty := 0;
  638. NumSameBitCells := 0;
  639. PrevBit := -1;
  640. // Horizontal mode:
  641. // for (int i = 0; i < matrix.height(); ++i) {
  642. // for (int j = 0; j < matrix.width(); ++j) {
  643. // int bit = matrix.get(i, j);
  644. // Vertical mode:
  645. // for (int i = 0; i < matrix.width(); ++i) {
  646. // for (int j = 0; j < matrix.height(); ++j) {
  647. // int bit = matrix.get(j, i);
  648. if (IsHorizontal) then
  649. begin
  650. ILimit := Matrix.Height;
  651. JLimit := Matrix.Width;
  652. end
  653. else
  654. begin
  655. ILimit := Matrix.Width;
  656. JLimit := Matrix.Height;
  657. end;
  658. TheArray := Matrix.GetArray;
  659.  
  660. for I := 0 to ILimit - 1 do
  661. begin
  662. for J := 0 to JLimit - 1 do
  663. begin
  664. if (IsHorizontal) then
  665. begin
  666. Bit := TheArray[I][J];
  667. end
  668. else
  669. begin
  670. Bit := TheArray[J][I];
  671. end;
  672. if (Bit = PrevBit) then
  673. begin
  674. Inc(NumSameBitCells);
  675. // Found five repetitive cells with the same color (bit).
  676. // We'll give penalty of 3.
  677. if (NumSameBitCells = 5) then
  678. begin
  679. Inc(Penalty, 3);
  680. end
  681. else if (NumSameBitCells > 5) then
  682. begin
  683. // After five repetitive cells, we'll add the penalty one
  684. // by one.
  685. Inc(Penalty, 1);;
  686. end;
  687. end
  688. else
  689. begin
  690. NumSameBitCells := 1; // Include the cell itself.
  691. PrevBit := Bit;
  692. end;
  693. end;
  694. NumSameBitCells := 0; // Clear at each row/column.
  695. end;
  696. Result := Penalty;
  697. end;
  698.  
  699. { TQRCode }
  700.  
  701. constructor TQRCode.Create;
  702. begin
  703. FMode := qmTerminator;
  704. FQRCodeError := False;
  705. FECLevel := nil;
  706. FVersion := -1;
  707. FMatrixWidth := -1;
  708. FMaskPattern := -1;
  709. FNumTotalBytes := -1;
  710. FNumDataBytes := -1;
  711. FNumECBytes := -1;
  712. FNumRSBlocks := -1;
  713. FMatrix := nil;
  714. end;
  715.  
  716. destructor TQRCode.Destroy;
  717. begin
  718. if (Assigned(FECLevel)) then
  719. begin
  720. FECLevel.Free;
  721. end;
  722. if (Assigned(FMatrix)) then
  723. begin
  724. FMatrix.Free;
  725. end;
  726. inherited;
  727. end;
  728.  
  729. function TQRCode.At(X, Y: Integer): Integer;
  730. var
  731. Value: Integer;
  732. begin
  733. // The value must be zero or one.
  734. Value := FMatrix.Get(X, Y);
  735. if (not((Value = 0) or (Value = 1))) then
  736. begin
  737. FQRCodeError := True;
  738. end;
  739. Result := Value;
  740. end;
  741.  
  742. function TQRCode.IsValid: Boolean;
  743. begin
  744. Result :=
  745. // First check if all version are not uninitialized.
  746. ((FECLevel <> nil) and (FVersion <> -1) and (FMatrixWidth <> -1) and
  747. (FMaskPattern <> -1) and (FNumTotalBytes <> -1) and (FNumDataBytes <> -1)
  748. and (FNumECBytes <> -1) and (FNumRSBlocks <> -1) and
  749. // Then check them in other ways..
  750. IsValidMaskPattern(FMaskPattern) and (FNumTotalBytes = FNumDataBytes +
  751. FNumECBytes) and
  752. // ByteMatrix stuff.
  753. (Assigned(FMatrix)) and (FMatrixWidth = FMatrix.Width) and
  754. // See 7.3.1 of JISX0510:2004 (Fp.5).
  755. (FMatrix.Width = FMatrix.Height)); // Must be square.
  756. end;
  757.  
  758. function TQRCode.IsValidMaskPattern(MaskPattern: Integer): Boolean;
  759. begin
  760. Result := (MaskPattern >= 0) and (MaskPattern < NUM_MASK_PATTERNS);
  761. end;
  762.  
  763. procedure TQRCode.SetMatrix(NewMatrix: TByteMatrix);
  764. begin
  765. if (Assigned(FMatrix)) then
  766. begin
  767. FMatrix.Free;
  768. FMatrix := nil;
  769. end;
  770. FMatrix := NewMatrix;
  771. end;
  772.  
  773. procedure TQRCode.SetAll(VersionNum, NumBytes, NumDataBytes, NumRSBlocks,
  774. NumECBytes, MatrixWidth: Integer);
  775. begin
  776. FVersion := VersionNum;
  777. FNumTotalBytes := NumBytes;
  778. FNumDataBytes := NumDataBytes;
  779. FNumRSBlocks := NumRSBlocks;
  780. FNumECBytes := NumECBytes;
  781. FMatrixWidth := MatrixWidth;
  782. end;
  783.  
  784. procedure TQRCode.SetECLevel(NewECLevel: TErrorCorrectionLevel);
  785. begin
  786. if (Assigned(FECLevel)) then
  787. begin
  788. FECLevel.Free;
  789. end;
  790. FECLevel := TErrorCorrectionLevel.Create;
  791. FECLevel.Assign(NewECLevel);
  792. end;
  793.  
  794. { TByteMatrix }
  795.  
  796. procedure TByteMatrix.Clear(Value: Byte);
  797. var
  798. X, Y: Integer;
  799. begin
  800. for Y := 0 to FHeight - 1 do
  801. begin
  802. for X := 0 to FWidth - 1 do
  803. begin
  804. Bytes[Y][X] := Value;
  805. end;
  806. end;
  807. end;
  808.  
  809. constructor TByteMatrix.Create(Width, Height: Integer);
  810. var
  811. Y: Integer;
  812. X: Integer;
  813. begin
  814. FWidth := Width;
  815. FHeight := Height;
  816. SetLength(Bytes, Height);
  817. for Y := 0 to Height - 1 do
  818. begin
  819. SetLength(Bytes[Y], Width);
  820. for X := 0 to Width - 1 do
  821. begin
  822. Bytes[Y][X] := 0;
  823. end;
  824. end;
  825. end;
  826.  
  827. function TByteMatrix.Get(X, Y: Integer): Integer;
  828. begin
  829. if (Bytes[Y][X] = 255) then
  830. Result := -1
  831. else
  832. Result := Bytes[Y][X];
  833. end;
  834.  
  835. function TByteMatrix.GetArray: T2DByteArray;
  836. begin
  837. Result := Bytes;
  838. end;
  839.  
  840. function TByteMatrix.Hash: string;
  841. var
  842. X, Y: Integer;
  843. Counter: Integer;
  844. CC: Integer;
  845. begin
  846. Result := '';
  847. for Y := 0 to FHeight - 1 do
  848. begin
  849. Counter := 0;
  850. for X := 0 to FWidth - 1 do
  851. begin
  852. CC := Get(X, Y);
  853. if (CC = -1) then
  854. CC := 255;
  855. Counter := Counter + CC;
  856. end;
  857. Result := Result + Char((Counter mod 26) + 65);
  858. end;
  859. end;
  860.  
  861. procedure TByteMatrix.SetBoolean(X, Y: Integer; Value: Boolean);
  862. begin
  863. Bytes[Y][X] := Byte(Value) and $FF;
  864. end;
  865.  
  866. procedure TByteMatrix.SetInteger(X, Y, Value: Integer);
  867. begin
  868. Bytes[Y][X] := Value and $FF;
  869. end;
  870.  
  871. procedure TByteMatrix.Assign(Source: TByteMatrix);
  872. var
  873. SourceLength: Integer;
  874. begin
  875. SourceLength := Length(Source.Bytes);
  876. SetLength(Bytes, SourceLength);
  877. if (SourceLength > 0) then
  878. begin
  879. Move(Source.Bytes[0], Bytes[0], SourceLength);
  880. end;
  881. FWidth := Source.Width;
  882. FHeight := Source.Height;
  883. end;
  884.  
  885. { TEncoder }
  886.  
  887. function TEncoder.CalculateMaskPenalty(Matrix: TByteMatrix): Integer;
  888. var
  889. Penalty: Integer;
  890. begin
  891. Penalty := 0;
  892. Inc(Penalty, ApplyMaskPenaltyRule1(Matrix));
  893. Inc(Penalty, ApplyMaskPenaltyRule2(Matrix));
  894. Inc(Penalty, ApplyMaskPenaltyRule3(Matrix));
  895. Inc(Penalty, ApplyMaskPenaltyRule4(Matrix));
  896. Result := Penalty;
  897. end;
  898.  
  899. { procedure TEncoder.Encode(const Content: string; ECLevel: TErrorCorrectionLevel; QRCode: TQRCode);
  900. begin
  901. Encode(Content, ECLevel, nil, QRCode);
  902. end; }
  903.  
  904. procedure TEncoder.Encode(const Content: string; EncodeOptions: Integer;
  905. ecLevel: TErrorCorrectionLevel; QRCode: TQRCode);
  906. var
  907. Mode: TMode;
  908. DataBits: TBitArray;
  909. FinalBits: TBitArray;
  910. HeaderBits: TBitArray;
  911. HeaderAndDataBits: TBitArray;
  912. Matrix: TByteMatrix;
  913. NumLetters: Integer;
  914. MatrixUtil: TMatrixUtil;
  915. BitsNeeded: Integer;
  916. ProvisionalBitsNeeded: Integer;
  917. ProvisionalVersion: TVersion;
  918. Version: TVersion;
  919. ECBlocks: TECBlocks;
  920. NumDataBytes: Integer;
  921. Dimension: Integer;
  922. FilteredContent: string;
  923. begin
  924. DataBits := TBitArray.Create;
  925. HeaderBits := TBitArray.Create;
  926.  
  927. // Pick an encoding mode appropriate for the content. Note that this will not attempt to use
  928. // multiple modes / segments even if that were more efficient. Twould be nice.
  929. // Collect data within the main segment, separately, to count its size if needed. Don't add it to
  930. // main payload yet.
  931.  
  932. Mode := ChooseMode(Content, EncodeOptions);
  933. FilteredContent := FilterContent(Content, Mode, EncodeOptions);
  934. AppendBytes(FilteredContent, Mode, DataBits, EncodeOptions);
  935.  
  936. // (With ECI in place,) Write the mode marker
  937. AppendModeInfo(Mode, HeaderBits);
  938.  
  939. // Hard part: need to know version to know how many bits length takes. But need to know how many
  940. // bits it takes to know version. First we take a guess at version by assuming version will be
  941. // the minimum, 1:
  942. ProvisionalVersion := TVersion.GetVersionForNumber(1);
  943. try
  944. ProvisionalBitsNeeded := HeaderBits.GetSize + GetModeCharacterCountBits
  945. (Mode, ProvisionalVersion) + DataBits.GetSize;
  946. finally
  947. ProvisionalVersion.Free;
  948. end;
  949.  
  950. ProvisionalVersion := TVersion.ChooseVersion(ProvisionalBitsNeeded, ecLevel);
  951. try
  952. // Use that guess to calculate the right version. I am still not sure this works in 100% of cases.
  953. BitsNeeded := HeaderBits.GetSize + GetModeCharacterCountBits(Mode,
  954. ProvisionalVersion) + DataBits.GetSize;
  955. Version := TVersion.ChooseVersion(BitsNeeded, ecLevel);
  956. finally
  957. ProvisionalVersion.Free;
  958. end;
  959.  
  960. HeaderAndDataBits := TBitArray.Create;
  961. FinalBits := TBitArray.Create;
  962. try
  963. HeaderAndDataBits.AppendBitArray(HeaderBits);
  964.  
  965. // Find "length" of main segment and write it
  966. if (Mode = qmByte) then
  967. begin
  968. NumLetters := DataBits.GetSizeInBytes;
  969. end
  970. else
  971. begin
  972. NumLetters := Length(FilteredContent);
  973. end;
  974. AppendLengthInfo(NumLetters, Version.VersionNumber, Mode,
  975. HeaderAndDataBits);
  976. // Put data together into the overall payload
  977. HeaderAndDataBits.AppendBitArray(DataBits);
  978.  
  979. ECBlocks := Version.GetECBlocksForLevel(ecLevel);
  980. NumDataBytes := Version.GetTotalCodewords - ECBlocks.GetTotalECCodewords;
  981.  
  982. // Terminate the bits properly.
  983. TerminateBits(NumDataBytes, HeaderAndDataBits);
  984.  
  985. // Interleave data bits with error correction code.
  986. InterleaveWithECBytes(HeaderAndDataBits, Version.GetTotalCodewords,
  987. NumDataBytes, ECBlocks.GetNumBlocks, FinalBits);
  988.  
  989. // QRCode qrCode = new QRCode(); // This is passed in
  990.  
  991. QRCode.SetECLevel(ecLevel);
  992. QRCode.Mode := Mode;
  993. QRCode.Version := Version.VersionNumber;
  994.  
  995. // Choose the mask pattern and set to "qrCode".
  996. Dimension := Version.GetDimensionForVersion;
  997. Matrix := TByteMatrix.Create(Dimension, Dimension);
  998.  
  999. QRCode.MaskPattern := ChooseMaskPattern(FinalBits, ecLevel,
  1000. Version.VersionNumber, Matrix);
  1001.  
  1002. Matrix.Free;
  1003. Matrix := TByteMatrix.Create(Dimension, Dimension);
  1004.  
  1005. // Build the matrix and set it to "qrCode".
  1006. MatrixUtil := TMatrixUtil.Create;
  1007. try
  1008. MatrixUtil.BuildMatrix(FinalBits, QRCode.ecLevel, QRCode.Version,
  1009. QRCode.MaskPattern, Matrix);
  1010. finally
  1011. MatrixUtil.Free;
  1012. end;
  1013.  
  1014. QRCode.SetMatrix(Matrix); // QRCode will free the matrix
  1015. finally
  1016. DataBits.Free;
  1017. HeaderAndDataBits.Free;
  1018. FinalBits.Free;
  1019. HeaderBits.Free;
  1020. Version.Free;
  1021. end;
  1022. end;
  1023.  
  1024. function TEncoder.FilterContent(const Content: string; Mode: TMode;
  1025. EncodeOptions: Integer): string;
  1026. var
  1027. X: Integer;
  1028. CanAdd: Boolean;
  1029. begin
  1030. Result := '';
  1031. // for X := 1 to Length(Content) do
  1032. for X := Low(Content) to High(Content) do // 2015-02-04,edited by vclclx。
  1033. begin
  1034. CanAdd := False;
  1035. if (Mode = qmNumeric) then
  1036. begin
  1037. CanAdd := (Content[X] >= '0') and (Content[X] <= '9');
  1038. end
  1039. else if (Mode = qmAlphanumeric) then
  1040. begin
  1041. CanAdd := GetAlphanumericCode(Ord(Content[X])) > 0;
  1042. end
  1043. else if (Mode = qmByte) then
  1044. begin
  1045. if (EncodeOptions = 3) then
  1046. begin
  1047. CanAdd := Ord(Content[X]) <= $FF;
  1048. end
  1049. else if ((EncodeOptions = 4) or (EncodeOptions = 5)) then
  1050. begin
  1051. CanAdd := True;
  1052. end;
  1053. end;
  1054. if (CanAdd) then
  1055. begin
  1056. Result := Result + Content[X];
  1057. end;
  1058. end;
  1059. end;
  1060.  
  1061. // Return the code point of the table used in alphanumeric mode or
  1062. // -1 if there is no corresponding code in the table.
  1063. function TEncoder.GetAlphanumericCode(Code: Integer): Integer;
  1064. begin
  1065. if (Code < Length(ALPHANUMERIC_TABLE)) then
  1066. begin
  1067. Result := ALPHANUMERIC_TABLE[Code];
  1068. end
  1069. else
  1070. begin
  1071. Result := -1;
  1072. end;
  1073. end;
  1074.  
  1075. // Choose the mode based on the content
  1076. function TEncoder.ChooseMode(const Content: string;
  1077. var EncodeOptions: Integer): TMode;
  1078. var
  1079. AllNumeric: Boolean;
  1080. AllAlphanumeric: Boolean;
  1081. AllISO: Boolean;
  1082. I: Integer;
  1083. C: WideChar;
  1084. begin
  1085. if (EncodeOptions = 0) then
  1086. begin
  1087. AllNumeric := Length(Content) > 0;
  1088. // I := 1;
  1089. // while (I <= Length(Content)) and (AllNumeric) do
  1090. I := Low(Content); // 2015-02-04,edited by vclclx。
  1091. while (I <= High(Content)) and (AllNumeric) do
  1092. // 2015-02-04,edited by vclclx。
  1093. begin
  1094. C := Content[I];
  1095. if ((C < '0') or (C > '9')) then
  1096. begin
  1097. AllNumeric := False;
  1098. end
  1099. else
  1100. begin
  1101. Inc(I);
  1102. end;
  1103. end;
  1104.  
  1105. if (not AllNumeric) then
  1106. begin
  1107. AllAlphanumeric := Length(Content) > 0;
  1108. // I := 1;
  1109. // while (I <= Length(Content)) and (AllAlphanumeric) do
  1110. I := Low(Content); // 2015-02-04,edited by vclclx。
  1111. while (I <= High(Content)) and (AllAlphanumeric) do
  1112. // 2015-02-04,edited by vclclx。
  1113. begin
  1114. C := Content[I];
  1115. if (GetAlphanumericCode(Ord(C)) < 0) then
  1116. begin
  1117. AllAlphanumeric := False;
  1118. end
  1119. else
  1120. begin
  1121. Inc(I);
  1122. end;
  1123. end;
  1124. end
  1125. else
  1126. begin
  1127. AllAlphanumeric := False;
  1128. end;
  1129.  
  1130. if (not AllAlphanumeric) then
  1131. begin
  1132. AllISO := Length(Content) > 0;
  1133. // I := 1;
  1134. // while (I <= Length(Content)) and (AllISO) do
  1135. I := Low(Content); // 2015-02-04,edited by vclclx。
  1136. while (I <= High(Content)) and (AllISO) do // 2015-02-04,edited by vclclx。
  1137. begin
  1138. C := Content[I];
  1139. if (Ord(C) > $FF) then
  1140. begin
  1141. AllISO := False;
  1142. end
  1143. else
  1144. begin
  1145. Inc(I);
  1146. end;
  1147. end;
  1148. end
  1149. else
  1150. begin
  1151. AllISO := False;
  1152. end;
  1153.  
  1154. if (AllNumeric) then
  1155. begin
  1156. Result := qmNumeric;
  1157. end
  1158. else if (AllAlphanumeric) then
  1159. begin
  1160. Result := qmAlphanumeric;
  1161. end
  1162. else if (AllISO) then
  1163. begin
  1164. Result := qmByte;
  1165. EncodeOptions := 3;
  1166. end
  1167. else
  1168. begin
  1169. Result := qmByte;
  1170. EncodeOptions := 4;
  1171. end;
  1172. end
  1173. else if (EncodeOptions = 1) then
  1174. begin
  1175. Result := qmNumeric;
  1176. end
  1177. else if (EncodeOptions = 2) then
  1178. begin
  1179. Result := qmAlphanumeric;
  1180. end
  1181. else
  1182. begin
  1183. Result := qmByte;
  1184. end;
  1185. end;
  1186.  
  1187. constructor TEncoder.Create;
  1188. begin
  1189. FEncoderError := False;
  1190. end;
  1191.  
  1192. { function TEncoder.IsOnlyDoubleByteKanji(const Content: string): Boolean;
  1193. var
  1194. I: Integer;
  1195. Char1: Integer;
  1196. begin
  1197. Result := True;
  1198. I := 0;
  1199. while ((I < Length(Content)) and Result) do
  1200. begin
  1201. Char1 := Ord(Content[I + 1]);
  1202. if (((Char1 < $81) or (Char1 > $9F)) and ((Char1 < $E0) or (Char1 > $EB))) then
  1203. begin
  1204. Result := False;
  1205. end;
  1206. end;
  1207. end; }
  1208.  
  1209. function TEncoder.ChooseMaskPattern(Bits: TBitArray;
  1210. ecLevel: TErrorCorrectionLevel; Version: Integer;
  1211. Matrix: TByteMatrix): Integer;
  1212. var
  1213. MinPenalty: Integer;
  1214. BestMaskPattern: Integer;
  1215. MaskPattern: Integer;
  1216. MatrixUtil: TMatrixUtil;
  1217. Penalty: Integer;
  1218. begin
  1219. MinPenalty := MaxInt;
  1220. BestMaskPattern := -1;
  1221.  
  1222. // We try all mask patterns to choose the best one.
  1223. for MaskPattern := 0 to NUM_MASK_PATTERNS - 1 do
  1224. begin
  1225. MatrixUtil := TMatrixUtil.Create;
  1226. try
  1227. MatrixUtil.BuildMatrix(Bits, ecLevel, Version, MaskPattern, Matrix);
  1228. finally
  1229. MatrixUtil.Free;
  1230. end;
  1231. Penalty := CalculateMaskPenalty(Matrix);
  1232. if (Penalty < MinPenalty) then
  1233. begin
  1234. MinPenalty := Penalty;
  1235. BestMaskPattern := MaskPattern;
  1236. end;
  1237. end;
  1238.  
  1239. Result := BestMaskPattern;
  1240. end;
  1241.  
  1242. // Terminate bits as described in 8.4.8 and 8.4.9 of JISX0510:2004 (p.24).
  1243. procedure TEncoder.TerminateBits(NumDataBytes: Integer; var Bits: TBitArray);
  1244. var
  1245. Capacity: Integer;
  1246. I: Integer;
  1247. NumBitsInLastByte: Integer;
  1248. NumPaddingBytes: Integer;
  1249. begin
  1250. Capacity := NumDataBytes shl 3;
  1251. if (Bits.GetSize > Capacity) then
  1252. begin
  1253. FEncoderError := True;
  1254. Exit;
  1255. end;
  1256. I := 0;
  1257. while ((I < 4) and (Bits.GetSize < Capacity)) do
  1258. begin
  1259. Bits.AppendBit(False);
  1260. Inc(I);
  1261. end;
  1262.  
  1263. // Append termination bits. See 8.4.8 of JISX0510:2004 (p.24) for details.
  1264. // If the last byte isn't 8-bit aligned, we'll add padding bits.
  1265. NumBitsInLastByte := Bits.GetSize and $07;
  1266. if (NumBitsInLastByte > 0) then
  1267. begin
  1268. for I := NumBitsInLastByte to 7 do
  1269. begin
  1270. Bits.AppendBit(False);
  1271. end;
  1272. end;
  1273.  
  1274. // If we have more space, we'll fill the space with padding patterns defined in 8.4.9 (p.24).
  1275. NumPaddingBytes := NumDataBytes - Bits.GetSizeInBytes;
  1276. for I := 0 to NumPaddingBytes - 1 do
  1277. begin
  1278. if ((I and $01) = 0) then
  1279. begin
  1280. Bits.AppendBits($EC, 8);
  1281. end
  1282. else
  1283. begin
  1284. Bits.AppendBits($11, 8);
  1285. end;
  1286. end;
  1287. if (Bits.GetSize <> Capacity) then
  1288. begin
  1289. FEncoderError := True;
  1290. end;
  1291. end;
  1292.  
  1293. // Get number of data bytes and number of error correction bytes for block id "blockID". Store
  1294. // the result in "numDataBytesInBlock", and "numECBytesInBlock". See table 12 in 8.5.1 of
  1295. // JISX0510:2004 (p.30)
  1296. procedure TEncoder.GetNumDataBytesAndNumECBytesForBlockID(NumTotalBytes,
  1297. NumDataBytes, NumRSBlocks, BlockID: Integer;
  1298. var NumDataBytesInBlock: TIntegerArray; var NumECBytesInBlock: TIntegerArray);
  1299. var
  1300. NumRSBlocksInGroup1: Integer;
  1301. NumRSBlocksInGroup2: Integer;
  1302. NumTotalBytesInGroup1: Integer;
  1303. NumTotalBytesInGroup2: Integer;
  1304. NumDataBytesInGroup1: Integer;
  1305. NumDataBytesInGroup2: Integer;
  1306. NumECBytesInGroup1: Integer;
  1307. NumECBytesInGroup2: Integer;
  1308. begin
  1309. if (BlockID >= NumRSBlocks) then
  1310. begin
  1311. FEncoderError := True;
  1312. Exit;
  1313. end;
  1314. // numRsBlocksInGroup2 = 196 % 5 = 1
  1315. NumRSBlocksInGroup2 := NumTotalBytes mod NumRSBlocks;
  1316. // numRsBlocksInGroup1 = 5 - 1 = 4
  1317. NumRSBlocksInGroup1 := NumRSBlocks - NumRSBlocksInGroup2;
  1318. // numTotalBytesInGroup1 = 196 / 5 = 39
  1319. NumTotalBytesInGroup1 := NumTotalBytes div NumRSBlocks;
  1320. // numTotalBytesInGroup2 = 39 + 1 = 40
  1321. NumTotalBytesInGroup2 := NumTotalBytesInGroup1 + 1;
  1322. // numDataBytesInGroup1 = 66 / 5 = 13
  1323. NumDataBytesInGroup1 := NumDataBytes div NumRSBlocks;
  1324. // numDataBytesInGroup2 = 13 + 1 = 14
  1325. NumDataBytesInGroup2 := NumDataBytesInGroup1 + 1;
  1326. // numEcBytesInGroup1 = 39 - 13 = 26
  1327. NumECBytesInGroup1 := NumTotalBytesInGroup1 - NumDataBytesInGroup1;
  1328. // numEcBytesInGroup2 = 40 - 14 = 26
  1329. NumECBytesInGroup2 := NumTotalBytesInGroup2 - NumDataBytesInGroup2;
  1330. // Sanity checks.
  1331. // 26 = 26
  1332. if (NumECBytesInGroup1 <> NumECBytesInGroup2) then
  1333. begin
  1334. FEncoderError := True;
  1335. Exit;
  1336. end;
  1337. // 5 = 4 + 1.
  1338. if (NumRSBlocks <> (NumRSBlocksInGroup1 + NumRSBlocksInGroup2)) then
  1339. begin
  1340. FEncoderError := True;
  1341. Exit;
  1342. end;
  1343. // 196 = (13 + 26) * 4 + (14 + 26) * 1
  1344. if (NumTotalBytes <> ((NumDataBytesInGroup1 + NumECBytesInGroup1) *
  1345. NumRSBlocksInGroup1) + ((NumDataBytesInGroup2 + NumECBytesInGroup2) *
  1346. NumRSBlocksInGroup2)) then
  1347. begin
  1348. FEncoderError := True;
  1349. Exit;
  1350. end;
  1351.  
  1352. if (BlockID < NumRSBlocksInGroup1) then
  1353. begin
  1354. NumDataBytesInBlock[0] := NumDataBytesInGroup1;
  1355. NumECBytesInBlock[0] := NumECBytesInGroup1;
  1356. end
  1357. else
  1358. begin
  1359. NumDataBytesInBlock[0] := NumDataBytesInGroup2;
  1360. NumECBytesInBlock[0] := NumECBytesInGroup2;
  1361. end;
  1362. end;
  1363.  
  1364. // Interleave "bits" with corresponding error correction bytes. On success, store the result in
  1365. // "result". The interleave rule is complicated. See 8.6 of JISX0510:2004 (p.37) for details.
  1366. procedure TEncoder.InterleaveWithECBytes(Bits: TBitArray;
  1367. NumTotalBytes, NumDataBytes, NumRSBlocks: Integer; var Result: TBitArray);
  1368. var
  1369. DataBytesOffset: Integer;
  1370. MaxNumDataBytes: Integer;
  1371. MaxNumECBytes: Integer;
  1372. Blocks: TObjectList<TBlockPair>;
  1373. NumDataBytesInBlock: TIntegerArray;
  1374. NumECBytesInBlock: TIntegerArray;
  1375. Size: Integer;
  1376. DataBytes: TByteArray;
  1377. ECBytes: TByteArray;
  1378. I, J: Integer;
  1379. BlockPair: TBlockPair;
  1380. begin
  1381. SetLength(ECBytes, 0);
  1382.  
  1383. // "bits" must have "getNumDataBytes" bytes of data.
  1384. if (Bits.GetSizeInBytes <> NumDataBytes) then
  1385. begin
  1386. FEncoderError := True;
  1387. Exit;
  1388. end;
  1389.  
  1390. // Step 1. Divide data bytes into blocks and generate error correction bytes for them. We'll
  1391. // store the divided data bytes blocks and error correction bytes blocks into "blocks".
  1392. DataBytesOffset := 0;
  1393. MaxNumDataBytes := 0;
  1394. MaxNumECBytes := 0;
  1395.  
  1396. // Since, we know the number of reedsolmon blocks, we can initialize the vector with the number.
  1397. Blocks := TObjectList<TBlockPair>.Create(True);
  1398. try
  1399. Blocks.Capacity := NumRSBlocks;
  1400.  
  1401. for I := 0 to NumRSBlocks - 1 do
  1402. begin
  1403. SetLength(NumDataBytesInBlock, 1);
  1404. SetLength(NumECBytesInBlock, 1);
  1405. GetNumDataBytesAndNumECBytesForBlockID(NumTotalBytes, NumDataBytes,
  1406. NumRSBlocks, I, NumDataBytesInBlock, NumECBytesInBlock);
  1407.  
  1408. Size := NumDataBytesInBlock[0];
  1409. SetLength(DataBytes, Size);
  1410. Bits.ToBytes(8 * DataBytesOffset, DataBytes, 0, Size);
  1411. ECBytes := GenerateECBytes(DataBytes, NumECBytesInBlock[0]);
  1412. BlockPair := TBlockPair.Create(DataBytes, ECBytes);
  1413. Blocks.Add(BlockPair);
  1414.  
  1415. MaxNumDataBytes := Max(MaxNumDataBytes, Size);
  1416. MaxNumECBytes := Max(MaxNumECBytes, Length(ECBytes));
  1417. Inc(DataBytesOffset, NumDataBytesInBlock[0]);
  1418. end;
  1419. if (NumDataBytes <> DataBytesOffset) then
  1420. begin
  1421. FEncoderError := True;
  1422. Exit;
  1423. end;
  1424.  
  1425. // First, place data blocks.
  1426. for I := 0 to MaxNumDataBytes - 1 do
  1427. begin
  1428. for J := 0 to Blocks.Count - 1 do
  1429. begin
  1430. DataBytes := TBlockPair(Blocks.Items[J]).GetDataBytes;
  1431. if (I < Length(DataBytes)) then
  1432. begin
  1433. Result.AppendBits(DataBytes[I], 8);
  1434. end;
  1435. end;
  1436. end;
  1437. // Then, place error correction blocks.
  1438. for I := 0 to MaxNumECBytes - 1 do
  1439. begin
  1440. for J := 0 to Blocks.Count - 1 do
  1441. begin
  1442. ECBytes := TBlockPair(Blocks.Items[J]).GetErrorCorrectionBytes;
  1443. if (I < Length(ECBytes)) then
  1444. begin
  1445. Result.AppendBits(ECBytes[I], 8);
  1446. end;
  1447. end;
  1448. end;
  1449. finally
  1450. Blocks.Free;
  1451. end;
  1452. if (NumTotalBytes <> Result.GetSizeInBytes) then // Should be same.
  1453. begin
  1454. FEncoderError := True;
  1455. Exit;
  1456. end;
  1457. end;
  1458.  
  1459. function TEncoder.GenerateECBytes(DataBytes: TByteArray;
  1460. NumECBytesInBlock: Integer): TByteArray;
  1461. var
  1462. NumDataBytes: Integer;
  1463. ToEncode: TIntegerArray;
  1464. ReedSolomonEncoder: TReedSolomonEncoder;
  1465. I: Integer;
  1466. ECBytes: TByteArray;
  1467. GenericGF: TGenericGF;
  1468. begin
  1469. NumDataBytes := Length(DataBytes);
  1470. SetLength(ToEncode, NumDataBytes + NumECBytesInBlock);
  1471.  
  1472. for I := 0 to NumDataBytes - 1 do
  1473. begin
  1474. ToEncode[I] := DataBytes[I] and $FF;
  1475. end;
  1476.  
  1477. GenericGF := TGenericGF.CreateQRCodeField256;
  1478. try
  1479. ReedSolomonEncoder := TReedSolomonEncoder.Create(GenericGF);
  1480. try
  1481. ReedSolomonEncoder.Encode(ToEncode, NumECBytesInBlock);
  1482. finally
  1483. ReedSolomonEncoder.Free;
  1484. end;
  1485. finally
  1486. GenericGF.Free;
  1487. end;
  1488.  
  1489. SetLength(ECBytes, NumECBytesInBlock);
  1490. for I := 0 to NumECBytesInBlock - 1 do
  1491. begin
  1492. ECBytes[I] := ToEncode[NumDataBytes + I];
  1493. end;
  1494.  
  1495. Result := ECBytes;
  1496. end;
  1497.  
  1498. // Append mode info. On success, store the result in "bits".
  1499. procedure TEncoder.AppendModeInfo(Mode: TMode; Bits: TBitArray);
  1500. begin
  1501. Bits.AppendBits(GetModeBits(Mode), 4);
  1502. end;
  1503.  
  1504. // Append length info. On success, store the result in "bits".
  1505. procedure TEncoder.AppendLengthInfo(NumLetters, VersionNum: Integer;
  1506. Mode: TMode; Bits: TBitArray);
  1507. var
  1508. NumBits: Integer;
  1509. Version: TVersion;
  1510. begin
  1511. Version := TVersion.GetVersionForNumber(VersionNum);
  1512. try
  1513. NumBits := GetModeCharacterCountBits(Mode, Version);
  1514. finally
  1515. Version.Free;
  1516. end;
  1517.  
  1518. if (NumLetters > ((1 shl NumBits) - 1)) then
  1519. begin
  1520. FEncoderError := True;
  1521. Exit;
  1522. end;
  1523.  
  1524. Bits.AppendBits(NumLetters, NumBits);
  1525. end;
  1526.  
  1527. // Append "bytes" in "mode" mode (encoding) into "bits". On success, store the result in "bits".
  1528. procedure TEncoder.AppendBytes(const Content: string; Mode: TMode;
  1529. Bits: TBitArray; EncodeOptions: Integer);
  1530. begin
  1531. if (Mode = qmNumeric) then
  1532. begin
  1533. AppendNumericBytes(Content, Bits);
  1534. end
  1535. else if (Mode = qmAlphanumeric) then
  1536. begin
  1537. AppendAlphanumericBytes(Content, Bits);
  1538. end
  1539. else if (Mode = qmByte) then
  1540. begin
  1541. Append8BitBytes(Content, Bits, EncodeOptions);
  1542. end
  1543. else if (Mode = qmKanji) then
  1544. begin
  1545. AppendKanjiBytes(Content, Bits);
  1546. end
  1547. else
  1548. begin
  1549. FEncoderError := True;
  1550. Exit;
  1551. end;
  1552. end;
  1553.  
  1554. procedure TEncoder.AppendNumericBytes(const Content: string; Bits: TBitArray);
  1555. var
  1556. ContentLength: Integer;
  1557. I: Integer;
  1558. Num1: Integer;
  1559. Num2: Integer;
  1560. Num3: Integer;
  1561. begin
  1562. ContentLength := Length(Content);
  1563. // I := 0;
  1564. // while (I < ContentLength) do
  1565. I := Low(Content); // 2015-02-04,edited by vclclx。
  1566. while (I <= High(Content)) do // 2015-02-04,edited by vclclx。
  1567. begin
  1568. // Num1 := Ord(Content[I + 0 + 1]) - Ord('0');
  1569. Num1 := Ord(Content[I + 0]) - Ord('0'); // 2015-02-04,edited by vclclx。
  1570. // if (I + 2 < ContentLength) then
  1571. if (I + 2 <= High(Content)) then // 2015-02-04,edited by vclclx。
  1572. begin
  1573. // Encode three numeric letters in ten bits.
  1574. // Num2 := Ord(Content[I + 1 + 1]) - Ord('0');
  1575. // Num3 := Ord(Content[I + 2 + 1]) - Ord('0');
  1576. Num2 := Ord(Content[I + 1]) - Ord('0'); // 2015-02-04,edited by vclclx。
  1577. Num3 := Ord(Content[I + 2]) - Ord('0'); // 2015-02-04,edited by vclclx。
  1578. Bits.AppendBits(Num1 * 100 + Num2 * 10 + Num3, 10);
  1579. Inc(I, 3);
  1580. end
  1581. else
  1582. // if (I + 1 < ContentLength) then
  1583. if (I + 1 <= High(Content)) then // 2015-02-04,edited by vclclx。
  1584. begin
  1585. // Encode two numeric letters in seven bits.
  1586. // Num2 := Ord(Content[I + 1 + 1]) - Ord('0');
  1587. Num2 := Ord(Content[I + 1]) - Ord('0'); // 2015-02-04,edited by vclclx。
  1588. Bits.AppendBits(Num1 * 10 + Num2, 7);
  1589. Inc(I, 2);
  1590. end
  1591. else
  1592. begin
  1593. // Encode one numeric letter in four bits.
  1594. Bits.AppendBits(Num1, 4);
  1595. Inc(I);
  1596. end;
  1597. end;
  1598. end;
  1599.  
  1600. procedure TEncoder.AppendAlphanumericBytes(const Content: string;
  1601. Bits: TBitArray);
  1602. var
  1603. ContentLength: Integer;
  1604. I: Integer;
  1605. Code1: Integer;
  1606. Code2: Integer;
  1607. begin
  1608. ContentLength := Length(Content);
  1609. // I := 0;
  1610. // while (I < ContentLength) do
  1611. I := Low(Content); // 2015-02-04,edited by vclclx。
  1612. while (I <= High(Content)) do // 2015-02-04,edited by vclclx。
  1613. begin
  1614. // Code1 := GetAlphanumericCode(Ord(Content[I + 0 + 1]));
  1615. Code1 := GetAlphanumericCode(Ord(Content[I + 0]));
  1616. // 2015-02-04,edited by vclclx。
  1617. if (Code1 = -1) then
  1618. begin
  1619. FEncoderError := True;
  1620. Exit;
  1621. end;
  1622. // if (I + 1 < ContentLength) then
  1623. if (I + 1 <= High(Content)) then // 2015-02-04,edited by vclclx。
  1624. begin
  1625. // Code2 := GetAlphanumericCode(Ord(Content[I + 1 + 1]));
  1626. Code2 := GetAlphanumericCode(Ord(Content[I + 1]));
  1627. // 2015-02-04,edited by vclclx。
  1628. if (Code2 = -1) then
  1629. begin
  1630. FEncoderError := True;
  1631. Exit;
  1632. end;
  1633. // Encode two alphanumeric letters in 11 bits.
  1634. Bits.AppendBits(Code1 * 45 + Code2, 11);
  1635. Inc(I, 2);
  1636. end
  1637. else
  1638. begin
  1639. // Encode one alphanumeric letter in six bits.
  1640. Bits.AppendBits(Code1, 6);
  1641. Inc(I);
  1642. end;
  1643. end;
  1644. end;
  1645.  
  1646. procedure TEncoder.Append8BitBytes(const Content: string; Bits: TBitArray;
  1647. EncodeOptions: Integer);
  1648. var
  1649. Bytes: TByteArray;
  1650. I: Integer;
  1651. // UTF8Version: string;
  1652. UTF8Bytes: TBytes; // 2015-02-04,edited by vclclx。
  1653. begin
  1654. SetLength(Bytes, 0);
  1655. if (EncodeOptions = 3) then
  1656. begin
  1657. SetLength(Bytes, Length(Content));
  1658. // for I := 1 to Length(Content) do
  1659. for I := Low(Content) to High(Content) do // 2015-02-04,edited by vclclx。
  1660. begin
  1661. // Bytes[I - 1] := Ord(Content[I]) and $FF;
  1662. Bytes[I] := Ord(Content[I]) and $FF; // 2015-02-04,edited by vclclx。
  1663. end;
  1664. end
  1665. else if (EncodeOptions = 4) then
  1666. begin
  1667. // Add the UTF-8 BOM
  1668. // UTF8Version := #$EF#$BB#$BF + UTF8Encode(Content);
  1669. // SetLength(Bytes, Length(UTF8Version));
  1670. // if (Length(UTF8Version) > 0) then
  1671. // begin
  1672. // Move(UTF8Version[1], Bytes[0], Length(UTF8Version));
  1673. // end;
  1674.  
  1675. // 2015-02-04,edited by vclclx。
  1676. Bytes := [$EF, $BB, $BF];
  1677. with TUTF8Encoding.Create do
  1678. try
  1679. UTF8Bytes := GetBytes(Content);
  1680. finally
  1681. Free;
  1682. end;
  1683. if Length(UTF8Bytes) > 0 then
  1684. begin
  1685. SetLength(Bytes, 3 + Length(UTF8Bytes));
  1686. Move(UTF8Bytes[0], Bytes[3], Length(UTF8Bytes));
  1687. end;
  1688. end
  1689. else if (EncodeOptions = 5) then
  1690. begin
  1691. // No BOM
  1692. // UTF8Version := UTF8Encode(Content);
  1693. // SetLength(Bytes, Length(UTF8Version));
  1694. // if (Length(UTF8Version) > 0) then
  1695. // begin
  1696. // Move(UTF8Version[1], Bytes[0], Length(UTF8Version));
  1697. // end;
  1698.  
  1699. // 2015-02-04,edited by vclclx。
  1700. with TUTF8Encoding.Create do
  1701. try
  1702. UTF8Bytes := GetBytes(Content);
  1703. finally
  1704. Free;
  1705. end;
  1706. if Length(UTF8Bytes) > 0 then
  1707. begin
  1708. SetLength(Bytes, Length(UTF8Bytes));
  1709. Move(UTF8Bytes[0], Bytes[0], Length(UTF8Bytes));
  1710. end;
  1711. end;
  1712. for I := 0 to Length(Bytes) - 1 do
  1713. begin
  1714. Bits.AppendBits(Bytes[I], 8);
  1715. end;
  1716. end;
  1717.  
  1718. procedure TEncoder.AppendKanjiBytes(const Content: string; Bits: TBitArray);
  1719. var
  1720. Bytes: TByteArray;
  1721. ByteLength: Integer;
  1722. I: Integer;
  1723. Byte1: Integer;
  1724. Byte2: Integer;
  1725. Code: Integer;
  1726. Subtracted: Integer;
  1727. Encoded: Integer;
  1728. begin
  1729. SetLength(Bytes, 0);
  1730. try
  1731.  
  1732. except
  1733. FEncoderError := True;
  1734. Exit;
  1735. end;
  1736.  
  1737. ByteLength := Length(Bytes);
  1738. I := 0;
  1739. while (I < ByteLength) do
  1740. begin
  1741. Byte1 := Bytes[I] and $FF;
  1742. Byte2 := Bytes[I + 1] and $FF;
  1743. Code := (Byte1 shl 8) or Byte2;
  1744. Subtracted := -1;
  1745. if ((Code >= $8140) and (Code <= $9FFC)) then
  1746. begin
  1747. Subtracted := Code - $8140;
  1748. end
  1749. else if ((Code >= $E040) and (Code <= $EBBF)) then
  1750. begin
  1751. Subtracted := Code - $C140;
  1752. end;
  1753. if (Subtracted = -1) then
  1754. begin
  1755. FEncoderError := True;
  1756. Exit;
  1757. end;
  1758. Encoded := ((Subtracted shr 8) * $C0) + (Subtracted and $FF);
  1759. Bits.AppendBits(Encoded, 13);
  1760. Inc(I, 2);
  1761. end;
  1762. end;
  1763.  
  1764. procedure TMatrixUtil.ClearMatrix(Matrix: TByteMatrix);
  1765. begin
  1766. Matrix.Clear(Byte(-1));
  1767. end;
  1768.  
  1769. constructor TMatrixUtil.Create;
  1770. begin
  1771. FMatrixUtilError := False;
  1772. end;
  1773.  
  1774. // Build 2D matrix of QR Code from "dataBits" with "ecLevel", "version" and "getMaskPattern". On
  1775. // success, store the result in "matrix" and return true.
  1776. procedure TMatrixUtil.BuildMatrix(DataBits: TBitArray;
  1777. ecLevel: TErrorCorrectionLevel; Version, MaskPattern: Integer;
  1778. Matrix: TByteMatrix);
  1779. begin
  1780. ClearMatrix(Matrix);
  1781. EmbedBasicPatterns(Version, Matrix);
  1782.  
  1783. // Type information appear with any version.
  1784. EmbedTypeInfo(ecLevel, MaskPattern, Matrix);
  1785.  
  1786. // Version info appear if version >= 7.
  1787. MaybeEmbedVersionInfo(Version, Matrix);
  1788.  
  1789. // Data should be embedded at end.
  1790. EmbedDataBits(DataBits, MaskPattern, Matrix);
  1791. end;
  1792.  
  1793. // Embed basic patterns. On success, modify the matrix and return true.
  1794. // The basic patterns are:
  1795. // - Position detection patterns
  1796. // - Timing patterns
  1797. // - Dark dot at the left bottom corner
  1798. // - Position adjustment patterns, if need be
  1799. procedure TMatrixUtil.EmbedBasicPatterns(Version: Integer; Matrix: TByteMatrix);
  1800. begin
  1801. // Let's get started with embedding big squares at corners.
  1802. EmbedPositionDetectionPatternsAndSeparators(Matrix);
  1803.  
  1804. // Then, embed the dark dot at the left bottom corner.
  1805. EmbedDarkDotAtLeftBottomCorner(Matrix);
  1806.  
  1807. // Position adjustment patterns appear if version >= 2.
  1808. MaybeEmbedPositionAdjustmentPatterns(Version, Matrix);
  1809.  
  1810. // Timing patterns should be embedded after position adj. patterns.
  1811. EmbedTimingPatterns(Matrix);
  1812. end;
  1813.  
  1814. // Embed type information. On success, modify the matrix.
  1815. procedure TMatrixUtil.EmbedTypeInfo(ecLevel: TErrorCorrectionLevel;
  1816. MaskPattern: Integer; Matrix: TByteMatrix);
  1817. var
  1818. TypeInfoBits: TBitArray;
  1819. I: Integer;
  1820. Bit: Boolean;
  1821. X1, Y1: Integer;
  1822. X2, Y2: Integer;
  1823. begin
  1824. TypeInfoBits := TBitArray.Create;
  1825. try
  1826. MakeTypeInfoBits(ecLevel, MaskPattern, TypeInfoBits);
  1827.  
  1828. for I := 0 to TypeInfoBits.GetSize - 1 do
  1829. begin
  1830. // Place bits in LSB to MSB order. LSB (least significant bit) is the last value in
  1831. // "typeInfoBits".
  1832. Bit := TypeInfoBits.Get(TypeInfoBits.GetSize - 1 - I);
  1833.  
  1834. // Type info bits at the left top corner. See 8.9 of JISX0510:2004 (p.46).
  1835. X1 := TYPE_INFO_COORDINATES[I][0];
  1836. Y1 := TYPE_INFO_COORDINATES[I][1];
  1837. Matrix.SetBoolean(X1, Y1, Bit);
  1838.  
  1839. if (I < 8) then
  1840. begin
  1841. // Right top corner.
  1842. X2 := Matrix.Width - I - 1;
  1843. Y2 := 8;
  1844. Matrix.SetBoolean(X2, Y2, Bit);
  1845. end
  1846. else
  1847. begin
  1848. // Left bottom corner.
  1849. X2 := 8;
  1850. Y2 := Matrix.Height - 7 + (I - 8);
  1851. Matrix.SetBoolean(X2, Y2, Bit);
  1852. end;
  1853. end;
  1854. finally
  1855. TypeInfoBits.Free;
  1856. end;
  1857. end;
  1858.  
  1859. // Embed version information if need be. On success, modify the matrix and return true.
  1860. // See 8.10 of JISX0510:2004 (p.47) for how to embed version information.
  1861. procedure TMatrixUtil.MaybeEmbedVersionInfo(Version: Integer;
  1862. Matrix: TByteMatrix);
  1863. var
  1864. VersionInfoBits: TBitArray;
  1865. I, J: Integer;
  1866. BitIndex: Integer;
  1867. Bit: Boolean;
  1868. begin
  1869. if (Version < 7) then
  1870. begin
  1871. Exit; // Don't need version info.
  1872. end;
  1873.  
  1874. VersionInfoBits := TBitArray.Create;
  1875. try
  1876. MakeVersionInfoBits(Version, VersionInfoBits);
  1877.  
  1878. BitIndex := 6 * 3 - 1; // It will decrease from 17 to 0.
  1879. for I := 0 to 5 do
  1880. begin
  1881. for J := 0 to 2 do
  1882. begin
  1883. // Place bits in LSB (least significant bit) to MSB order.
  1884. Bit := VersionInfoBits.Get(BitIndex);
  1885. Dec(BitIndex);
  1886. // Left bottom corner.
  1887. Matrix.SetBoolean(I, Matrix.Height - 11 + J, Bit);
  1888. // Right bottom corner.
  1889. Matrix.SetBoolean(Matrix.Height - 11 + J, I, Bit);
  1890. end;
  1891. end;
  1892. finally
  1893. VersionInfoBits.Free;
  1894. end;
  1895. end;
  1896.  
  1897. // Embed "dataBits" using "getMaskPattern". On success, modify the matrix and return true.
  1898. // For debugging purposes, it skips masking process if "getMaskPattern" is -1.
  1899. // See 8.7 of JISX0510:2004 (p.38) for how to embed data bits.
  1900. procedure TMatrixUtil.EmbedDataBits(DataBits: TBitArray; MaskPattern: Integer;
  1901. Matrix: TByteMatrix);
  1902. var
  1903. BitIndex: Integer;
  1904. Direction: Integer;
  1905. X, Y, I, XX: Integer;
  1906. Bit: Boolean;
  1907. MaskUtil: TMaskUtil;
  1908. begin
  1909. MaskUtil := TMaskUtil.Create;
  1910. try
  1911. BitIndex := 0;
  1912. Direction := -1;
  1913. // Start from the right bottom cell.
  1914. X := Matrix.Width - 1;
  1915. Y := Matrix.Height - 1;
  1916. while (X > 0) do
  1917. begin
  1918. // Skip the vertical timing pattern.
  1919. if (X = 6) then
  1920. begin
  1921. Dec(X, 1);
  1922. end;
  1923. while ((Y >= 0) and (Y < Matrix.Height)) do
  1924. begin
  1925. for I := 0 to 1 do
  1926. begin
  1927. XX := X - I;
  1928. // Skip the cell if it's not empty.
  1929. if (not IsEmpty(Matrix.Get(XX, Y))) then
  1930. begin
  1931. Continue;
  1932. end;
  1933.  
  1934. if (BitIndex < DataBits.GetSize) then
  1935. begin
  1936. Bit := DataBits.Get(BitIndex);
  1937. Inc(BitIndex);
  1938. end
  1939. else
  1940. begin
  1941. // Padding bit. If there is no bit left, we'll fill the left cells with 0, as described
  1942. // in 8.4.9 of JISX0510:2004 (p. 24).
  1943. Bit := False;
  1944. end;
  1945.  
  1946. // Skip masking if mask_pattern is -1.
  1947. if (MaskPattern <> -1) then
  1948. begin
  1949. if (MaskUtil.GetDataMaskBit(MaskPattern, XX, Y)) then
  1950. begin
  1951. Bit := not Bit;
  1952. end;
  1953. end;
  1954. Matrix.SetBoolean(XX, Y, Bit);
  1955. end;
  1956. Inc(Y, Direction);
  1957. end;
  1958. Direction := -Direction; // Reverse the direction.
  1959. Inc(Y, Direction);
  1960. Dec(X, 2); // Move to the left.
  1961. end;
  1962. finally
  1963. MaskUtil.Free;
  1964. end;
  1965.  
  1966. // All bits should be consumed.
  1967. if (BitIndex <> DataBits.GetSize()) then
  1968. begin
  1969. FMatrixUtilError := True;
  1970. Exit;
  1971. end;
  1972. end;
  1973.  
  1974. // Return the position of the most significant bit set (to one) in the "value". The most
  1975. // significant bit is position 32. If there is no bit set, return 0. Examples:
  1976. // - findMSBSet(0) => 0
  1977. // - findMSBSet(1) => 1
  1978. // - findMSBSet(255) => 8
  1979. function TMatrixUtil.FindMSBSet(Value: Integer): Integer;
  1980. var
  1981. NumDigits: Integer;
  1982. begin
  1983. NumDigits := 0;
  1984. while (Value <> 0) do
  1985. begin
  1986. Value := Value shr 1;
  1987. Inc(NumDigits);
  1988. end;
  1989. Result := NumDigits;
  1990. end;
  1991.  
  1992. // Calculate BCH (Bose-Chaudhuri-Hocquenghem) code for "value" using polynomial "poly". The BCH
  1993. // code is used for encoding type information and version information.
  1994. // Example: Calculation of version information of 7.
  1995. // f(x) is created from 7.
  1996. // - 7 = 000111 in 6 bits
  1997. // - f(x) = x^2 + x^1 + x^0
  1998. // g(x) is given by the standard (p. 67)
  1999. // - g(x) = x^12 + x^11 + x^10 + x^9 + x^8 + x^5 + x^2 + 1
  2000. // Multiply f(x) by x^(18 - 6)
  2001. // - f'(x) = f(x) * x^(18 - 6)
  2002. // - f'(x) = x^14 + x^13 + x^12
  2003. // Calculate the remainder of f'(x) / g(x)
  2004. // x^2
  2005. // __________________________________________________
  2006. // g(x) )x^14 + x^13 + x^12
  2007. // x^14 + x^13 + x^12 + x^11 + x^10 + x^7 + x^4 + x^2
  2008. // --------------------------------------------------
  2009. // x^11 + x^10 + x^7 + x^4 + x^2
  2010. //
  2011. // The remainder is x^11 + x^10 + x^7 + x^4 + x^2
  2012. // Encode it in binary: 110010010100
  2013. // The return value is 0xc94 (1100 1001 0100)
  2014. //
  2015. // Since all coefficients in the polynomials are 1 or 0, we can do the calculation by bit
  2016. // operations. We don't care if cofficients are positive or negative.
  2017. function TMatrixUtil.CalculateBCHCode(Value, Poly: Integer): Integer;
  2018. var
  2019. MSBSetInPoly: Integer;
  2020. begin
  2021. // If poly is "1 1111 0010 0101" (version info poly), msbSetInPoly is 13. We'll subtract 1
  2022. // from 13 to make it 12.
  2023. MSBSetInPoly := FindMSBSet(Poly);
  2024. Value := Value shl (MSBSetInPoly - 1);
  2025. // Do the division business using exclusive-or operations.
  2026. while (FindMSBSet(Value) >= MSBSetInPoly) do
  2027. begin
  2028. Value := Value xor (Poly shl (FindMSBSet(Value) - MSBSetInPoly));
  2029. end;
  2030. // Now the "value" is the remainder (i.e. the BCH code)
  2031. Result := Value;
  2032. end;
  2033.  
  2034. // Make bit vector of type information. On success, store the result in "bits" and return true.
  2035. // Encode error correction level and mask pattern. See 8.9 of
  2036. // JISX0510:2004 (p.45) for details.
  2037. procedure TMatrixUtil.MakeTypeInfoBits(ecLevel: TErrorCorrectionLevel;
  2038. MaskPattern: Integer; Bits: TBitArray);
  2039. var
  2040. TypeInfo: Integer;
  2041. BCHCode: Integer;
  2042. MaskBits: TBitArray;
  2043. begin
  2044. if ((MaskPattern >= 0) and (MaskPattern < NUM_MASK_PATTERNS)) then
  2045. begin
  2046. TypeInfo := (ecLevel.Bits shl 3) or MaskPattern;
  2047. Bits.AppendBits(TypeInfo, 5);
  2048.  
  2049. BCHCode := CalculateBCHCode(TypeInfo, TYPE_INFO_POLY);
  2050. Bits.AppendBits(BCHCode, 10);
  2051.  
  2052. MaskBits := TBitArray.Create;
  2053. try
  2054. MaskBits.AppendBits(TYPE_INFO_MASK_PATTERN, 15);
  2055. Bits.XorOperation(MaskBits);
  2056. finally
  2057. MaskBits.Free;
  2058. end;
  2059.  
  2060. if (Bits.GetSize <> 15) then // Just in case.
  2061. begin
  2062. FMatrixUtilError := True;
  2063. Exit;
  2064. end;
  2065. end;
  2066. end;
  2067.  
  2068. // Make bit vector of version information. On success, store the result in "bits" and return true.
  2069. // See 8.10 of JISX0510:2004 (p.45) for details.
  2070. procedure TMatrixUtil.MakeVersionInfoBits(Version: Integer; Bits: TBitArray);
  2071. var
  2072. BCHCode: Integer;
  2073. begin
  2074. Bits.AppendBits(Version, 6);
  2075. BCHCode := CalculateBCHCode(Version, VERSION_INFO_POLY);
  2076. Bits.AppendBits(BCHCode, 12);
  2077.  
  2078. if (Bits.GetSize() <> 18) then
  2079. begin
  2080. FMatrixUtilError := True;
  2081. Exit;
  2082. end;
  2083. end;
  2084.  
  2085. // Check if "value" is empty.
  2086. function TMatrixUtil.IsEmpty(Value: Integer): Boolean;
  2087. begin
  2088. Result := (Value = -1);
  2089. end;
  2090.  
  2091. procedure TMatrixUtil.EmbedTimingPatterns(Matrix: TByteMatrix);
  2092. var
  2093. I: Integer;
  2094. Bit: Integer;
  2095. begin
  2096. // -8 is for skipping position detection patterns (size 7), and two horizontal/vertical
  2097. // separation patterns (size 1). Thus, 8 = 7 + 1.
  2098. for I := 8 to Matrix.Width - 9 do
  2099. begin
  2100. Bit := (I + 1) mod 2;
  2101. // Horizontal line.
  2102. if (IsEmpty(Matrix.Get(I, 6))) then
  2103. begin
  2104. Matrix.SetInteger(I, 6, Bit);
  2105. end;
  2106. // Vertical line.
  2107. if (IsEmpty(Matrix.Get(6, I))) then
  2108. begin
  2109. Matrix.SetInteger(6, I, Bit);
  2110. end;
  2111. end;
  2112. end;
  2113.  
  2114. // Embed the lonely dark dot at left bottom corner. JISX0510:2004 (p.46)
  2115. procedure TMatrixUtil.EmbedDarkDotAtLeftBottomCorner(Matrix: TByteMatrix);
  2116. begin
  2117. if (Matrix.Get(8, Matrix.Height - 8) = 0) then
  2118. begin
  2119. FMatrixUtilError := True;
  2120. Exit;
  2121. end;
  2122. Matrix.SetInteger(8, Matrix.Height - 8, 1);
  2123. end;
  2124.  
  2125. procedure TMatrixUtil.EmbedHorizontalSeparationPattern(XStart, YStart: Integer;
  2126. Matrix: TByteMatrix);
  2127. var
  2128. X: Integer;
  2129. begin
  2130. // We know the width and height.
  2131. for X := 0 to 7 do
  2132. begin
  2133. if (not IsEmpty(Matrix.Get(XStart + X, YStart))) then
  2134. begin
  2135. FMatrixUtilError := True;
  2136. Exit;
  2137. end;
  2138. Matrix.SetInteger(XStart + X, YStart, HORIZONTAL_SEPARATION_PATTERN[0][X]);
  2139. end;
  2140. end;
  2141.  
  2142. procedure TMatrixUtil.EmbedVerticalSeparationPattern(XStart, YStart: Integer;
  2143. Matrix: TByteMatrix);
  2144. var
  2145. Y: Integer;
  2146. begin
  2147. // We know the width and height.
  2148. for Y := 0 to 6 do
  2149. begin
  2150. if (not IsEmpty(Matrix.Get(XStart, YStart + Y))) then
  2151. begin
  2152. FMatrixUtilError := True;
  2153. Exit;
  2154. end;
  2155. Matrix.SetInteger(XStart, YStart + Y, VERTICAL_SEPARATION_PATTERN[Y][0]);
  2156. end;
  2157. end;
  2158.  
  2159. // Note that we cannot unify the function with embedPositionDetectionPattern() despite they are
  2160. // almost identical, since we cannot write a function that takes 2D arrays in different sizes in
  2161. // C/C++. We should live with the fact.
  2162. procedure TMatrixUtil.EmbedPositionAdjustmentPattern(XStart, YStart: Integer;
  2163. Matrix: TByteMatrix);
  2164. var
  2165. X, Y: Integer;
  2166. begin
  2167. // We know the width and height.
  2168. for Y := 0 to 4 do
  2169. begin
  2170. for X := 0 to 4 do
  2171. begin
  2172. if (not IsEmpty(Matrix.Get(XStart + X, YStart + Y))) then
  2173. begin
  2174. FMatrixUtilError := True;
  2175. Exit;
  2176. end;
  2177. Matrix.SetInteger(XStart + X, YStart + Y,
  2178. POSITION_ADJUSTMENT_PATTERN[Y][X]);
  2179. end;
  2180. end;
  2181. end;
  2182.  
  2183. procedure TMatrixUtil.EmbedPositionDetectionPattern(XStart, YStart: Integer;
  2184. Matrix: TByteMatrix);
  2185. var
  2186. X, Y: Integer;
  2187. begin
  2188. // We know the width and height.
  2189. for Y := 0 to 6 do
  2190. begin
  2191. for X := 0 to 6 do
  2192. begin
  2193. if (not IsEmpty(Matrix.Get(XStart + X, YStart + Y))) then
  2194. begin
  2195. FMatrixUtilError := True;
  2196. Exit;
  2197. end;
  2198. Matrix.SetInteger(XStart + X, YStart + Y,
  2199. POSITION_DETECTION_PATTERN[Y][X]);
  2200. end;
  2201. end;
  2202. end;
  2203.  
  2204. // Embed position detection patterns and surrounding vertical/horizontal separators.
  2205. procedure TMatrixUtil.EmbedPositionDetectionPatternsAndSeparators
  2206. (Matrix: TByteMatrix);
  2207. var
  2208. PDPWidth: Integer;
  2209. HSPWidth: Integer;
  2210. VSPSize: Integer;
  2211. begin
  2212. // Embed three big squares at corners.
  2213. PDPWidth := Length(POSITION_DETECTION_PATTERN[0]);
  2214. // Left top corner.
  2215. EmbedPositionDetectionPattern(0, 0, Matrix);
  2216. // Right top corner.
  2217. EmbedPositionDetectionPattern(Matrix.Width - PDPWidth, 0, Matrix);
  2218. // Left bottom corner.
  2219. EmbedPositionDetectionPattern(0, Matrix.Width - PDPWidth, Matrix);
  2220.  
  2221. // Embed horizontal separation patterns around the squares.
  2222. HSPWidth := Length(HORIZONTAL_SEPARATION_PATTERN[0]);
  2223. // Left top corner.
  2224. EmbedHorizontalSeparationPattern(0, HSPWidth - 1, Matrix);
  2225. // Right top corner.
  2226. EmbedHorizontalSeparationPattern(Matrix.Width - HSPWidth,
  2227. HSPWidth - 1, Matrix);
  2228. // Left bottom corner.
  2229. EmbedHorizontalSeparationPattern(0, Matrix.Width - HSPWidth, Matrix);
  2230.  
  2231. // Embed vertical separation patterns around the squares.
  2232. VSPSize := Length(VERTICAL_SEPARATION_PATTERN);
  2233. // Left top corner.
  2234. EmbedVerticalSeparationPattern(VSPSize, 0, Matrix);
  2235. // Right top corner.
  2236. EmbedVerticalSeparationPattern(Matrix.Height - VSPSize - 1, 0, Matrix);
  2237. // Left bottom corner.
  2238. EmbedVerticalSeparationPattern(VSPSize, Matrix.Height - VSPSize, Matrix);
  2239. end;
  2240.  
  2241. // Embed position adjustment patterns if need be.
  2242. procedure TMatrixUtil.MaybeEmbedPositionAdjustmentPatterns(Version: Integer;
  2243. Matrix: TByteMatrix);
  2244. var
  2245. Index: Integer;
  2246. Coordinates: array of Integer;
  2247. NumCoordinates: Integer;
  2248. X, Y, I, J: Integer;
  2249. begin
  2250. if (Version >= 2) then
  2251. begin
  2252. Index := Version - 1;
  2253. NumCoordinates :=
  2254. Length(POSITION_ADJUSTMENT_PATTERN_COORDINATE_TABLE[Index]);
  2255. SetLength(Coordinates, NumCoordinates);
  2256. Move(POSITION_ADJUSTMENT_PATTERN_COORDINATE_TABLE[Index][0], Coordinates[0],
  2257. NumCoordinates * SizeOf(Integer));
  2258. for I := 0 to NumCoordinates - 1 do
  2259. begin
  2260. for J := 0 to NumCoordinates - 1 do
  2261. begin
  2262. Y := Coordinates[I];
  2263. X := Coordinates[J];
  2264. if ((X = -1) or (Y = -1)) then
  2265. begin
  2266. Continue;
  2267. end;
  2268. // If the cell is unset, we embed the position adjustment pattern here.
  2269. if (IsEmpty(Matrix.Get(X, Y))) then
  2270. begin
  2271. // -2 is necessary since the x/y coordinates point to the center of the pattern, not the
  2272. // left top corner.
  2273. EmbedPositionAdjustmentPattern(X - 2, Y - 2, Matrix);
  2274. end;
  2275. end;
  2276. end;
  2277. end;
  2278. end;
  2279.  
  2280. { TBitArray }
  2281.  
  2282. procedure TBitArray.AppendBits(Value, NumBits: Integer);
  2283. var
  2284. NumBitsLeft: Integer;
  2285. begin
  2286. if ((NumBits < 0) or (NumBits > 32)) then
  2287. begin
  2288.  
  2289. end;
  2290. EnsureCapacity(Size + NumBits);
  2291. for NumBitsLeft := NumBits downto 1 do
  2292. begin
  2293. AppendBit(((Value shr (NumBitsLeft - 1)) and $01) = 1);
  2294. end;
  2295. end;
  2296.  
  2297. constructor TBitArray.Create(Size: Integer);
  2298.  
  2299. begin
  2300. Size := Size;
  2301. SetLength(Bits, (Size + 31) shr 5);
  2302. end;
  2303.  
  2304. constructor TBitArray.Create;
  2305. begin
  2306. Size := 0;
  2307. SetLength(Bits, 1);
  2308. end;
  2309.  
  2310. function TBitArray.Get(I: Integer): Boolean;
  2311. begin
  2312. Result := (Bits[I shr 5] and (1 shl (I and $1F))) <> 0;
  2313. end;
  2314.  
  2315. function TBitArray.GetSize: Integer;
  2316. begin
  2317. Result := Size;
  2318. end;
  2319.  
  2320. function TBitArray.GetSizeInBytes: Integer;
  2321. begin
  2322. Result := (Size + 7) shr 3;
  2323. end;
  2324.  
  2325. procedure TBitArray.SetBit(Index: Integer);
  2326. begin
  2327. Bits[Index shr 5] := Bits[Index shr 5] or (1 shl (Index and $1F));
  2328. end;
  2329.  
  2330. procedure TBitArray.AppendBit(Bit: Boolean);
  2331. begin
  2332. EnsureCapacity(Size + 1);
  2333. if (Bit) then
  2334. begin
  2335. Bits[Size shr 5] := Bits[Size shr 5] or (1 shl (Size and $1F));
  2336. end;
  2337. Inc(Size);
  2338. end;
  2339.  
  2340. procedure TBitArray.ToBytes(BitOffset: Integer; Source: TByteArray;
  2341. Offset, NumBytes: Integer);
  2342. var
  2343. I: Integer;
  2344. J: Integer;
  2345. TheByte: Integer;
  2346. begin
  2347. for I := 0 to NumBytes - 1 do
  2348. begin
  2349. TheByte := 0;
  2350. for J := 0 to 7 do
  2351. begin
  2352. if (Get(BitOffset)) then
  2353. begin
  2354. TheByte := TheByte or (1 shl (7 - J));
  2355. end;
  2356. Inc(BitOffset);
  2357. end;
  2358. Source[Offset + I] := TheByte;
  2359. end;
  2360. end;
  2361.  
  2362. procedure TBitArray.XorOperation(Other: TBitArray);
  2363. var
  2364. I: Integer;
  2365. begin
  2366. if (Length(Bits) = Length(Other.Bits)) then
  2367. begin
  2368. for I := 0 to Length(Bits) - 1 do
  2369. begin
  2370. // The last byte could be incomplete (i.e. not have 8 bits in
  2371. // it) but there is no problem since 0 XOR 0 == 0.
  2372. Bits[I] := Bits[I] xor Other.Bits[I];
  2373. end;
  2374. end;
  2375. end;
  2376.  
  2377. procedure TBitArray.AppendBitArray(NewBitArray: TBitArray);
  2378. var
  2379. OtherSize: Integer;
  2380. I: Integer;
  2381. begin
  2382. OtherSize := NewBitArray.GetSize;
  2383. EnsureCapacity(Size + OtherSize);
  2384. for I := 0 to OtherSize - 1 do
  2385. begin
  2386. AppendBit(NewBitArray.Get(I));
  2387. end;
  2388. end;
  2389.  
  2390. procedure TBitArray.EnsureCapacity(Size: Integer);
  2391. begin
  2392. if (Size > (Length(Bits) shl 5)) then
  2393. begin
  2394. SetLength(Bits, Size);
  2395. end;
  2396. end;
  2397.  
  2398. { TErrorCorrectionLevel }
  2399.  
  2400. procedure TErrorCorrectionLevel.Assign(Source: TErrorCorrectionLevel);
  2401. begin
  2402. Self.FBits := Source.FBits;
  2403. end;
  2404.  
  2405. function TErrorCorrectionLevel.Ordinal: Integer;
  2406. begin
  2407. Result := 0;
  2408. end;
  2409.  
  2410. { TVersion }
  2411.  
  2412. class function TVersion.ChooseVersion(NumInputBits: Integer;
  2413. ecLevel: TErrorCorrectionLevel): TVersion;
  2414. var
  2415. VersionNum: Integer;
  2416. Version: TVersion;
  2417. NumBytes: Integer;
  2418. ECBlocks: TECBlocks;
  2419. NumECBytes: Integer;
  2420. NumDataBytes: Integer;
  2421. TotalInputBytes: Integer;
  2422. begin
  2423. Result := nil;
  2424. // In the following comments, we use numbers of Version 7-H.
  2425. for VersionNum := 1 to 40 do
  2426. begin
  2427. Version := TVersion.GetVersionForNumber(VersionNum);
  2428.  
  2429. // numBytes = 196
  2430. NumBytes := Version.GetTotalCodewords;
  2431. // getNumECBytes = 130
  2432. ECBlocks := Version.GetECBlocksForLevel(ecLevel);
  2433. NumECBytes := ECBlocks.GetTotalECCodewords;
  2434. // getNumDataBytes = 196 - 130 = 66
  2435. NumDataBytes := NumBytes - NumECBytes;
  2436. TotalInputBytes := (NumInputBits + 7) div 8;
  2437.  
  2438. if (NumDataBytes >= TotalInputBytes) then
  2439. begin
  2440. Result := Version;
  2441. Exit;
  2442. end
  2443. else
  2444. begin
  2445. Version.Free;
  2446. end;
  2447. end;
  2448. end;
  2449.  
  2450. constructor TVersion.Create(VersionNumber: Integer;
  2451. AlignmentPatternCenters: array of Integer; ECBlocks1, ECBlocks2, ECBlocks3,
  2452. ECBlocks4: TECBlocks);
  2453. var
  2454. Total: Integer;
  2455. ECBlock: TECB;
  2456. ECBArray: TECBArray;
  2457. I: Integer;
  2458. begin
  2459. Self.VersionNumber := VersionNumber;
  2460. SetLength(Self.AlignmentPatternCenters, Length(AlignmentPatternCenters));
  2461. if (Length(AlignmentPatternCenters) > 0) then
  2462. begin
  2463. Move(AlignmentPatternCenters[0], Self.AlignmentPatternCenters[0],
  2464. Length(AlignmentPatternCenters) * SizeOf(Integer));
  2465. end;
  2466. SetLength(ECBlocks, 4);
  2467. ECBlocks[0] := ECBlocks1;
  2468. ECBlocks[1] := ECBlocks2;
  2469. ECBlocks[2] := ECBlocks3;
  2470. ECBlocks[3] := ECBlocks4;
  2471. Total := 0;
  2472. ECCodewords := ECBlocks1.GetECCodewordsPerBlock;
  2473. ECBArray := ECBlocks1.GetECBlocks;
  2474. for I := 0 to Length(ECBArray) - 1 do
  2475. begin
  2476. ECBlock := ECBArray[I];
  2477. Inc(Total, ECBlock.GetCount * (ECBlock.GetDataCodewords + ECCodewords));
  2478. end;
  2479. TotalCodewords := Total;
  2480. end;
  2481.  
  2482. destructor TVersion.Destroy;
  2483. var
  2484. X: Integer;
  2485. begin
  2486. for X := 0 to Length(ECBlocks) - 1 do
  2487. begin
  2488. ECBlocks[X].Free;
  2489. end;
  2490. inherited;
  2491. end;
  2492.  
  2493. function TVersion.GetDimensionForVersion: Integer;
  2494. begin
  2495. Result := 17 + 4 * VersionNumber;
  2496. end;
  2497.  
  2498. function TVersion.GetECBlocksForLevel(ecLevel: TErrorCorrectionLevel)
  2499. : TECBlocks;
  2500. begin
  2501. Result := ECBlocks[ecLevel.Ordinal];
  2502. end;
  2503.  
  2504. function TVersion.GetTotalCodewords: Integer;
  2505. begin
  2506. Result := TotalCodewords;
  2507. end;
  2508.  
  2509. class function TVersion.GetVersionForNumber(VersionNum: Integer): TVersion;
  2510. begin
  2511. if (VersionNum = 1) then
  2512. begin
  2513. Result := TVersion.Create(1, [], TECBlocks.Create(7, TECB.Create(1, 19)),
  2514. TECBlocks.Create(10, TECB.Create(1, 16)),
  2515. TECBlocks.Create(13, TECB.Create(1, 13)),
  2516. TECBlocks.Create(17, TECB.Create(1, 9)));
  2517. end
  2518. else if (VersionNum = 2) then
  2519. begin
  2520. Result := TVersion.Create(2, [6, 18],
  2521. TECBlocks.Create(10, TECB.Create(1, 34)),
  2522. TECBlocks.Create(16, TECB.Create(1, 28)),
  2523. TECBlocks.Create(22, TECB.Create(1, 22)),
  2524. TECBlocks.Create(28, TECB.Create(1, 16)));
  2525. end
  2526. else if (VersionNum = 3) then
  2527. begin
  2528. Result := TVersion.Create(3, [6, 22],
  2529. TECBlocks.Create(15, TECB.Create(1, 55)),
  2530. TECBlocks.Create(26, TECB.Create(1, 44)),
  2531. TECBlocks.Create(18, TECB.Create(2, 17)),
  2532. TECBlocks.Create(22, TECB.Create(2, 13)));
  2533. end
  2534. else if (VersionNum = 4) then
  2535. begin
  2536. Result := TVersion.Create(4, [6, 26],
  2537. TECBlocks.Create(20, TECB.Create(1, 80)),
  2538. TECBlocks.Create(18, TECB.Create(2, 32)),
  2539. TECBlocks.Create(26, TECB.Create(2, 24)),
  2540. TECBlocks.Create(16, TECB.Create(4, 9)));
  2541. end
  2542. else if (VersionNum = 5) then
  2543. begin
  2544. Result := TVersion.Create(5, [6, 30],
  2545. TECBlocks.Create(26, TECB.Create(1, 108)),
  2546. TECBlocks.Create(24, TECB.Create(2, 43)),
  2547. TECBlocks.Create(18, TECB.Create(2, 15), TECB.Create(2, 16)),
  2548. TECBlocks.Create(22, TECB.Create(2, 11), TECB.Create(2, 12)));
  2549. end
  2550. else if (VersionNum = 6) then
  2551. begin
  2552. Result := TVersion.Create(6, [6, 34],
  2553. TECBlocks.Create(18, TECB.Create(2, 68)),
  2554. TECBlocks.Create(16, TECB.Create(4, 27)),
  2555. TECBlocks.Create(24, TECB.Create(4, 19)),
  2556. TECBlocks.Create(28, TECB.Create(4, 15)));
  2557. end
  2558. else if (VersionNum = 7) then
  2559. begin
  2560. Result := TVersion.Create(7, [6, 22, 38],
  2561. TECBlocks.Create(20, TECB.Create(2, 78)),
  2562. TECBlocks.Create(18, TECB.Create(4, 31)),
  2563. TECBlocks.Create(18, TECB.Create(2, 14), TECB.Create(4, 15)),
  2564. TECBlocks.Create(26, TECB.Create(4, 13), TECB.Create(1, 14)));
  2565. end
  2566. else if (VersionNum = 8) then
  2567. begin
  2568. Result := TVersion.Create(8, [6, 24, 42],
  2569. TECBlocks.Create(24, TECB.Create(2, 97)),
  2570. TECBlocks.Create(22, TECB.Create(2, 38), TECB.Create(2, 39)),
  2571. TECBlocks.Create(22, TECB.Create(4, 18), TECB.Create(2, 19)),
  2572. TECBlocks.Create(26, TECB.Create(4, 14), TECB.Create(2, 15)));
  2573. end
  2574. else if (VersionNum = 9) then
  2575. begin
  2576. Result := TVersion.Create(9, [6, 26, 46],
  2577. TECBlocks.Create(30, TECB.Create(2, 116)),
  2578. TECBlocks.Create(22, TECB.Create(3, 36), TECB.Create(2, 37)),
  2579. TECBlocks.Create(20, TECB.Create(4, 16), TECB.Create(4, 17)),
  2580. TECBlocks.Create(24, TECB.Create(4, 12), TECB.Create(4, 13)));
  2581. end
  2582. else if (VersionNum = 10) then
  2583. begin
  2584. Result := TVersion.Create(10, [6, 28, 50],
  2585. TECBlocks.Create(18, TECB.Create(2, 68), TECB.Create(2, 69)),
  2586. TECBlocks.Create(26, TECB.Create(4, 43), TECB.Create(1, 44)),
  2587. TECBlocks.Create(24, TECB.Create(6, 19), TECB.Create(2, 20)),
  2588. TECBlocks.Create(28, TECB.Create(6, 15), TECB.Create(2, 16)));
  2589. end
  2590. else if (VersionNum = 11) then
  2591. begin
  2592. Result := TVersion.Create(11, [6, 30, 54],
  2593. TECBlocks.Create(20, TECB.Create(4, 81)),
  2594. TECBlocks.Create(30, TECB.Create(1, 50), TECB.Create(4, 51)),
  2595. TECBlocks.Create(28, TECB.Create(4, 22), TECB.Create(4, 23)),
  2596. TECBlocks.Create(24, TECB.Create(3, 12), TECB.Create(8, 13)));
  2597. end
  2598. else if (VersionNum = 12) then
  2599. begin
  2600. Result := TVersion.Create(12, [6, 32, 58],
  2601. TECBlocks.Create(24, TECB.Create(2, 92), TECB.Create(2, 93)),
  2602. TECBlocks.Create(22, TECB.Create(6, 36), TECB.Create(2, 37)),
  2603. TECBlocks.Create(26, TECB.Create(4, 20), TECB.Create(6, 21)),
  2604. TECBlocks.Create(28, TECB.Create(7, 14), TECB.Create(4, 15)));
  2605. end
  2606. else if (VersionNum = 13) then
  2607. begin
  2608. Result := TVersion.Create(13, [6, 34, 62],
  2609. TECBlocks.Create(26, TECB.Create(4, 107)),
  2610. TECBlocks.Create(22, TECB.Create(8, 37), TECB.Create(1, 38)),
  2611. TECBlocks.Create(24, TECB.Create(8, 20), TECB.Create(4, 21)),
  2612. TECBlocks.Create(22, TECB.Create(12, 11), TECB.Create(4, 12)));
  2613. end
  2614. else if (VersionNum = 14) then
  2615. begin
  2616. Result := TVersion.Create(14, [6, 26, 46, 66],
  2617. TECBlocks.Create(30, TECB.Create(3, 115), TECB.Create(1, 116)),
  2618. TECBlocks.Create(24, TECB.Create(4, 40), TECB.Create(5, 41)),
  2619. TECBlocks.Create(20, TECB.Create(11, 16), TECB.Create(5, 17)),
  2620. TECBlocks.Create(24, TECB.Create(11, 12), TECB.Create(5, 13)));
  2621. end
  2622. else if (VersionNum = 15) then
  2623. begin
  2624. Result := TVersion.Create(15, [6, 26, 48, 70],
  2625. TECBlocks.Create(22, TECB.Create(5, 87), TECB.Create(1, 88)),
  2626. TECBlocks.Create(24, TECB.Create(5, 41), TECB.Create(5, 42)),
  2627. TECBlocks.Create(30, TECB.Create(5, 24), TECB.Create(7, 25)),
  2628. TECBlocks.Create(24, TECB.Create(11, 12), TECB.Create(7, 13)));
  2629. end
  2630. else if (VersionNum = 16) then
  2631. begin
  2632. Result := TVersion.Create(16, [6, 26, 50, 74],
  2633. TECBlocks.Create(24, TECB.Create(5, 98), TECB.Create(1, 99)),
  2634. TECBlocks.Create(28, TECB.Create(7, 45), TECB.Create(3, 46)),
  2635. TECBlocks.Create(24, TECB.Create(15, 19), TECB.Create(2, 20)),
  2636. TECBlocks.Create(30, TECB.Create(3, 15), TECB.Create(13, 16)));
  2637. end
  2638. else if (VersionNum = 17) then
  2639. begin
  2640. Result := TVersion.Create(17, [6, 30, 54, 78],
  2641. TECBlocks.Create(28, TECB.Create(1, 107), TECB.Create(5, 108)),
  2642. TECBlocks.Create(28, TECB.Create(10, 46), TECB.Create(1, 47)),
  2643. TECBlocks.Create(28, TECB.Create(1, 22), TECB.Create(15, 23)),
  2644. TECBlocks.Create(28, TECB.Create(2, 14), TECB.Create(17, 15)));
  2645. end
  2646. else if (VersionNum = 18) then
  2647. begin
  2648. Result := TVersion.Create(18, [6, 30, 56, 82],
  2649. TECBlocks.Create(30, TECB.Create(5, 120), TECB.Create(1, 121)),
  2650. TECBlocks.Create(26, TECB.Create(9, 43), TECB.Create(4, 44)),
  2651. TECBlocks.Create(28, TECB.Create(17, 22), TECB.Create(1, 23)),
  2652. TECBlocks.Create(28, TECB.Create(2, 14), TECB.Create(19, 15)));
  2653. end
  2654. else if (VersionNum = 19) then
  2655. begin
  2656. Result := TVersion.Create(19, [6, 30, 58, 86],
  2657. TECBlocks.Create(28, TECB.Create(3, 113), TECB.Create(4, 114)),
  2658. TECBlocks.Create(26, TECB.Create(3, 44), TECB.Create(11, 45)),
  2659. TECBlocks.Create(26, TECB.Create(17, 21), TECB.Create(4, 22)),
  2660. TECBlocks.Create(26, TECB.Create(9, 13), TECB.Create(16, 14)));
  2661. end
  2662. else if (VersionNum = 20) then
  2663. begin
  2664. Result := TVersion.Create(20, [6, 34, 62, 90],
  2665. TECBlocks.Create(28, TECB.Create(3, 107), TECB.Create(5, 108)),
  2666. TECBlocks.Create(26, TECB.Create(3, 41), TECB.Create(13, 42)),
  2667. TECBlocks.Create(30, TECB.Create(15, 24), TECB.Create(5, 25)),
  2668. TECBlocks.Create(28, TECB.Create(15, 15), TECB.Create(10, 16)));
  2669. end
  2670. else if (VersionNum = 21) then
  2671. begin
  2672. Result := TVersion.Create(21, [6, 28, 50, 72, 94],
  2673. TECBlocks.Create(28, TECB.Create(4, 116), TECB.Create(4, 117)),
  2674. TECBlocks.Create(26, TECB.Create(17, 42)),
  2675. TECBlocks.Create(28, TECB.Create(17, 22), TECB.Create(6, 23)),
  2676. TECBlocks.Create(30, TECB.Create(19, 16), TECB.Create(6, 17)));
  2677. end
  2678. else if (VersionNum = 22) then
  2679. begin
  2680. Result := TVersion.Create(22, [6, 26, 50, 74, 98],
  2681. TECBlocks.Create(28, TECB.Create(2, 111), TECB.Create(7, 112)),
  2682. TECBlocks.Create(28, TECB.Create(17, 46)),
  2683. TECBlocks.Create(30, TECB.Create(7, 24), TECB.Create(16, 25)),
  2684. TECBlocks.Create(24, TECB.Create(34, 13)));
  2685. end
  2686. else if (VersionNum = 23) then
  2687. begin
  2688. Result := TVersion.Create(23, [6, 30, 54, 78, 102],
  2689. TECBlocks.Create(30, TECB.Create(4, 121), TECB.Create(5, 122)),
  2690. TECBlocks.Create(28, TECB.Create(4, 47), TECB.Create(14, 48)),
  2691. TECBlocks.Create(30, TECB.Create(11, 24), TECB.Create(14, 25)),
  2692. TECBlocks.Create(30, TECB.Create(16, 15), TECB.Create(14, 16)));
  2693. end
  2694. else if (VersionNum = 24) then
  2695. begin
  2696. Result := TVersion.Create(24, [6, 28, 54, 80, 106],
  2697. TECBlocks.Create(30, TECB.Create(6, 117), TECB.Create(4, 118)),
  2698. TECBlocks.Create(28, TECB.Create(6, 45), TECB.Create(14, 46)),
  2699. TECBlocks.Create(30, TECB.Create(11, 24), TECB.Create(16, 25)),
  2700. TECBlocks.Create(30, TECB.Create(30, 16), TECB.Create(2, 17)));
  2701. end
  2702. else if (VersionNum = 25) then
  2703. begin
  2704. Result := TVersion.Create(25, [6, 32, 58, 84, 110],
  2705. TECBlocks.Create(26, TECB.Create(8, 106), TECB.Create(4, 107)),
  2706. TECBlocks.Create(28, TECB.Create(8, 47), TECB.Create(13, 48)),
  2707. TECBlocks.Create(30, TECB.Create(7, 24), TECB.Create(22, 25)),
  2708. TECBlocks.Create(30, TECB.Create(22, 15), TECB.Create(13, 16)));
  2709. end
  2710. else if (VersionNum = 26) then
  2711. begin
  2712. Result := TVersion.Create(26, [6, 30, 58, 86, 114],
  2713. TECBlocks.Create(28, TECB.Create(10, 114), TECB.Create(2, 115)),
  2714. TECBlocks.Create(28, TECB.Create(19, 46), TECB.Create(4, 47)),
  2715. TECBlocks.Create(28, TECB.Create(28, 22), TECB.Create(6, 23)),
  2716. TECBlocks.Create(30, TECB.Create(33, 16), TECB.Create(4, 17)));
  2717. end
  2718. else if (VersionNum = 27) then
  2719. begin
  2720. Result := TVersion.Create(27, [6, 34, 62, 90, 118],
  2721. TECBlocks.Create(30, TECB.Create(8, 122), TECB.Create(4, 123)),
  2722. TECBlocks.Create(28, TECB.Create(22, 45), TECB.Create(3, 46)),
  2723. TECBlocks.Create(30, TECB.Create(8, 23), TECB.Create(26, 24)),
  2724. TECBlocks.Create(30, TECB.Create(12, 15), TECB.Create(28, 16)));
  2725. end
  2726. else if (VersionNum = 28) then
  2727. begin
  2728. Result := TVersion.Create(28, [6, 26, 50, 74, 98, 122],
  2729. TECBlocks.Create(30, TECB.Create(3, 117), TECB.Create(10, 118)),
  2730. TECBlocks.Create(28, TECB.Create(3, 45), TECB.Create(23, 46)),
  2731. TECBlocks.Create(30, TECB.Create(4, 24), TECB.Create(31, 25)),
  2732. TECBlocks.Create(30, TECB.Create(11, 15), TECB.Create(31, 16)));
  2733. end
  2734. else if (VersionNum = 29) then
  2735. begin
  2736. Result := TVersion.Create(29, [6, 30, 54, 78, 102, 126],
  2737. TECBlocks.Create(30, TECB.Create(7, 116), TECB.Create(7, 117)),
  2738. TECBlocks.Create(28, TECB.Create(21, 45), TECB.Create(7, 46)),
  2739. TECBlocks.Create(30, TECB.Create(1, 23), TECB.Create(37, 24)),
  2740. TECBlocks.Create(30, TECB.Create(19, 15), TECB.Create(26, 16)));
  2741. end
  2742. else if (VersionNum = 30) then
  2743. begin
  2744. Result := TVersion.Create(30, [6, 26, 52, 78, 104, 130],
  2745. TECBlocks.Create(30, TECB.Create(5, 115), TECB.Create(10, 116)),
  2746. TECBlocks.Create(28, TECB.Create(19, 47), TECB.Create(10, 48)),
  2747. TECBlocks.Create(30, TECB.Create(15, 24), TECB.Create(25, 25)),
  2748. TECBlocks.Create(30, TECB.Create(23, 15), TECB.Create(25, 16)));
  2749. end
  2750. else if (VersionNum = 31) then
  2751. begin
  2752. Result := TVersion.Create(31, [6, 30, 56, 82, 108, 134],
  2753. TECBlocks.Create(30, TECB.Create(13, 115), TECB.Create(3, 116)),
  2754. TECBlocks.Create(28, TECB.Create(2, 46), TECB.Create(29, 47)),
  2755. TECBlocks.Create(30, TECB.Create(42, 24), TECB.Create(1, 25)),
  2756. TECBlocks.Create(30, TECB.Create(23, 15), TECB.Create(28, 16)));
  2757. end
  2758. else if (VersionNum = 32) then
  2759. begin
  2760. Result := TVersion.Create(32, [6, 34, 60, 86, 112, 138],
  2761. TECBlocks.Create(30, TECB.Create(17, 115)),
  2762. TECBlocks.Create(28, TECB.Create(10, 46), TECB.Create(23, 47)),
  2763. TECBlocks.Create(30, TECB.Create(10, 24), TECB.Create(35, 25)),
  2764. TECBlocks.Create(30, TECB.Create(19, 15), TECB.Create(35, 16)));
  2765. end
  2766. else if (VersionNum = 33) then
  2767. begin
  2768. Result := TVersion.Create(33, [6, 30, 58, 86, 114, 142],
  2769. TECBlocks.Create(30, TECB.Create(17, 115), TECB.Create(1, 116)),
  2770. TECBlocks.Create(28, TECB.Create(14, 46), TECB.Create(21, 47)),
  2771. TECBlocks.Create(30, TECB.Create(29, 24), TECB.Create(19, 25)),
  2772. TECBlocks.Create(30, TECB.Create(11, 15), TECB.Create(46, 16)));
  2773. end
  2774. else if (VersionNum = 34) then
  2775. begin
  2776. Result := TVersion.Create(34, [6, 34, 62, 90, 118, 146],
  2777. TECBlocks.Create(30, TECB.Create(13, 115), TECB.Create(6, 116)),
  2778. TECBlocks.Create(28, TECB.Create(14, 46), TECB.Create(23, 47)),
  2779. TECBlocks.Create(30, TECB.Create(44, 24), TECB.Create(7, 25)),
  2780. TECBlocks.Create(30, TECB.Create(59, 16), TECB.Create(1, 17)));
  2781. end
  2782. else if (VersionNum = 35) then
  2783. begin
  2784. Result := TVersion.Create(35, [6, 30, 54, 78, 102, 126, 150],
  2785. TECBlocks.Create(30, TECB.Create(12, 121), TECB.Create(7, 122)),
  2786. TECBlocks.Create(28, TECB.Create(12, 47), TECB.Create(26, 48)),
  2787. TECBlocks.Create(30, TECB.Create(39, 24), TECB.Create(14, 25)),
  2788. TECBlocks.Create(30, TECB.Create(22, 15), TECB.Create(41, 16)));
  2789. end
  2790. else if (VersionNum = 36) then
  2791. begin
  2792. Result := TVersion.Create(36, [6, 24, 50, 76, 102, 128, 154],
  2793. TECBlocks.Create(30, TECB.Create(6, 121), TECB.Create(14, 122)),
  2794. TECBlocks.Create(28, TECB.Create(6, 47), TECB.Create(34, 48)),
  2795. TECBlocks.Create(30, TECB.Create(46, 24), TECB.Create(10, 25)),
  2796. TECBlocks.Create(30, TECB.Create(2, 15), TECB.Create(64, 16)));
  2797. end
  2798. else if (VersionNum = 37) then
  2799. begin
  2800. Result := TVersion.Create(37, [6, 28, 54, 80, 106, 132, 158],
  2801. TECBlocks.Create(30, TECB.Create(17, 122), TECB.Create(4, 123)),
  2802. TECBlocks.Create(28, TECB.Create(29, 46), TECB.Create(14, 47)),
  2803. TECBlocks.Create(30, TECB.Create(49, 24), TECB.Create(10, 25)),
  2804. TECBlocks.Create(30, TECB.Create(24, 15), TECB.Create(46, 16)));
  2805. end
  2806. else if (VersionNum = 38) then
  2807. begin
  2808. Result := TVersion.Create(38, [6, 32, 58, 84, 110, 136, 162],
  2809. TECBlocks.Create(30, TECB.Create(4, 122), TECB.Create(18, 123)),
  2810. TECBlocks.Create(28, TECB.Create(13, 46), TECB.Create(32, 47)),
  2811. TECBlocks.Create(30, TECB.Create(48, 24), TECB.Create(14, 25)),
  2812. TECBlocks.Create(30, TECB.Create(42, 15), TECB.Create(32, 16)));
  2813. end
  2814. else if (VersionNum = 39) then
  2815. begin
  2816. Result := TVersion.Create(39, [6, 26, 54, 82, 110, 138, 166],
  2817. TECBlocks.Create(30, TECB.Create(20, 117), TECB.Create(4, 118)),
  2818. TECBlocks.Create(28, TECB.Create(40, 47), TECB.Create(7, 48)),
  2819. TECBlocks.Create(30, TECB.Create(43, 24), TECB.Create(22, 25)),
  2820. TECBlocks.Create(30, TECB.Create(10, 15), TECB.Create(67, 16)));
  2821. end
  2822. else if (VersionNum = 40) then
  2823. begin
  2824. Result := TVersion.Create(40, [6, 30, 58, 86, 114, 142, 170],
  2825. TECBlocks.Create(30, TECB.Create(19, 118), TECB.Create(6, 119)),
  2826. TECBlocks.Create(28, TECB.Create(18, 47), TECB.Create(31, 48)),
  2827. TECBlocks.Create(30, TECB.Create(34, 24), TECB.Create(34, 25)),
  2828. TECBlocks.Create(30, TECB.Create(20, 15), TECB.Create(61, 16)));
  2829. end
  2830. else
  2831. begin
  2832. Result := nil;
  2833. end;
  2834. end;
  2835.  
  2836. { TMaskUtil }
  2837.  
  2838. // Return the mask bit for "getMaskPattern" at "x" and "y". See 8.8 of JISX0510:2004 for mask
  2839. // pattern conditions.
  2840. function TMaskUtil.GetDataMaskBit(MaskPattern, X, Y: Integer): Boolean;
  2841. var
  2842. Intermediate: Integer;
  2843. Temp: Integer;
  2844. begin
  2845. Intermediate := 0;
  2846. if ((MaskPattern >= 0) and (MaskPattern < NUM_MASK_PATTERNS)) then
  2847. begin
  2848. case (MaskPattern) of
  2849. 0:
  2850. Intermediate := (Y + X) and 1;
  2851. 1:
  2852. Intermediate := Y and 1;
  2853. 2:
  2854. Intermediate := X mod 3;
  2855. 3:
  2856. Intermediate := (Y + X) mod 3;
  2857. 4:
  2858. Intermediate := ((Y shr 1) + (X div 3)) and 1;
  2859. 5:
  2860. begin
  2861. Temp := Y * X;
  2862. Intermediate := (Temp and 1) + (Temp mod 3);
  2863. end;
  2864. 6:
  2865. begin
  2866. Temp := Y * X;
  2867. Intermediate := ((Temp and 1) + (Temp mod 3)) and 1;
  2868. end;
  2869. 7:
  2870. begin
  2871. Temp := Y * X;
  2872. Intermediate := ((Temp mod 3) + ((Y + X) and 1)) and 1;
  2873. end;
  2874. end;
  2875. end;
  2876. Result := Intermediate = 0;
  2877. end;
  2878.  
  2879. { TECBlocks }
  2880.  
  2881. constructor TECBlocks.Create(ECCodewordsPerBlock: Integer; ECBlocks: TECB);
  2882. begin
  2883. Self.ECCodewordsPerBlock := ECCodewordsPerBlock;
  2884. SetLength(Self.ECBlocks, 1);
  2885. Self.ECBlocks[0] := ECBlocks;
  2886. end;
  2887.  
  2888. constructor TECBlocks.Create(ECCodewordsPerBlock: Integer;
  2889. ECBlocks1, ECBlocks2: TECB);
  2890. begin
  2891. Self.ECCodewordsPerBlock := ECCodewordsPerBlock;
  2892. SetLength(Self.ECBlocks, 2);
  2893. ECBlocks[0] := ECBlocks1;
  2894. ECBlocks[1] := ECBlocks2;
  2895. end;
  2896.  
  2897. destructor TECBlocks.Destroy;
  2898. var
  2899. X: Integer;
  2900. begin
  2901. for X := 0 to Length(ECBlocks) - 1 do
  2902. begin
  2903. ECBlocks[X].Free;
  2904. end;
  2905. inherited;
  2906. end;
  2907.  
  2908. function TECBlocks.GetECBlocks: TECBArray;
  2909. begin
  2910. Result := ECBlocks;
  2911. end;
  2912.  
  2913. function TECBlocks.GetECCodewordsPerBlock: Integer;
  2914. begin
  2915. Result := ECCodewordsPerBlock;
  2916. end;
  2917.  
  2918. function TECBlocks.GetNumBlocks: Integer;
  2919. var
  2920. Total: Integer;
  2921. I: Integer;
  2922. begin
  2923. Total := 0;
  2924. for I := 0 to Length(ECBlocks) - 1 do
  2925. begin
  2926. Inc(Total, ECBlocks[I].GetCount);
  2927. end;
  2928. Result := Total;
  2929. end;
  2930.  
  2931. function TECBlocks.GetTotalECCodewords: Integer;
  2932. begin
  2933. Result := ECCodewordsPerBlock * GetNumBlocks;
  2934. end;
  2935.  
  2936. { TBlockPair }
  2937.  
  2938. constructor TBlockPair.Create(BA1, BA2: TByteArray);
  2939. begin
  2940. FDataBytes := BA1;
  2941. FErrorCorrectionBytes := BA2;
  2942. end;
  2943.  
  2944. function TBlockPair.GetDataBytes: TByteArray;
  2945. begin
  2946. Result := FDataBytes;
  2947. end;
  2948.  
  2949. function TBlockPair.GetErrorCorrectionBytes: TByteArray;
  2950. begin
  2951. Result := FErrorCorrectionBytes;
  2952. end;
  2953.  
  2954. { TReedSolomonEncoder }
  2955.  
  2956. function TReedSolomonEncoder.BuildGenerator(Degree: Integer): TGenericGFPoly;
  2957. var
  2958. LastGenerator: TGenericGFPoly;
  2959. NextGenerator: TGenericGFPoly;
  2960. Poly: TGenericGFPoly;
  2961. D: Integer;
  2962. CA: TIntegerArray;
  2963. begin
  2964. if (Degree >= FCachedGenerators.Count) then
  2965. begin
  2966. LastGenerator := TGenericGFPoly
  2967. (FCachedGenerators[FCachedGenerators.Count - 1]);
  2968.  
  2969. for D := FCachedGenerators.Count to Degree do
  2970. begin
  2971. SetLength(CA, 2);
  2972. CA[0] := 1;
  2973. CA[1] := FField.Exp(D - 1 + FField.GetGeneratorBase);
  2974. Poly := TGenericGFPoly.Create(FField, CA);
  2975. NextGenerator := LastGenerator.Multiply(Poly);
  2976. FCachedGenerators.Add(NextGenerator);
  2977. LastGenerator := NextGenerator;
  2978. end;
  2979. end;
  2980. Result := TGenericGFPoly(FCachedGenerators[Degree]);
  2981. end;
  2982.  
  2983. constructor TReedSolomonEncoder.Create(AField: TGenericGF);
  2984. var
  2985. GenericGFPoly: TGenericGFPoly;
  2986. IntArray: TIntegerArray;
  2987. begin
  2988. FField := AField;
  2989.  
  2990. // Contents of FCachedGenerators will be freed by FGenericGF.Destroy
  2991. FCachedGenerators := TObjectList<TGenericGFPoly>.Create(False);
  2992.  
  2993. SetLength(IntArray, 1);
  2994. IntArray[0] := 1;
  2995. GenericGFPoly := TGenericGFPoly.Create(AField, IntArray);
  2996. FCachedGenerators.Add(GenericGFPoly);
  2997. end;
  2998.  
  2999. destructor TReedSolomonEncoder.Destroy;
  3000. begin
  3001. FCachedGenerators.Free;
  3002. inherited;
  3003. end;
  3004.  
  3005. procedure TReedSolomonEncoder.Encode(ToEncode: TIntegerArray; ECBytes: Integer);
  3006. var
  3007. DataBytes: Integer;
  3008. Generator: TGenericGFPoly;
  3009. InfoCoefficients: TIntegerArray;
  3010. Info: TGenericGFPoly;
  3011. Remainder: TGenericGFPoly;
  3012. Coefficients: TIntegerArray;
  3013. NumZeroCoefficients: Integer;
  3014. I: Integer;
  3015. begin
  3016. SetLength(Coefficients, 0);
  3017. if (ECBytes > 0) then
  3018. begin
  3019. DataBytes := Length(ToEncode) - ECBytes;
  3020. if (DataBytes > 0) then
  3021. begin
  3022. Generator := BuildGenerator(ECBytes);
  3023. SetLength(InfoCoefficients, DataBytes);
  3024. InfoCoefficients := Copy(ToEncode, 0, DataBytes);
  3025. Info := TGenericGFPoly.Create(FField, InfoCoefficients);
  3026. Info := Info.MultiplyByMonomial(ECBytes, 1);
  3027. Remainder := Info.Divide(Generator)[1];
  3028. Coefficients := Remainder.GetCoefficients;
  3029. NumZeroCoefficients := ECBytes - Length(Coefficients);
  3030. for I := 0 to NumZeroCoefficients - 1 do
  3031. begin
  3032. ToEncode[DataBytes + I] := 0;
  3033. end;
  3034. Move(Coefficients[0], ToEncode[DataBytes + NumZeroCoefficients],
  3035. Length(Coefficients) * SizeOf(Integer));
  3036. end;
  3037. end;
  3038. end;
  3039.  
  3040. { TECB }
  3041.  
  3042. constructor TECB.Create(Count, DataCodewords: Integer);
  3043. begin
  3044. Self.Count := Count;
  3045. Self.DataCodewords := DataCodewords;
  3046. end;
  3047.  
  3048. function TECB.GetCount: Integer;
  3049. begin
  3050. Result := Count;
  3051. end;
  3052.  
  3053. function TECB.GetDataCodewords: Integer;
  3054. begin
  3055. Result := DataCodewords;
  3056. end;
  3057.  
  3058. { TGenericGFPoly }
  3059.  
  3060. function TGenericGFPoly.AddOrSubtract(Other: TGenericGFPoly): TGenericGFPoly;
  3061. var
  3062. SmallerCoefficients: TIntegerArray;
  3063. LargerCoefficients: TIntegerArray;
  3064. Temp: TIntegerArray;
  3065. SumDiff: TIntegerArray;
  3066. LengthDiff: Integer;
  3067. I: Integer;
  3068. begin
  3069. SetLength(SmallerCoefficients, 0);
  3070. SetLength(LargerCoefficients, 0);
  3071. SetLength(Temp, 0);
  3072. SetLength(SumDiff, 0);
  3073.  
  3074. Result := nil;
  3075. if (Assigned(Other)) then
  3076. begin
  3077. if (FField = Other.FField) then
  3078. begin
  3079. if (IsZero) then
  3080. begin
  3081. Result := Other;
  3082. Exit;
  3083. end;
  3084.  
  3085. if (Other.IsZero) then
  3086. begin
  3087. Result := Self;
  3088. Exit;
  3089. end;
  3090.  
  3091. SmallerCoefficients := FCoefficients;
  3092. LargerCoefficients := Other.Coefficients;
  3093. if (Length(SmallerCoefficients) > Length(LargerCoefficients)) then
  3094. begin
  3095. Temp := SmallerCoefficients;
  3096. SmallerCoefficients := LargerCoefficients;
  3097. LargerCoefficients := Temp;
  3098. end;
  3099. SetLength(SumDiff, Length(LargerCoefficients));
  3100. LengthDiff := Length(LargerCoefficients) - Length(SmallerCoefficients);
  3101.  
  3102. // Copy high-order terms only found in higher-degree polynomial's coefficients
  3103. if (LengthDiff > 0) then
  3104. begin
  3105. // SumDiff := Copy(LargerCoefficients, 0, LengthDiff);
  3106. Move(LargerCoefficients[0], SumDiff[0], LengthDiff * SizeOf(Integer));
  3107. end;
  3108.  
  3109. for I := LengthDiff to Length(LargerCoefficients) - 1 do
  3110. begin
  3111. SumDiff[I] := TGenericGF.AddOrSubtract
  3112. (SmallerCoefficients[I - LengthDiff], LargerCoefficients[I]);
  3113. end;
  3114.  
  3115. Result := TGenericGFPoly.Create(FField, SumDiff);
  3116. end;
  3117. end;
  3118. end;
  3119.  
  3120. function TGenericGFPoly.Coefficients: TIntegerArray;
  3121. begin
  3122. Result := FCoefficients;
  3123. end;
  3124.  
  3125. constructor TGenericGFPoly.Create(AField: TGenericGF;
  3126. ACoefficients: TIntegerArray);
  3127. var
  3128. CoefficientsLength: Integer;
  3129. FirstNonZero: Integer;
  3130. begin
  3131. FField := AField;
  3132. SetLength(FField.FPolyList, Length(FField.FPolyList) + 1);
  3133. FField.FPolyList[Length(FField.FPolyList) - 1] := Self;
  3134. CoefficientsLength := Length(ACoefficients);
  3135. if ((CoefficientsLength > 1) and (ACoefficients[0] = 0)) then
  3136. begin
  3137. // Leading term must be non-zero for anything except the constant polynomial "0"
  3138. FirstNonZero := 1;
  3139. while ((FirstNonZero < CoefficientsLength) and
  3140. (ACoefficients[FirstNonZero] = 0)) do
  3141. begin
  3142. Inc(FirstNonZero);
  3143. end;
  3144.  
  3145. if (FirstNonZero = CoefficientsLength) then
  3146. begin
  3147. FCoefficients := AField.GetZero.Coefficients;
  3148. end
  3149. else
  3150. begin
  3151. SetLength(FCoefficients, CoefficientsLength - FirstNonZero);
  3152. FCoefficients := Copy(ACoefficients, FirstNonZero, Length(FCoefficients));
  3153. end;
  3154. end
  3155. else
  3156. begin
  3157. FCoefficients := ACoefficients;
  3158. end;
  3159. end;
  3160.  
  3161. destructor TGenericGFPoly.Destroy;
  3162. begin
  3163. Self.FField := FField;
  3164. inherited;
  3165. end;
  3166.  
  3167. function TGenericGFPoly.Divide(Other: TGenericGFPoly): TGenericGFPolyArray;
  3168. var
  3169. Quotient: TGenericGFPoly;
  3170. Remainder: TGenericGFPoly;
  3171. DenominatorLeadingTerm: Integer;
  3172. InverseDenominatorLeadingTerm: Integer;
  3173. DegreeDifference: Integer;
  3174. Scale: Integer;
  3175. Term: TGenericGFPoly;
  3176. IterationQuotient: TGenericGFPoly;
  3177. begin
  3178. SetLength(Result, 0);
  3179. if ((FField = Other.FField) and (not Other.IsZero)) then
  3180. begin
  3181.  
  3182. Quotient := FField.GetZero;
  3183. Remainder := Self;
  3184.  
  3185. DenominatorLeadingTerm := Other.GetCoefficient(Other.GetDegree);
  3186. InverseDenominatorLeadingTerm := FField.Inverse(DenominatorLeadingTerm);
  3187.  
  3188. while ((Remainder.GetDegree >= Other.GetDegree) and
  3189. (not Remainder.IsZero)) do
  3190. begin
  3191. DegreeDifference := Remainder.GetDegree - Other.GetDegree;
  3192. Scale := FField.Multiply(Remainder.GetCoefficient(Remainder.GetDegree),
  3193. InverseDenominatorLeadingTerm);
  3194. Term := Other.MultiplyByMonomial(DegreeDifference, Scale);
  3195. IterationQuotient := FField.BuildMonomial(DegreeDifference, Scale);
  3196. Quotient := Quotient.AddOrSubtract(IterationQuotient);
  3197. Remainder := Remainder.AddOrSubtract(Term);
  3198. end;
  3199.  
  3200. SetLength(Result, 2);
  3201. Result[0] := Quotient;
  3202. Result[1] := Remainder;
  3203. end;
  3204. end;
  3205.  
  3206. function TGenericGFPoly.GetCoefficient(Degree: Integer): Integer;
  3207. begin
  3208. Result := FCoefficients[Length(FCoefficients) - 1 - Degree];
  3209. end;
  3210.  
  3211. function TGenericGFPoly.GetCoefficients: TIntegerArray;
  3212. begin
  3213. Result := FCoefficients;
  3214. end;
  3215.  
  3216. function TGenericGFPoly.GetDegree: Integer;
  3217. begin
  3218. Result := Length(FCoefficients) - 1;
  3219. end;
  3220.  
  3221. function TGenericGFPoly.IsZero: Boolean;
  3222. begin
  3223. Result := FCoefficients[0] = 0;
  3224. end;
  3225.  
  3226. function TGenericGFPoly.Multiply(Other: TGenericGFPoly): TGenericGFPoly;
  3227. var
  3228. ACoefficients: TIntegerArray;
  3229. BCoefficients: TIntegerArray;
  3230. Product: TIntegerArray;
  3231. ALength: Integer;
  3232. BLength: Integer;
  3233. I: Integer;
  3234. J: Integer;
  3235. ACoeff: Integer;
  3236. begin
  3237. SetLength(ACoefficients, 0);
  3238. SetLength(BCoefficients, 0);
  3239. Result := nil;
  3240.  
  3241. if (FField = Other.FField) then
  3242. begin
  3243. if (IsZero or Other.IsZero) then
  3244. begin
  3245. Result := FField.GetZero;
  3246. Exit;
  3247. end;
  3248.  
  3249. ACoefficients := FCoefficients;
  3250. ALength := Length(ACoefficients);
  3251. BCoefficients := Other.Coefficients;
  3252. BLength := Length(BCoefficients);
  3253. SetLength(Product, ALength + BLength - 1);
  3254. for I := 0 to ALength - 1 do
  3255. begin
  3256. ACoeff := ACoefficients[I];
  3257. for J := 0 to BLength - 1 do
  3258. begin
  3259. Product[I + J] := TGenericGF.AddOrSubtract(Product[I + J],
  3260. FField.Multiply(ACoeff, BCoefficients[J]));
  3261. end;
  3262. end;
  3263. Result := TGenericGFPoly.Create(FField, Product);
  3264. end;
  3265. end;
  3266.  
  3267. function TGenericGFPoly.MultiplyByMonomial(Degree, Coefficient: Integer)
  3268. : TGenericGFPoly;
  3269. var
  3270. I: Integer;
  3271. Size: Integer;
  3272. Product: TIntegerArray;
  3273. begin
  3274. Result := nil;
  3275. if (Degree >= 0) then
  3276. begin
  3277. if (Coefficient = 0) then
  3278. begin
  3279. Result := FField.GetZero;
  3280. Exit;
  3281. end;
  3282. Size := Length(Coefficients);
  3283. SetLength(Product, Size + Degree);
  3284. for I := 0 to Size - 1 do
  3285. begin
  3286. Product[I] := FField.Multiply(FCoefficients[I], Coefficient);
  3287. end;
  3288. Result := TGenericGFPoly.Create(FField, Product);
  3289. end;
  3290. end;
  3291.  
  3292. { TGenericGF }
  3293.  
  3294. class function TGenericGF.AddOrSubtract(A, B: Integer): Integer;
  3295. begin
  3296. Result := A xor B;
  3297. end;
  3298.  
  3299. function TGenericGF.BuildMonomial(Degree, Coefficient: Integer): TGenericGFPoly;
  3300. var
  3301. Coefficients: TIntegerArray;
  3302. begin
  3303. CheckInit();
  3304.  
  3305. if (Degree >= 0) then
  3306. begin
  3307. if (Coefficient = 0) then
  3308. begin
  3309. Result := FZero;
  3310. Exit;
  3311. end;
  3312. SetLength(Coefficients, Degree + 1);
  3313. Coefficients[0] := Coefficient;
  3314. Result := TGenericGFPoly.Create(Self, Coefficients);
  3315. end
  3316. else
  3317. begin
  3318. Result := nil;
  3319. end;
  3320. end;
  3321.  
  3322. procedure TGenericGF.CheckInit;
  3323. begin
  3324. if (not FInitialized) then
  3325. begin
  3326. Initialize;
  3327. end;
  3328. end;
  3329.  
  3330. constructor TGenericGF.Create(Primitive, Size, B: Integer);
  3331. begin
  3332. FInitialized := False;
  3333. FPrimitive := Primitive;
  3334. FSize := Size;
  3335. FGeneratorBase := B;
  3336. if (FSize < 0) then
  3337. begin
  3338. Initialize;
  3339. end;
  3340. end;
  3341.  
  3342. class function TGenericGF.CreateQRCodeField256: TGenericGF;
  3343. begin
  3344. Result := TGenericGF.Create($011D, 256, 0);
  3345. end;
  3346.  
  3347. destructor TGenericGF.Destroy;
  3348. var
  3349. X: Integer;
  3350. Y: Integer;
  3351. begin
  3352. for X := 0 to Length(FPolyList) - 1 do
  3353. begin
  3354. if (Assigned(FPolyList[X])) then
  3355. begin
  3356. for Y := X + 1 to Length(FPolyList) - 1 do
  3357. begin
  3358. if (FPolyList[Y] = FPolyList[X]) then
  3359. begin
  3360. FPolyList[Y] := nil;
  3361. end;
  3362. end;
  3363. FPolyList[X].Free;
  3364. end;
  3365. end;
  3366. inherited;
  3367. end;
  3368.  
  3369. function TGenericGF.Exp(A: Integer): Integer;
  3370. begin
  3371. CheckInit;
  3372. Result := FExpTable[A];
  3373. end;
  3374.  
  3375. function TGenericGF.GetGeneratorBase: Integer;
  3376. begin
  3377. Result := FGeneratorBase;
  3378. end;
  3379.  
  3380. function TGenericGF.GetZero: TGenericGFPoly;
  3381. begin
  3382. CheckInit;
  3383. Result := FZero;
  3384. end;
  3385.  
  3386. procedure TGenericGF.Initialize;
  3387. var
  3388. X: Integer;
  3389. I: Integer;
  3390. CA: TIntegerArray;
  3391. begin
  3392. SetLength(FExpTable, FSize);
  3393. SetLength(FLogTable, FSize);
  3394. X := 1;
  3395. for I := 0 to FSize - 1 do
  3396. begin
  3397. FExpTable[I] := X;
  3398. X := X shl 1; // x = x * 2; we're assuming the generator alpha is 2
  3399. if (X >= FSize) then
  3400. begin
  3401. X := X xor FPrimitive;
  3402. X := X and (FSize - 1);
  3403. end;
  3404. end;
  3405.  
  3406. for I := 0 to FSize - 2 do
  3407. begin
  3408. FLogTable[FExpTable[I]] := I;
  3409. end;
  3410.  
  3411. // logTable[0] == 0 but this should never be used
  3412.  
  3413. SetLength(CA, 1);
  3414. CA[0] := 0;
  3415. FZero := TGenericGFPoly.Create(Self, CA);
  3416.  
  3417. SetLength(CA, 1);
  3418. CA[0] := 1;
  3419. FOne := TGenericGFPoly.Create(Self, CA);
  3420.  
  3421. FInitialized := True;
  3422. end;
  3423.  
  3424. function TGenericGF.Inverse(A: Integer): Integer;
  3425. begin
  3426. CheckInit;
  3427.  
  3428. if (A <> 0) then
  3429. begin
  3430. Result := FExpTable[FSize - FLogTable[A] - 1];
  3431. end
  3432. else
  3433. begin
  3434. Result := 0;
  3435. end;
  3436. end;
  3437.  
  3438. function TGenericGF.Multiply(A, B: Integer): Integer;
  3439. begin
  3440. CheckInit;
  3441. if ((A <> 0) and (B <> 0)) then
  3442. begin
  3443. Result := FExpTable[(FLogTable[A] + FLogTable[B]) mod (FSize - 1)];
  3444. end
  3445. else
  3446. begin
  3447. Result := 0;
  3448. end;
  3449. end;
  3450.  
  3451. function GenerateQRCode(const Input: string; EncodeOptions: Integer)
  3452. : T2DBooleanArray;
  3453. var
  3454. Encoder: TEncoder;
  3455. Level: TErrorCorrectionLevel;
  3456. QRCode: TQRCode;
  3457. X: Integer;
  3458. Y: Integer;
  3459. begin
  3460. Level := TErrorCorrectionLevel.Create;
  3461. Level.FBits := 1;
  3462. Encoder := TEncoder.Create;
  3463. QRCode := TQRCode.Create;
  3464. try
  3465. Encoder.Encode(Input, EncodeOptions, Level, QRCode);
  3466. if (Assigned(QRCode.FMatrix)) then
  3467. begin
  3468. SetLength(Result, QRCode.FMatrix.FHeight);
  3469. for Y := 0 to QRCode.FMatrix.FHeight - 1 do
  3470. begin
  3471. SetLength(Result[Y], QRCode.FMatrix.FWidth);
  3472. for X := 0 to QRCode.FMatrix.FWidth - 1 do
  3473. begin
  3474. Result[Y][X] := QRCode.FMatrix.Get(Y, X) = 1;
  3475. end;
  3476. end;
  3477. end;
  3478. finally
  3479. QRCode.Free;
  3480. Encoder.Free;
  3481. Level.Free;
  3482. end;
  3483. end;
  3484.  
  3485. { TDelphiZXingQRCode }
  3486.  
  3487. constructor TDelphiZXingQRCode.Create;
  3488. begin
  3489. FData := '';
  3490. FEncoding := qrAuto;
  3491. FQuietZone := 4;
  3492. FRows := 0;
  3493. FColumns := 0;
  3494. end;
  3495.  
  3496. function TDelphiZXingQRCode.GetIsBlack(Row, Column: Integer): Boolean;
  3497. begin
  3498. Dec(Row, FQuietZone);
  3499. Dec(Column, FQuietZone);
  3500. if ((Row >= 0) and (Column >= 0) and (Row < (FRows - FQuietZone * 2)) and
  3501. (Column < (FColumns - FQuietZone * 2))) then
  3502. begin
  3503. Result := FElements[Column, Row];
  3504. end
  3505. else
  3506. begin
  3507. Result := False;
  3508. end;
  3509. end;
  3510.  
  3511. procedure TDelphiZXingQRCode.SetData(const NewData: string);
  3512. begin
  3513. if (FData <> NewData) then
  3514. begin
  3515. FData := NewData;
  3516. Update;
  3517. end;
  3518. end;
  3519.  
  3520. procedure TDelphiZXingQRCode.SetEncoding(NewEncoding: TQRCodeEncoding);
  3521. begin
  3522. if (FEncoding <> NewEncoding) then
  3523. begin
  3524. FEncoding := NewEncoding;
  3525. Update;
  3526. end;
  3527. end;
  3528.  
  3529. procedure TDelphiZXingQRCode.SetQuietZone(NewQuietZone: Integer);
  3530. begin
  3531. if ((FQuietZone <> NewQuietZone) and (NewQuietZone >= 0) and
  3532. (NewQuietZone <= 100)) then
  3533. begin
  3534. FQuietZone := NewQuietZone;
  3535. Update;
  3536. end;
  3537. end;
  3538.  
  3539. procedure TDelphiZXingQRCode.Update;
  3540. begin
  3541. FElements := GenerateQRCode(FData, Ord(FEncoding));
  3542. FRows := Length(FElements) + FQuietZone * 2;
  3543. FColumns := FRows;
  3544. end;
  3545.  
  3546. procedure TDelphiZXingQRCode.DrawQrcode(imgQRCode: TImage;
  3547. QRCode: TDelphiZXingQRCode);
  3548. const
  3549. downsizeQuality: Integer = 2;
  3550. // bigger value, better quality, slower rendering
  3551. var
  3552. Row, Column: Integer;
  3553. pixelColor: TAlphaColor;
  3554. vBitMapData: TBitmapData;
  3555. pixelCount, Y, X: Integer;
  3556. columnPixel, rowPixel: Integer;
  3557. function GetPixelCount(AWidth, AHeight: Single): Integer;
  3558. begin
  3559. if QRCode.Rows > 0 then
  3560. Result := Trunc(Min(AWidth, AHeight)) div QRCode.Rows
  3561. else
  3562. Result := 0;
  3563. end;
  3564.  
  3565. begin
  3566. pixelCount := GetPixelCount(imgQRCode.Width, imgQRCode.Height);
  3567. imgQRCode.DisableInterpolation := False;
  3568. if imgQRCode.WrapMode = TImageWrapMode.iwStretch then
  3569. imgQRCode.WrapMode := TImageWrapMode.iwCenter;
  3570. imgQRCode.DisableInterpolation := True;
  3571.  
  3572. case imgQRCode.WrapMode of
  3573. TImageWrapMode.iwOriginal, TImageWrapMode.iwTile, TImageWrapMode.iwCenter:
  3574. begin
  3575. if pixelCount > 0 then
  3576. imgQRCode.Bitmap.SetSize(QRCode.Columns * pixelCount,
  3577. QRCode.Rows * pixelCount);
  3578. end;
  3579. TImageWrapMode.iwFit:
  3580. begin
  3581. if pixelCount > 0 then
  3582. begin
  3583. imgQRCode.Bitmap.SetSize(QRCode.Columns * pixelCount *
  3584. downsizeQuality, QRCode.Rows * pixelCount * downsizeQuality);
  3585. pixelCount := pixelCount * downsizeQuality;
  3586. end;
  3587. end;
  3588. end;
  3589. try
  3590. imgQRCode.Bitmap.Canvas.Clear(TAlphaColors.White);
  3591. if pixelCount > 0 then
  3592. begin
  3593. if imgQRCode.Bitmap.Map(TMapAccess.maWrite, vBitMapData) then
  3594. begin
  3595. try
  3596. for Row := 0 to QRCode.Rows - 1 do
  3597. begin
  3598. for Column := 0 to QRCode.Columns - 1 do
  3599. begin
  3600. if (QRCode.IsBlack[Row, Column]) then
  3601. pixelColor := TAlphaColors.Black
  3602. else
  3603. pixelColor := TAlphaColors.White;
  3604. columnPixel := Column * pixelCount;
  3605. rowPixel := Row * pixelCount;
  3606. for X := 0 to pixelCount - 1 do
  3607. for Y := 0 to pixelCount - 1 do
  3608. vBitMapData.SetPixel(columnPixel + X, rowPixel + Y,
  3609. pixelColor);
  3610. end;
  3611. end;
  3612. finally
  3613. imgQRCode.Bitmap.Unmap(vBitMapData);
  3614. end;
  3615. end;
  3616. end;
  3617. finally
  3618. end;
  3619. end;
  3620.  
  3621. end.

http://www.cnblogs.com/qiufeng2014/p/4281761.html

Delphi xe7 FireMonkey / Mobile (Android, iOS)生成 QR Code完整实例的更多相关文章

  1. Delphi xe7 up1 调用android振动功能

    Delphi xe7 up1 调用android振动功能 振动用到以下4个单元: Androidapi.JNI.App,Androidapi.JNIBridge,Androidapi.JNI.Os,A ...

  2. VS2015 VB.Net利用QrCodeNet生成QR Code

    Step by step Create QR Code with QrCodeNet Step.1 新建項目 Step.2 下載QrCodeNet代碼,解壓\QrCodeNet\sourceCode\ ...

  3. php和jquery生成QR Code

    php生产QR Code 下载qrcode源码,地址:https://sourceforge.net/projects/phpqrcode/files/releases/ 1.解压后引入qrlib.p ...

  4. VS2015 C#利用QrCodeNet生成QR Code

    Step by step Create QR Code with QrCodeNet Step.1 新建項目 Step.2 在窗口中拖入一個Button Step.3 下載QrCodeNet代碼,解壓 ...

  5. 在线生成 QR Code

    http://tool.oschina.net/qr 在线生成二维码(QR码)-采用ZXing与d-project

  6. iOS Workflow 分享 - Create QR Code

    上次我分享了一个 Scan QR Code 的 Workflow,这次我分享一个正好相反的.如果我要分享一个 URL(或者是一段非常短的文本)给别人,我就可以用这个 Workflow 来生成 QR C ...

  7. Delphi APP 開發入門(二)Android/iOS設定,Hello World

    Delphi APP 開發入門(二)Android/iOS設定,Hello World 分享: Share on facebookShare on twitterShare on google_plu ...

  8. [修复] Firemonkey 画线问题(Android & iOS 平台)

    问题:官方 QC 的一个 Firemonkey 移动平台画线问题: RSP-14309: [iOS & Android] Delphi 10.1 Berlin - drawing proble ...

  9. [修复] Firemonkey 使用 DrawPath 断线问题(Android & iOS 平台)

    问题:使用 Canvas.DrawPath 绘制时,最后一点无法画到终点位置.(这个问题要在粗线才能察觉) 适用:Delphi 10 Seattle (或更早的版本) for Android & ...

随机推荐

  1. 【分享送书】NGUI全面实践教程V3.8.2 活动开始了!!

    [分享送书]NGUI全面实践教程V3.8.2 活动开始了!! 活动奖品:   活动地址:http://dwz.cn/JHdlu

  2. TODO:Half Half的设计

    IMessageHandler :消息同步处理接口 AbsQueue:消息队列处理层,可以使用Template Method进行设计 INetWorkLayer:专门处理网络IO的,并附带多线程与异步 ...

  3. ural 1153. Supercomputer

    1153. Supercomputer Time limit: 2.0 secondMemory limit: 64 MB To check the speed of JCN Corporation ...

  4. BZOJ4123 : [Baltic2015]Hacker

    黑掉的一定是一个长度为$\lfloor\frac{n+1}{2}\rfloor$的区间. 于是枚举初始点,然后查询包含它的区间的最小值. 通过维护前后缀最小值+单调队列$O(n)$解决. #inclu ...

  5. [leetCode][012] Two Sum (1)

    [题目]: Given an array of integers, find two numbers such that they add up to a specific target number ...

  6. [Unity2D]精灵动画

    通常我们在游戏里面创建的精灵比如玩家主角,它在移动的过程中一般会带有一些动画的效果,比如两只脚前后地移动,那么这种动画效果的实现和控制就可以通过Unity2D的动画系统来实现. 要添加这样的动画,首先 ...

  7. 【POJ】2954 Triangle(pick定理)

    http://poj.org/problem?id=2954 表示我交了20+次... 为什么呢?因为多组数据我是这样判断的:da=sum{a[i].x+a[i].y},然后!da就表示没有数据了QA ...

  8. 【BZOJ】1002: [FJOI2007]轮状病毒(DP+规律+高精度)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1002 其实我还是看题解的,而且看了题解也没明白那公式怎么来的T_T,先水过了先把....以后研究一下 ...

  9. 【wikioi】1285 宠物收养所

    题目链接:http://www.wikioi.com/problem/1285/ 算法:Splay 刚开始看到这题,就注意到特征abs了,并且数据n<=80000显然不能暴力,只能用nlgn的做 ...

  10. oracle系列--第二篇 oracle下载

    对于很多新手来说,包括我之前也是这样,知道oracle数据库,但是就是不知道在哪里下载.有时候,上到oracle官方网站上面都找不到下载的地方. 这不像apache里面那么直接,我们想下载如:tomc ...