TiffOutputSet.java
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.imaging.formats.tiff.write;
import static org.apache.commons.imaging.formats.tiff.constants.TiffConstants.DEFAULT_TIFF_BYTE_ORDER;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.imaging.ImagingException;
import org.apache.commons.imaging.common.RationalNumber;
import org.apache.commons.imaging.formats.tiff.constants.GpsTagConstants;
import org.apache.commons.imaging.formats.tiff.constants.TiffDirectoryConstants;
import org.apache.commons.imaging.formats.tiff.taginfos.TagInfo;
import org.apache.commons.imaging.internal.Debug;
public final class TiffOutputSet implements Iterable<TiffOutputDirectory> {
private static final String NEWLINE = System.lineSeparator();
public final ByteOrder byteOrder;
private final List<TiffOutputDirectory> directories = new ArrayList<>();
public TiffOutputSet() {
this(DEFAULT_TIFF_BYTE_ORDER);
}
public TiffOutputSet(final ByteOrder byteOrder) {
this.byteOrder = byteOrder;
}
public void addDirectory(final TiffOutputDirectory directory) throws ImagingException {
if (null != findDirectory(directory.getType())) {
throw new ImagingException("Output set already contains a directory of that type.");
}
directories.add(directory);
}
public TiffOutputDirectory addExifDirectory() throws ImagingException {
final TiffOutputDirectory result = new TiffOutputDirectory(TiffDirectoryConstants.DIRECTORY_TYPE_EXIF, byteOrder);
addDirectory(result);
return result;
}
public TiffOutputDirectory addGpsDirectory() throws ImagingException {
final TiffOutputDirectory result = new TiffOutputDirectory(TiffDirectoryConstants.DIRECTORY_TYPE_GPS, byteOrder);
addDirectory(result);
return result;
}
public TiffOutputDirectory addInteroperabilityDirectory() throws ImagingException {
getOrCreateExifDirectory();
final TiffOutputDirectory result = new TiffOutputDirectory(TiffDirectoryConstants.DIRECTORY_TYPE_INTEROPERABILITY, byteOrder);
addDirectory(result);
return result;
}
public TiffOutputDirectory addRootDirectory() throws ImagingException {
final TiffOutputDirectory result = new TiffOutputDirectory(TiffDirectoryConstants.DIRECTORY_TYPE_ROOT, byteOrder);
addDirectory(result);
return result;
}
public void dump() {
Debug.debug(this.toString());
}
public TiffOutputDirectory findDirectory(final int directoryType) {
for (final TiffOutputDirectory directory : directories) {
if (directory.getType() == directoryType) {
return directory;
}
}
return null;
}
public TiffOutputField findField(final int tag) {
for (final TiffOutputDirectory directory : directories) {
final TiffOutputField field = directory.findField(tag);
if (null != field) {
return field;
}
}
return null;
}
public TiffOutputField findField(final TagInfo tagInfo) {
return findField(tagInfo.tag);
}
public List<TiffOutputDirectory> getDirectories() {
return new ArrayList<>(directories);
}
public TiffOutputDirectory getExifDirectory() {
return findDirectory(TiffDirectoryConstants.DIRECTORY_TYPE_EXIF);
}
public TiffOutputDirectory getGpsDirectory() {
return findDirectory(TiffDirectoryConstants.DIRECTORY_TYPE_GPS);
}
public TiffOutputDirectory getInteroperabilityDirectory() {
return findDirectory(TiffDirectoryConstants.DIRECTORY_TYPE_INTEROPERABILITY);
}
public TiffOutputDirectory getOrCreateExifDirectory() throws ImagingException {
// EXIF directory requires root directory.
getOrCreateRootDirectory();
final TiffOutputDirectory result = findDirectory(TiffDirectoryConstants.DIRECTORY_TYPE_EXIF);
if (null != result) {
return result;
}
return addExifDirectory();
}
public TiffOutputDirectory getOrCreateGpsDirectory() throws ImagingException {
// GPS directory requires EXIF directory
getOrCreateExifDirectory();
final TiffOutputDirectory result = findDirectory(TiffDirectoryConstants.DIRECTORY_TYPE_GPS);
if (null != result) {
return result;
}
return addGpsDirectory();
}
public TiffOutputDirectory getOrCreateRootDirectory() throws ImagingException {
final TiffOutputDirectory result = findDirectory(TiffDirectoryConstants.DIRECTORY_TYPE_ROOT);
if (null != result) {
return result;
}
return addRootDirectory();
}
protected List<AbstractTiffOutputItem> getOutputItems(final TiffOutputSummary outputSummary) throws ImagingException {
final List<AbstractTiffOutputItem> result = new ArrayList<>();
for (final TiffOutputDirectory directory : directories) {
result.addAll(directory.getOutputItems(outputSummary));
}
return result;
}
public TiffOutputDirectory getRootDirectory() {
return findDirectory(TiffDirectoryConstants.DIRECTORY_TYPE_ROOT);
}
public boolean isEmpty() {
return directories.isEmpty();
}
@Override
public Iterator<TiffOutputDirectory> iterator() {
return directories.iterator();
}
public void removeField(final int tag) {
for (final TiffOutputDirectory directory : directories) {
directory.removeField(tag);
}
}
public void removeField(final TagInfo tagInfo) {
removeField(tagInfo.tag);
}
/**
* A convenience method to update GPS values in EXIF metadata.
*
* @param longitude Longitude in degrees E, negative values are W.
* @param latitude latitude in degrees N, negative values are S.
* @throws ImagingException if it fails to write the new data to the GPS directory
*/
public void setGpsInDegrees(double longitude, double latitude) throws ImagingException {
final TiffOutputDirectory gpsDirectory = getOrCreateGpsDirectory();
gpsDirectory.removeField(GpsTagConstants.GPS_TAG_GPS_VERSION_ID);
gpsDirectory.add(GpsTagConstants.GPS_TAG_GPS_VERSION_ID, GpsTagConstants.gpsVersion());
final String longitudeRef = longitude < 0 ? "W" : "E";
longitude = Math.abs(longitude);
final String latitudeRef = latitude < 0 ? "S" : "N";
latitude = Math.abs(latitude);
gpsDirectory.removeField(GpsTagConstants.GPS_TAG_GPS_LONGITUDE_REF);
gpsDirectory.add(GpsTagConstants.GPS_TAG_GPS_LONGITUDE_REF, longitudeRef);
gpsDirectory.removeField(GpsTagConstants.GPS_TAG_GPS_LATITUDE_REF);
gpsDirectory.add(GpsTagConstants.GPS_TAG_GPS_LATITUDE_REF, latitudeRef);
{
double value = longitude;
final double longitudeDegrees = (long) value;
value %= 1;
value *= 60.0;
final double longitudeMinutes = (long) value;
value %= 1;
value *= 60.0;
final double longitudeSeconds = value;
gpsDirectory.removeField(GpsTagConstants.GPS_TAG_GPS_LONGITUDE);
gpsDirectory.add(GpsTagConstants.GPS_TAG_GPS_LONGITUDE, RationalNumber.valueOf(longitudeDegrees), RationalNumber.valueOf(longitudeMinutes),
RationalNumber.valueOf(longitudeSeconds));
}
{
double value = latitude;
final double latitudeDegrees = (long) value;
value %= 1;
value *= 60.0;
final double latitudeMinutes = (long) value;
value %= 1;
value *= 60.0;
final double latitudeSeconds = value;
gpsDirectory.removeField(GpsTagConstants.GPS_TAG_GPS_LATITUDE);
gpsDirectory.add(GpsTagConstants.GPS_TAG_GPS_LATITUDE, RationalNumber.valueOf(latitudeDegrees), RationalNumber.valueOf(latitudeMinutes),
RationalNumber.valueOf(latitudeSeconds));
}
}
@Override
public String toString() {
return toString(null);
}
public String toString(String prefix) {
if (prefix == null) {
prefix = "";
}
final StringBuilder result = new StringBuilder(39);
result.append(prefix);
result.append("TiffOutputSet {");
result.append(NEWLINE);
result.append(prefix);
result.append("byteOrder: ");
result.append(byteOrder);
result.append(NEWLINE);
for (int i = 0; i < directories.size(); i++) {
final TiffOutputDirectory directory = directories.get(i);
result.append(String.format("%s\tdirectory %d: %s (%d)%n", prefix, i, directory.description(), directory.getType()));
for (final TiffOutputField field : directory) {
result.append(prefix);
result.append("\t\tfield ").append(i).append(": ").append(field.tagInfo);
result.append(NEWLINE);
}
}
result.append(prefix);
result.append('}');
result.append(NEWLINE);
return result.toString();
}
}