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

Last change on this file since 15744 was 15217, checked in by Don-vip, 7 years ago

see #17848 - update to metadata-extractor 2.12.0

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