// // FileIntentToImageQuery.swift // shortcut // // Created by Bailey Townsend on 6/30/25. // import ATProtoKit import AppIntents import CoreGraphics import Foundation import ImageIO import Photos import UIKit public func IntentFileToImageQuery(files: [IntentFile], altText: [String]) async throws -> [ATProtoTools.ImageQuery] { var imageQueries: [ATProtoTools.ImageQuery] = [] for (index, image) in files.enumerated() { if image.availableContentTypes.contains(.heic) { let heicImage = try await image.withFile( contentType: .heic, fileHandler: { url, openInPlace in guard let image = UIImage(contentsOfFile: url.absoluteURL.path()) else { throw GenericIntentError.message( "Failed to load image \(image.filename).") } return image } ) let fileName = image.filename if let jpegData = heicImage.jpegData(compressionQuality: 0.1) { imageQueries.append( ATProtoTools.ImageQuery( imageData: jpegData, fileName: fileName, altText: altText[safe: index], aspectRatio: AppBskyLexicon.Embed.AspectRatioDefinition( width: Int(heicImage.size.width), height: Int(heicImage.size.height)) )) } } else if image.availableContentTypes.contains(.jpeg) { let jpeg = try await image.withFile( contentType: .jpeg, fileHandler: { url, openInPlace in guard let image = UIImage(contentsOfFile: url.absoluteURL.path()) else { throw GenericIntentError.message( "Failed to load image \(image.filename).") } return image } ) if let jpegData = jpeg.jpegData(compressionQuality: 0.1) { imageQueries.append( ATProtoTools.ImageQuery( imageData: jpegData, fileName: image.filename, altText: altText[safe: index], aspectRatio: AppBskyLexicon.Embed.AspectRatioDefinition( width: Int(jpeg.size.width), height: Int(jpeg.size.height)) )) } } else if image.availableContentTypes.contains(.png) { let png = try await image.withFile( contentType: .png, fileHandler: { url, openInPlace in guard let image = UIImage(contentsOfFile: url.absoluteURL.path()) else { throw GenericIntentError.message( "Failed to load image \(image.filename).") } return image } ) if let jpegData = png.jpegData(compressionQuality: 0.1) { imageQueries.append( ATProtoTools.ImageQuery( imageData: jpegData, fileName: image.filename, altText: altText[safe: index], aspectRatio: AppBskyLexicon.Embed.AspectRatioDefinition( width: Int(png.size.width), height: Int(png.size.height)) )) } } else { //Just yolo it imageQueries.append( ATProtoTools.ImageQuery( imageData: image.data, fileName: image.filename, altText: altText[safe: index], aspectRatio: nil )) } } return imageQueries } private func extractCaptionFromImageData(_ data: Data) -> String? { guard let imageSource = CGImageSourceCreateWithData(data as CFData, nil) else { return nil } guard let metadata = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, nil) as? [String: Any] else { return nil } // Check EXIF UserComment // if let exifDict = metadata[kCGImagePropertyExifDictionary as String] as? [String: Any], // let userComment = exifDict[kCGImagePropertyExifUserComment as String] as? String // { // return userComment.isEmpty ? nil : userComment // } // Check IPTC Caption // if let iptcDict = metadata[kCGImagePropertyIPTCDictionary as String] as? [String: Any], // let caption = iptcDict[kCGImagePropertyIPTCCaptionAbstract as String] as? String // { // return caption.isEmpty ? nil : caption // } // Check TIFF ImageDescription if let tiffDict = metadata[kCGImagePropertyTIFFDictionary as String] as? [String: Any], let description = tiffDict[kCGImagePropertyTIFFImageDescription as String] as? String { return description.isEmpty ? nil : description } return nil } extension Array { subscript(safe index: Int) -> Element? { return indices.contains(index) ? self[index] : nil } }