Issue 563: Support non-rectangular Data Matrix
[zxing.git] / core / src / com / google / zxing / datamatrix / decoder / Version.java
1 /*\r
2  * Copyright 2007 ZXing authors\r
3  *\r
4  * Licensed under the Apache License, Version 2.0 (the "License");\r
5  * you may not use this file except in compliance with the License.\r
6  * You may obtain a copy of the License at\r
7  *\r
8  *      http://www.apache.org/licenses/LICENSE-2.0\r
9  *\r
10  * Unless required by applicable law or agreed to in writing, software\r
11  * distributed under the License is distributed on an "AS IS" BASIS,\r
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
13  * See the License for the specific language governing permissions and\r
14  * limitations under the License.\r
15  */\r
16 \r
17 package com.google.zxing.datamatrix.decoder;\r
18 \r
19 import com.google.zxing.FormatException;\r
20 \r
21 /**\r
22  * The Version object encapsulates attributes about a particular\r
23  * size Data Matrix Code.\r
24  *\r
25  * @author bbrown@google.com (Brian Brown)\r
26  */\r
27 public final class Version {\r
28 \r
29   private static final Version[] VERSIONS = buildVersions();\r
30 \r
31   private final int versionNumber;\r
32   private final int symbolSizeRows;\r
33   private final int symbolSizeColumns;\r
34   private final int dataRegionSizeRows;\r
35   private final int dataRegionSizeColumns;\r
36   private final ECBlocks ecBlocks;\r
37   private final int totalCodewords;\r
38 \r
39   private Version(int versionNumber,\r
40                   int symbolSizeRows,\r
41                   int symbolSizeColumns,\r
42                   int dataRegionSizeRows,\r
43                   int dataRegionSizeColumns,\r
44                   ECBlocks ecBlocks) {\r
45     this.versionNumber = versionNumber;\r
46     this.symbolSizeRows = symbolSizeRows;\r
47     this.symbolSizeColumns = symbolSizeColumns;\r
48     this.dataRegionSizeRows = dataRegionSizeRows;\r
49     this.dataRegionSizeColumns = dataRegionSizeColumns;\r
50     this.ecBlocks = ecBlocks;\r
51     \r
52     // Calculate the total number of codewords\r
53     int total = 0;\r
54     int ecCodewords = ecBlocks.getECCodewords();\r
55     ECB[] ecbArray = ecBlocks.getECBlocks();\r
56     for (int i = 0; i < ecbArray.length; i++) {\r
57       ECB ecBlock = ecbArray[i];\r
58       total += ecBlock.getCount() * (ecBlock.getDataCodewords() + ecCodewords);\r
59     }\r
60     this.totalCodewords = total;\r
61   }\r
62 \r
63   public int getVersionNumber() {\r
64     return versionNumber;\r
65   }\r
66 \r
67   public int getSymbolSizeRows() {\r
68     return symbolSizeRows;\r
69   }\r
70   \r
71   public int getSymbolSizeColumns() {\r
72     return symbolSizeColumns;\r
73   }\r
74   \r
75   public int getDataRegionSizeRows() {\r
76     return dataRegionSizeRows;\r
77   }\r
78   \r
79   public int getDataRegionSizeColumns() {\r
80     return dataRegionSizeColumns;\r
81   }\r
82   \r
83   public int getTotalCodewords() {\r
84     return totalCodewords;\r
85   }\r
86   \r
87   ECBlocks getECBlocks() {\r
88     return ecBlocks;\r
89   }\r
90 \r
91   /**\r
92    * <p>Deduces version information from Data Matrix dimensions.</p>\r
93    *\r
94    * @param numRows Number of rows in modules\r
95    * @param numColumns Number of columns in modules\r
96    * @return {@link Version} for a Data Matrix Code of those dimensions\r
97    * @throws FormatException if dimensions do correspond to a valid Data Matrix size\r
98    */\r
99   public static Version getVersionForDimensions(int numRows, int numColumns) throws FormatException {\r
100     if ((numRows & 0x01) != 0 || (numColumns & 0x01) != 0) {\r
101       throw FormatException.getFormatInstance();\r
102     }\r
103     \r
104     // TODO(bbrown): This is doing a linear search through the array of versions.\r
105     // If we interleave the rectangular versions with the square versions we could\r
106     // do a binary search.\r
107     int numVersions = VERSIONS.length;\r
108     for (int i = 0; i < numVersions; ++i){\r
109       Version version = VERSIONS[i];\r
110       if (version.symbolSizeRows == numRows && version.symbolSizeColumns == numColumns) {\r
111         return version;\r
112       }\r
113     }\r
114     \r
115     throw FormatException.getFormatInstance();\r
116   }\r
117 \r
118   /**\r
119    * <p>Encapsulates a set of error-correction blocks in one symbol version. Most versions will\r
120    * use blocks of differing sizes within one version, so, this encapsulates the parameters for\r
121    * each set of blocks. It also holds the number of error-correction codewords per block since it\r
122    * will be the same across all blocks within one version.</p>\r
123    */\r
124   static final class ECBlocks {\r
125     private final int ecCodewords;\r
126     private final ECB[] ecBlocks;\r
127 \r
128     private ECBlocks(int ecCodewords, ECB ecBlocks) {\r
129       this.ecCodewords = ecCodewords;\r
130       this.ecBlocks = new ECB[] { ecBlocks };\r
131     }\r
132 \r
133     private ECBlocks(int ecCodewords, ECB ecBlocks1, ECB ecBlocks2) {\r
134       this.ecCodewords = ecCodewords;\r
135       this.ecBlocks = new ECB[] { ecBlocks1, ecBlocks2 };\r
136     }\r
137 \r
138     int getECCodewords() {\r
139       return ecCodewords;\r
140     }\r
141 \r
142     ECB[] getECBlocks() {\r
143       return ecBlocks;\r
144     }\r
145   }\r
146 \r
147   /**\r
148    * <p>Encapsualtes the parameters for one error-correction block in one symbol version.\r
149    * This includes the number of data codewords, and the number of times a block with these\r
150    * parameters is used consecutively in the Data Matrix code version's format.</p>\r
151    */\r
152   static final class ECB {\r
153     private final int count;\r
154     private final int dataCodewords;\r
155 \r
156     private ECB(int count, int dataCodewords) {\r
157       this.count = count;\r
158       this.dataCodewords = dataCodewords;\r
159     }\r
160 \r
161     int getCount() {\r
162       return count;\r
163     }\r
164 \r
165     int getDataCodewords() {\r
166       return dataCodewords;\r
167     }\r
168   }\r
169 \r
170   public String toString() {\r
171     return String.valueOf(versionNumber);\r
172   }\r
173 \r
174   /**\r
175    * See ISO 16022:2006 5.5.1 Table 7\r
176    */\r
177   private static Version[] buildVersions() {\r
178     return new Version[]{\r
179         new Version(1, 10, 10, 8, 8,\r
180             new ECBlocks(5, new ECB(1, 3))),\r
181         new Version(2, 12, 12, 10, 10,\r
182             new ECBlocks(7, new ECB(1, 5))),\r
183         new Version(3, 14, 14, 12, 12,\r
184             new ECBlocks(10, new ECB(1, 8))),\r
185         new Version(4, 16, 16, 14, 14,\r
186             new ECBlocks(12, new ECB(1, 12))),\r
187         new Version(5, 18, 18, 16, 16,\r
188             new ECBlocks(14, new ECB(1, 18))),\r
189         new Version(6, 20, 20, 18, 18,\r
190             new ECBlocks(18, new ECB(1, 22))),\r
191         new Version(7, 22, 22, 20, 20,\r
192             new ECBlocks(20, new ECB(1, 30))),\r
193         new Version(8, 24, 24, 22, 22,\r
194             new ECBlocks(24, new ECB(1, 36))),\r
195         new Version(9, 26, 26, 24, 24,\r
196             new ECBlocks(28, new ECB(1, 44))),\r
197         new Version(10, 32, 32, 14, 14,\r
198             new ECBlocks(36, new ECB(1, 62))),\r
199         new Version(11, 36, 36, 16, 16,\r
200             new ECBlocks(42, new ECB(1, 86))),\r
201         new Version(12, 40, 40, 18, 18,\r
202             new ECBlocks(48, new ECB(1, 114))),\r
203         new Version(13, 44, 44, 20, 20,\r
204             new ECBlocks(56, new ECB(1, 144))),\r
205         new Version(14, 48, 48, 22, 22,\r
206             new ECBlocks(68, new ECB(1, 174))),\r
207         new Version(15, 52, 52, 24, 24,\r
208             new ECBlocks(42, new ECB(2, 102))),\r
209         new Version(16, 64, 64, 14, 14,\r
210             new ECBlocks(56, new ECB(2, 140))),\r
211         new Version(17, 72, 72, 16, 16,\r
212             new ECBlocks(36, new ECB(4, 92))),\r
213         new Version(18, 80, 80, 18, 18,\r
214             new ECBlocks(48, new ECB(4, 114))),\r
215         new Version(19, 88, 88, 20, 20,\r
216             new ECBlocks(56, new ECB(4, 144))),\r
217         new Version(20, 96, 96, 22, 22,\r
218             new ECBlocks(68, new ECB(4, 174))),\r
219         new Version(21, 104, 104, 24, 24,\r
220             new ECBlocks(56, new ECB(6, 136))),\r
221         new Version(22, 120, 120, 18, 18,\r
222             new ECBlocks(68, new ECB(6, 175))),\r
223         new Version(23, 132, 132, 20, 20,\r
224             new ECBlocks(62, new ECB(8, 163))),\r
225         new Version(24, 144, 144, 22, 22,\r
226             new ECBlocks(62, new ECB(8, 156), new ECB(2, 155))),\r
227         new Version(25, 8, 18, 6, 16,\r
228             new ECBlocks(7, new ECB(1, 5))),\r
229         new Version(26, 8, 32, 6, 14,\r
230             new ECBlocks(11, new ECB(1, 10))),\r
231         new Version(27, 12, 26, 10, 24,\r
232             new ECBlocks(14, new ECB(1, 16))),\r
233         new Version(28, 12, 36, 10, 16,\r
234             new ECBlocks(18, new ECB(1, 22))),\r
235         new Version(29, 16, 36, 14, 16,\r
236             new ECBlocks(24, new ECB(1, 32))),\r
237         new Version(30, 16, 48, 14, 22,\r
238             new ECBlocks(28, new ECB(1, 49)))\r
239     };\r
240   }\r
241 \r
242 }\r