Modifying Image Metadata

Read Image, modify metadata, and re-write image in pure Java

Disclaimer: I designed and wrote the various metadata readers/writers mainly for internal use in my ImageIO library, and did not carefully consider use by third parties. For this reason, the API may not be "perfect" in this sense. But what you want to do should be perfectly doable. :-)


While the specific Directory implementations are indeed read-only, you can easily create your own subclass of AbstractDirectory that is mutable. Or just use any Collection<? extends Entry> you like and wrap it in a TIFFDirectory or IFD before writing. I prefer the latter, so I'll show that first.

Note that a typical JPEG Exif segment contains two IFDs, IFD0 for the main JPEG image, and IFD1 for the thumbnail. Thus you need to tread it as a CompoundDirectory:

CompoundDirectory exif = (CompoundDirectory) new TIFFReader().read(input);
List<Directory> ifds = new ArrayList<>;

for (int i = 0; i < exif.directoryCount(); i++) {
List<Entry> entries = new ArrayList<>();

for (Entry entry : exif.getDirectory(i)) {
entries.add(entry);
}

// TODO: Do stuff with entries, remove, add, change, etc...

ifds.add(new IFD(entries));
}

// Write Exif
new TIFFWriter().write(new TIFFDirectory(ifds), output);

You could also create your own mutable Directory:

public final class MutableDirectory extends AbstractDirectory {
public MutableDirectory (final Collection<? extends Entry> entries) {
super(entries);
}

public boolean isReadOnly() {
return false;
}

// NOTE: While the above is all you need to make it *mutable*,
// TIFF/Exif does not allow entries with duplicate IDs,
// you need to handle this somehow. The below code is untested...
@Override
public boolean add(Entry entry) {
Entry existing = getEntryById(entry.getIdentifier());

if (existing != null) {
remove(existing);
}

super.add(entry);
}
}

The reason for not implementing mutable directories is exactly that the semantics for how entries are handled may differ from format to format.

Modifying Image Metadata

I’m answering this myself since I found out why it wasn’t saving the data and it looks like this question can help others.

My code is correct, the only issue is that I wasn’t formatting the date properly. Since the date wasn’t in the correct format it was getting pruned by the frameworks. I formatted the date like this and it saved and displayed properly:

let formatter = DateFormatter()
formatter.dateFormat = "yyyy:MM:dd HH:mm:ss"
exif[ImagePropertyExifDateTimeDigitized] = formatter.string(from: Date())

This was in place of the line:

exif[ImagePropertyExifDateTimeDigitized] = Date() as CFDate

The output is now (again pruned to only the relevant properties):

unmodified properties
{
"{Exif}" = {
DateTimeDigitized = "2007:07:31 17:42:01";
DateTimeOriginal = "2007:07:31 17:42:01";
};
}

modified properties
{
"{Exif}" = {
DateTimeDigitized = "2017:05:12 01:04:14";
DateTimeOriginal = "2007:07:31 17:42:01";
};
}

saved properties
{
"{Exif}" = {
DateTimeDigitized = "2017:05:12 01:04:14";
DateTimeOriginal = "2007:07:31 17:42:01";
};
}

How to modify EXIF metadata for JPEG images using Coldfusion?

I know that there are XMP and IPTC custom tags out there, I googled now and seems that javaloader.cfc + some java lib are your only sure option.

EDIT: Since I work on stock photography application I got interested and found this command line tool which could do the trick:

http://www.sno.phy.queensu.ca/~phil/exiftool/

How to modify image metadata ( EXIF ) in iOS without duplicating?

As noted in the comment, I don't believe this is possible.

AssetsLibrary doesn't allow modifying of the original asset at all, everything is saved as a new asset with a reference to the original.

With the new PhotoKit library in iOS 8 they do allow modifying of the asset, but I do not see anything there that allows you to modify the metadata either.

Taking a glance at ImageIO there are methods to modify metadata, but again, nothing to save it to the photo library.
With this, however, you could probably replace a file on disk with another one with modified exif data.

edit to elaborate:
According to answers here it seems like ALAssets provide a URL that does not point to the disk. I believe that means that you have no way of getting the acutual URL of the image to overwrite it, though not in the photos library.

I would suggest you file this as an enhancement to Apple if its that important, if many people request the same thing, they might add it in the future! It does seem that they don't want people messing with this stuff though..

Swift how to modify exif info in images taken from mobile camera

Yes! Finally I made a trick to modify the EXIF info. At first, you can get EXIF info from info[UIImagePickerControllerMediaMetadata] and NSData without EXIF from picked UIImage by UIImageJPEGRepresentation. Then, you can create a new NSDictionary with modified EXIF info. After that, call my function in the following, you can get image NSData with modified EXIF!

func saveImageWithImageData(data: NSData, properties: NSDictionary, completion: (data: NSData, path: NSURL) -> Void) {

let imageRef: CGImageSourceRef = CGImageSourceCreateWithData((data as CFDataRef), nil)!
let uti: CFString = CGImageSourceGetType(imageRef)!
let dataWithEXIF: NSMutableData = NSMutableData(data: data)
let destination: CGImageDestinationRef = CGImageDestinationCreateWithData((dataWithEXIF as CFMutableDataRef), uti, 1, nil)!

CGImageDestinationAddImageFromSource(destination, imageRef, 0, (properties as CFDictionaryRef))
CGImageDestinationFinalize(destination)

var paths: [AnyObject] = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
let savePath: String = paths[0].stringByAppendingPathComponent("exif.jpg")

let manager: NSFileManager = NSFileManager.defaultManager()
manager.createFileAtPath(savePath, contents: dataWithEXIF, attributes: nil)

completion(data: dataWithEXIF,path: NSURL(string: savePath)!)

print("image with EXIF info converting to NSData: Done! Ready to upload! ")

}

Modifying JPEG Metadata without Recompressing Image in iOS

What I was looking for was a read-modify-write operation for image files that allowed changes but otherwise maintained unaltered data. I've determined through research and testing that this is not possible in iOS. The closest mechanism available is CGImage processing, but this only allows you to read selected information from a source image (such as image, thumbnail, properties), and then use some of that information (image, properties) to create a new destination file. There's no way to include a thumbnail in the new destination file, and no way to get around recompressing the image.



Related Topics



Leave a reply



Submit