0

When completing a task I have stumbled upon an iOS 13+ API that can solve my problem - https://developer.apple.com/documentation/quicklookthumbnailing/creating_quick_look_thumbnails_to_preview_files_in_your_app

It works as intended, but to complete my task I need to save created thumbnail to a disk, which I am trying to do using - https://developer.apple.com/documentation/quicklookthumbnailing/qlthumbnailgenerator/3237298-savebestrepresentation

func saveBestRepresentation(for request: QLThumbnailGenerator.Request, 
                         to fileURL: URL, 
                contentType: String, 
                 completion completionHandler: @escaping (Error?) -> Void)

Here is my code:

/// Uses quick look to asynchronously create best possible thumbnail image at path
static func createThumbnailFor(_ inputUrl: URL, at outputUrl: URL) {
    let size: CGSize = CGSize(width: 60, height: 90)
    let scale = UIScreen.main.scale

// Create the thumbnail request.
let request =
    QLThumbnailGenerator.Request(
        fileAt: inputUrl,
        size: size,
        scale: scale,
        representationTypes: .all)

// Retrieve the singleton instance of the thumbnail generator and generate the thumbnails.
let generator = QLThumbnailGenerator.shared
generator.saveBestRepresentation(for: request, to: outputUrl, contentType: "image/jpg") { (error) in
    if let error = error {
        print(error.localizedDescription)
    }
}

}

I am receiving the following error:

2020-07-28 13:08:01.259835+0300 SomeAppName[4748:1236635] *** Terminating app due to uncaught exception 'QLThumbnailGeneratorInvalidContentType', reason: 'image/jpg is not a supported image type'

I have tried many different types and looked through the headers but it only says that 'The content type of the thumbnail image that you want to save. Use a type that is supported by CGImageDestination, such as kUTTypePNG or kUTTypeJPEG.'. Unfortunately kUTTypePNG and kUTTypeJPEG are both deprecated. What content type should work in this case?

T. Pasichnyk
  • 702
  • 3
  • 16

3 Answers3

1

The iOS 14 way:

At the top of the file, import UniformTypeIdentifiers. Now change

contentType: "image/jpg"

to

contentType: UTType.jpeg.identifier
matt
  • 515,959
  • 87
  • 875
  • 1,141
0

"public.png" works for me.

Kap
  • 1
0

MIME types (e.g. "image/jpg") and UTIs (e.g. "public.jpeg") are two different things. Apple APIs take UTIs, generally, including the one you are trying to use. Symbols like kUTTypeJPEG are just names for constant strings. You can use a string literal instead of the symbolic name if you wish.

Some common examples:

"public.jpeg"  (kUTTypeJPEG)
"public.png"  (kUTTypePNG)
"com.compuserve.gif" (kUTTypeGIF)
"public.tiff"  (kUTTypeTIFF)
"public.heic"  (no symbolic name defined)

For fun, how about "com.microsoft.bmp" (kUTTypeBMP)

If you know the MIME type, you can get the UTI like so:

uti = UTTypeCreatePreferredIdentifierForTag( kUTTagClassMIMEType, mimeType, (CFStringRef)0);

If you know the UTI, you can get the MIME type like so:

mimeType = UTTypeCopyPreferredTagWithClass( uti, kUTTagClassMIMEType);

If you want the list of UTIs you can use in your case you can:

CFArrayRef utis = CGImageDestinationCopyTypeIdentifiers();

(These are all C snippets. Swift may be slightly different.)

Mustang
  • 363
  • 2
  • 9
  • No, in iOS 14, kUTTypePNG and kUTTypeJPEG and similar constants are deprecated. – matt Dec 23 '20 at 00:53
  • @matt I think if you're suggesting that I can no longer pass UTIs to APIs that take UTIs, you should check again. My suggestion was to use string literals, not the symbolic names that are claimed to be deprecated. – Mustang Dec 23 '20 at 02:29
  • And I’m saying that for iOS 14 that’s not the right answer to the deprecation problem. You're certainly right to point out that a mime type is not a UTI! But the correct way to get to the UTIs in question is e.g. `UTType.jpeg.identifier`. – matt Dec 23 '20 at 02:34
  • @matt, so what is the right answer exactly? I'm using this exact API as I speak. Apple has never had symbolic names for all the UTIs--ever. It was always appropriate to use strings instead of these constants because Apple does string compares not pointer compares. Just call CGImageDestinationCopyTypeIdentifiers to see the growing number of UTIs in ImageIO. I don't have iOS 14 SDK on my machine right now so I don't know how the many APIs that use UTIs are marked. So what are you supposed to pass as UTI parameters if not strings? – Mustang Dec 23 '20 at 02:43
  • @matt, sorry a better example of the growing UTI list is seen by calling CGImageSourceCopyTypeIdentifiers. – Mustang Dec 23 '20 at 02:44
  • @matt, ahhh a swift-ism 'UTType.jpeg.identifier' --whatever. I wouldn't be surprised if there are still a lot of missing symbolic constants. It's all strings in the end. For example is there a symbolic way to give the UTI "com.apple.atx" or say "com.leica.raw-image"? If not, then I stand by my answer. Further Apple's API better not care whether I use the predefined constant or a string that exactly matches--one heckofalotof code would break if they did. – Mustang Dec 23 '20 at 02:51