source: josm/trunk/src/com/drew/metadata/jpeg/HuffmanTablesDirectory.java@ 13500

Last change on this file since 13500 was 13061, checked in by Don-vip, 6 years ago

fix #15505 - update to metadata-extractor 2.10.1

  • Property svn:eol-style set to native
File size: 15.6 KB
Line 
1/*
2 * Copyright 2002-2017 Drew Noakes
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 * More information about this project is available at:
17 *
18 * https://drewnoakes.com/code/exif/
19 * https://github.com/drewnoakes/metadata-extractor
20 */
21package com.drew.metadata.jpeg;
22
23import java.util.ArrayList;
24import java.util.Arrays;
25import java.util.HashMap;
26import java.util.List;
27import com.drew.lang.annotations.NotNull;
28import com.drew.metadata.Directory;
29import com.drew.metadata.MetadataException;
30
31/**
32 * Directory of tables for the DHT (Define Huffman Table(s)) segment.
33 *
34 * @author Nadahar
35 */
36@SuppressWarnings("WeakerAccess")
37public class HuffmanTablesDirectory extends Directory {
38
39 public static final int TAG_NUMBER_OF_TABLES = 1;
40
41 protected static final byte[] TYPICAL_LUMINANCE_DC_LENGTHS = {
42 (byte) 0x00, (byte) 0x01, (byte) 0x05, (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x01,
43 (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00
44 };
45
46 protected static final byte[] TYPICAL_LUMINANCE_DC_VALUES = {
47 (byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, (byte) 0x05, (byte) 0x06, (byte) 0x07,
48 (byte) 0x08, (byte) 0x09, (byte) 0x0A, (byte) 0x0B
49 };
50
51 protected static final byte[] TYPICAL_CHROMINANCE_DC_LENGTHS = {
52 (byte) 0x00, (byte) 0x03, (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x01,
53 (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00
54 };
55
56 protected static final byte[] TYPICAL_CHROMINANCE_DC_VALUES = {
57 (byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, (byte) 0x05, (byte) 0x06, (byte) 0x07,
58 (byte) 0x08, (byte) 0x09, (byte) 0x0A, (byte) 0x0B
59 };
60
61 protected static final byte[] TYPICAL_LUMINANCE_AC_LENGTHS = {
62 (byte) 0x00, (byte) 0x02, (byte) 0x01, (byte) 0x03, (byte) 0x03, (byte) 0x02, (byte) 0x04, (byte) 0x03,
63 (byte) 0x05, (byte) 0x05, (byte) 0x04, (byte) 0x04, (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x7D
64 };
65
66 protected static final byte[] TYPICAL_LUMINANCE_AC_VALUES = {
67 (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x00, (byte) 0x04, (byte) 0x11, (byte) 0x05, (byte) 0x12,
68 (byte) 0x21, (byte) 0x31, (byte) 0x41, (byte) 0x06, (byte) 0x13, (byte) 0x51, (byte) 0x61, (byte) 0x07,
69 (byte) 0x22, (byte) 0x71, (byte) 0x14, (byte) 0x32, (byte) 0x81, (byte) 0x91, (byte) 0xA1, (byte) 0x08,
70 (byte) 0x23, (byte) 0x42, (byte) 0xB1, (byte) 0xC1, (byte) 0x15, (byte) 0x52, (byte) 0xD1, (byte) 0xF0,
71 (byte) 0x24, (byte) 0x33, (byte) 0x62, (byte) 0x72, (byte) 0x82, (byte) 0x09, (byte) 0x0A, (byte) 0x16,
72 (byte) 0x17, (byte) 0x18, (byte) 0x19, (byte) 0x1A, (byte) 0x25, (byte) 0x26, (byte) 0x27, (byte) 0x28,
73 (byte) 0x29, (byte) 0x2A, (byte) 0x34, (byte) 0x35, (byte) 0x36, (byte) 0x37, (byte) 0x38, (byte) 0x39,
74 (byte) 0x3A, (byte) 0x43, (byte) 0x44, (byte) 0x45, (byte) 0x46, (byte) 0x47, (byte) 0x48, (byte) 0x49,
75 (byte) 0x4A, (byte) 0x53, (byte) 0x54, (byte) 0x55, (byte) 0x56, (byte) 0x57, (byte) 0x58, (byte) 0x59,
76 (byte) 0x5A, (byte) 0x63, (byte) 0x64, (byte) 0x65, (byte) 0x66, (byte) 0x67, (byte) 0x68, (byte) 0x69,
77 (byte) 0x6A, (byte) 0x73, (byte) 0x74, (byte) 0x75, (byte) 0x76, (byte) 0x77, (byte) 0x78, (byte) 0x79,
78 (byte) 0x7A, (byte) 0x83, (byte) 0x84, (byte) 0x85, (byte) 0x86, (byte) 0x87, (byte) 0x88, (byte) 0x89,
79 (byte) 0x8A, (byte) 0x92, (byte) 0x93, (byte) 0x94, (byte) 0x95, (byte) 0x96, (byte) 0x97, (byte) 0x98,
80 (byte) 0x99, (byte) 0x9A, (byte) 0xA2, (byte) 0xA3, (byte) 0xA4, (byte) 0xA5, (byte) 0xA6, (byte) 0xA7,
81 (byte) 0xA8, (byte) 0xA9, (byte) 0xAA, (byte) 0xB2, (byte) 0xB3, (byte) 0xB4, (byte) 0xB5, (byte) 0xB6,
82 (byte) 0xB7, (byte) 0xB8, (byte) 0xB9, (byte) 0xBA, (byte) 0xC2, (byte) 0xC3, (byte) 0xC4, (byte) 0xC5,
83 (byte) 0xC6, (byte) 0xC7, (byte) 0xC8, (byte) 0xC9, (byte) 0xCA, (byte) 0xD2, (byte) 0xD3, (byte) 0xD4,
84 (byte) 0xD5, (byte) 0xD6, (byte) 0xD7, (byte) 0xD8, (byte) 0xD9, (byte) 0xDA, (byte) 0xE1, (byte) 0xE2,
85 (byte) 0xE3, (byte) 0xE4, (byte) 0xE5, (byte) 0xE6, (byte) 0xE7, (byte) 0xE8, (byte) 0xE9, (byte) 0xEA,
86 (byte) 0xF1, (byte) 0xF2, (byte) 0xF3, (byte) 0xF4, (byte) 0xF5, (byte) 0xF6, (byte) 0xF7, (byte) 0xF8,
87 (byte) 0xF9, (byte) 0xFA
88 };
89
90 protected static final byte[] TYPICAL_CHROMINANCE_AC_LENGTHS = {
91 (byte) 0x00, (byte) 0x02, (byte) 0x01, (byte) 0x02, (byte) 0x04, (byte) 0x04, (byte) 0x03, (byte) 0x04,
92 (byte) 0x07, (byte) 0x05, (byte) 0x04, (byte) 0x04, (byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x77
93 };
94
95 protected static final byte[] TYPICAL_CHROMINANCE_AC_VALUES = {
96 (byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x11, (byte) 0x04, (byte) 0x05, (byte) 0x21,
97 (byte) 0x31, (byte) 0x06, (byte) 0x12, (byte) 0x41, (byte) 0x51, (byte) 0x07, (byte) 0x61, (byte) 0x71,
98 (byte) 0x13, (byte) 0x22, (byte) 0x32, (byte) 0x81, (byte) 0x08, (byte) 0x14, (byte) 0x42, (byte) 0x91,
99 (byte) 0xA1, (byte) 0xB1, (byte) 0xC1, (byte) 0x09, (byte) 0x23, (byte) 0x33, (byte) 0x52, (byte) 0xF0,
100 (byte) 0x15, (byte) 0x62, (byte) 0x72, (byte) 0xD1, (byte) 0x0A, (byte) 0x16, (byte) 0x24, (byte) 0x34,
101 (byte) 0xE1, (byte) 0x25, (byte) 0xF1, (byte) 0x17, (byte) 0x18, (byte) 0x19, (byte) 0x1A, (byte) 0x26,
102 (byte) 0x27, (byte) 0x28, (byte) 0x29, (byte) 0x2A, (byte) 0x35, (byte) 0x36, (byte) 0x37, (byte) 0x38,
103 (byte) 0x39, (byte) 0x3A, (byte) 0x43, (byte) 0x44, (byte) 0x45, (byte) 0x46, (byte) 0x47, (byte) 0x48,
104 (byte) 0x49, (byte) 0x4A, (byte) 0x53, (byte) 0x54, (byte) 0x55, (byte) 0x56, (byte) 0x57, (byte) 0x58,
105 (byte) 0x59, (byte) 0x5A, (byte) 0x63, (byte) 0x64, (byte) 0x65, (byte) 0x66, (byte) 0x67, (byte) 0x68,
106 (byte) 0x69, (byte) 0x6A, (byte) 0x73, (byte) 0x74, (byte) 0x75, (byte) 0x76, (byte) 0x77, (byte) 0x78,
107 (byte) 0x79, (byte) 0x7A, (byte) 0x82, (byte) 0x83, (byte) 0x84, (byte) 0x85, (byte) 0x86, (byte) 0x87,
108 (byte) 0x88, (byte) 0x89, (byte) 0x8A, (byte) 0x92, (byte) 0x93, (byte) 0x94, (byte) 0x95, (byte) 0x96,
109 (byte) 0x97, (byte) 0x98, (byte) 0x99, (byte) 0x9A, (byte) 0xA2, (byte) 0xA3, (byte) 0xA4, (byte) 0xA5,
110 (byte) 0xA6, (byte) 0xA7, (byte) 0xA8, (byte) 0xA9, (byte) 0xAA, (byte) 0xB2, (byte) 0xB3, (byte) 0xB4,
111 (byte) 0xB5, (byte) 0xB6, (byte) 0xB7, (byte) 0xB8, (byte) 0xB9, (byte) 0xBA, (byte) 0xC2, (byte) 0xC3,
112 (byte) 0xC4, (byte) 0xC5, (byte) 0xC6, (byte) 0xC7, (byte) 0xC8, (byte) 0xC9, (byte) 0xCA, (byte) 0xD2,
113 (byte) 0xD3, (byte) 0xD4, (byte) 0xD5, (byte) 0xD6, (byte) 0xD7, (byte) 0xD8, (byte) 0xD9, (byte) 0xDA,
114 (byte) 0xE2, (byte) 0xE3, (byte) 0xE4, (byte) 0xE5, (byte) 0xE6, (byte) 0xE7, (byte) 0xE8, (byte) 0xE9,
115 (byte) 0xEA, (byte) 0xF2, (byte) 0xF3, (byte) 0xF4, (byte) 0xF5, (byte) 0xF6, (byte) 0xF7, (byte) 0xF8,
116 (byte) 0xF9, (byte) 0xFA
117 };
118
119 @NotNull
120 protected final List<HuffmanTable> tables = new ArrayList<HuffmanTable>(4);
121
122 @NotNull
123 protected static final HashMap<Integer, String> _tagNameMap = new HashMap<Integer, String>();
124
125 static
126 {
127 _tagNameMap.put(TAG_NUMBER_OF_TABLES, "Number of Tables");
128 }
129
130 public HuffmanTablesDirectory()
131 {
132 this.setDescriptor(new HuffmanTablesDescriptor(this));
133 }
134
135 @Override
136 @NotNull
137 public String getName()
138 {
139 return "Huffman";
140 }
141
142 @Override
143 @NotNull
144 protected HashMap<Integer, String> getTagNameMap()
145 {
146 return _tagNameMap;
147 }
148
149 /**
150 * @param tableNumber The zero-based index of the table. This number is normally between 0 and 3.
151 * Use {@link #getNumberOfTables} for bounds-checking.
152 * @return The {@link HuffmanTable} having the specified number.
153 */
154 @NotNull
155 public HuffmanTable getTable(int tableNumber)
156 {
157 return tables.get(tableNumber);
158 }
159
160 /**
161 * @return The number of Huffman tables held by this {@link HuffmanTablesDirectory} instance.
162 */
163 public int getNumberOfTables() throws MetadataException
164 {
165 return getInt(HuffmanTablesDirectory.TAG_NUMBER_OF_TABLES);
166 }
167
168 /**
169 * @return The {@link List} of {@link HuffmanTable}s in this
170 * {@link Directory}.
171 */
172 @NotNull
173 protected List<HuffmanTable> getTables() {
174 return tables;
175 }
176
177 /**
178 * Evaluates whether all the tables in this {@link HuffmanTablesDirectory}
179 * are "typical" Huffman tables.
180 * <p>
181 * "Typical" has a special meaning in this context as the JPEG standard
182 * (ISO/IEC 10918 or ITU-T T.81) defines 4 Huffman tables that has been
183 * developed from the average statistics of a large set of images with 8-bit
184 * precision. Using these instead of calculating the optimal Huffman tables
185 * for a given image is faster, and is preferred by many hardware encoders
186 * and some hardware decoders.
187 * <p>
188 * Even though the JPEG standard doesn't define these as "standard tables"
189 * and requires a decoder to be able to read any valid Huffman tables, some
190 * are in reality limited decoding images using these "typical" tables.
191 * Standards like DCF (Design rule for Camera File system) and DLNA (Digital
192 * Living Network Alliance) actually requires any compliant JPEG to use only
193 * the "typical" Huffman tables.
194 * <p>
195 * This is also related to the term "optimized" JPEG. An "optimized" JPEG is
196 * a JPEG that doesn't use the "typical" Huffman tables.
197 *
198 * @return Whether or not all the tables in this
199 * {@link HuffmanTablesDirectory} are the predefined "typical"
200 * Huffman tables.
201 */
202 public boolean isTypical() {
203 if (tables.size() == 0) {
204 return false;
205 }
206 for (HuffmanTable table : tables) {
207 if (!table.isTypical()) {
208 return false;
209 }
210 }
211 return true;
212 }
213
214 /**
215 * The opposite of {@link #isTypical()}.
216 *
217 * @return Whether or not the tables in this {@link HuffmanTablesDirectory}
218 * are "optimized" - which means that at least one of them aren't
219 * one of the "typical" Huffman tables.
220 */
221 public boolean isOptimized() {
222 return !isTypical();
223 }
224
225 /**
226 * An instance of this class holds a JPEG Huffman table.
227 */
228 public static class HuffmanTable {
229 private final int tableLength;
230 private final HuffmanTableClass tableClass;
231 private final int tableDestinationId;
232 private final byte[] lengthBytes;
233 private final byte[] valueBytes;
234
235 public HuffmanTable (
236 @NotNull HuffmanTableClass
237 tableClass,
238 int tableDestinationId,
239 @NotNull byte[] lBytes,
240 @NotNull byte[] vBytes
241 ) {
242 this.tableClass = tableClass;
243 this.tableDestinationId = tableDestinationId;
244 this.lengthBytes = lBytes;
245 this.valueBytes = vBytes;
246 this.tableLength = vBytes.length + 17;
247 }
248
249 /**
250 * @return The table length in bytes.
251 */
252 public int getTableLength() {
253 return tableLength;
254 }
255
256
257 /**
258 * @return The {@link HuffmanTableClass} of this table.
259 */
260 public HuffmanTableClass getTableClass() {
261 return tableClass;
262 }
263
264
265 /**
266 * @return the the destination identifier for this table.
267 */
268 public int getTableDestinationId() {
269 return tableDestinationId;
270 }
271
272
273 /**
274 * @return A byte array with the L values for this table.
275 */
276 public byte[] getLengthBytes() {
277 if (lengthBytes == null)
278 return null;
279 byte[] result = new byte[lengthBytes.length];
280 System.arraycopy(lengthBytes, 0, result, 0, lengthBytes.length);
281 return result;
282 }
283
284
285 /**
286 * @return A byte array with the V values for this table.
287 */
288 public byte[] getValueBytes() {
289 if (valueBytes == null)
290 return null;
291 byte[] result = new byte[valueBytes.length];
292 System.arraycopy(valueBytes, 0, result, 0, valueBytes.length);
293 return result;
294 }
295
296 /**
297 * Evaluates whether this table is a "typical" Huffman table.
298 * <p>
299 * "Typical" has a special meaning in this context as the JPEG standard
300 * (ISO/IEC 10918 or ITU-T T.81) defines 4 Huffman tables that has been
301 * developed from the average statistics of a large set of images with
302 * 8-bit precision. Using these instead of calculating the optimal
303 * Huffman tables for a given image is faster, and is preferred by many
304 * hardware encoders and some hardware decoders.
305 * <p>
306 * Even though the JPEG standard doesn't define these as
307 * "standard tables" and requires a decoder to be able to read any valid
308 * Huffman tables, some are in reality limited decoding images using
309 * these "typical" tables. Standards like DCF (Design rule for Camera
310 * File system) and DLNA (Digital Living Network Alliance) actually
311 * requires any compliant JPEG to use only the "typical" Huffman tables.
312 * <p>
313 * This is also related to the term "optimized" JPEG. An "optimized"
314 * JPEG is a JPEG that doesn't use the "typical" Huffman tables.
315 *
316 * @return Whether or not this table is one of the predefined "typical"
317 * Huffman tables.
318 */
319 public boolean isTypical() {
320 if (tableClass == HuffmanTableClass.DC) {
321 return
322 Arrays.equals(lengthBytes, TYPICAL_LUMINANCE_DC_LENGTHS) &&
323 Arrays.equals(valueBytes, TYPICAL_LUMINANCE_DC_VALUES) ||
324 Arrays.equals(lengthBytes, TYPICAL_CHROMINANCE_DC_LENGTHS) &&
325 Arrays.equals(valueBytes, TYPICAL_CHROMINANCE_DC_VALUES);
326 } else if (tableClass == HuffmanTableClass.AC) {
327 return
328 Arrays.equals(lengthBytes, TYPICAL_LUMINANCE_AC_LENGTHS) &&
329 Arrays.equals(valueBytes, TYPICAL_LUMINANCE_AC_VALUES) ||
330 Arrays.equals(lengthBytes, TYPICAL_CHROMINANCE_AC_LENGTHS) &&
331 Arrays.equals(valueBytes, TYPICAL_CHROMINANCE_AC_VALUES);
332 }
333 return false;
334 }
335
336 /**
337 * The opposite of {@link #isTypical()}.
338 *
339 * @return Whether or not this table is "optimized" - which means that
340 * it isn't one of the "typical" Huffman tables.
341 */
342 public boolean isOptimized() {
343 return !isTypical();
344 }
345
346 public enum HuffmanTableClass {
347 DC,
348 AC,
349 UNKNOWN;
350
351 public static HuffmanTableClass typeOf(int value) {
352 switch (value) {
353 case 0: return DC;
354 case 1 : return AC;
355 default: return UNKNOWN;
356 }
357 }
358 }
359 }
360}
Note: See TracBrowser for help on using the repository browser.