package de.dpa.oss.metadata.mapper.imaging.backend.exiftool; import com.google.common.collect.ListMultimap; import de.dpa.oss.metadata.mapper.imaging.backend.exiftool.taginfo.TagGroup; import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * This builder can only be used for operations modifying the image. For other operations refer to * {@link ExifToolWrapper} directly */ public class ExifTool { private final File inputSource; private List<String> tagModifications = new ArrayList<>(); private List<String> codedCharsetOptions = new ArrayList<>(); private List<String> tagGroupsToClear = new ArrayList<>(); /** * This flag controls whether exiftool should overwrite the original or should backup the file to * "originalfilename.original" */ private boolean overwriteOriginal = true; public enum CodedCharset { /* ESC % G or UTF8*/ UTF8("UTF8"), /* ESC . A */ LATIN1("\u001B.A"); CodedCharset(final String codepageId) { this.codepageId = codepageId; } private final String codepageId; public String getCodepageId() { return codepageId; } } public static ExifTool modifyImage(final File image) { if (image == null) throw new IllegalArgumentException( "image cannot be null and must be a valid stream of image data."); if (!image.canWrite()) throw new SecurityException( "Unable to read the given image [" + image.getAbsolutePath() + "], ensure that the image exists at the given path and that the executing Java process has permissions to read it."); return new ExifTool(image); } private ExifTool(final File inputSource) { this.inputSource = inputSource; } /** * @param overwriteOriginal if false then exiftool will preserve the original file by copying the original content to * the file ending with suffix "original" * Default is true */ public ExifTool overwriteOriginalFile( final boolean overwriteOriginal) { this.overwriteOriginal = overwriteOriginal; return this; } public ExifTool setImageMetadata(ListMultimap<String, String> tags) { if (tags == null || tags.size() == 0) throw new IllegalArgumentException( "tags cannot be null and must contain 1 or more Tag to query the image for."); for (Map.Entry<String, String> entry : tags.entries()) { tagModifications.add("-" + entry.getKey() + "=" + entry.getValue()); } return this; } public ExifTool useEncodingCharsetForIPTC(final CodedCharset codedCharset) { this.codedCharsetOptions.add("-IPTC:codedcharacterset=" + codedCharset.getCodepageId()); return this; } /** * Call either * <pre> * exiftool -listx -S * </pre> * or {@link ExifToolWrapper#getSupportedTagsOfGroups()} to get the list of TagGroups which contains the group name * (g0 / {@link TagGroup#getName()}) and the specific location ( g1 / {@link TagGroup#getSpecificLocation()}) */ public ExifTool clearTagGroup(final String groupName, final String specificLocation) { tagGroupsToClear.add("-" + groupName + ":" + specificLocation + "="); return this; } /** * Removes all tag groups within the given media. */ public ExifTool clearAllTagGroups() { tagGroupsToClear.add("-all="); return this; } public void execute(final ExifToolWrapper exifTool) throws ExifToolIntegrationException { final List<String> cmdArgs = new ArrayList<>(); cmdArgs.addAll(this.codedCharsetOptions); cmdArgs.addAll(tagGroupsToClear); cmdArgs.addAll(tagModifications); if( overwriteOriginal ) { cmdArgs.add("-overwrite_original"); } exifTool.runExiftool(inputSource, cmdArgs); } }