How to Add Exif Data to an Image

How do I add exif data to an image?

You can save a large amount of space, especially if you have a large number of images..

Add the following to text.txt (format of the IPTC tags taken from here):

2#110#Credit="My Company"
2#05#Object Name="THE_OBJECT_NAME"
2#55#Date Created="2011-02-03 12:45"
2#80#By-line="BY-LINE?"
2#110#Credit="The CREDIT"
2#115#Source="SOURCE"
2#116#Copyright Notice="THE COPYRIGHT"
2#118#Contact="THE CONTACT"
2#120#Caption="AKA Title"

Strip all existing exif data from the image

mogrify -strip image.jpg

Add the credit to your image

mogrify -profile 8BIMTEXT:text.txt image.jpg

Write EXIF data after have added image to MediaStore

I solved.
The problem was that the file was not syncronized on disk.

So, here how it works for saving the image:

ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.DISPLAY_NAME, filename);
values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
values.put(MediaStore.MediaColumns.DATE_ADDED, now);
values.put(MediaStore.MediaColumns.DATE_MODIFIED, now);

ContentResolver resolver = context.getContentResolver();
Uri uri = resolver.insert( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values );

try( ParcelFileDescriptor pfd = resolver.openFileDescriptor(uri,"w") )
{
FileDescriptor fd = pfd.getFileDescriptor();

try( OutputStream stream = new FileOutputStream(fd) )
{
// Perform operations on "stream".
mBitmap.compress( Bitmap.CompressFormat.JPEG, 90, stream );
}

// Synch data with disk. It's mandatory to be able later to call writeExif
fd.sync(); // <---- HERE THE SOLUTION

} catch( IOException e )
{
e.printStackTrace();
}

And how I add Exif metadata:

private void writeExif( Uri uri, List<String> exifStr )
{
try( ParcelFileDescriptor imagePfd = getContentResolver().openFileDescriptor(uri, "rw") )
{
ExifInterface exif = new ExifInterface( imagePfd.getFileDescriptor() );

for( int i = 0; i < ExifAttributes.length; i++ )
{
String value = exifStr.get(i);
if( value != null )
exif.setAttribute(ExifAttributes[i], value);
}

exif.saveAttributes();
}
catch( Exception e )
{
e.printStackTrace();
}
}

Adding EXIF Info to Images in C#

System.Drawing allows modifying the image properties with PropertyItems/SetPropertyItem. A sample can be found here.

But this access is quite basic and there are quite a few libraries around (see for instance How to edit EXIF data in .NET). So I wonder if it's worth the trouble.

After all, only JPEG and TIFF files support EXIF metadata according to Wikipedia.

How to write exif metadata to an image (not the camera roll, just a UIImage or JPEG)

UIImage does not contain metadata information (it is stripped). So if you want to save it without using the imagepicker method (not in camera roll):

Follow the answer here to write to a file with the metadata intact:

Problem setting exif data for an image

no idea why would this be downvoted but here is the method:

In this case im getting the image through AVFoundation and this is what goes in the

[[self stillImageOutput] captureStillImageAsynchronouslyFromConnection:videoConnection 
completionHandler:^(CMSampleBufferRef imageSampleBuffer, NSError *error)
{
// code here
}

block code:

    CFDictionaryRef metaDict = CMCopyDictionaryOfAttachments(NULL, imageSampleBuffer, kCMAttachmentMode_ShouldPropagate);

CFMutableDictionaryRef mutable = CFDictionaryCreateMutableCopy(NULL, 0, metaDict);

// Create formatted date
NSTimeZone *timeZone = [NSTimeZone timeZoneWithName:@"UTC"];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setTimeZone:timeZone];
[formatter setDateFormat:@"HH:mm:ss.SS"];

// Create GPS Dictionary
NSDictionary *gpsDict = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithFloat:fabs(loc.coordinate.latitude)], kCGImagePropertyGPSLatitude
, ((loc.coordinate.latitude >= 0) ? @"N" : @"S"), kCGImagePropertyGPSLatitudeRef
, [NSNumber numberWithFloat:fabs(loc.coordinate.longitude)], kCGImagePropertyGPSLongitude
, ((loc.coordinate.longitude >= 0) ? @"E" : @"W"), kCGImagePropertyGPSLongitudeRef
, [formatter stringFromDate:[loc timestamp]], kCGImagePropertyGPSTimeStamp
, [NSNumber numberWithFloat:fabs(loc.altitude)], kCGImagePropertyGPSAltitude
, nil];

// The gps info goes into the gps metadata part

CFDictionarySetValue(mutable, kCGImagePropertyGPSDictionary, (__bridge void *)gpsDict);

// Here just as an example im adding the attitude matrix in the exif comment metadata

CMRotationMatrix m = att.rotationMatrix;
GLKMatrix4 attMat = GLKMatrix4Make(m.m11, m.m12, m.m13, 0, m.m21, m.m22, m.m23, 0, m.m31, m.m32, m.m33, 0, 0, 0, 0, 1);

NSMutableDictionary *EXIFDictionary = (__bridge NSMutableDictionary*)CFDictionaryGetValue(mutable, kCGImagePropertyExifDictionary);

[EXIFDictionary setValue:NSStringFromGLKMatrix4(attMat) forKey:(NSString *)kCGImagePropertyExifUserComment];

CFDictionarySetValue(mutable, kCGImagePropertyExifDictionary, (__bridge void *)EXIFDictionary);

NSData *jpeg = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer] ;

After this code you will have your image in the jpeg nsdata and the correspoding dictionary for that image in the mutable cfdictionary.

All you have to do now is:

    CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)jpeg, NULL);

CFStringRef UTI = CGImageSourceGetType(source); //this is the type of image (e.g., public.jpeg)

NSMutableData *dest_data = [NSMutableData data];


CGImageDestinationRef destination = CGImageDestinationCreateWithData((__bridge CFMutableDataRef)dest_data,UTI,1,NULL);

if(!destination) {
NSLog(@"***Could not create image destination ***");
}

//add the image contained in the image source to the destination, overidding the old metadata with our modified metadata
CGImageDestinationAddImageFromSource(destination,source,0, (CFDictionaryRef) mutable);

//tell the destination to write the image data and metadata into our data object.
//It will return false if something goes wrong
BOOL success = CGImageDestinationFinalize(destination);

if(!success) {
NSLog(@"***Could not create data from image destination ***");
}

//now we have the data ready to go, so do whatever you want with it
//here we just write it to disk at the same path we were passed

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0]; // Get documents folder
NSString *dataPath = [documentsDirectory stringByAppendingPathComponent:@"ImagesFolder"];

NSError *error;
if (![[NSFileManager defaultManager] fileExistsAtPath:dataPath])
[[NSFileManager defaultManager] createDirectoryAtPath:dataPath withIntermediateDirectories:NO attributes:nil error:&error]; //Create folder

// NSString *imageName = @"ImageName";

NSString *fullPath = [dataPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.jpg", name]]; //add our image to the path

[dest_data writeToFile:fullPath atomically:YES];

//cleanup

CFRelease(destination);
CFRelease(source);

Note how I'm not saving using the ALAssets but directly into a folder of my choice.

Btw most of this code can be found in the link I posted at first.

Editing jpeg EXIF data with Java

Apache commons Imaging works for me.

I have extended the sample provided here

So obviously my client code looks like this

public static void main(String[] args) throws ImageWriteException, ImageReadException, IOException {
new WriteExifMetadataExample().changeExifMetadata(new File("somefilename.jpg"), new File("result_file.jpg"));
}

and the extended method in WriteExifMetadataExample

public void changeExifMetadata(final File jpegImageFile, final File dst)
throws IOException, ImageReadException, ImageWriteException {
OutputStream os = null;
boolean canThrow = false;
try {
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);
}



final TiffOutputDirectory exifDirectory = outputSet
.getOrCreateRootDirectory();
exifDirectory
.removeField(ExifTagConstants.EXIF_TAG_SOFTWARE);
exifDirectory.add(ExifTagConstants.EXIF_TAG_SOFTWARE,
"SomeKind");

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

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

canThrow = true;
} finally {
IoUtils.closeQuietly(canThrow, os);
}
}

Please pay attention only to line where I add additional tag

final TiffOutputDirectory exifDirectory = outputSet
.getOrCreateRootDirectory();
exifDirectory
.removeField(ExifTagConstants.EXIF_TAG_SOFTWARE);
exifDirectory.add(ExifTagConstants.EXIF_TAG_SOFTWARE,
"SomeKind");

as a result EXIF tag was properly added

Sample Image


To change the comments tag you can do the following

        final TiffOutputDirectory exifDirectory = outputSet.getOrCreateRootDirectory();
exifDirectory.removeField(MicrosoftTagConstants.EXIF_TAG_XPCOMMENT);
exifDirectory.add(MicrosoftTagConstants.EXIF_TAG_XPCOMMENT, "SomeKind");

the full list of available constants is in the package:

org.apache.commons.imaging.formats.tiff.constants

Sample Image

How to write Exif data to image in Swift with lat long

Please check this below answer.
you got error due to nil value on EXIFDictionary and GPSDictionary

 var image = info[UIImagePickerControllerOriginalImage] as! UIImage
let jpeg = UIImageJPEGRepresentation(image, 1.0)
var source: CGImageSource? = nil
source = CGImageSourceCreateWithData((jpeg as CFData?)!, nil)
let metadata = CGImageSourceCopyPropertiesAtIndex(source!, 0, nil) as? [AnyHashable: Any]
var metadataAsMutable = metadata
var EXIFDictionary = (metadataAsMutable?[(kCGImagePropertyExifDictionary as String)]) as? [AnyHashable: Any]
var GPSDictionary = (metadataAsMutable?[(kCGImagePropertyGPSDictionary as String)]) as? [AnyHashable: Any]

if !(EXIFDictionary != nil) {
EXIFDictionary = [AnyHashable: Any]()
}
if !(GPSDictionary != nil) {
GPSDictionary = [AnyHashable: Any]()
}

GPSDictionary![(kCGImagePropertyGPSLatitude as String)] = 30.21313
GPSDictionary![(kCGImagePropertyGPSLongitude as String)] = 76.22346
EXIFDictionary![(kCGImagePropertyExifUserComment as String)] = "Hello Image"

let UTI: CFString = CGImageSourceGetType(source!)!
let dest_data = NSMutableData()
let destination: CGImageDestination = CGImageDestinationCreateWithData(dest_data as CFMutableData, UTI, 1, nil)!
CGImageDestinationAddImageFromSource(destination, source!, 0, (metadataAsMutable as CFDictionary?))
CGImageDestinationFinalize(destination)

Writing EXIF metadata to images in Android

Ok, Somebody (offline) pointed me to a useful resource. The ExifInterface looks like what I was searching for. Android-er has a post demonstrating how to read EXIF metadata in Android and I think writing should not be very different.

I don't know, but can we EXIF to write arbitrary metadata, ie. other than those specified in the ExifInterface documentation (like latitude, longitude, flash etc). If not, what could be a preferred method of writing arbitrary metadata to image files?

Thanks



Related Topics



Leave a reply



Submit