Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unknown Hint Identifier for Image MIME Types #62

Closed
mattt opened this issue Apr 22, 2019 · 4 comments
Closed

Unknown Hint Identifier for Image MIME Types #62

mattt opened this issue Apr 22, 2019 · 4 comments
Milestone

Comments

@mattt
Copy link

mattt commented Apr 22, 2019

On iOS 10 (building with Xcode 10.2), calling the parseAsImage(scale:) method to process HTTP requests for remote images causes the following error message to be logged to the console:

extractOptions:147: *** unknown hint identifier 'kCGImageSourceTypeIdentifierHint:image/jpeg' -- ignoring...

I can confirm that a similar error message occurs when attempting to load PNG images as well.

Looking at the implementation of this method, I traced the issue to the following line in the private UIImage initializer called from that method:

options = [kCGImageSourceTypeIdentifierHint: mimeType as CFString]

According to Apple's documentation, CGImageSourceCreateWithData expects kCGImageSourceTypeIdentifierHint to be a UTI, rather than a MIME type. For example, according to Apple's Image I/O Programming Guide, the correct UTI for a JPEG image would be public.jpeg.

One potential fix would be to use UTTypeCreatePreferredIdentifierForTag to get the UTI corresponding to the MIME type like so:

import CoreServices

let mimeType = "image/jpeg"
let uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, mimeType as! CFString, kUTTypeImage)

uti?.takeRetainedValue() // public.jpeg

My one concern with this approach is that I'm unfamiliar with the performance characteristics of UTTypeCreatePreferredIdentifierForTag, and don't know if calling this method incurs a static initialization cost to build up the list of supported UTIs (and if so, how often). It'd be unfortunate if the computation to generate the type hint took longer than it would otherwise.

If you also share this concern, an alternative approach would be to hardcode the lookup for only the supported MIME types from a list derived from either this table in the docs or by calling CGImageSourceCopyTypeIdentifiers(_:). The downside to this approach is that it is liable to become stale over time, and at the time of writing, the list is actually quite large (primarily because of disparate RAW camera image types):

["public.jpeg", "public.png", "com.compuserve.gif", "com.canon.tif-raw-image", "com.adobe.raw-image", "com.dxo.raw-image", "com.canon.cr2-raw-image", "com.canon.cr3-raw-image", "com.leafamerica.raw-image", "com.hasselblad.fff-raw-image", "com.hasselblad.3fr-raw-image", "com.nikon.raw-image", "com.nikon.nrw-raw-image", "com.pentax.raw-image", "com.samsung.raw-image", "com.sony.raw-image", "com.sony.sr2-raw-image", "com.sony.arw-raw-image", "com.epson.raw-image", "com.kodak.raw-image", "public.tiff", "public.jpeg-2000", "com.apple.atx", "org.khronos.astc", "org.khronos.ktx", "public.avci", "public.heic", "public.heif", "com.canon.crw-raw-image", "com.fuji.raw-image", "com.panasonic.raw-image", "com.panasonic.rw2-raw-image", "com.leica.raw-image", "com.leica.rwl-raw-image", "com.konicaminolta.raw-image", "com.olympus.sr-raw-image", "com.olympus.or-raw-image", "com.olympus.raw-image", "com.phaseone.raw-image", "com.microsoft.ico", "com.microsoft.bmp", "com.apple.icns", "com.adobe.photoshop-image", "com.microsoft.cur", "com.truevision.tga-image", "com.ilm.openexr-image", "com.sgi.sgi-image", "public.radiance", "public.pbm", "public.mpo-image", "public.pvr", "com.microsoft.dds"]

Finally, the null solution would be to simply remove the type hint altogether.

@lilyball
Copy link
Collaborator

Thanks for the detailed issue! I'm surprised I didn't notice before that this is supposed to be a UTI.

I know that the initial set of UTIs are loaded from a bundle on disk somewhere, though LaunchServices also maintains a dynamic registry of UTIs from apps on the system. I'm not sure if creating a UTI from a MIME type does any XPC past the initial load to access that dynamic registry, though if it does, hopefully it would cache the results for a given MIME type. I'll do a bit of performance testing right now and see what it actually costs to look up UTIs.

@lilyball
Copy link
Collaborator

In quick testing on macOS, first time calling UTTypeCreatePreferredIdentifierForTag costs about 2.5ms. Calling it repeatedly with the same input drops down to about 20µs instead. Switching to a different MIME type has a 60–90µs cost before dropping back down to 20µs.

If anything, iOS can be presumed to be faster, due to the lack of a central UTI registry beyond the built-in types.

This seems fast enough that it's worth keeping. I'll push out a fix for this today. Thanks again!

@lilyball lilyball added this to the Next milestone Apr 24, 2019
@lilyball
Copy link
Collaborator

This is now published as v4.4.0.

@mattt
Copy link
Author

mattt commented Apr 24, 2019

In quick testing on macOS, first time calling UTTypeCreatePreferredIdentifierForTag costs about 2.5ms. Calling it repeatedly with the same input drops down to about 20µs instead. Switching to a different MIME type has a 60–90µs cost before dropping back down to 20µs.

That's exactly the kind of behavior I was hoping for.

Thanks so much for taking a look and for the quick turnaround on the fix!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants