Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you overwrite image metadata?

I can't seem to get image metadata to be written to the image correctly if the key/val is already present in the original image metadata with CGImageDestination. It works just fine if it they key/val is not present in the original metadata.

It's almost as though image metadata properties in the original image take precedence over modifications. Is this some kind of byzantine formatting issue I am not aware of, where I need to populate the key/val in some unusual way, a bug, or? Anyone else seen this?

Code and output below, for both cases where it works properly (if the value is not already set) and fails to write (if the value is already set to something else).

Any help appreciated greatly appreciated.

Here is where/how I create the image NSData:

// convert the existing asset to nsdata to overwrite itself
ALAssetRepresentation* rep = [asset defaultRepresentation];
Byte* buffer               = (Byte*)malloc(rep.size);
NSUInteger buffered        = [rep getBytes:buffer fromOffset:0.0 length:rep.size error:nil];
NSData* imageData          = [NSData dataWithBytesNoCopy:buffer length:buffered freeWhenDone:YES];

// write the metadata directly into the nsdata of the image itself
NSData* newImage = [self writeMetadataIntoImageData:imageData metadata:newMetadata];

Here is the actual modification of the metadata:

- (NSData*)writeMetadataIntoImageData:(NSData*)imageData metadata:(NSMutableDictionary*)metadataAsMutable
{
    // create an imagesourceref
    CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef) imageData, NULL);

    // read and log pre write metadata
    NSDictionary* metadata = (NSDictionary *) CFBridgingRelease(CGImageSourceCopyPropertiesAtIndex(source,0,NULL));
    NSLog(@"Before:\n------------------------------%@\n------------------------------", metadata);

    // set the new metadata keys here
    NSMutableDictionary* iptc = [metadataAsMutable[(NSString*)kCGImagePropertyIPTCDictionary] mutableCopy];
    if (!iptc)
    {
        iptc = [NSMutableDictionary dictionaryWithCapacity:1];
    }
    iptc[(NSString*)kCGImagePropertyIPTCCaptionAbstract] = @"Hardcoded Caption";
    metadataAsMutable[(NSString*)kCGImagePropertyIPTCDictionary] = iptc;

    // log the new metadata as we want it written
    NSLog(@"Parameter:\n------------------------------%@\n------------------------------", metadataAsMutable);

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

    // create a new data object and write the new image into it
    NSMutableData *dest_data = [NSMutableData data];
    CGImageDestinationRef destination = CGImageDestinationCreateWithData((__bridge CFMutableDataRef)dest_data,UTI,1,NULL);
    if(!destination)
    {
        NSLog(@"Error: 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, (__bridge CFDictionaryRef) metadataAsMutable);

    BOOL success = NO;
    success = CGImageDestinationFinalize(destination);
    if(!success)
    {
        NSLog(@"Error: Could not create data from image destination");
    }

    // read and log post write metadata
    CGImageSourceRef  source2;
    source2 = CGImageSourceCreateWithData((__bridge CFDataRef) dest_data, NULL);
    NSDictionary *metadata2 = (NSDictionary *) CFBridgingRelease(CGImageSourceCopyPropertiesAtIndex(source2,0,NULL));
    NSLog(@"After:\n------------------------------%@\n------------------------------", metadata2);

    // cleanup
    CFRelease(destination);

    // return the new data
    return dest_data;
}

Here are the NSLogs for when the image has an existing value for the key:

Before:
------------------------------{
    <...snip...>
    "{IPTC}" =     {
        "Caption/Abstract" = Blurry;
        DateCreated = 20130923;
        DigitalCreationDate = 20130923;
        DigitalCreationTime = 173815;
        Keywords =         (
            fake
        );
        SupplementalCategory =         (
            fake
        );
        TimeCreated = 173815;
    };
    <...snip...>
}
------------------------------
Parameter:
------------------------------{
    <...snip...>
    "{IPTC}" =     {
        "Caption/Abstract" = "Hardcoded Caption";
        DateCreated = 20130923;
        DigitalCreationDate = 20130923;
        DigitalCreationTime = 173815;
        Keywords =         (
            fake
        );
        SupplementalCategory =         (
            fake
        );
        TimeCreated = 173815;
    };
    <...snip...>
}
------------------------------
After:
------------------------------{
    <...snip...>
    "{IPTC}" =     {
        "Caption/Abstract" = Blurry;
        DateCreated = 20130923;
        DigitalCreationDate = 20130923;
        DigitalCreationTime = 173815;
        Keywords =         (
            fake
        );
        SupplementalCategory =         (
            fake
        );
        TimeCreated = 173815;
    };
    <...snip...>
}
------------------------------

Here are the NSLogs for when the image has no value for the key:

Before:
------------------------------{
    <...snip...>
    "{IPTC}" =     {
        DateCreated = 20130925;
        DigitalCreationDate = 20130925;
        DigitalCreationTime = 192856;
        Keywords =         (
            fake
        );
        SupplementalCategory =         (
            fake
        );
        TimeCreated = 192856;
    };
    <...snip...>
}
------------------------------
Parameter:
------------------------------{
    <...snip...>
    "{IPTC}" =     {
        "Caption/Abstract" = "Hardcoded Caption";
        DateCreated = 20130925;
        DigitalCreationDate = 20130925;
        DigitalCreationTime = 192856;
        Keywords =         (
            fake
        );
        SupplementalCategory =         (
            fake
        );
        TimeCreated = 192856;
    };
    <...snip...>
}
------------------------------
After:
------------------------------{
    <...snip...>
    "{IPTC}" =     {
        "Caption/Abstract" = "Hardcoded Caption";
        DateCreated = 20130925;
        DigitalCreationDate = 20130925;
        DigitalCreationTime = 192856;
        Keywords =         (
            fake
        );
        SupplementalCategory =         (
            fake
        );
        TimeCreated = 192856;
    };
    <...snip...>
}
------------------------------
like image 570
Scott Allen Avatar asked Sep 26 '13 16:09

Scott Allen


People also ask

Can you change metadata date on a photo?

In the metadata screen, you can change the Date/Time taken next to the field Date Time Original under Camera Data (exif). You can also batch change dates by selecting multiple files and changing the date the same way for a group of images.

Can you erase metadata from photos?

Navigate to the folder holding the images you want to edit. Select the file (or files) you wish to delete metadata from. Right-click and select Properties, then Details. Select Remove Properties and Personal Information.

How do I edit the metadata in a JPEG?

To edit the metadata on image files, right-click the file and select Properties. In the image properties, click on the Details tab. The details tab shows all the metadata contained within the photograph. You can quickly edit the information by clicking the value field next to the property.


1 Answers

According to the IPTC documentation the description field is bound to the TIFF and EXIF address. changing the value in the TIFF it updates also the IPTC entry! thank you user2452250 for the tip.

like image 77
modus Avatar answered Sep 28 '22 08:09

modus