51 lines
1.6 KiB
Swift
51 lines
1.6 KiB
Swift
import AppKit
|
|
|
|
|
|
enum ImageLoaderError: Error
|
|
{
|
|
case loadFailed(_ message: String)
|
|
}
|
|
|
|
struct NSImageLoader: LoaderProtocol
|
|
{
|
|
typealias T = Image
|
|
|
|
func load(url: URL) -> T?
|
|
{
|
|
guard let image = try? NSImageLoader.loadImage(url: url) else { return nil }
|
|
return image
|
|
}
|
|
|
|
static func loadImage(url: URL) throws -> Image
|
|
{
|
|
try autoreleasepool
|
|
{
|
|
// Open as a Core Graphics image
|
|
guard let nsImg = NSImage(contentsOf: url),
|
|
let image = nsImg.cgImage(forProposedRect: nil, context: nil, hints: nil)
|
|
else { throw ImageLoaderError.loadFailed("Failed to open image \"\(url.absoluteString)\"") }
|
|
|
|
// Convert to 8-bit ARGB (SRGB) w/ premultiplied alpha
|
|
let alphaInfo = image.alphaInfo == .none ? CGImageAlphaInfo.noneSkipLast : CGImageAlphaInfo.premultipliedLast
|
|
guard let colourspace = CGColorSpace(name: CGColorSpace.sRGB),
|
|
let context = CGContext(data: nil,
|
|
width: image.width,
|
|
height: image.height,
|
|
bitsPerComponent: 8,
|
|
bytesPerRow: image.width * 4,
|
|
space: colourspace,
|
|
bitmapInfo: alphaInfo.rawValue | CGBitmapInfo.byteOrder32Big.rawValue)
|
|
else { throw ImageLoaderError.loadFailed("Coudn't create graphics context") }
|
|
let flipVertical = CGAffineTransform(a: 1, b: 0, c: 0, d: -1, tx: 0, ty: CGFloat(image.height))
|
|
context.concatenate(flipVertical)
|
|
context.draw(image, in: CGRect(x: 0, y: 0, width: image.width, height: image.height))
|
|
|
|
guard let data = context.data else { throw ImageLoaderError.loadFailed("what") }
|
|
return Image(
|
|
pixels: Data(bytes: data, count: 4 * image.width * image.height),
|
|
width: image.width,
|
|
height: image.height)
|
|
}
|
|
}
|
|
}
|