I got Apple's sample code for 'SamplePhotosApp' and in the photo album grid photo layout, trying to detect DNG RAW files (put up a badge if it's DNG).
Default cellForItemAt:
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let asset = fetchResult.object(at: indexPath.item)
// Dequeue a GridViewCell.
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: String(describing: GridViewCell.self), for: indexPath) as? GridViewCell
else { fatalError("unexpected cell in collection view") }
// Add a badge to the cell if the PHAsset represents a Live Photo.
if asset.mediaSubtypes.contains(.photoLive) {
cell.livePhotoBadgeImage = PHLivePhotoView.livePhotoBadgeImage(options: .overContent)
}
// Request an image for the asset from the PHCachingImageManager.
cell.representedAssetIdentifier = asset.localIdentifier
imageManager.requestImage(for: asset, targetSize: thumbnailSize, contentMode: .aspectFill, options: nil, resultHandler: { image, _ in
// The cell may have been recycled by the time this handler gets called;
// set the cell's thumbnail image only if it's still showing the same asset.
if cell.representedAssetIdentifier == asset.localIdentifier {
cell.thumbnailImage = image
}
})
return cell
}
With DNG files, there could be a preview or thumbnail (with iOS11) embedded in it, and of course a completely separate JPEG attached to it.
With above code, requestImage still displays DNG files by pulling out its embedded JPEG. However, it doesn't know that the PHAsset is actually a DNG file.
How can I find out if the PHAsset is a DNG?
let fileExtension = ((asset.value(forKey: "uniformTypeIdentifier") as! NSString).pathExtension as NSString).uppercased
if fileExtension == "DNG" || fileExtension == "RAW-IMAGE" {
//Show RAW Badge
}
Above works only if the DNG file has just the preview JPEG embedded. If it has a regular full-size JPEG embedded, it recognize the PHAsset as a JPEG.
I've been told to try this:
let res = PHAssetResource.assetResources(for: asset)
But a certain asset could have several number of resources (adjustment data, etc). How would I be able to make this work?
Some conceptual background: there are sort of three levels to work at in PhotoKit...
When you work with PHAsset
and friends, you're at an abstract model level. Each asset is an entry in the Photos database — a single "thing" that appears as a thumbnail in the Photos app. At this layer it's just an "thing" (not, say, a pixel buffer or video data stream).
When you work with PHImageManager
, you're still sort of working in the abstract. You're telling PhotoKit, "give me an image (or video) that's an appropriate way to display this asset to the user in these circumstances." What kind of file(s) contain the asset's original data is still abstracted away at this level.
Each one of those abstract "things" might have one or more original files providing its image or video data, intrinsic metadata, etc. To work with such issues (including file format), you need to work with PHAssetResource
(and possibly PHAssetResourceManager
).
So, if you're looking to find out whether an asset contains RAW or DNG data, you'll need to look at its resources.
Use PHAssetResource
.
assetResources(for:)
to get the set of resources corresponding to an asset.
Narrow down the list of resources by checking the type
property for each — an asset backed by a RAW or DNG file should store it in a resource of the alternatePhoto
type. (Though there's at least some possibility that third-party apps could write DNG files using the fullSizePhoto
type, so you might check there, too.)
Check the uniformTypeIdentifier
property for each resource in your narrowed list. The UTI for DNG files is "com.adobe.raw-image"
(in Xcode 9 there's a string constant for this, AVFileTypeDNG). That's probably fine if you want just DNG files, but to more broadly check for RAW files it's probably better test whether the resource's UTI conforms to "public.camera-raw-image"
aka kUTTypeRawImage
.