[4231] | 1 | /*
|
---|
[6127] | 2 | * Copyright 2002-2012 Drew Noakes
|
---|
[4231] | 3 | *
|
---|
[6127] | 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
|
---|
[4231] | 7 | *
|
---|
[6127] | 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/
|
---|
[4231] | 20 | */
|
---|
| 21 | package com.drew.imaging.jpeg;
|
---|
| 22 |
|
---|
[6127] | 23 | import com.drew.lang.annotations.NotNull;
|
---|
| 24 | import com.drew.lang.annotations.Nullable;
|
---|
| 25 |
|
---|
[4231] | 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
|
---|
[6127] | 33 | * within the Jpeg. For example, it may be convenient to store only the non-image
|
---|
[4231] | 34 | * segments when analysing (or serializing) metadata.
|
---|
[6127] | 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
|
---|
[4231] | 40 | */
|
---|
| 41 | public class JpegSegmentData implements Serializable
|
---|
| 42 | {
|
---|
[6127] | 43 | private static final long serialVersionUID = 7110175216435025451L;
|
---|
[4231] | 44 |
|
---|
| 45 | /** A map of byte[], keyed by the segment marker */
|
---|
[6127] | 46 | @NotNull
|
---|
| 47 | private final HashMap<Byte, List<byte[]>> _segmentDataMap = new HashMap<Byte, List<byte[]>>(10);
|
---|
[4231] | 48 |
|
---|
[6127] | 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)
|
---|
[4231] | 56 | {
|
---|
[6127] | 57 | final List<byte[]> segmentList = getOrCreateSegmentList(segmentMarker);
|
---|
[4231] | 58 | segmentList.add(segmentBytes);
|
---|
| 59 | }
|
---|
| 60 |
|
---|
[6127] | 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
|
---|
[4231] | 67 | public byte[] getSegment(byte segmentMarker)
|
---|
| 68 | {
|
---|
| 69 | return getSegment(segmentMarker, 0);
|
---|
| 70 | }
|
---|
| 71 |
|
---|
[6127] | 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
|
---|
[4231] | 80 | public byte[] getSegment(byte segmentMarker, int occurrence)
|
---|
| 81 | {
|
---|
[6127] | 82 | final List<byte[]> segmentList = getSegmentList(segmentMarker);
|
---|
[4231] | 83 |
|
---|
| 84 | if (segmentList==null || segmentList.size()<=occurrence)
|
---|
| 85 | return null;
|
---|
| 86 | else
|
---|
[6127] | 87 | return segmentList.get(occurrence);
|
---|
[4231] | 88 | }
|
---|
| 89 |
|
---|
[6127] | 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)
|
---|
[4231] | 98 | {
|
---|
[6127] | 99 | final List<byte[]> segmentList = getSegmentList(segmentMarker);
|
---|
| 100 | return segmentList==null ? new ArrayList<byte[]>() : segmentList;
|
---|
[4231] | 101 | }
|
---|
| 102 |
|
---|
[6127] | 103 | @Nullable
|
---|
| 104 | public List<byte[]> getSegmentList(byte segmentMarker)
|
---|
[4231] | 105 | {
|
---|
[6127] | 106 | return _segmentDataMap.get(Byte.valueOf(segmentMarker));
|
---|
[4231] | 107 | }
|
---|
| 108 |
|
---|
[6127] | 109 | @NotNull
|
---|
| 110 | private List<byte[]> getOrCreateSegmentList(byte segmentMarker)
|
---|
[4231] | 111 | {
|
---|
[6127] | 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;
|
---|
[4231] | 120 | }
|
---|
| 121 |
|
---|
[6127] | 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)
|
---|
[4231] | 128 | {
|
---|
[6127] | 129 | final List<byte[]> segmentList = getSegmentList(segmentMarker);
|
---|
| 130 | return segmentList == null ? 0 : segmentList.size();
|
---|
[4231] | 131 | }
|
---|
| 132 |
|
---|
[6127] | 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)
|
---|
[4231] | 141 | {
|
---|
[6127] | 142 | final List<byte[]> segmentList = _segmentDataMap.get(Byte.valueOf(segmentMarker));
|
---|
| 143 | segmentList.remove(occurrence);
|
---|
[4231] | 144 | }
|
---|
| 145 |
|
---|
[6127] | 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 | */
|
---|
[4231] | 160 | public boolean containsSegment(byte segmentMarker)
|
---|
| 161 | {
|
---|
[6127] | 162 | return _segmentDataMap.containsKey(Byte.valueOf(segmentMarker));
|
---|
[4231] | 163 | }
|
---|
| 164 |
|
---|
[6127] | 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
|
---|
[4231] | 172 | {
|
---|
[6127] | 173 | FileOutputStream fileOutputStream = null;
|
---|
[4231] | 174 | try
|
---|
| 175 | {
|
---|
[6127] | 176 | fileOutputStream = new FileOutputStream(file);
|
---|
| 177 | new ObjectOutputStream(fileOutputStream).writeObject(segmentData);
|
---|
[4231] | 178 | }
|
---|
| 179 | finally
|
---|
| 180 | {
|
---|
[6127] | 181 | if (fileOutputStream!=null)
|
---|
| 182 | fileOutputStream.close();
|
---|
[4231] | 183 | }
|
---|
| 184 | }
|
---|
| 185 |
|
---|
[6127] | 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
|
---|
[4231] | 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 | }
|
---|