1 | /*
|
---|
2 | * Copyright 2002-2015 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 | */
|
---|
21 | package com.drew.metadata.jpeg;
|
---|
22 |
|
---|
23 | import com.drew.imaging.jpeg.JpegSegmentMetadataReader;
|
---|
24 | import com.drew.imaging.jpeg.JpegSegmentType;
|
---|
25 | import com.drew.lang.SequentialByteArrayReader;
|
---|
26 | import com.drew.lang.SequentialReader;
|
---|
27 | import com.drew.lang.annotations.NotNull;
|
---|
28 | import com.drew.metadata.Metadata;
|
---|
29 |
|
---|
30 | import java.io.IOException;
|
---|
31 | import java.util.Arrays;
|
---|
32 |
|
---|
33 | /**
|
---|
34 | * Decodes JPEG SOFn data, populating a {@link Metadata} object with tag values in a {@link JpegDirectory}.
|
---|
35 | *
|
---|
36 | * @author Drew Noakes https://drewnoakes.com
|
---|
37 | * @author Darrell Silver http://www.darrellsilver.com
|
---|
38 | */
|
---|
39 | public class JpegReader implements JpegSegmentMetadataReader
|
---|
40 | {
|
---|
41 | @NotNull
|
---|
42 | public Iterable<JpegSegmentType> getSegmentTypes()
|
---|
43 | {
|
---|
44 | // NOTE that some SOFn values do not exist
|
---|
45 | return Arrays.asList(
|
---|
46 | JpegSegmentType.SOF0,
|
---|
47 | JpegSegmentType.SOF1,
|
---|
48 | JpegSegmentType.SOF2,
|
---|
49 | JpegSegmentType.SOF3,
|
---|
50 | // JpegSegmentType.SOF4,
|
---|
51 | JpegSegmentType.SOF5,
|
---|
52 | JpegSegmentType.SOF6,
|
---|
53 | JpegSegmentType.SOF7,
|
---|
54 | JpegSegmentType.SOF8,
|
---|
55 | JpegSegmentType.SOF9,
|
---|
56 | JpegSegmentType.SOF10,
|
---|
57 | JpegSegmentType.SOF11,
|
---|
58 | // JpegSegmentType.SOF12,
|
---|
59 | JpegSegmentType.SOF13,
|
---|
60 | JpegSegmentType.SOF14,
|
---|
61 | JpegSegmentType.SOF15
|
---|
62 | );
|
---|
63 | }
|
---|
64 |
|
---|
65 | public void readJpegSegments(@NotNull Iterable<byte[]> segments, @NotNull Metadata metadata, @NotNull JpegSegmentType segmentType)
|
---|
66 | {
|
---|
67 | for (byte[] segmentBytes : segments) {
|
---|
68 | extract(segmentBytes, metadata, segmentType);
|
---|
69 | }
|
---|
70 | }
|
---|
71 |
|
---|
72 | public void extract(byte[] segmentBytes, Metadata metadata, JpegSegmentType segmentType)
|
---|
73 | {
|
---|
74 | JpegDirectory directory = new JpegDirectory();
|
---|
75 | metadata.addDirectory(directory);
|
---|
76 |
|
---|
77 | // The value of TAG_COMPRESSION_TYPE is determined by the segment type found
|
---|
78 | directory.setInt(JpegDirectory.TAG_COMPRESSION_TYPE, segmentType.byteValue - JpegSegmentType.SOF0.byteValue);
|
---|
79 |
|
---|
80 | SequentialReader reader = new SequentialByteArrayReader(segmentBytes);
|
---|
81 |
|
---|
82 | try {
|
---|
83 | directory.setInt(JpegDirectory.TAG_DATA_PRECISION, reader.getUInt8());
|
---|
84 | directory.setInt(JpegDirectory.TAG_IMAGE_HEIGHT, reader.getUInt16());
|
---|
85 | directory.setInt(JpegDirectory.TAG_IMAGE_WIDTH, reader.getUInt16());
|
---|
86 | short componentCount = reader.getUInt8();
|
---|
87 | directory.setInt(JpegDirectory.TAG_NUMBER_OF_COMPONENTS, componentCount);
|
---|
88 |
|
---|
89 | // for each component, there are three bytes of data:
|
---|
90 | // 1 - Component ID: 1 = Y, 2 = Cb, 3 = Cr, 4 = I, 5 = Q
|
---|
91 | // 2 - Sampling factors: bit 0-3 vertical, 4-7 horizontal
|
---|
92 | // 3 - Quantization table number
|
---|
93 | for (int i = 0; i < (int)componentCount; i++) {
|
---|
94 | final int componentId = reader.getUInt8();
|
---|
95 | final int samplingFactorByte = reader.getUInt8();
|
---|
96 | final int quantizationTableNumber = reader.getUInt8();
|
---|
97 | final JpegComponent component = new JpegComponent(componentId, samplingFactorByte, quantizationTableNumber);
|
---|
98 | directory.setObject(JpegDirectory.TAG_COMPONENT_DATA_1 + i, component);
|
---|
99 | }
|
---|
100 | } catch (IOException ex) {
|
---|
101 | directory.addError(ex.getMessage());
|
---|
102 | }
|
---|
103 | }
|
---|
104 | }
|
---|