1 | /*
|
---|
2 | * Copyright 2002-2012 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 | * http://drewnoakes.com/code/exif/
|
---|
19 | * http://code.google.com/p/metadata-extractor/
|
---|
20 | */
|
---|
21 | package com.drew.imaging.jpeg;
|
---|
22 |
|
---|
23 | import com.drew.lang.annotations.NotNull;
|
---|
24 | import com.drew.lang.annotations.Nullable;
|
---|
25 |
|
---|
26 | import java.io.*;
|
---|
27 | import java.util.ArrayList;
|
---|
28 | import java.util.HashMap;
|
---|
29 | import java.util.List;
|
---|
30 |
|
---|
31 | /**
|
---|
32 | * Holds a collection of Jpeg data segments. This need not necessarily be all segments
|
---|
33 | * within the Jpeg. For example, it may be convenient to store only the non-image
|
---|
34 | * segments when analysing (or serializing) metadata.
|
---|
35 | * <p/>
|
---|
36 | * Segments are keyed via their segment marker (a byte). Where multiple segments use the
|
---|
37 | * same segment marker, they will all be stored and available.
|
---|
38 | *
|
---|
39 | * @author Drew Noakes http://drewnoakes.com
|
---|
40 | */
|
---|
41 | public class JpegSegmentData implements Serializable
|
---|
42 | {
|
---|
43 | private static final long serialVersionUID = 7110175216435025451L;
|
---|
44 |
|
---|
45 | /** A map of byte[], keyed by the segment marker */
|
---|
46 | @NotNull
|
---|
47 | private final HashMap<Byte, List<byte[]>> _segmentDataMap = new HashMap<Byte, List<byte[]>>(10);
|
---|
48 |
|
---|
49 | /**
|
---|
50 | * Adds segment bytes to the collection.
|
---|
51 | * @param segmentMarker
|
---|
52 | * @param segmentBytes
|
---|
53 | */
|
---|
54 | @SuppressWarnings({ "MismatchedQueryAndUpdateOfCollection" })
|
---|
55 | public void addSegment(byte segmentMarker, @NotNull byte[] segmentBytes)
|
---|
56 | {
|
---|
57 | final List<byte[]> segmentList = getOrCreateSegmentList(segmentMarker);
|
---|
58 | segmentList.add(segmentBytes);
|
---|
59 | }
|
---|
60 |
|
---|
61 | /**
|
---|
62 | * Gets the first Jpeg segment data for the specified marker.
|
---|
63 | * @param segmentMarker the byte identifier for the desired segment
|
---|
64 | * @return a byte[] containing segment data or null if no data exists for that segment
|
---|
65 | */
|
---|
66 | @Nullable
|
---|
67 | public byte[] getSegment(byte segmentMarker)
|
---|
68 | {
|
---|
69 | return getSegment(segmentMarker, 0);
|
---|
70 | }
|
---|
71 |
|
---|
72 | /**
|
---|
73 | * Gets segment data for a specific occurrence and marker. Use this method when more than one occurrence
|
---|
74 | * of segment data for a given marker exists.
|
---|
75 | * @param segmentMarker identifies the required segment
|
---|
76 | * @param occurrence the zero-based index of the occurrence
|
---|
77 | * @return the segment data as a byte[], or null if no segment exists for the marker & occurrence
|
---|
78 | */
|
---|
79 | @Nullable
|
---|
80 | public byte[] getSegment(byte segmentMarker, int occurrence)
|
---|
81 | {
|
---|
82 | final List<byte[]> segmentList = getSegmentList(segmentMarker);
|
---|
83 |
|
---|
84 | if (segmentList==null || segmentList.size()<=occurrence)
|
---|
85 | return null;
|
---|
86 | else
|
---|
87 | return segmentList.get(occurrence);
|
---|
88 | }
|
---|
89 |
|
---|
90 | /**
|
---|
91 | * Returns all instances of a given Jpeg segment. If no instances exist, an empty sequence is returned.
|
---|
92 | *
|
---|
93 | * @param segmentMarker a number which identifies the type of Jpeg segment being queried
|
---|
94 | * @return zero or more byte arrays, each holding the data of a Jpeg segment
|
---|
95 | */
|
---|
96 | @NotNull
|
---|
97 | public Iterable<byte[]> getSegments(byte segmentMarker)
|
---|
98 | {
|
---|
99 | final List<byte[]> segmentList = getSegmentList(segmentMarker);
|
---|
100 | return segmentList==null ? new ArrayList<byte[]>() : segmentList;
|
---|
101 | }
|
---|
102 |
|
---|
103 | @Nullable
|
---|
104 | public List<byte[]> getSegmentList(byte segmentMarker)
|
---|
105 | {
|
---|
106 | return _segmentDataMap.get(Byte.valueOf(segmentMarker));
|
---|
107 | }
|
---|
108 |
|
---|
109 | @NotNull
|
---|
110 | private List<byte[]> getOrCreateSegmentList(byte segmentMarker)
|
---|
111 | {
|
---|
112 | List<byte[]> segmentList;
|
---|
113 | if (_segmentDataMap.containsKey(segmentMarker)) {
|
---|
114 | segmentList = _segmentDataMap.get(segmentMarker);
|
---|
115 | } else {
|
---|
116 | segmentList = new ArrayList<byte[]>();
|
---|
117 | _segmentDataMap.put(segmentMarker, segmentList);
|
---|
118 | }
|
---|
119 | return segmentList;
|
---|
120 | }
|
---|
121 |
|
---|
122 | /**
|
---|
123 | * Returns the count of segment data byte arrays stored for a given segment marker.
|
---|
124 | * @param segmentMarker identifies the required segment
|
---|
125 | * @return the segment count (zero if no segments exist).
|
---|
126 | */
|
---|
127 | public int getSegmentCount(byte segmentMarker)
|
---|
128 | {
|
---|
129 | final List<byte[]> segmentList = getSegmentList(segmentMarker);
|
---|
130 | return segmentList == null ? 0 : segmentList.size();
|
---|
131 | }
|
---|
132 |
|
---|
133 | /**
|
---|
134 | * Removes a specified instance of a segment's data from the collection. Use this method when more than one
|
---|
135 | * occurrence of segment data for a given marker exists.
|
---|
136 | * @param segmentMarker identifies the required segment
|
---|
137 | * @param occurrence the zero-based index of the segment occurrence to remove.
|
---|
138 | */
|
---|
139 | @SuppressWarnings({ "MismatchedQueryAndUpdateOfCollection" })
|
---|
140 | public void removeSegmentOccurrence(byte segmentMarker, int occurrence)
|
---|
141 | {
|
---|
142 | final List<byte[]> segmentList = _segmentDataMap.get(Byte.valueOf(segmentMarker));
|
---|
143 | segmentList.remove(occurrence);
|
---|
144 | }
|
---|
145 |
|
---|
146 | /**
|
---|
147 | * Removes all segments from the collection having the specified marker.
|
---|
148 | * @param segmentMarker identifies the required segment
|
---|
149 | */
|
---|
150 | public void removeSegment(byte segmentMarker)
|
---|
151 | {
|
---|
152 | _segmentDataMap.remove(Byte.valueOf(segmentMarker));
|
---|
153 | }
|
---|
154 |
|
---|
155 | /**
|
---|
156 | * Determines whether data is present for a given segment marker.
|
---|
157 | * @param segmentMarker identifies the required segment
|
---|
158 | * @return true if data exists, otherwise false
|
---|
159 | */
|
---|
160 | public boolean containsSegment(byte segmentMarker)
|
---|
161 | {
|
---|
162 | return _segmentDataMap.containsKey(Byte.valueOf(segmentMarker));
|
---|
163 | }
|
---|
164 |
|
---|
165 | /**
|
---|
166 | * Serialises the contents of a JpegSegmentData to a file.
|
---|
167 | * @param file to file to write from
|
---|
168 | * @param segmentData the data to write
|
---|
169 | * @throws IOException if problems occur while writing
|
---|
170 | */
|
---|
171 | public static void toFile(@NotNull File file, @NotNull JpegSegmentData segmentData) throws IOException
|
---|
172 | {
|
---|
173 | FileOutputStream fileOutputStream = null;
|
---|
174 | try
|
---|
175 | {
|
---|
176 | fileOutputStream = new FileOutputStream(file);
|
---|
177 | new ObjectOutputStream(fileOutputStream).writeObject(segmentData);
|
---|
178 | }
|
---|
179 | finally
|
---|
180 | {
|
---|
181 | if (fileOutputStream!=null)
|
---|
182 | fileOutputStream.close();
|
---|
183 | }
|
---|
184 | }
|
---|
185 |
|
---|
186 | /**
|
---|
187 | * Deserialises the contents of a JpegSegmentData from a file.
|
---|
188 | * @param file the file to read from
|
---|
189 | * @return the JpegSegmentData as read
|
---|
190 | * @throws IOException if problems occur while reading
|
---|
191 | * @throws ClassNotFoundException if problems occur while deserialising
|
---|
192 | */
|
---|
193 | @NotNull
|
---|
194 | public static JpegSegmentData fromFile(@NotNull File file) throws IOException, ClassNotFoundException
|
---|
195 | {
|
---|
196 | ObjectInputStream inputStream = null;
|
---|
197 | try
|
---|
198 | {
|
---|
199 | inputStream = new ObjectInputStream(new FileInputStream(file));
|
---|
200 | return (JpegSegmentData)inputStream.readObject();
|
---|
201 | }
|
---|
202 | finally
|
---|
203 | {
|
---|
204 | if (inputStream!=null)
|
---|
205 | inputStream.close();
|
---|
206 | }
|
---|
207 | }
|
---|
208 | }
|
---|