Example usage for org.apache.commons.imaging.formats.tiff.write TiffOutputDirectory removeField

List of usage examples for org.apache.commons.imaging.formats.tiff.write TiffOutputDirectory removeField

Introduction

In this page you can find the example usage for org.apache.commons.imaging.formats.tiff.write TiffOutputDirectory removeField.

Prototype

public void removeField(final int tag) 

Source Link

Usage

From source file:adams.flow.transformer.exiftagoperation.ApacheCommonsExifTagWrite.java

/**
 * Processes the incoming data./*from  w  ww  .  j  a v a  2 s .  c om*/
 *
 * @param input   the input to process
 * @param errors   for storing errors
 * @return      the generated output
 */
@Override
protected Object doProcess(Object input, MessageCollection errors) {
    Object result;
    File inputFile;
    File tmpFile;
    JpegImageMetadata meta;
    TiffImageMetadata exif;
    TiffOutputSet outputSet;
    TiffOutputDirectory exifDir;
    FileOutputStream fos;
    BufferedOutputStream bos;

    result = null;

    if (input instanceof String)
        inputFile = new PlaceholderFile((String) input).getAbsoluteFile();
    else
        inputFile = ((File) input).getAbsoluteFile();
    tmpFile = TempUtils.createTempFile(getClass().getSimpleName().toLowerCase() + "-", ".jpg");

    fos = null;
    bos = null;
    try {
        meta = (JpegImageMetadata) Imaging.getMetadata(inputFile);
        if (meta != null) {
            exif = meta.getExif();
            if (exif != null) {
                outputSet = exif.getOutputSet();
                if (outputSet != null) {
                    exifDir = outputSet.getOrCreateExifDirectory();
                    if (exifDir != null) {
                        exifDir.removeField(m_Tag.getTagInfo());
                        if (m_Tag.getTagInfo() instanceof TagInfoAscii)
                            exifDir.add((TagInfoAscii) m_Tag.getTagInfo(), m_Value);
                        else if (m_Tag.getTagInfo() instanceof TagInfoByte)
                            exifDir.add((TagInfoByte) m_Tag.getTagInfo(), Byte.parseByte(m_Value));
                        else if (m_Tag.getTagInfo() instanceof TagInfoShort)
                            exifDir.add((TagInfoShort) m_Tag.getTagInfo(), Short.parseShort(m_Value));
                        else if (m_Tag.getTagInfo() instanceof TagInfoDouble)
                            exifDir.add((TagInfoDouble) m_Tag.getTagInfo(), Double.parseDouble(m_Value));
                        else if (m_Tag.getTagInfo() instanceof TagInfoFloat)
                            exifDir.add((TagInfoFloat) m_Tag.getTagInfo(), Float.parseFloat(m_Value));
                        else if (m_Tag.getTagInfo() instanceof TagInfoRational)
                            exifDir.add((TagInfoRational) m_Tag.getTagInfo(),
                                    RationalNumber.valueOf(Double.parseDouble(m_Value)));
                        else
                            errors.add("Unhandled tag info type: " + Utils.classToString(m_Tag.getTagInfo()));
                        if (errors.isEmpty()) {
                            fos = new FileOutputStream(tmpFile);
                            bos = new BufferedOutputStream(fos);
                            new ExifRewriter().updateExifMetadataLossless(inputFile, bos, outputSet);
                            if (!FileUtils.copy(tmpFile, inputFile))
                                errors.add("Failed to replace " + inputFile + " with updated EXIF from "
                                        + tmpFile);
                            if (!FileUtils.delete(tmpFile))
                                errors.add("Failed to delete tmp file: " + tmpFile);
                        }
                    } else {
                        errors.add("Failed to obtain EXIF directory: " + input);
                    }
                } else {
                    errors.add("Failed to obtain output set: " + input);
                }
            } else {
                errors.add("No EXIF meta-data available: " + input);
            }
        } else {
            errors.add("No meta-data available: " + input);
        }
    } catch (Exception e) {
        errors.add("Failed to read EXIF tag " + m_Tag + " from: " + input, e);
    } finally {
        FileUtils.closeQuietly(bos);
        FileUtils.closeQuietly(fos);
    }

    if (errors.isEmpty())
        result = input;

    return result;
}

From source file:org.apache.commons.imaging.examples.WriteExifMetadataExample.java

/**
 * This example illustrates how to add/update EXIF metadata in a JPEG file.
 * /*from   w  ww.j a  v  a  2s .c o m*/
 * @param jpegImageFile
 *            A source image file.
 * @param dst
 *            The output file.
 * @throws IOException
 * @throws ImageReadException
 * @throws ImageWriteException
 */
public void changeExifMetadata(final File jpegImageFile, final File dst)
        throws IOException, ImageReadException, ImageWriteException {

    try (FileOutputStream fos = new FileOutputStream(dst); OutputStream os = new BufferedOutputStream(fos);) {

        TiffOutputSet outputSet = null;

        // note that metadata might be null if no metadata is found.
        final ImageMetadata metadata = Imaging.getMetadata(jpegImageFile);
        final JpegImageMetadata jpegMetadata = (JpegImageMetadata) metadata;
        if (null != jpegMetadata) {
            // note that exif might be null if no Exif metadata is found.
            final TiffImageMetadata exif = jpegMetadata.getExif();

            if (null != exif) {
                // TiffImageMetadata class is immutable (read-only).
                // TiffOutputSet class represents the Exif data to write.
                //
                // Usually, we want to update existing Exif metadata by
                // changing
                // the values of a few fields, or adding a field.
                // In these cases, it is easiest to use getOutputSet() to
                // start with a "copy" of the fields read from the image.
                outputSet = exif.getOutputSet();
            }
        }

        // if file does not contain any exif metadata, we create an empty
        // set of exif metadata. Otherwise, we keep all of the other
        // existing tags.
        if (null == outputSet) {
            outputSet = new TiffOutputSet();
        }

        {
            // Example of how to add a field/tag to the output set.
            //
            // Note that you should first remove the field/tag if it already
            // exists in this directory, or you may end up with duplicate
            // tags. See above.
            //
            // Certain fields/tags are expected in certain Exif directories;
            // Others can occur in more than one directory (and often have a
            // different meaning in different directories).
            //
            // TagInfo constants often contain a description of what
            // directories are associated with a given tag.
            //
            final TiffOutputDirectory exifDirectory = outputSet.getOrCreateExifDirectory();
            // make sure to remove old value if present (this method will
            // not fail if the tag does not exist).
            exifDirectory.removeField(ExifTagConstants.EXIF_TAG_APERTURE_VALUE);
            exifDirectory.add(ExifTagConstants.EXIF_TAG_APERTURE_VALUE, new RationalNumber(3, 10));
        }

        {
            // Example of how to add/update GPS info to output set.

            // New York City
            final double longitude = -74.0; // 74 degrees W (in Degrees East)
            final double latitude = 40 + 43 / 60.0; // 40 degrees N (in Degrees
            // North)

            outputSet.setGPSInDegrees(longitude, latitude);
        }

        // printTagValue(jpegMetadata, TiffConstants.TIFF_TAG_DATE_TIME);

        new ExifRewriter().updateExifMetadataLossless(jpegImageFile, os, outputSet);
    }
}

From source file:org.apache.commons.imaging.examples.WriteExifMetadataExample.java

/**
 * This example illustrates how to remove a tag (if present) from EXIF
 * metadata in a JPEG file./*from  www.j av  a2s  . co m*/
 * 
 * In this case, we remove the "aperture" tag from the EXIF metadata if
 * present.
 * 
 * @param jpegImageFile
 *            A source image file.
 * @param dst
 *            The output file.
 * @throws IOException
 * @throws ImageReadException
 * @throws ImageWriteException
 */
public void removeExifTag(final File jpegImageFile, final File dst)
        throws IOException, ImageReadException, ImageWriteException {
    try (FileOutputStream fos = new FileOutputStream(dst); OutputStream os = new BufferedOutputStream(fos)) {
        TiffOutputSet outputSet = null;

        // note that metadata might be null if no metadata is found.
        final ImageMetadata metadata = Imaging.getMetadata(jpegImageFile);
        final JpegImageMetadata jpegMetadata = (JpegImageMetadata) metadata;
        if (null != jpegMetadata) {
            // note that exif might be null if no Exif metadata is found.
            final TiffImageMetadata exif = jpegMetadata.getExif();

            if (null != exif) {
                // TiffImageMetadata class is immutable (read-only).
                // TiffOutputSet class represents the Exif data to write.
                //
                // Usually, we want to update existing Exif metadata by
                // changing
                // the values of a few fields, or adding a field.
                // In these cases, it is easiest to use getOutputSet() to
                // start with a "copy" of the fields read from the image.
                outputSet = exif.getOutputSet();
            }
        }

        if (null == outputSet) {
            // file does not contain any exif metadata. We don't need to
            // update the file; just copy it.
            FileUtils.copyFile(jpegImageFile, dst);
            return;
        }

        {
            // Example of how to remove a single tag/field.
            // There are two ways to do this.

            // Option 1: brute force
            // Note that this approach is crude: Exif data is organized in
            // directories. The same tag/field may appear in more than one
            // directory, and have different meanings in each.
            outputSet.removeField(ExifTagConstants.EXIF_TAG_APERTURE_VALUE);

            // Option 2: precision
            // We know the exact directory the tag should appear in, in this
            // case the "exif" directory.
            // One complicating factor is that in some cases, manufacturers
            // will place the same tag in different directories.
            // To learn which directory a tag appears in, either refer to
            // the constants in ExifTagConstants.java or go to Phil Harvey's
            // EXIF website.
            final TiffOutputDirectory exifDirectory = outputSet.getExifDirectory();
            if (null != exifDirectory) {
                exifDirectory.removeField(ExifTagConstants.EXIF_TAG_APERTURE_VALUE);
            }
        }

        new ExifRewriter().updateExifMetadataLossless(jpegImageFile, os, outputSet);
    }
}

From source file:org.openstreetmap.josm.plugins.mapillary.io.export.MapillaryExportWriterThread.java

@Override
public void run() {
    this.monitor.setCustomText("Downloaded 0/" + this.amount);
    BufferedImage img;//from  w w w.  ja  va 2s .com
    MapillaryAbstractImage mimg;
    String finalPath = "";
    for (int i = 0; i < this.amount; i++) {
        try {
            img = this.queue.take();
            mimg = this.queueImages.take();
            if (img == null || mimg == null)
                throw new IllegalStateException("Null image");
            if (this.path == null && mimg instanceof MapillaryImportedImage) {
                String path = ((MapillaryImportedImage) mimg).getFile().getPath();
                finalPath = path.substring(0, path.lastIndexOf('.'));
            } else if (mimg instanceof MapillaryImage) {
                finalPath = this.path + '/' + ((MapillaryImage) mimg).getKey();
            } else if (mimg instanceof MapillaryImportedImage) {
                finalPath = this.path + '/' + ((MapillaryImportedImage) mimg).getFile().getName();
            }

            // Transforms the image into a byte array.
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            ImageIO.write(img, "jpg", outputStream);
            byte[] imageBytes = outputStream.toByteArray();

            // Write EXIF tags
            TiffOutputSet outputSet = null;
            TiffOutputDirectory exifDirectory;
            TiffOutputDirectory gpsDirectory;
            // If the image is imported, loads the rest of the EXIF data.
            if (mimg instanceof MapillaryImportedImage) {
                final ImageMetadata metadata = Imaging.getMetadata(((MapillaryImportedImage) mimg).getFile());
                final JpegImageMetadata jpegMetadata = (JpegImageMetadata) metadata;
                if (null != jpegMetadata) {
                    final TiffImageMetadata exif = jpegMetadata.getExif();
                    if (null != exif) {
                        outputSet = exif.getOutputSet();
                    }
                }
            }
            if (null == outputSet) {
                outputSet = new TiffOutputSet();
            }
            exifDirectory = outputSet.getOrCreateExifDirectory();
            gpsDirectory = outputSet.getOrCreateGPSDirectory();

            gpsDirectory.removeField(GpsTagConstants.GPS_TAG_GPS_IMG_DIRECTION_REF);
            gpsDirectory.add(GpsTagConstants.GPS_TAG_GPS_IMG_DIRECTION_REF,
                    GpsTagConstants.GPS_TAG_GPS_IMG_DIRECTION_REF_VALUE_TRUE_NORTH);

            gpsDirectory.removeField(GpsTagConstants.GPS_TAG_GPS_IMG_DIRECTION);
            gpsDirectory.add(GpsTagConstants.GPS_TAG_GPS_IMG_DIRECTION,
                    RationalNumber.valueOf(mimg.getMovingCa()));

            exifDirectory.removeField(ExifTagConstants.EXIF_TAG_DATE_TIME_ORIGINAL);
            if (mimg instanceof MapillaryImportedImage) {
                exifDirectory.add(ExifTagConstants.EXIF_TAG_DATE_TIME_ORIGINAL,
                        mimg.getDate("yyyy/MM/dd HH:mm:ss"));
            } else if (mimg instanceof MapillaryImage) {
                exifDirectory.add(ExifTagConstants.EXIF_TAG_DATE_TIME_ORIGINAL,
                        mimg.getDate("yyyy/MM/dd HH/mm/ss"));
            }
            outputSet.setGPSInDegrees(mimg.getMovingLatLon().lon(), mimg.getMovingLatLon().lat());
            OutputStream os = new BufferedOutputStream(new FileOutputStream(finalPath + ".jpg"));
            new ExifRewriter().updateExifMetadataLossless(imageBytes, os, outputSet);

            os.close();
        } catch (InterruptedException e) {
            Main.info("Mapillary export cancelled");
            return;
        } catch (IOException | ImageReadException | ImageWriteException e) {
            Main.error(e);
        }

        // Increases the progress bar.
        this.monitor.worked(PleaseWaitProgressMonitor.PROGRESS_BAR_MAX / this.amount);
        this.monitor.setCustomText("Downloaded " + (i + 1) + "/" + this.amount);
    }
}

From source file:org.openstreetmap.josm.plugins.mapillary.oauth.UploadUtils.java

/**
 * Returns a file containing the picture and an updated version of the EXIF
 * tags./*from   w w  w.j av a2  s . c om*/
 *
 * @param image The image to be uploaded
 * @return A File object containing the picture and an updated version of the
 * EXIF tags.
 * @throws ImageReadException  if there are errors reading the image from the file.
 * @throws IOException         if there are errors getting the metadata from the file or writing
 *                             the output.
 * @throws ImageWriteException if there are errors writing the image in the file.
 */
static File updateFile(MapillaryImportedImage image)
        throws ImageReadException, IOException, ImageWriteException {
    TiffOutputSet outputSet = null;
    TiffOutputDirectory exifDirectory;
    TiffOutputDirectory gpsDirectory;
    TiffOutputDirectory rootDirectory;

    // If the image is imported, loads the rest of the EXIF data.
    JpegImageMetadata jpegMetadata = null;
    try {
        ImageMetadata metadata = Imaging.getMetadata(image.getFile());
        jpegMetadata = (JpegImageMetadata) metadata;
    } catch (Exception e) {
        Main.warn(e);
    }

    if (null != jpegMetadata) {
        final TiffImageMetadata exif = jpegMetadata.getExif();
        if (null != exif) {
            outputSet = exif.getOutputSet();
        }
    }
    if (null == outputSet) {
        outputSet = new TiffOutputSet();
    }
    gpsDirectory = outputSet.getOrCreateGPSDirectory();
    exifDirectory = outputSet.getOrCreateExifDirectory();
    rootDirectory = outputSet.getOrCreateRootDirectory();

    gpsDirectory.removeField(GpsTagConstants.GPS_TAG_GPS_IMG_DIRECTION_REF);
    gpsDirectory.add(GpsTagConstants.GPS_TAG_GPS_IMG_DIRECTION_REF,
            GpsTagConstants.GPS_TAG_GPS_IMG_DIRECTION_REF_VALUE_TRUE_NORTH);

    gpsDirectory.removeField(GpsTagConstants.GPS_TAG_GPS_IMG_DIRECTION);
    gpsDirectory.add(GpsTagConstants.GPS_TAG_GPS_IMG_DIRECTION, RationalNumber.valueOf(image.getMovingCa()));

    exifDirectory.removeField(ExifTagConstants.EXIF_TAG_DATE_TIME_ORIGINAL);
    exifDirectory.add(ExifTagConstants.EXIF_TAG_DATE_TIME_ORIGINAL, image.getDate("yyyy/MM/dd HH:mm:ss"));

    // Removes the ImageDescription tag, that causes problems in the upload.
    rootDirectory.removeField(TiffTagConstants.TIFF_TAG_IMAGE_DESCRIPTION);

    outputSet.setGPSInDegrees(image.getMovingLatLon().lon(), image.getMovingLatLon().lat());
    File tempFile = File.createTempFile("imagetoupload_" + c, ".tmp");
    c++;
    OutputStream os = new BufferedOutputStream(new FileOutputStream(tempFile));

    // Transforms the image into a byte array.
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    ImageIO.write(image.getImage(), "jpg", outputStream);
    byte[] imageBytes = outputStream.toByteArray();
    new ExifRewriter().updateExifMetadataLossless(imageBytes, os, outputSet);
    os.close();
    return tempFile;
}

From source file:oulib.aws.s3.S3Util.java

/**
 * Pull out Tiff metadata from input S3 object and inject into the 
 * content of target S3 Object;<br>
 * Generate the new output S3 object that has the metadata from input object.
 * //from   www .j  ava2  s. co m
 * @param s3client : S3 client
 * @param obj1 : input object that provides metadata
 * @param obj2 : target object that receives metadata
 * 
 * @return PutObjectResult
 */
public static PutObjectResult copyS3ObjectTiffMetadata(AmazonS3 s3client, S3Object obj1, S3Object obj2) {

    PutObjectResult result = null;

    BufferedInputStream bufferedInputStrean = null;
    ByteArrayOutputStream byteArrayOutputStream = null;
    ByteArrayInputStream byteArrayInputStream = null;
    ByteArrayInputStream bis = null;
    S3ObjectInputStream content1 = null;
    S3ObjectInputStream content2 = null;
    String targetBucketName = obj2.getBucketName();
    String outputKey = obj2.getKey().split(".tif")[0] + "-copied.tif";

    ImageMetadata metadata1, metadata2;
    TiffImageMetadata tiffMetadata1, tiffMetadata2;
    TiffOutputSet output1, output2;

    try {
        content1 = obj1.getObjectContent();
        content2 = obj2.getObjectContent();

        byte[] bytes1 = IOUtils.toByteArray(content1);
        byte[] bytes2 = IOUtils.toByteArray(content2);

        metadata1 = Imaging.getMetadata(bytes1);
        metadata2 = Imaging.getMetadata(bytes2);

        tiffMetadata1 = (TiffImageMetadata) metadata1;
        tiffMetadata2 = (TiffImageMetadata) metadata2;

        output1 = tiffMetadata1.getOutputSet();
        output2 = tiffMetadata2.getOutputSet();

        TiffOutputDirectory rootDir = output2.getOrCreateRootDirectory();
        TiffOutputDirectory exifDir = output2.getOrCreateExifDirectory();
        TiffOutputDirectory gpsDir = output2.getOrCreateGPSDirectory();

        if (null != output1.getRootDirectory()) {
            List<TiffOutputField> fs = output1.getRootDirectory().getFields();
            for (TiffOutputField f1 : fs) {
                if (null == rootDir.findField(f1.tag)
                        // CANNOT create the output image with this tag included!
                        && !"PlanarConfiguration".equals(f1.tagInfo.name)) {
                    rootDir.add(f1);
                }
            }
        }

        if (null != output1.getExifDirectory()) {
            for (TiffOutputField f2 : output1.getExifDirectory().getFields()) {
                exifDir.removeField(f2.tagInfo);
                exifDir.add(f2);
            }
        }

        if (null != output1.getGPSDirectory()) {
            for (TiffOutputField f3 : output1.getGPSDirectory().getFields()) {
                gpsDir.removeField(f3.tagInfo);
                gpsDir.add(f3);
            }
        }

        byteArrayOutputStream = new ByteArrayOutputStream();
        TiffImageWriterLossy writerLossy = new TiffImageWriterLossy(output2.byteOrder);
        writerLossy.write(byteArrayOutputStream, output2);

        byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());

        ObjectMetadata metadata = new ObjectMetadata();
        metadata.setContentLength(byteArrayOutputStream.toByteArray().length);
        metadata.setContentType("image/tiff");
        metadata.setLastModified(new Date());

        result = s3client
                .putObject(new PutObjectRequest(targetBucketName, outputKey, byteArrayInputStream, metadata));

    } catch (ImageReadException | IOException | ImageWriteException ex) {
        Logger.getLogger(S3Util.class.getName()).log(Level.SEVERE, null, ex);
    } finally {
        try {
            if (null != content1) {
                content1.close();
            }
            if (null != content2) {
                content2.close();
            }
            if (null != bufferedInputStrean) {
                bufferedInputStrean.close();
            }
            if (null != byteArrayInputStream) {
                byteArrayInputStream.close();
            }
            if (null != byteArrayOutputStream) {
                byteArrayOutputStream.close();
            }
            if (null != bis) {
                bis.close();
            }
        } catch (IOException ex) {
            Logger.getLogger(S3Util.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    return result;
}

From source file:oulib.aws.s3.S3Util.java

/**
 * /*from w  w  w.j  a v  a2s.c  o  m*/
 * @param exifDirectory : TiffOutputDirectory
 * @param tagInfo : TagInfo defined the field type
 * @param value : value of the new field
 * @throws ImageWriteException
 * @throws NoMatchingTagInfoException 
 */
public static void addTiffOutputFieldIntoTiffOutputDirectory(TiffOutputDirectory exifDirectory, TagInfo tagInfo,
        Object value) throws ImageWriteException, NoMatchingTagInfoException {

    exifDirectory.removeField(tagInfo);

    if (tagInfo instanceof TagInfoAscii) {
        exifDirectory.add((TagInfoAscii) tagInfo, String.valueOf(value));
    } else if (tagInfo instanceof TagInfoByte) {
        final TagInfoByte byteInfo = (TagInfoByte) tagInfo;
        //            exifDirectory.add(byteInfo, String.valueOf(value).getBytes());
    }
    /**
     * Implement more taginfo types here....
     */
    else {
        throw new NoMatchingTagInfoException("Cannot find the matching Exif Tag type information!");
    }
}

From source file:slash.navigation.photo.PhotoFormat.java

public void write(PhotoPosition position, File source, OutputStream target) throws IOException {
    try {/*from ww w  .  jav a2 s  .  c  om*/
        ImageMetadata metadata = Imaging.getMetadata(source);
        TiffImageMetadata tiffImageMetadata = extractTiffImageMetadata(metadata);

        TiffOutputSet outputSet = null;
        if (tiffImageMetadata != null)
            outputSet = tiffImageMetadata.getOutputSet();
        if (outputSet == null)
            outputSet = new TiffOutputSet();

        TiffOutputDirectory rootDirectory = outputSet.getOrCreateRootDirectory();
        rootDirectory.removeField(TIFF_TAG_MAKE);
        rootDirectory.removeField(TIFF_TAG_MODEL);

        rootDirectory.add(TIFF_TAG_MAKE, position.getMake());
        rootDirectory.add(TIFF_TAG_MODEL, position.getModel());

        TiffOutputDirectory exifDirectory = outputSet.getOrCreateExifDirectory();
        exifDirectory.removeField(EXIF_TAG_USER_COMMENT);
        exifDirectory.removeField(EXIF_TAG_EXIF_IMAGE_WIDTH);
        exifDirectory.removeField(EXIF_TAG_EXIF_IMAGE_LENGTH);
        exifDirectory.removeField(EXIF_TAG_FNUMBER);
        exifDirectory.removeField(EXIF_TAG_EXPOSURE_TIME);
        exifDirectory.removeField(EXIF_TAG_FLASH);
        exifDirectory.removeField(EXIF_TAG_FOCAL_LENGTH);
        exifDirectory.removeField(EXIF_TAG_ISO);

        exifDirectory.add(EXIF_TAG_USER_COMMENT, position.getDescription());
        if (position.getWidth() != null)
            exifDirectory.add(EXIF_TAG_EXIF_IMAGE_WIDTH, position.getWidth().shortValue());
        if (position.getHeight() != null)
            exifDirectory.add(EXIF_TAG_EXIF_IMAGE_LENGTH, position.getHeight().shortValue());
        exifDirectory.add(EXIF_TAG_FNUMBER, position.getfNumber());
        exifDirectory.add(EXIF_TAG_EXPOSURE_TIME, position.getExposure());
        if (position.getFlash() != null)
            exifDirectory.add(EXIF_TAG_FLASH, position.getFlash().shortValue());
        exifDirectory.add(EXIF_TAG_FOCAL_LENGTH, position.getFocal());
        if (position.getPhotographicSensitivity() != null)
            exifDirectory.add(EXIF_TAG_ISO, position.getPhotographicSensitivity().shortValue());

        TiffOutputDirectory gpsDirectory = outputSet.getOrCreateGPSDirectory();
        gpsDirectory.removeField(GPS_TAG_GPS_VERSION_ID);
        gpsDirectory.add(GPS_TAG_GPS_VERSION_ID, (byte) 2, (byte) 3, (byte) 0, (byte) 0);

        gpsDirectory.removeField(GPS_TAG_GPS_LONGITUDE);
        gpsDirectory.removeField(GPS_TAG_GPS_LONGITUDE_REF);
        gpsDirectory.removeField(GPS_TAG_GPS_LATITUDE);
        gpsDirectory.removeField(GPS_TAG_GPS_LATITUDE_REF);
        gpsDirectory.removeField(GPS_TAG_GPS_ALTITUDE);
        gpsDirectory.removeField(GPS_TAG_GPS_ALTITUDE_REF);
        gpsDirectory.removeField(GPS_TAG_GPS_SPEED);
        gpsDirectory.removeField(GPS_TAG_GPS_SPEED_REF);
        gpsDirectory.removeField(GPS_TAG_GPS_DATE_STAMP);
        gpsDirectory.removeField(GPS_TAG_GPS_TIME_STAMP);
        gpsDirectory.removeField(GPS_TAG_GPS_IMG_DIRECTION);
        gpsDirectory.removeField(GPS_TAG_GPS_SATELLITES);
        gpsDirectory.removeField(GPS_TAG_GPS_MEASURE_MODE);
        gpsDirectory.removeField(GPS_TAG_GPS_DOP);

        if (position.getLongitude() != null && position.getLatitude() != null)
            outputSet.setGPSInDegrees(position.getLongitude(), position.getLatitude());

        if (position.getElevation() != null) {
            gpsDirectory.add(GPS_TAG_GPS_ALTITUDE, RationalNumber.valueOf(abs(position.getElevation())));
            gpsDirectory.add(GPS_TAG_GPS_ALTITUDE_REF, (byte) (position.getElevation() > 0 ? 0 : 1));
        }

        if (position.getSpeed() != null) {
            gpsDirectory.add(GPS_TAG_GPS_SPEED, RationalNumber.valueOf(position.getSpeed()));
            gpsDirectory.add(GPS_TAG_GPS_SPEED_REF, GPS_TAG_GPS_SPEED_REF_VALUE_KMPH);
        }

        if (position.getTime() != null) {
            Calendar calendar = position.getTime().getCalendar();

            gpsDirectory.add(GPS_TAG_GPS_TIME_STAMP, RationalNumber.valueOf(calendar.get(HOUR_OF_DAY)),
                    RationalNumber.valueOf(calendar.get(MINUTE)), RationalNumber.valueOf(calendar.get(SECOND)));
            String dateStamp = XXXX_FORMAT.format(calendar.get(YEAR)) + ":"
                    + XX_FORMAT.format(calendar.get(MONTH) + 1) + ":"
                    + XX_FORMAT.format(calendar.get(DAY_OF_MONTH));
            gpsDirectory.add(GPS_TAG_GPS_DATE_STAMP, dateStamp);
        }

        if (position.getHeading() != null)
            gpsDirectory.add(GPS_TAG_GPS_IMG_DIRECTION, RationalNumber.valueOf(position.getHeading()));

        if (position.getSatellites() != null)
            gpsDirectory.add(GPS_TAG_GPS_SATELLITES, position.getSatellites().toString());

        if (position.getPdop() != null) {
            gpsDirectory.add(GPS_TAG_GPS_MEASURE_MODE,
                    Integer.toString(GPS_TAG_GPS_MEASURE_MODE_VALUE_3_DIMENSIONAL_MEASUREMENT));
            gpsDirectory.add(GPS_TAG_GPS_DOP, RationalNumber.valueOf(position.getPdop()));
        } else if (position.getHdop() != null) {
            gpsDirectory.add(GPS_TAG_GPS_MEASURE_MODE,
                    Integer.toString(GPS_TAG_GPS_MEASURE_MODE_VALUE_2_DIMENSIONAL_MEASUREMENT));
            gpsDirectory.add(GPS_TAG_GPS_DOP, RationalNumber.valueOf(position.getHdop()));
        }

        new ExifRewriter().updateExifMetadataLossless(source, target, outputSet);
    } catch (ImageReadException | ImageWriteException e) {
        throw new IOException(e);
    }
}