Example usage for org.apache.commons.imaging.formats.tiff TiffImageMetadata getOutputSet

List of usage examples for org.apache.commons.imaging.formats.tiff TiffImageMetadata getOutputSet

Introduction

In this page you can find the example usage for org.apache.commons.imaging.formats.tiff TiffImageMetadata getOutputSet.

Prototype

public TiffOutputSet getOutputSet() throws ImageWriteException 

Source Link

Usage

From source file:net.tourbook.tour.photo.TourPhotoManager.java

/**
 * This example illustrates how to set the GPS values in JPEG EXIF metadata.
 * /*  w w  w . j a va2 s .  com*/
 * @param jpegImageFile
 *            A source image file.
 * @param destinationFile
 *            The output file.
 * @param latitude
 * @param longitude
 * @throws IOException
 * @throws ImageReadException
 * @throws ImageWriteException
 */
private void setExifGPSTag_IntoImageFile_WithExifRewriter(final File jpegImageFile, final File destinationFile,
        final double latitude, final double longitude)
        throws IOException, ImageReadException, ImageWriteException {

    OutputStream os = null;

    try {

        TiffOutputSet outputSet = null;

        // note that metadata might be null if no metadata is found.
        final IImageMetadata 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/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);
        }

        os = new FileOutputStream(destinationFile);
        os = new BufferedOutputStream(os);

        /**
         * the lossless method causes an exception after 3 times writing the image file,
         * therefore the lossy method is used
         * 
         * <pre>
         * 
         * org.apache.commons.imaging.formats.jpeg.exif.ExifRewriter$ExifOverflowException: APP1 Segment is too long: 65564
         *    at org.apache.commons.imaging.formats.jpeg.exif.ExifRewriter.writeSegmentsReplacingExif(ExifRewriter.java:552)
         *    at org.apache.commons.imaging.formats.jpeg.exif.ExifRewriter.updateExifMetadataLossless(ExifRewriter.java:393)
         *    at org.apache.commons.imaging.formats.jpeg.exif.ExifRewriter.updateExifMetadataLossless(ExifRewriter.java:293)
         *    at net.tourbook.photo.PhotosAndToursView.setExifGPSTag_IntoPhoto(PhotosAndToursView.java:2309)
         *    at net.tourbook.photo.PhotosAndToursView.setExifGPSTag(PhotosAndToursView.java:2141)
         * 
         * </pre>
         */
        //         new ExifRewriter().updateExifMetadataLossless(jpegImageFile, os, outputSet);
        //         new ExifRewriter().updateExifMetadataLossy(jpegImageFile, os, outputSet);

        os.close();
        os = null;
    } finally {
        if (os != null) {
            try {
                os.close();
            } catch (final IOException e) {

            }
        }
    }
}

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

/**
 * This example illustrates how to add/update EXIF metadata in a JPEG file.
 * //w  w  w .ja  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  w w w  . j  a v  a 2  s  .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.apache.commons.imaging.examples.WriteExifMetadataExample.java

/**
 * This example illustrates how to set the GPS values in JPEG EXIF metadata.
 * /*from ww w .j av  a 2 s  .com*/
 * @param jpegImageFile
 *            A source image file.
 * @param dst
 *            The output file.
 * @throws IOException
 * @throws ImageReadException
 * @throws ImageWriteException
 */
public void setExifGPSTag(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/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);
        }

        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  v a2s.  c  om*/
    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./* www .  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.
 * //  w  w  w  .j  a v a 2 s. c o 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

/**
 * Add data into tiff exif metadata/*from w ww  .j  av a  2 s .  co m*/
 * 
 * @param tiffMetadata : TiffImageMetadata
 * @param data : map of data
 */
public static void addTiffOutputFieldIntoTiffMetadata(TiffImageMetadata tiffMetadata,
        Map<TagInfo, Object> data) {
    try {
        TiffOutputSet output = tiffMetadata.getOutputSet();
        TiffOutputDirectory exifDirectory = output.getOrCreateExifDirectory();
        for (TagInfo tagInfo : data.keySet()) {
            addTiffOutputFieldIntoTiffOutputDirectory(exifDirectory, tagInfo, data.get(tagInfo));
        }
    } catch (ImageWriteException | NoMatchingTagInfoException ex) {
        Logger.getLogger(S3Util.class.getName()).log(Level.SEVERE, null, ex);
    }

}

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

public void write(PhotoPosition position, File source, OutputStream target) throws IOException {
    try {/*from www  .ja  v a 2s.com*/
        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);
    }
}