View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.imaging.formats.jpeg;
18  
19  import java.awt.Dimension;
20  import java.awt.image.BufferedImage;
21  import java.io.ByteArrayInputStream;
22  import java.io.IOException;
23  import java.util.ArrayList;
24  import java.util.List;
25  
26  import javax.imageio.ImageIO;
27  
28  import org.apache.commons.imaging.ImageReadException;
29  import org.apache.commons.imaging.Imaging;
30  import org.apache.commons.imaging.ImagingException;
31  import org.apache.commons.imaging.common.ImageMetadata;
32  import org.apache.commons.imaging.formats.tiff.JpegImageData;
33  import org.apache.commons.imaging.formats.tiff.TiffField;
34  import org.apache.commons.imaging.formats.tiff.TiffImageData;
35  import org.apache.commons.imaging.formats.tiff.TiffImageMetadata;
36  import org.apache.commons.imaging.formats.tiff.taginfos.TagInfo;
37  import org.apache.commons.imaging.util.Debug;
38  
39  public class JpegImageMetadata implements ImageMetadata {
40      private final JpegPhotoshopMetadata photoshop;
41      private final TiffImageMetadata exif;
42      private static final String NEWLINE = System.getProperty("line.separator");
43  
44      public JpegImageMetadata(final JpegPhotoshopMetadata photoshop,
45              final TiffImageMetadata exif) {
46          this.photoshop = photoshop;
47          this.exif = exif;
48      }
49  
50      public TiffImageMetadata getExif() {
51          return exif;
52      }
53  
54      public JpegPhotoshopMetadata getPhotoshop() {
55          return photoshop;
56      }
57  
58      public TiffField findEXIFValue(final TagInfo tagInfo) {
59          try {
60              return exif != null ? exif.findField(tagInfo) : null;
61          } catch (final ImageReadException cannotHappen) {
62              return null;
63          }
64      }
65  
66      public TiffField findEXIFValueWithExactMatch(final TagInfo tagInfo) {
67          try {
68              return exif != null ? exif.findField(tagInfo, true) : null;
69          } catch (final ImageReadException cannotHappen) {
70              return null;
71          }
72      }
73  
74      /**
75       * Returns the size of the first JPEG thumbnail found in the EXIF metadata.
76       * 
77       * @return Thumbnail width and height or null if no thumbnail.
78       * @throws ImageReadException
79       * @throws IOException
80       */
81      public Dimension getEXIFThumbnailSize() throws ImageReadException,
82              IOException {
83          final byte[] data = getEXIFThumbnailData();
84  
85          if (data != null) {
86              return Imaging.getImageSize(data);
87          }
88          return null;
89      }
90  
91      /**
92       * Returns the data of the first JPEG thumbnail found in the EXIF metadata.
93       * 
94       * @return JPEG data or null if no thumbnail.
95       * @throws ImageReadException
96       * @throws IOException
97       */
98      public byte[] getEXIFThumbnailData() throws ImageReadException, IOException {
99          if (exif == null) {
100             return null;
101         }
102         final List<? extends ImageMetadataItem> dirs = exif.getDirectories();
103         for (final ImageMetadataItem d : dirs) {
104             final TiffImageMetadata.Directory dir = (TiffImageMetadata.Directory) d;
105 
106             byte[] data = null;
107             if (dir.getJpegImageData() != null) {
108                 data = dir.getJpegImageData().getData(); // TODO clone?
109             }
110             // Support other image formats here.
111 
112             if (data != null) {
113                 return data;
114             }
115         }
116         return null;
117     }
118 
119     /**
120      * Get the thumbnail image if available.
121      * 
122      * @return the thumbnail image. May be <code>null</code> if no image could
123      *         be found.
124      * @throws ImageReadException
125      * @throws IOException
126      */
127     public BufferedImage getEXIFThumbnail() throws ImageReadException,
128             IOException {
129 
130         if (exif == null) {
131             return null;
132         }
133 
134         final List<? extends ImageMetadataItem> dirs = exif.getDirectories();
135         for (final ImageMetadataItem d : dirs) {
136             final TiffImageMetadata.Directory dir = (TiffImageMetadata.Directory) d;
137             // Debug.debug("dir", dir);
138             BufferedImage image = dir.getThumbnail();
139             if (null != image) {
140                 return image;
141             }
142 
143             final JpegImageData jpegImageData = dir.getJpegImageData();
144             if (jpegImageData != null) {
145                 // JPEG thumbnail as JPEG or other format; try to parse.
146                 boolean imageSucceeded = false;
147                 try {
148                     image = Imaging.getBufferedImage(jpegImageData.getData());
149                     imageSucceeded = true;
150                 } catch (final ImagingException imagingException) { // NOPMD
151                 } catch (final IOException ioException) { // NOPMD
152                 } finally {
153                     // our JPEG reading is still a bit buggy -
154                     // fall back to ImageIO on error
155                     if (!imageSucceeded) {
156                         final ByteArrayInputStream input = new ByteArrayInputStream(
157                                 jpegImageData.getData());
158                         image = ImageIO.read(input);
159                     }
160                 }
161                 if (image != null) {
162                     return image;
163                 }
164             }
165         }
166 
167         return null;
168     }
169 
170     public TiffImageData getRawImageData() {
171         if (exif == null) {
172             return null;
173         }
174         final List<? extends ImageMetadataItem> dirs = exif.getDirectories();
175         for (final ImageMetadataItem d : dirs) {
176             final TiffImageMetadata.Directory dir = (TiffImageMetadata.Directory) d;
177             // Debug.debug("dir", dir);
178             final TiffImageData rawImageData = dir.getTiffImageData();
179             if (null != rawImageData) {
180                 return rawImageData;
181             }
182         }
183 
184         return null;
185     }
186 
187     @Override
188     public List<ImageMetadataItem> getItems() {
189         final List<ImageMetadataItem> result = new ArrayList<>();
190 
191         if (null != exif) {
192             result.addAll(exif.getItems());
193         }
194 
195         if (null != photoshop) {
196             result.addAll(photoshop.getItems());
197         }
198 
199         return result;
200     }
201 
202     @Override
203     public String toString() {
204         return toString(null);
205     }
206 
207     @Override
208     public String toString(String prefix) {
209         if (prefix == null) {
210             prefix = "";
211         }
212 
213         final StringBuilder result = new StringBuilder();
214 
215         result.append(prefix);
216         if (null == exif) {
217             result.append("No Exif metadata.");
218         } else {
219             result.append("Exif metadata:");
220             result.append(NEWLINE);
221             result.append(exif.toString("\t"));
222         }
223 
224         // if (null != exif && null != photoshop)
225         result.append(NEWLINE);
226 
227         result.append(prefix);
228         if (null == photoshop) {
229             result.append("No Photoshop (IPTC) metadata.");
230         } else {
231             result.append("Photoshop (IPTC) metadata:");
232             result.append(NEWLINE);
233             result.append(photoshop.toString("\t"));
234         }
235 
236         return result.toString();
237     }
238 
239     public void dump() {
240         Debug.debug(this.toString());
241     }
242 
243 }