Thanks. Yes, the alpha info is indeed "premultipliedLast" but I can't see how I can change that. Any idea where to set that flag?
Post
Replies
Boosts
Views
Activity
The flag seems to be when you create the CIContext CIContext(options: [CIContextOption.outputPremultiplied: false])
After making that change, Alpha info no longer say its premultiplied, but I'm still getting a more or less the same result:
[120, 145, 195, 170] -> [145, 174, 233, 170]
I can't see a direct way to read the bytes in the tiff. I've tried:
func printTiffBytes(url:URL) {
if let imageSource = CGImageSourceCreateWithURL(url as CFURL, nil),
let image = CGImageSourceCreateImageAtIndex(imageSource, 0, nil) {
let width = image.width
let height = image.height
let bitsPerComponent = image.bitsPerComponent
let bytesPerRow = image.bytesPerRow
let totalBytes = height * bytesPerRow
let colorSpace = CGColorSpaceCreateDeviceRGB()
// let colorSpace = CGColorSpace(name: CGColorSpace.linearSRGB)!
//let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.last.rawValue) // Error! unsupported parameter combination
let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue)
let data = UnsafeMutableRawPointer.allocate(byteCount: totalBytes, alignment: MemoryLayout<UInt8>.alignment)
defer { data.deallocate() }
if let context = CGContext(data: data,
width: width,
height: height,
bitsPerComponent: bitsPerComponent,
bytesPerRow: bytesPerRow,
space: colorSpace,
bitmapInfo: bitmapInfo.rawValue) {
context.draw(image, in: CGRect(x: 0.0, y: 0.0, width: CGFloat(width), height: CGFloat(height)))
let buffer = data.assumingMemoryBound(to: UInt8.self)
for i in 0..<totalBytes {
print(buffer[i])
}
}
}
}
but I cannot get it to wrk with CGImageAlphaInfo.last so I'm not all that confident this is really what's in the tiff. But for the test pixel [120, 145, 195, 170] I get [155,116
,97,170] (I guess RGB order is reversed?)
ImageMagick give this:
(233,174,145,170) #E9AE91AA srgba(233,174,145,0.666667)
So it seems the problem is the saving rather than the loading.
I'm reading the texture data like this:
let region = MTLRegionMake2D(0, 0, w, h)
var a = Array<UInt8>(repeating:0, count: 4*w*h)
texture.getBytes(&a, bytesPerRow: (4 * MemoryLayout<UInt8>.size * w), from: region, mipmapLevel: 0)
I create textures like this
let descriptor = MTLTextureDescriptor.texture2DDescriptor(pixelFormat:.bgra8Unorm_srgb , width: width, height: height, mipmapped: false)
descriptor.usage = MTLTextureUsage(rawValue: MTLTextureUsage.renderTarget.rawValue | MTLTextureUsage.shaderRead.rawValue | MTLTextureUsage.shaderWrite.rawValue)
let texture = device.makeTexture(descriptor: descriptor)!
And for testing I'm filling the textures with known pixel data like this:
var a:[UInt8] = ...
texture.replace(region: region, mipmapLevel: 0, withBytes: &a, bytesPerRow: (4 * MemoryLayout<UInt8>.size * w))
Then I load the textures from the tiff data with MTKTextureLoader:
func loadTexture(data:Data) throws -> MTLTexture {
let usage = MTLTextureUsage(rawValue: MTLTextureUsage.renderTarget.rawValue | MTLTextureUsage.shaderRead.rawValue | MTLTextureUsage.shaderWrite.rawValue)
return try loader.newTexture(data: data,options:[MTKTextureLoader.Option.textureUsage:usage.rawValue,MTKTextureLoader.Option.origin:MTKTextureLoader.Origin.flippedVertically.rawValue])
}
Problem solved - I just didn't understand how to perform the gesture. It's a two handed gesture, so you need to hold down the option key in the simulator to get two points.