简体   繁体   中英

Detecting that iOS image data is HEIF or HEIC

My server doesn't support the HEIF format. So I need to transform it to JPEG before uploading from my app.

I do this:

UIImage *image = [UIImage imageWithData:imageData];                                 
NSData *data=UIImageJPEGRepresentation(image, 1.0);

But how can I know that the data is HEIF (or HEIC) ? I can look at a file:

([filePath hasSuffix:@".HEIC"] || [filePath hasSuffix:@".heic"])

But I don't think it's a good answer. Is there any other solution?

Both existing answers have good recommendations, but to attempt to tell the whole story...

UIImage doesn't represent an image file or even binary data in an image-file format . A UIImage is best thought of as an abstract representation of the displayable image encoded in that data — that is, a UIImage is the result of the decoding process. By the time you have a UIImage object, it doesn't care what file format it came from.

So, as @Ladislav's answer notes, if you have a UIImage already and you just want to get data in a particular image file format, call one of the convenience functions for getting a UIImage into a file-formatted data. As its name might suggest, UIImageJPEGRepresentation returns data appropriate for writing to a JPEG file.

If you already have a UIImage , UIImageJPEGRepresentation is probably your best bet, since you can use it regardless of the original image format.


As @ScottCorscadden implies , if you don't have a UIImage (yet) because you're working at a lower level such that you have access to the original file data, then you'll need to inspect that data to divine its format, or ask whatever source you got the data from for metadata describing its format.

If you want to inspect the data itself, you're best off reading up on the HIEF format standards. See nokiatech , MPEG group , orwikipedia .

There's a lot going on in the HEIF container format and the possible kinds of media that can be stored within, so deciding if you have not just a HEIF file, but an HEIF/HEVC file compatible with this-or-that viewer could be tricky. Since you're talking about excluding things your server doesn't support, it might be easier to code from the perspective of including only the things that your server does support. That is, if you have data with no metadata, look for something like the JPEG magic number 0xffd8ff , and use that to exclude anything that isn't JPEG.

Better, though, might be to look for metadata. If you're picking images from the Photos library with PHImageManager. requestImageData(for:options:resultHandler:) , the second parameter to your result handler is the Uniform Type Identifier for the image data: for HEIF and HEIC files, public.heif , public.heif-standard , and public.heic have been spotted in the wild.

(Again, though, if you're looking for "images my sever doesn't support", you're better off checking for the formats your server does support and rejecting anything not on that list, rather than trying to identify all the possible unsupported formats.)

When you are sending to your server you are most likely decoding the UIImage and sending it as Data so just do

let data = UIImageJPEGRepresentation(image, 0.9)

Just decide what quality works best for you, here it is 0.9

Well, you could look at magic bytes - JPEG and PNG certainly are known, and I seem to see some references that HEIF (.heic) starts with a NUL byte. If you're using any of the PHImageManager methods like requestImageDataForAsset:options:resultHandler , that resultHandler will be passed a NSString * _Nullable dataUTI reference. There's a decent WWDC video/slides on this (possibly here ) that suggest if the UTI is not kUTTypeJPEG you convert it (and the slides have some lower-level sample code in swift to do it that preserve orientation too).

I should also mention, if you have control at your app layer and all uploads come from there, do all this there.

If you're using Photos framework and are importing images from photo library, there's a solution that was mentioned briefly during WWDC17. First, import core services:

import MobileCoreServices

Then, when you request the image, check the UTType that is returned as a second parameter to your block:

// asset: PHAsset
PHImageManager.default().requestImageData(for: asset, options: nil) { imageData, dataUTI, orientation, info in
  guard let dataUTI = dataUTI else { return }
  if !(UTTypeConformsTo(dataUTI as CFString, kUTTypeJPEG) || UTTypeConformsTo(dataUTI as CFString, kUTTypePNG)) {
    // imageData is neither JPG not PNG, possibly subject for transcoding
  }
}

Other UTTypes can be found here

A bit late to the party, but other than checking the extension (after the last dot), you can also check for the "magic number" aka file signature. Byte 5 to 8 should give you the constant "ftyp". The following 4 bytes would be the major brand, which I believe is one of "mif1", "heic" and "heix". For example, the first 12 bytes of a .heic image would be:

00 00 00 18 66 74 79 70 6d 69 66 31

which, after removing 0s and trim the result, literally decoded to ftypmif1 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM