iOS, Swift, Image Metadata, XMP, DJI Drones - ios

I'm writing an iOS Swift app to fetch metadata from DJI drone images. I'm trying to access the Xmp.drone-dji.X metadata. The iOS/Swift CGImageSource and CGImageMetadata libraries/classes get almost all of the metadata out of the image but not the Xmp.drone-dji. When I get a list of tags, those tag/values are not listed. I know the tags/data are in the images because I've examined the images using exif, exiv2, etc.
Any suggestions?
Here is the code I'm using so far:
result.itemProvider.loadDataRepresentation(forTypeIdentifier: UTType.image.identifier)
{ data, err in
if let data = data {
let src = CGImageSourceCreateWithData(data as CFData,nil)!
let md = CGImageSourceCopyPropertiesAtIndex(src,0,nil) as! NSDictionary
let md2 = CGImageSourceCopyMetadataAtIndex(src,0,nil)
}
Thanks,
Bobby

So, after a lot of searching, trial and error, I have found an answer.
I was not able to get any of the CGImage swift libraries to extract this info for me.
Adobe has a c++ library that parses xmp/xml data out of images and it purports to support iOS. I didnt want the hassle of building c++ on iOS, importing that into Xcode and then dealing with the fact that thrown errors do not propagate well from c++/objectiveC to Swift.
So, at a high level, I did the following:
get the bytes of the raw image as CFData or Data then cast to a String
then use String.range() to find beginning of XML/XMP data in image
searching for substring <?xpacket begin
use String.range() to find end of XML/XMP data in image
using substring <?xpacket end.*?>
Extract the XML document out of image data String
Use Swift XMLParser class to parse the XML and then copying attributes and
elements as necessary. I just simply added what I wanted to already
existing Exif NSdictionary returned by CGImage classes.
Happy to answer questions on this approach. My code will eventually be uploaded to GitHub under OpenAthenaIOS project.
Bobby

Related

Custom defined file metadata keys [Swift]

I'm currently trying to save a jpeg representation of a UIImage with additional custom metadata (e.g. Thermal temperature statistics etc.). These don't fit within the apple predefined keys (https://developer.apple.com/documentation/imageio/cgimageproperties), so solutions I've found don't apply to my scenario.
I've tried saving the metadata with the image as a dictionary of keys and values, but the image is saved without the additional metadata.
func saveImage(imageToSave: UIImage, metadata: NSMutableDictionary) {
if let data: Data = imageToSave.jpegData(compressionQuality: ThermalImageView.JPEG_COMPRESSION) {
let fileName = self.buildFileName();
let source = CGImageSourceCreateWithData(data as CFData, nil)!;
let uniformTypeIdentifier = CGImageSourceGetType(source)!;
let destination = CGImageDestinationCreateWithURL(fileName as CFURL, uniformTypeIdentifier, 1, nil)!;
CGImageDestinationAddImageFromSource(destination, source, 0, metadata);
CGImageDestinationFinalize(destination);
}
}
When I try to read these values back with ExifTool (exiftool -j filename.jpg), the metadata is nowhere to be found. I expected this to happen as Apple seems to restrict what keys you can add to your metadata. So, is there a way to do this or should I go another route?
Thanks!
Edit: I think I may be barking up the wrong tree here. It seems like what I actually want to do is modify the header with additional metadata.
Photos framework is a way to go when dealing with metadata of assets. Moreover, PHAsset is the object you'd like to tinker with. https://developer.apple.com/documentation/photokit/phasset
One related question is: https://forums.developer.apple.com/thread/60664
If you still want to have it in your current way, perhaps try this? https://github.com/Nikita2k/SimpleExif

Looking for Xcode Swift examples to decompress gzipped Json data

I am trying to decompressed a Json data stream. I've found various decompression solutions, the native zlib seems easier, the other cocoa pod solutions produced new problems. The setting advised in native zlib inflate/deflate for swift3 on iOS seems working, the problem is what's next. I've thoroughly searched the net, only found C or Obj-C example codes but not Swift's. Thanks.
Another solution I tried was with https://github.com/mw99/DataCompression. But I had problem trying to set it up according to the instruction so look into the short codes and took out the part that I think should work for me, hard-coded some of the options. But no matter which algorithm I tried, perform() return nil.
I also tried unzip(), it failed at guard header >> 8 & 0b1111 == 0b1000. The web address automatic download a gzip file which can be decompressed into a Json file.
var routeFile: JsonRouteFile?
UIApplication.shared.isNetworkActivityIndicatorVisible = true
let urlRoute:URL = URL(string: "http://data.taipei/bus/ROUTE")!
DispatchQueue.global().async {
do {
let data:Data = try Data(contentsOf: urlRoute)
routeFile = try JSONDecoder().decode(JsonRouteFile?.self, from: data.decompress()!)
`
https://github.com/1024jp/GzipSwift works.
I didn't go through the enter installation though. Just dragged the file over.

Ios swift - storing uiimage in document directory and path in core data

I'm currently storing my images directly in core data and experiencing issues when having to retrieve a high quality images.
I was advised to store the images in the document directory and save a path in core-data as to not store the actual images there but simply the address of where I can go and find it.
Can someone push me in the right direction? Can't seem to find the appropriate guidance?
I was able to find the answers to all my questions in this youtube video -
https://www.youtube.com/watch?v=6vk4UrJR8WM
This is the github with the file that has instructions as to how to complete this - https://github.com/TDAbboud/WeightLogger-Images
Try Hanake cache: https://github.com/Haneke/Haneke
It worked really well for me personally with the same problem. It makes a sometimes painful task pretty easy.
Save an image in Document directory is easy this code is not optimized is just for give you a hint( you should manage errors, optionals etc). Suppose that you already have a valid UIImage instance called image and a valid image name String called imageName
let data = UIImagePNGRepresentation(image)
// Unwrapping the data optional
if let data = data {
let paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
let path = (paths.first! as! NSString).stringByAppendingPathComponent(imageName)
data.writeToFile(path, options: [])
//Save the path into your managed object
}

how to read data in rich content files using NSFilehandler

This is my swift code simplified:
func readContent(url:NSURL!){
do {
let file: NSFileHandle? = try NSFileHandle(forReadingFromURL: url)
if (file != nil){
file?.seekToFileOffset(10)
let content=file!.readDataOfLength(5)
print(String(data: content, encoding: NSASCIIStringEncoding))
file!.closeFile()
}
}catch {
}
}
I am building a file reader, that could read text files and pdfs. I am using NSFileHandler because I need to keep track of the position where the reading is happening.
I am able to read text files without a problem. However with pdfs I am having two problems:
How do I get the type of encoding used to encore the pdf? NSASCIIStringEncoding for instance does not work fine with text file but not with the pdf file. I am getting strange characters. I imaging that there is a way to detect the encoding. I have been following https://developer.apple.com/library/ios/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/Introduction/Introduction.html and I haven't found anything addressing this issue on stack overflow.
Given the fact that pdfs may contain text, images and videos how do I identify these contents while reading.. I read that magic numbers might do it https://en.wikipedia.org/wiki/Magic_number_(programming)#Magic_numbers_in_files but I read that there are not advisable http://www.techrepublic.com/article/avoid-using-magic-numbers-and-string-literals-in-your-code/. In addition I have not yet found a guide on how to use them.
please note that it is important for me to keep track of the Offset while reading.

How can I get raw data of image from UIPasteboard if it's copied by another app (such as photos, safari, etc..)

Is there a way to get raw data of image from UIPasteboard instead of UIImage if it's copied by another app such as photos or mobile safari?
I'm currently facing wired differences between IOS 6.0 and IOS 6.1(7.0 also)
In IOS 6.0, UIPasteboard's item of the copied image by photos or mobile safari contains raw data of the image.
But In IOS 6.1 and above, it contains UIImage instead of raw data.
In IOS 6.0, copied item of UIPasteboard is below
Printing description of array:
<__NSArrayM 0x8a804c0>(
{
"com.compuserve.gif" = <47494638 39614002 ...... 3b3a2000 3b>;
"public.url" = "url of the image....";
}
)
In IOS 6.1 and above, it contains UIImage instead of raw data.
Printing description of array:
<__NSArrayM 0xa25b7b0>(
{
"com.compuserve.gif" = "<UIImage: 0x9429570>";
"public.url" = "url of the image...";
}
)
If that image format is PNG or JPEG, it's not that bad.
(I still have to compress again if it's JEPG though.)
But when I try to paste animated gif image, it becomes more complicated.
I don't know even it's passible to create animated gif image from normal UIImage.
I can download again from original url, but downloading data that I already have seems not good solution I think.
And also, if it's copied from photos app, there's no such url. (there's some mysterious uri named "com.apple.mobileslideshow.asset-object-id-uri" that is undocumented instead of url)
There seems a workaround, because when I try to do exactly same action between photos and email app, It works properly
Any suggestions?
Well now, I figured it out myself.
You can simply get raw (binary)data of the image form general pasteboard by sending
dataForPasteboardType:(NSSting*)PasteboardType message to general pasteboard, if it's copied from Apple's built-in Mobile Safari or Photos App. (#"com.compuserve.gif" for the pasteboard type in my case)
I myself feel a bit foolish for not having checked all the passible methods sooner. :(
My confusion comes from items property of the UIPasteboard.
I thought that items are containing all of data of current pasteboard. So I try to save that array from pasteboard and want to use it later, but I were totally wrong.
As documented in UIPasteboard Class Reference, the items property contains dictionary with key being the representation type and the "value" the object associated with that type.
At this point of time, The "value" refers really "value" of the representation, not the data of that type. This meaning of the "value" is the same as the value of thesetValue: forPasteboardType: method.
On the other words, you cannot retrieve raw(binary) data of the image from items property, even if you set the image to the pasteboard by sending setData: forPasteboardType: message.(I tested it on IOS 7)
In addition, raw data of the image from items property in IOS 6.0 seems a bug of that OS version. (This may not true, it's just my opinion)
You can get NSData from UIPasteboard if you specify right PasteboardType:
NSData* pasteData = [[UIPasteboard generalPasteboard] dataForPasteboardType:(NSString*)kUTTypeJPEG];
Do not forget to import
<MobileCoreServices/MobileCoreServices.h>
The UIPasteBoard will contain whatever is placed in it. It's up to the app that is copying to the paste board to put the contents in the proper format. The app can place items as raw binary data or as objects such as UIImage in the paste board.
If you're getting something different between iOS versions, you're probably using different versions of the app or it's simply copying things differently.
You're right that you can't represent an animated GIF in a UIImage because a UIImage only contains a single image. Perhaps the app is just copying the first frame's bitmap data in that case?
You can convert a UIImage to raw JPEG data using UIImageJPEGRepresentation.

Resources