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 }