Skip to content

Instantly share code, notes, and snippets.

@JoshuaSullivan
Last active April 17, 2024 10:48
Show Gist options
  • Star 12 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save JoshuaSullivan/b575d96bfd8a4177d8d46352e5f36458 to your computer and use it in GitHub Desktop.
Save JoshuaSullivan/b575d96bfd8a4177d8d46352e5f36458 to your computer and use it in GitHub Desktop.
Here are the Swift 2.3 and Swift 3.0 versions of the ColorCubeHelper class.
//
// ColorCubeHelper.swift
//
// Created by Joshua Sullivan on 10/01/16.
// Copyright © 2016 Joshua Sullivan. All rights reserved.
//
import UIKit
import Accelerate
public final class ColorCubeHelper {
public enum ColorCubeError: ErrorType {
case IncorrectImageSize
case MissingImageData
case UnableToCreateDataProvider
}
public static func createColorCubeData(inputImage image: UIImage, cubeDimension: Int) throws -> NSData {
// Set up some variables for calculating memory size.
let imageSize = image.size
let dim = Int(imageSize.width)
let pixels = dim * dim
let channels = 4
// If the number of pixels doesn't match what's needed for the supplied cube dimension, abort.
guard pixels == cubeDimension * cubeDimension * cubeDimension else {
throw ColorCubeError.IncorrectImageSize
}
// We don't need a sizeof() because uint_8t is explicitly 1 byte.
let memSize = pixels * channels
// Get the UIImage's backing CGImageRef
guard let img = image.CGImage else {
throw ColorCubeError.MissingImageData
}
// Get a reference to the CGImage's data provider.
guard let inProvider = CGImageGetDataProvider(img) else {
throw ColorCubeError.UnableToCreateDataProvider
}
let inBitmapData = CGDataProviderCopyData(inProvider)
let inBuffer = CFDataGetBytePtr(inBitmapData)
// Calculate the size of the float buffer and allocate it.
let floatSize = memSize * sizeof(Float.self)
let finalBuffer = unsafeBitCast(malloc(floatSize), UnsafeMutablePointer<Float>.self)
// Convert the uint_8t to float. Note: a uint of 255 will convert to 255.0f.
vDSP_vfltu8(inBuffer, 1, finalBuffer, 1, UInt(memSize))
// Divide each float by 255.0 to get the 0-1 range we are looking for.
var divisor = Float(255.0)
vDSP_vsdiv(finalBuffer, 1, &divisor, finalBuffer, 1, UInt(memSize))
// Don't copy the bytes, just have the NSData take ownership of the buffer.
let cubeData = NSData(bytesNoCopy: finalBuffer, length: floatSize, freeWhenDone: true)
return cubeData
}
}
//
// ColorCubeHelper.swift
//
// Created by Joshua Sullivan on 10/10/16.
// Copyright © 2016 Joshua Sullivan. All rights reserved.
//
import UIKit
import Accelerate
public class ColorCubeHelper {
public enum ColorCubeError: Error {
case incorrectImageSize
case missingImageData
case unableToCreateDataProvider
case unableToGetBitmpaDataBuffer
}
public static func createColorCubeData(inputImage image: UIImage, cubeDimension: Int) throws -> Data {
// Set up some variables for calculating memory size.
let imageSize = image.size
let dim = Int(imageSize.width)
let pixels = dim * dim
let channels = 4
// If the number of pixels doesn't match what's needed for the supplied cube dimension, abort.
guard pixels == cubeDimension * cubeDimension * cubeDimension else {
throw ColorCubeError.incorrectImageSize
}
// We don't need a sizeof() because uint_8t is explicitly 1 byte.
let memSize = pixels * channels
// Get the UIImage's backing CGImageRef
guard let img = image.cgImage else {
throw ColorCubeError.missingImageData
}
// Get a reference to the CGImage's data provider.
guard let inProvider = img.dataProvider else {
throw ColorCubeError.unableToCreateDataProvider
}
let inBitmapData = inProvider.data
guard let inBuffer = CFDataGetBytePtr(inBitmapData) else {
throw ColorCubeError.unableToGetBitmpaDataBuffer
}
// Calculate the size of the float buffer and allocate it.
let floatSize = memSize * MemoryLayout<Float>.size
let finalBuffer = unsafeBitCast(malloc(floatSize), to:UnsafeMutablePointer<Float>.self)
// Convert the uint_8t to float. Note: a uint of 255 will convert to 255.0f.
vDSP_vfltu8(inBuffer, 1, finalBuffer, 1, UInt(memSize))
// Divide each float by 255.0 to get the 0-1 range we are looking for.
var divisor = Float(255.0)
vDSP_vsdiv(finalBuffer, 1, &divisor, finalBuffer, 1, UInt(memSize))
// Don't copy the bytes, just have the NSData take ownership of the buffer.
let cubeData = NSData(bytesNoCopy: finalBuffer, length: floatSize, freeWhenDone: true)
return cubeData as Data
}
}
guard let colorCubeImage = UIImage(named: "MyColorEffect-64.png") else {
preconditionFailure("Couldn't load the cube data image.")
}
do {
let data = try ColorCubeHelper.createColorCubeData(inputImage: colorCubeImage, cubeDimension: 64)
let params: [String : Any] = [ "inputCubeData" : data ]
let filter = CIFilter(name: "CIColorCube", withInputParameters: params)
// Now you can use the filter.
} catch {
debugPrint("Unable to create cube data: \(error)")
}
@muukii
Copy link

muukii commented Mar 29, 2021

I'm working on this FluidGroup/Brightroom#78

@elteclagol
Copy link

elteclagol commented Mar 29, 2021

@JoshuaSullivan
I have another question.
Your code uses CIColorCube, but we have also CIColorCubeWithColorSpace.
Do you know the differences between them?

I don't know the technical differences between them, but when I use CIColorCubeWithColorSpace the results are the expected and when I use CIColorCube they aren't.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment