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.examples;
18  
19  import java.io.BufferedOutputStream;
20  import java.io.File;
21  import java.io.FileOutputStream;
22  import java.io.IOException;
23  import java.io.OutputStream;
24  
25  import org.apache.commons.imaging.Imaging;
26  import org.apache.commons.imaging.ImagingException;
27  import org.apache.commons.imaging.common.ImageMetadata;
28  import org.apache.commons.imaging.common.RationalNumber;
29  import org.apache.commons.imaging.formats.jpeg.JpegImageMetadata;
30  import org.apache.commons.imaging.formats.jpeg.exif.ExifRewriter;
31  import org.apache.commons.imaging.formats.tiff.TiffImageMetadata;
32  import org.apache.commons.imaging.formats.tiff.constants.ExifTagConstants;
33  import org.apache.commons.imaging.formats.tiff.write.TiffOutputDirectory;
34  import org.apache.commons.imaging.formats.tiff.write.TiffOutputSet;
35  import org.apache.commons.io.FileUtils;
36  
37  public class WriteExifMetadataExample {
38      /**
39       * This example illustrates how to add/update EXIF metadata in a JPEG file.
40       *
41       * @param jpegImageFile A source image file.
42       * @param dst           The output file.
43       * @throws IOException
44       * @throws ImagingException
45       * @throws ImagingException
46       */
47      public void changeExifMetadata(final File jpegImageFile, final File dst) throws IOException, ImagingException, ImagingException {
48  
49          try (FileOutputStream fos = new FileOutputStream(dst);
50                  OutputStream os = new BufferedOutputStream(fos)) {
51  
52              TiffOutputSet outputSet = null;
53  
54              // note that metadata might be null if no metadata is found.
55              final ImageMetadata metadata = Imaging.getMetadata(jpegImageFile);
56              final JpegImageMetadata jpegMetadata = (JpegImageMetadata) metadata;
57              if (null != jpegMetadata) {
58                  // note that exif might be null if no Exif metadata is found.
59                  final TiffImageMetadata exif = jpegMetadata.getExif();
60  
61                  if (null != exif) {
62                      // TiffImageMetadata class is immutable (read-only).
63                      // TiffOutputSet class represents the Exif data to write.
64                      //
65                      // Usually, we want to update existing Exif metadata by
66                      // changing
67                      // the values of a few fields, or adding a field.
68                      // In these cases, it is easiest to use getOutputSet() to
69                      // start with a "copy" of the fields read from the image.
70                      outputSet = exif.getOutputSet();
71                  }
72              }
73  
74              // if file does not contain any exif metadata, we create an empty
75              // set of exif metadata. Otherwise, we keep all of the other
76              // existing tags.
77              if (null == outputSet) {
78                  outputSet = new TiffOutputSet();
79              }
80  
81              {
82                  // Example of how to add a field/tag to the output set.
83                  //
84                  // Note that you should first remove the field/tag if it already
85                  // exists in this directory, or you may end up with duplicate
86                  // tags. See above.
87                  //
88                  // Certain fields/tags are expected in certain Exif directories;
89                  // Others can occur in more than one directory (and often have a
90                  // different meaning in different directories).
91                  //
92                  // TagInfo constants often contain a description of what
93                  // directories are associated with a given tag.
94                  //
95                  final TiffOutputDirectory exifDirectory = outputSet.getOrCreateExifDirectory();
96                  // make sure to remove old value if present (this method will
97                  // not fail if the tag does not exist).
98                  exifDirectory.removeField(ExifTagConstants.EXIF_TAG_APERTURE_VALUE);
99                  exifDirectory.add(ExifTagConstants.EXIF_TAG_APERTURE_VALUE, new RationalNumber(3, 10));
100             }
101 
102             {
103                 // Example of how to add/update GPS info to output set.
104 
105                 // New York City
106                 final double longitude = -74.0; // 74 degrees W (in Degrees East)
107                 final double latitude = 40 + 43 / 60.0; // 40 degrees N (in Degrees
108                 // North)
109 
110                 outputSet.setGpsInDegrees(longitude, latitude);
111             }
112 
113             // printTagValue(jpegMetadata, TiffConstants.TIFF_TAG_DATE_TIME);
114 
115             new ExifRewriter().updateExifMetadataLossless(jpegImageFile, os, outputSet);
116         }
117     }
118 
119     public void removeExifMetadata(final File jpegImageFile, final File dst) throws IOException, ImagingException, ImagingException {
120         try (FileOutputStream fos = new FileOutputStream(dst);
121                 OutputStream os = new BufferedOutputStream(fos)) {
122             new ExifRewriter().removeExifMetadata(jpegImageFile, os);
123         }
124     }
125 
126     /**
127      * This example illustrates how to remove a tag (if present) from EXIF metadata in a JPEG file.
128      *
129      * In this case, we remove the "aperture" tag from the EXIF metadata if present.
130      *
131      * @param jpegImageFile A source image file.
132      * @param dst           The output file.
133      * @throws IOException
134      * @throws ImagingException
135      * @throws ImagingException
136      */
137     public void removeExifTag(final File jpegImageFile, final File dst) throws IOException, ImagingException, ImagingException {
138         try (FileOutputStream fos = new FileOutputStream(dst);
139                 OutputStream os = new BufferedOutputStream(fos)) {
140             TiffOutputSet outputSet = null;
141 
142             // note that metadata might be null if no metadata is found.
143             final ImageMetadata metadata = Imaging.getMetadata(jpegImageFile);
144             final JpegImageMetadata jpegMetadata = (JpegImageMetadata) metadata;
145             if (null != jpegMetadata) {
146                 // note that exif might be null if no Exif metadata is found.
147                 final TiffImageMetadata exif = jpegMetadata.getExif();
148 
149                 if (null != exif) {
150                     // TiffImageMetadata class is immutable (read-only).
151                     // TiffOutputSet class represents the Exif data to write.
152                     //
153                     // Usually, we want to update existing Exif metadata by
154                     // changing
155                     // the values of a few fields, or adding a field.
156                     // In these cases, it is easiest to use getOutputSet() to
157                     // start with a "copy" of the fields read from the image.
158                     outputSet = exif.getOutputSet();
159                 }
160             }
161 
162             if (null == outputSet) {
163                 // file does not contain any exif metadata. We don't need to
164                 // update the file; just copy it.
165                 FileUtils.copyFile(jpegImageFile, dst);
166                 return;
167             }
168 
169             {
170                 // Example of how to remove a single tag/field.
171                 // There are two ways to do this.
172 
173                 // Option 1: brute force
174                 // Note that this approach is crude: Exif data is organized in
175                 // directories. The same tag/field may appear in more than one
176                 // directory, and have different meanings in each.
177                 outputSet.removeField(ExifTagConstants.EXIF_TAG_APERTURE_VALUE);
178 
179                 // Option 2: precision
180                 // We know the exact directory the tag should appear in, in this
181                 // case the "exif" directory.
182                 // One complicating factor is that in some cases, manufacturers
183                 // will place the same tag in different directories.
184                 // To learn which directory a tag appears in, either refer to
185                 // the constants in ExifTagConstants.java or go to Phil Harvey's
186                 // EXIF website.
187                 final TiffOutputDirectory exifDirectory = outputSet.getExifDirectory();
188                 if (null != exifDirectory) {
189                     exifDirectory.removeField(ExifTagConstants.EXIF_TAG_APERTURE_VALUE);
190                 }
191             }
192 
193             new ExifRewriter().updateExifMetadataLossless(jpegImageFile, os, outputSet);
194         }
195     }
196 
197     /**
198      * This example illustrates how to set the GPS values in JPEG EXIF metadata.
199      *
200      * @param jpegImageFile A source image file.
201      * @param dst           The output file.
202      * @throws IOException
203      * @throws ImagingException
204      * @throws ImagingException
205      */
206     public void setExifGPSTag(final File jpegImageFile, final File dst) throws IOException, ImagingException, ImagingException {
207         try (FileOutputStream fos = new FileOutputStream(dst);
208                 OutputStream os = new BufferedOutputStream(fos)) {
209             TiffOutputSet outputSet = null;
210 
211             // note that metadata might be null if no metadata is found.
212             final ImageMetadata metadata = Imaging.getMetadata(jpegImageFile);
213             final JpegImageMetadata jpegMetadata = (JpegImageMetadata) metadata;
214             if (null != jpegMetadata) {
215                 // note that exif might be null if no Exif metadata is found.
216                 final TiffImageMetadata exif = jpegMetadata.getExif();
217 
218                 if (null != exif) {
219                     // TiffImageMetadata class is immutable (read-only).
220                     // TiffOutputSet class represents the Exif data to write.
221                     //
222                     // Usually, we want to update existing Exif metadata by
223                     // changing
224                     // the values of a few fields, or adding a field.
225                     // In these cases, it is easiest to use getOutputSet() to
226                     // start with a "copy" of the fields read from the image.
227                     outputSet = exif.getOutputSet();
228                 }
229             }
230 
231             // if file does not contain any exif metadata, we create an empty
232             // set of exif metadata. Otherwise, we keep all of the other
233             // existing tags.
234             if (null == outputSet) {
235                 outputSet = new TiffOutputSet();
236             }
237 
238             {
239                 // Example of how to add/update GPS info to output set.
240 
241                 // New York City
242                 final double longitude = -74.0; // 74 degrees W (in Degrees East)
243                 final double latitude = 40 + 43 / 60.0; // 40 degrees N (in Degrees
244                 // North)
245 
246                 outputSet.setGpsInDegrees(longitude, latitude);
247             }
248 
249             new ExifRewriter().updateExifMetadataLossless(jpegImageFile, os, outputSet);
250         }
251     }
252 
253 }