Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
folium-app
GitHub Repository: folium-app/Folium
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)
    }
}