Path: blob/a-new-beginning/Folium-iOS/Extensions/CGImage.swift
2 views
//
// CGImage.swift
// Folium-iOS
//
// Created by Jarrod Norwell on 20/7/2025.
//
import CoreGraphics
import Foundation
extension CGImage {
static func grapeIcon(buffer: UnsafeMutablePointer<UInt32>, width: Int = 32, height: Int = 32) -> CGImage? {
.genericRGBA8888(buffer, width, height)
}
static func genericBGRA8888(_ buffer: UnsafeMutablePointer<UInt8>, _ width: Int, _ height: Int) -> CGImage? {
let colorSpaceRef = CGColorSpaceCreateDeviceRGB()
let bitsPerComponent = 8
let bytesPerPixel = 4
let bitsPerPixel = bytesPerPixel * bitsPerComponent
let bytesPerRow = bytesPerPixel * width
let totalBytes = height * bytesPerRow
let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.first.rawValue).union(.byteOrderDefault)
guard let providerRef = CGDataProvider(dataInfo: nil, data: buffer, size: totalBytes,
releaseData: { _, _, _ in }) else {
return nil
}
var imageRef: CGImage? = nil
imageRef = CGImage(width: width, height: height, bitsPerComponent: bitsPerComponent, bitsPerPixel: bitsPerPixel,
bytesPerRow: bytesPerRow, space: colorSpaceRef, bitmapInfo: bitmapInfo, provider: providerRef,
decode: nil, shouldInterpolate: false, intent: .defaultIntent)
return imageRef
}
static func genericRGB888(_ buffer: UnsafeMutablePointer<UInt8>, _ width: Int, _ height: Int) -> CGImage? {
let colorSpaceRef = CGColorSpaceCreateDeviceRGB()
let bitsPerComponent = 8
let bytesPerPixel = 3
let bitsPerPixel = bytesPerPixel * bitsPerComponent
let bytesPerRow = bytesPerPixel * width
let totalBytes = height * bytesPerRow
let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.none.rawValue).union(.byteOrderDefault)
guard let providerRef = CGDataProvider(dataInfo: nil, data: buffer, size: totalBytes,
releaseData: { _, _, _ in }) else {
return nil
}
var imageRef: CGImage? = nil
imageRef = CGImage(width: width, height: height, bitsPerComponent: bitsPerComponent, bitsPerPixel: bitsPerPixel,
bytesPerRow: bytesPerRow, space: colorSpaceRef, bitmapInfo: bitmapInfo, provider: providerRef,
decode: nil, shouldInterpolate: false, intent: .defaultIntent)
return imageRef
}
static func genericRGBA8888(_ buffer: UnsafeMutablePointer<UInt32>, _ width: Int, _ height: Int) -> CGImage? {
let colorSpaceRef = CGColorSpaceCreateDeviceRGB()
let bitsPerComponent = 8
let bytesPerPixel = 4
let bitsPerPixel = bytesPerPixel * bitsPerComponent
let bytesPerRow = bytesPerPixel * width
let totalBytes = height * bytesPerRow
let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.noneSkipLast.rawValue).union(.byteOrderDefault)
guard let providerRef = CGDataProvider(dataInfo: nil, data: buffer, size: totalBytes,
releaseData: { _, _, _ in }) else {
return nil
}
var imageRef: CGImage? = nil
imageRef = CGImage(width: width, height: height, bitsPerComponent: bitsPerComponent, bitsPerPixel: bitsPerPixel,
bytesPerRow: bytesPerRow, space: colorSpaceRef, bitmapInfo: bitmapInfo, provider: providerRef,
decode: nil, shouldInterpolate: false, intent: .defaultIntent)
return imageRef
}
static func ds_dsi(_ buffer: UnsafeMutablePointer<UInt32>, _ width: Int, _ height: Int) -> CGImage? {
let colorSpaceRef = CGColorSpaceCreateDeviceRGB()
let bitsPerComponent = 8
let bytesPerPixel = 4
let bitsPerPixel = bytesPerPixel * bitsPerComponent
let bytesPerRow = bytesPerPixel * width
let totalBytes = height * bytesPerRow
let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.noneSkipFirst.rawValue).union(CGBitmapInfo.byteOrder32Little)
guard let providerRef = CGDataProvider(dataInfo: nil, data: buffer, size: totalBytes,
releaseData: { _, _, _ in }) else {
return nil
}
var imageRef: CGImage? = nil
imageRef = CGImage(width: width, height: height, bitsPerComponent: bitsPerComponent, bitsPerPixel: bitsPerPixel,
bytesPerRow: bytesPerRow, space: colorSpaceRef, bitmapInfo: bitmapInfo, provider: providerRef,
decode: nil, shouldInterpolate: false, intent: .defaultIntent)
return imageRef
}
static func gb(_ pointer: UnsafeMutablePointer<UInt8>, _ width: Int, _ height: Int) -> CGImage? {
let bitsPerComponent = 8
let bytesPerPixel = 1
let bitsPerPixel = bytesPerPixel * bitsPerComponent
let bytesPerRow = bytesPerPixel * width
let size = height * bytesPerRow
guard let provider: CGDataProvider = .init(dataInfo: nil, data: pointer, size: size, releaseData: { _, data, _ in
data.deallocate()
}) else {
return nil
}
return .init(width: width,
height: height,
bitsPerComponent: bitsPerComponent,
bitsPerPixel: bitsPerPixel,
bytesPerRow: bytesPerRow,
space: CGColorSpaceCreateDeviceRGB(),
bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.noneSkipLast.rawValue).union(.byteOrder32Little),
provider: provider,
decode: nil,
shouldInterpolate: false,
intent: .defaultIntent)
}
static func gba(_ buffer: UnsafeMutablePointer<UInt32>, _ width: Int, _ height: Int) -> CGImage? {
let colorSpaceRef = CGColorSpaceCreateDeviceRGB()
let bitsPerComponent = 8
let bytesPerPixel = 4
let bitsPerPixel = bytesPerPixel * bitsPerComponent
let bytesPerRow = bytesPerPixel * width
let totalBytes = height * bytesPerRow
let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.noneSkipFirst.rawValue).union(.byteOrder32Little)
guard let providerRef = CGDataProvider(dataInfo: nil, data: buffer, size: totalBytes,
releaseData: { _, _, _ in }) else {
return nil
}
var imageRef: CGImage? = nil
imageRef = CGImage(width: width, height: height, bitsPerComponent: bitsPerComponent, bitsPerPixel: bitsPerPixel,
bytesPerRow: bytesPerRow, space: colorSpaceRef, bitmapInfo: bitmapInfo, provider: providerRef,
decode: nil, shouldInterpolate: false, intent: .defaultIntent)
return imageRef
}
static func nes(_ buffer: [UInt8], _ width: Int, _ height: Int) -> CGImage? {
guard let data: CFData = CFDataCreate(nil, buffer, width * height * 3) else {
print("no data")
return nil
}
guard let provider: CGDataProvider = .init(data: data) else {
print ("no provider")
return nil
}
return .init(
width: width,
height: height,
bitsPerComponent: 8,
bitsPerPixel: 24,
bytesPerRow: width * 3,
space: CGColorSpaceCreateDeviceRGB(),
bitmapInfo: CGBitmapInfo(rawValue: .zero),
provider: provider,
decode: nil,
shouldInterpolate: false,
intent: .defaultIntent
)
}
static func psx_bgr555(_ pointer: UnsafeMutableRawPointer, _ width: Int, _ height: Int) -> CGImage? {
let pixelCount = width * height
let pixels = pointer.bindMemory(to: UInt16.self, capacity: pixelCount)
let bytesPerPixel = 3
let bytesPerRow = bytesPerPixel * width
let size = bytesPerRow * height
let data: UnsafeMutablePointer<UInt8> = .allocate(capacity: size)
for i in 0 ..< pixelCount {
let pixel = pixels[i]
let blue: UInt8 = .init((pixel & 0x1F) << 3 | (pixel & 0x1F) >> 2)
let green: UInt8 = .init(((pixel >> 5) & 0x1F) << 3 | ((pixel >> 5) & 0x1F) >> 2)
let red: UInt8 = .init(((pixel >> 10) & 0x1F) << 3 | ((pixel >> 10) & 0x1F) >> 2)
let offset = i * 3
data[offset + 0] = blue
data[offset + 1] = green
data[offset + 2] = red
}
guard let provider: CGDataProvider = .init(dataInfo: nil, data: data, size: size, releaseData: { _, data, _ in
data.deallocate()
}) else {
data.deallocate()
return nil
}
return .init(
width: width,
height: height,
bitsPerComponent: 8,
bitsPerPixel: 24,
bytesPerRow: bytesPerRow,
space: CGColorSpaceCreateDeviceRGB(),
bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.none.rawValue),
provider: provider,
decode: nil,
shouldInterpolate: false,
intent: .defaultIntent
)
}
static func psx_rgb888(_ pointer: UnsafeMutablePointer<UInt16>, _ width: Int, _ height: Int) -> CGImage? {
let bytesPerPixel = 3
let bytesPerRow = width * bytesPerPixel
let totalBytes = bytesPerRow * height
// Allocate buffer for tightly packed RGB24
let data = UnsafeMutablePointer<UInt8>.allocate(capacity: totalBytes)
var texOffset = 0
for y in 0..<height {
var gpuOffset = y * width
var x = 0
while x < width {
// PSX 24-bit: 3 words = 2 pixels
let c1 = pointer[gpuOffset]; gpuOffset += 1
let c2 = pointer[gpuOffset]; gpuOffset += 1
let c3 = pointer[gpuOffset]; gpuOffset += 1
// Pixel 0
data[texOffset + 0] = UInt8(c1 & 0xFF) // R0
data[texOffset + 1] = UInt8((c1 >> 8) & 0xFF) // G0
data[texOffset + 2] = UInt8(c2 & 0xFF) // B0
// Pixel 1
data[texOffset + 3] = UInt8((c2 >> 8) & 0xFF) // R1
data[texOffset + 4] = UInt8(c3 & 0xFF) // G1
data[texOffset + 5] = UInt8((c3 >> 8) & 0xFF) // B1
texOffset += 6
x += 2
}
}
// Wrap buffer in NSData for CGDataProvider
let nsData = NSData(bytesNoCopy: data, length: totalBytes, freeWhenDone: true)
guard let provider = CGDataProvider(data: nsData) else {
data.deallocate()
return nil
}
return CGImage(
width: width,
height: height,
bitsPerComponent: 8,
bitsPerPixel: 24,
bytesPerRow: bytesPerRow,
space: CGColorSpaceCreateDeviceRGB(),
bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.none.rawValue),
provider: provider,
decode: nil,
shouldInterpolate: false,
intent: .defaultIntent
)
}
static func newSnes(_ pointer: UnsafeMutablePointer<UInt16>, _ width: Int, _ height: Int) -> CGImage? {
let pixelCount = width * height
var rgba = [UInt8](repeating: 0, count: pixelCount * 4)
for i in 0..<pixelCount {
let pixel = pointer[i]
// RGB565 extraction (most common)
let red = UInt8((pixel >> 11) & 0x1F)
let green = UInt8((pixel >> 5) & 0x3F)
let blue = UInt8(pixel & 0x1F)
// Expand to 8-bit
let r8 = (red << 3) | (red >> 2)
let g8 = (green << 2) | (green >> 4)
let b8 = (blue << 3) | (blue >> 2)
rgba[i * 4 + 0] = r8
rgba[i * 4 + 1] = g8
rgba[i * 4 + 2] = b8
rgba[i * 4 + 3] = 255
}
let data = Data(rgba)
guard let provider = CGDataProvider(data: data as CFData) else {
return nil
}
return CGImage(
width: width,
height: height,
bitsPerComponent: 8,
bitsPerPixel: 32,
bytesPerRow: width * 4,
space: CGColorSpaceCreateDeviceRGB(),
bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.noneSkipLast.rawValue),
provider: provider,
decode: nil,
shouldInterpolate: false,
intent: .defaultIntent
)
}
static func snes(_ pointer: UnsafeMutablePointer<UInt8>, _ width: Int, _ height: Int) -> CGImage? {
let bitsPerComponent = 8
let bytesPerPixel = 4
let bitsPerPixel = bytesPerPixel * bitsPerComponent
let bytesPerRow = bytesPerPixel * width
let size = height * bytesPerRow
guard let provider: CGDataProvider = .init(dataInfo: nil, data: pointer, size: size, releaseData: { info, data, size in
}) else {
return nil
}
// guard let provider: CGDataProvider = .init(dataInfo: nil, data: pointer, size: size, releaseData: { _, data, _ in
// data.deallocate()
// }) else {
// return nil
// }
return .init(width: width,
height: height,
bitsPerComponent: bitsPerComponent,
bitsPerPixel: bitsPerPixel,
bytesPerRow: bytesPerRow,
space: CGColorSpaceCreateDeviceRGB(),
bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.noneSkipLast.rawValue).union(.byteOrder32Little),
provider: provider,
decode: nil,
shouldInterpolate: false,
intent: .defaultIntent)
}
static func genesis(_ pointer: UnsafeMutablePointer<UInt32>, _ width: Int, _ height: Int) -> CGImage? {
let bitsPerComponent = 8
let bytesPerPixel = 4
let bitsPerPixel = bytesPerPixel * bitsPerComponent
let bytesPerRow = bytesPerPixel * width
let size = height * bytesPerRow
guard let provider: CGDataProvider = .init(dataInfo: nil, data: pointer, size: size, releaseData: { info, data, size in
}) else {
return nil
}
return .init(width: width,
height: height,
bitsPerComponent: bitsPerComponent,
bitsPerPixel: bitsPerPixel,
bytesPerRow: bytesPerRow,
space: CGColorSpaceCreateDeviceRGB(),
bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.first.rawValue).union(.byteOrderDefault),
provider: provider,
decode: nil,
shouldInterpolate: false,
intent: .defaultIntent)
}
}