iOS Question EXIF data

JanPRO

Well-Known Member
Licensed User
Longtime User
Hi,
B4X:
Dim NaObj As NativeObject = Me
    Dim EXIFMap As Map = NaObj.RunMethod("GetEXIF::",Array("PNG",LoadBitmap(File.DirAssets,"p2.png")))

    For Each key In EXIFMap.Keys
    Log(key & ": " & EXIFMap.Get(key))
    Next

#If OBJC
#import <ImageIO/ImageIO.h>

-(B4IMap*) GetEXIF:(NSString *) Type :(UIImage *) Image{
  NSDictionary* EXIFDic = nil;
  NSData* ImageData;
  if ([Type isEqualToString:@"JPEG"]){
  ImageData =  UIImageJPEGRepresentation(Image, 0.0);
  }else if ([Type isEqualToString:@"PNG"]){
  ImageData =  UIImagePNGRepresentation(Image);
  }

  CGImageSourceRef source = CGImageSourceCreateWithData((CFDataRef)ImageData, NULL);

  if (source){
  CFDictionaryRef MetadataRef = CGImageSourceCopyPropertiesAtIndex(source,0,NULL);
  if (MetadataRef){
  EXIFDic = [NSDictionary dictionaryWithDictionary : (__bridge NSDictionary *)MetadataRef];
  CFRelease (MetadataRef);
  }
  CFRelease(source);
  source = nil;
  }
  NSArray * Keys = [EXIFDic allKeys];
  NSArray * Values = [EXIFDic allValues];
  B4IMap * Map;
  Map = [B4IMap new];
  [Map Initialize];

  int i;
  for (i = 0; i < [Keys count]; i++){
  [Map Put:(NSObject*)([Keys objectAtIndex:i]) :(NSObject*)([Values objectAtIndex:i])];
  }
  return Map;
}
#End If

The values are always 1 :(, maybe somebody can do something with that ...
 
Last edited:
Upvote 0

hzchrisfang

Member
Licensed User
Longtime User
Thank you JanPRO!
I can get some values:
B4X:
{JFIF}: {
    DensityUnit = 0;
    JFIFVersion =     (
        1,
        0,
        1
    );
    XDensity = 72;
    YDensity = 72;
}
Orientation: 1
PixelWidth: 1920
{TIFF}: {
    Orientation = 1;
}
ColorModel: RGB
{Exif}: {
    ColorSpace = 1;
    PixelXDimension = 1920;
    PixelYDimension = 1080;
}
Depth: 8
PixelHeight: 1080

but how to write exif data into a photo?
 
Upvote 0

JanPRO

Well-Known Member
Licensed User
Longtime User
Hi, based on http://stackoverflow.com/questions/...tadata-exif-gps-tiff-in-iphones-photo-library:

B4X:
Dim NaObj As NativeObject = Me
'Save to PhotoAlbum
NaObj.RunMethod("SetGPS:Type:GPSLatitude:GPSLongitude:GPSLatitudeRef:GPSLongitudeRef:DataPath:WriteInPhotoAlbum:",Array(LoadBitmap(File.DirAssets,"x.jpg"),"JPEG",1.1,2.2,"lat_ref","lon_ref",Null,True))
'Save to Directory
NaObj.RunMethod("SetGPS:Type:GPSLatitude:GPSLongitude:GPSLatitudeRef:GPSLongitudeRef:DataPath:WriteInPhotoAlbum:",Array(LoadBitmap(File.DirAssets,"x.jpg"),"JPEG",1.1,2.2,"lat_ref","lon_ref",File.Combine(File.DirDocuments,"x.jpeg"),False))
End Sub

#If OBJC
#import <ImageIO/ImageIO.h>
#import <AssetsLibrary/AssetsLibrary.h>

- (void)SetGPS:(UIImage *)Image Type:(NSString*)Type GPSLatitude:(float)GPSLatitude GPSLongitude:(float)GPSLongitude GPSLatitudeRef:(NSString*)GPSLatitudeRef GPSLongitudeRef:(NSString*)GPSLongitudeRef DataPath:(NSString*)DataPath WriteInPhotoAlbum:(BOOL)WriteInPhotoAlbum {

  NSData* ImageData;
 
  if ([Type isEqualToString:@"JPEG"]){
     ImageData =  UIImageJPEGRepresentation(Image, 1.0);
  }else if ([Type isEqualToString:@"PNG"]){
     ImageData =  UIImagePNGRepresentation(Image);
  }

   CGImageSourceRef source = CGImageSourceCreateWithData((CFDataRef)ImageData, NULL);
   
  NSDictionary *metadata = (__bridge NSDictionary *) CGImageSourceCopyPropertiesAtIndex(source, 0, NULL);
  NSMutableDictionary *metadataAsMutable = [metadata mutableCopy];
   
  NSMutableDictionary *GPSDictionary = [[metadataAsMutable objectForKey:(NSString *)kCGImagePropertyGPSDictionary]mutableCopy];


  if(!GPSDictionary)
  {
     NSDictionary * dictionary = nil;
  GPSDictionary = [NSMutableDictionary dictionary];
  }


  [GPSDictionary setValue:[NSNumber numberWithFloat:GPSLatitude] forKey:(NSString*)kCGImagePropertyGPSLatitude];
  [GPSDictionary setValue:[NSNumber numberWithFloat:GPSLongitude] forKey:(NSString*)kCGImagePropertyGPSLongitude];
  [GPSDictionary setValue:GPSLatitudeRef forKey:(NSString*)kCGImagePropertyGPSLatitudeRef];
  [GPSDictionary setValue:GPSLongitudeRef forKey:(NSString*)kCGImagePropertyGPSLongitudeRef];

  [metadataAsMutable setObject:GPSDictionary forKey:(NSString *)kCGImagePropertyGPSDictionary];
   
   if (WriteInPhotoAlbum == YES){
   
     ALAssetsLibrary *library = [ALAssetsLibrary alloc];
     ALAssetsLibraryWriteImageCompletionBlock imageWriteCompletionBlock =
     ^(NSURL *newURL, NSError *error) {
  if (error) {
  NSLog( @"Error writing image with metadata to Photo Library: %@", error );
  } else {
  NSLog( @"Wrote image %@ with metadata %@ to Photo Library",newURL,metadataAsMutable);
  }
     };
     [library writeImageToSavedPhotosAlbum:Image.CGImage
  metadata:metadataAsMutable
  completionBlock:imageWriteCompletionBlock];
   
   }else{
   
     CFStringRef UTI = CGImageSourceGetType(source);
     NSMutableData *dest_data = [NSMutableData data];

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

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

     CGImageDestinationAddImageFromSource(destination, source, 0, (CFDictionaryRef) metadataAsMutable);

     BOOL success = NO;
     success = CGImageDestinationFinalize(destination);
     
     if(!success){
      NSLog(@"-------- could not create data from image destination----------");
     }else{
       [dest_data writeToFile:DataPath atomically:YES];
       NSLog( @"Wrote image to %@ with metadata %@",DataPath,metadataAsMutable);
     }

   }
   
}
#End If

I have not tested yet. It should work ....
 
Last edited:
Upvote 0

JanPRO

Well-Known Member
Licensed User
Longtime User
B4X:
'Orientations:
'Up = 0
'Down = 1
'Left = 2
'Right = 3
'UpMirrored = 4
'DownMirrored = 5
'LeftMirrored = 6
'RightMirrored = 7

Sub SetOrientation(b As Bitmap, O As Int) As Bitmap
    Dim NaObj2 As NativeObject = b
    Dim NaObj As NativeObject
    Return NaObj.Initialize("UIImage").RunMethod("imageWithCGImage:scale:orientation:",Array(NaObj2.RunMethod("CGImage",Null),NaObj2.RunMethod("scale",Null),o))
End Sub


;)
 
Upvote 0

jazzzzzzz

Active Member
Licensed User
Longtime User
Why cant you create a complete library like jpeg library for android..! It will be helpful for the community
 
Upvote 0

JanPRO

Well-Known Member
Licensed User
Longtime User
Why cant you create a complete library like jpeg library for android..
I have never written that I can't do it ;) :)
Maybe I am going to write a class, but a library is not needed here.

Jan
 
Upvote 0

wl

Well-Known Member
Licensed User
Longtime User
This code is working great. However it cant' seem to be able to return the DateTimeOriginal value (kCGImagePropertyExifDateTimeOriginal).

Any idea ?

Thanks
 
Upvote 0

CaptKronos

Active Member
Licensed User
Longtime User
Try doing it this way. Just query theExifMap for the values you require. (You can also use theMetaMap for other useful information such as getting the dimensions of an image without having to load the image.)

B4X:
Dim theMetaMap As Map=getImageMetaData(filename)
Dim theExifMap As Map=theMetaMap.get("{Exif}")

public Sub getImageMetaData(filename As String) As Map
    Dim nome As NativeObject=Me
    Dim imageMetaData As Object = nome.RunMethod("getImageMetaData:",Array(filename))
    Return NSDictionaryToMap(imageMetaData)
End Sub

Sub NSDictionaryToMap(Dictionary As Object) As Map
    Dim NewMap As NativeObject
    NewMap = NewMap.Initialize("B4IMap").RunMethod("convertToMap:",Array(Dictionary)) 
    Return NewMap
End Sub


#if OBJC

#import <ImageIO/ImageIO.h>

- (NSDictionary*) getImageMetaData : (NSString*) file
{
    NSDictionary* dic   =   nil;
    NSURL *imageFileURL = [NSURL fileURLWithPath: file];
    CGImageSourceRef imageSource = CGImageSourceCreateWithURL((CFURLRef)imageFileURL, nil);
    if (imageSource == nil) {
        return nil;
    }   
    CFDictionaryRef imageProperties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, nil);
    CFRelease(imageSource);
    if (imageProperties != nil) {
        if ( imageProperties )
        {
            NSDictionary* immutableImageProerties = (__bridge NSDictionary *)imageProperties;
            if ( immutableImageProerties )
            {
                dic =
                [ NSDictionary dictionaryWithDictionary : (__bridge NSDictionary *)imageProperties ];
            }
           
            CFRelease (imageProperties);
        }
    }
    return dic;
}
#End If
 
  • Like
Reactions: wl
Upvote 0

wl

Well-Known Member
Licensed User
Longtime User
Hi, based on http://stackoverflow.com/questions/...tadata-exif-gps-tiff-in-iphones-photo-library:

B4X:
Dim NaObj As NativeObject = Me
'Save to PhotoAlbum
NaObj.RunMethod("SetGPS:Type:GPSLatitude:GPSLongitude:GPSLatitudeRef:GPSLongitudeRef:DataPath:WriteInPhotoAlbum:",Array(LoadBitmap(File.DirAssets,"x.jpg"),"JPEG",1.1,2.2,"lat_ref","lon_ref",Null,True))
'Save to Directory
NaObj.RunMethod("SetGPS:Type:GPSLatitude:GPSLongitude:GPSLatitudeRef:GPSLongitudeRef:DataPath:WriteInPhotoAlbum:",Array(LoadBitmap(File.DirAssets,"x.jpg"),"JPEG",1.1,2.2,"lat_ref","lon_ref",File.Combine(File.DirDocuments,"x.jpeg"),False))
End Sub

#If OBJC
#import <ImageIO/ImageIO.h>
#import <AssetsLibrary/AssetsLibrary.h>

- (void)SetGPS:(UIImage *)Image Type:(NSString*)Type GPSLatitude:(float)GPSLatitude GPSLongitude:(float)GPSLongitude GPSLatitudeRef:(NSString*)GPSLatitudeRef GPSLongitudeRef:(NSString*)GPSLongitudeRef DataPath:(NSString*)DataPath WriteInPhotoAlbum:(BOOL)WriteInPhotoAlbum {

  NSData* ImageData;
 
  if ([Type isEqualToString:@"JPEG"]){
     ImageData =  UIImageJPEGRepresentation(Image, 1.0);
  }else if ([Type isEqualToString:@"PNG"]){
     ImageData =  UIImagePNGRepresentation(Image);
  }

   CGImageSourceRef source = CGImageSourceCreateWithData((CFDataRef)ImageData, NULL);
 
  NSDictionary *metadata = (__bridge NSDictionary *) CGImageSourceCopyPropertiesAtIndex(source, 0, NULL);
  NSMutableDictionary *metadataAsMutable = [metadata mutableCopy];
 
  NSMutableDictionary *GPSDictionary = [[metadataAsMutable objectForKey:(NSString *)kCGImagePropertyGPSDictionary]mutableCopy];


  if(!GPSDictionary)
  {
     NSDictionary * dictionary = nil;
  GPSDictionary = [NSMutableDictionary dictionary];
  }


  [GPSDictionary setValue:[NSNumber numberWithFloat:GPSLatitude] forKey:(NSString*)kCGImagePropertyGPSLatitude];
  [GPSDictionary setValue:[NSNumber numberWithFloat:GPSLongitude] forKey:(NSString*)kCGImagePropertyGPSLongitude];
  [GPSDictionary setValue:GPSLatitudeRef forKey:(NSString*)kCGImagePropertyGPSLatitudeRef];
  [GPSDictionary setValue:GPSLongitudeRef forKey:(NSString*)kCGImagePropertyGPSLongitudeRef];

  [metadataAsMutable setObject:GPSDictionary forKey:(NSString *)kCGImagePropertyGPSDictionary];
 
   if (WriteInPhotoAlbum == YES){
 
     ALAssetsLibrary *library = [ALAssetsLibrary alloc];
     ALAssetsLibraryWriteImageCompletionBlock imageWriteCompletionBlock =
     ^(NSURL *newURL, NSError *error) {
  if (error) {
  NSLog( @"Error writing image with metadata to Photo Library: %@", error );
  } else {
  NSLog( @"Wrote image %@ with metadata %@ to Photo Library",newURL,metadataAsMutable);
  }
     };
     [library writeImageToSavedPhotosAlbum:Image.CGImage
  metadata:metadataAsMutable
  completionBlock:imageWriteCompletionBlock];
 
   }else{
 
     CFStringRef UTI = CGImageSourceGetType(source);
     NSMutableData *dest_data = [NSMutableData data];

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

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

     CGImageDestinationAddImageFromSource(destination, source, 0, (CFDictionaryRef) metadataAsMutable);

     BOOL success = NO;
     success = CGImageDestinationFinalize(destination);
   
     if(!success){
      NSLog(@"-------- could not create data from image destination----------");
     }else{
       [dest_data writeToFile:DataPath atomically:YES];
       NSLog( @"Wrote image to %@ with metadata %@",DataPath,metadataAsMutable);
     }

   }
 
}
#End If

I have not tested yet. It should work ....

Hi,

I need to set GPS coordinates in a JPEG file, but it seems this code is not working on my iOS 12 device. Am I missing somthing ?
It seems it just does nothing: the image is unaffected.

UPDATE: it seems the GPS coordinates ARE bieng stored, but it seems there is no offset to it (or something) so that the properties of Windows does not show the coodinates, whereas a specialized application does
Thanks
 
Last edited:
Upvote 0
Top