blob: 2d301ae8bc2cc88afd27859f3a32d974d808ce2c [file] [log] [blame] [edit]
// RUN: %target-run-simple-swift
// REQUIRES: executable_test
// REQUIRES: rdar50244151
// REQUIRES: objc_interop
// UNSUPPORTED: OS=watchos
import StdlibUnittest
import Accelerate
var Accelerate_vImageTests = TestSuite("Accelerate_vImage")
if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) {
let width = UInt(64)
let height = UInt(32)
let widthi = 64
let heighti = 32
//===----------------------------------------------------------------------===//
//
// MARK: Converter
//
//===----------------------------------------------------------------------===//
Accelerate_vImageTests.test("vImage/CVConverters") {
let colorSpace = CGColorSpaceCreateDeviceRGB()
let cgFormat = vImage_CGImageFormat(bitsPerComponent: 8,
bitsPerPixel: 32,
colorSpace: colorSpace,
bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.first.rawValue),
renderingIntent: .defaultIntent)!
let cvFormat = vImageCVImageFormat.make(format: .format32ABGR,
matrix: kvImage_ARGBToYpCbCrMatrix_ITU_R_601_4.pointee,
chromaSiting: .center,
colorSpace: colorSpace,
alphaIsOpaqueHint: false)!
let coreVideoToCoreGraphics = try! vImageConverter.make(sourceFormat: cvFormat,
destinationFormat: cgFormat,
flags: .printDiagnosticsToConsole)
let coreGraphicsToCoreVideo = try! vImageConverter.make(sourceFormat: cgFormat,
destinationFormat: cvFormat,
flags: .printDiagnosticsToConsole)
let pixels: [UInt8] = (0 ..< width * height * 4).map { _ in
return UInt8.random(in: 0 ..< 255)
}
let image = makeRGBA8888Image(from: pixels,
width: width,
height: height)!
let sourceCGBuffer = try! vImage_Buffer(cgImage: image)
var intermediateCVBuffer = try! vImage_Buffer(width: widthi, height: heighti, bitsPerPixel: 32)
var destinationCGBuffer = try! vImage_Buffer(width: widthi, height: heighti, bitsPerPixel: 32)
try! coreGraphicsToCoreVideo.convert(source: sourceCGBuffer,
destination: &intermediateCVBuffer)
try! coreVideoToCoreGraphics.convert(source: intermediateCVBuffer,
destination: &destinationCGBuffer)
let destinationPixels: [UInt8] = arrayFromBuffer(buffer: destinationCGBuffer,
channelCount: 4,
count: pixels.count)
expectEqual(destinationPixels, pixels)
expectEqual(coreVideoToCoreGraphics.destinationBuffers(colorSpace: colorSpace),
coreGraphicsToCoreVideo.sourceBuffers(colorSpace: colorSpace))
expectEqual(coreVideoToCoreGraphics.sourceBuffers(colorSpace: colorSpace),
coreGraphicsToCoreVideo.destinationBuffers(colorSpace: colorSpace))
}
/* Disabled due to <rdar://problem/50209312>
Accelerate_vImageTests.test("vImage/BufferOrder") {
let sourceFormat = vImage_CGImageFormat(bitsPerComponent: 8,
bitsPerPixel: 32,
colorSpace: CGColorSpaceCreateDeviceCMYK(),
bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.none.rawValue),
renderingIntent: .defaultIntent)!
let destinationFormat = vImage_CGImageFormat(bitsPerComponent: 8,
bitsPerPixel: 24,
colorSpace: CGColorSpace(name: CGColorSpace.genericLab)!,
bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.none.rawValue),
renderingIntent: .defaultIntent)!
let converter = try! vImageConverter.make(sourceFormat: sourceFormat,
destinationFormat: destinationFormat)
let sBuffers = converter.sourceBuffers(colorSpace: sourceFormat.colorSpace.takeRetainedValue())
let dBuffers = converter.destinationBuffers(colorSpace: destinationFormat.colorSpace.takeRetainedValue())
expectEqual(sBuffers, [.coreGraphics])
expectEqual(dBuffers, [.coreGraphics])
}
*/
Accelerate_vImageTests.test("vImage/AnyToAnyError") {
var error = kvImageNoError
let format = vImage_CGImageFormat(bitsPerComponent: 8,
bitsPerPixel: 32,
colorSpace: CGColorSpaceCreateDeviceCMYK(),
bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.none.rawValue),
renderingIntent: .defaultIntent)!
expectCrashLater()
_ = try! vImageConverter.make(sourceFormat: format,
destinationFormat: format,
flags: .imageExtend)
}
Accelerate_vImageTests.test("vImage/AnyToAny") {
let pixels: [UInt8] = (0 ..< width * height * 4).map { _ in
return UInt8.random(in: 0 ..< 255)
}
let image = makeRGBA8888Image(from: pixels,
width: width,
height: height)!
let sourceFormat = vImage_CGImageFormat(cgImage: image)!
let destinationFormat = vImage_CGImageFormat(bitsPerComponent: 8,
bitsPerPixel: 32,
colorSpace: CGColorSpaceCreateDeviceCMYK(),
bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.none.rawValue),
renderingIntent: .defaultIntent)!
let sourceBuffer = try! vImage_Buffer(cgImage: image)
var destinationBuffer = try! vImage_Buffer(width: widthi, height: heighti,
bitsPerPixel: 32)
// New API
let converter = try! vImageConverter.make(sourceFormat: sourceFormat,
destinationFormat: destinationFormat)
try! converter.convert(source: sourceBuffer,
destination: &destinationBuffer)
let mustOperateOutOfPlace = try! converter.mustOperateOutOfPlace(source: sourceBuffer,
destination: destinationBuffer)
// Legacy API
var legacyDestinationBuffer = try! vImage_Buffer(width: widthi, height: heighti,
bitsPerPixel: 32)
var legacyConverter: vImageConverter?
withUnsafePointer(to: destinationFormat) { dest in
withUnsafePointer(to: sourceFormat) { src in
legacyConverter = vImageConverter_CreateWithCGImageFormat(
src,
dest,
nil,
vImage_Flags(kvImageNoFlags),
nil)?.takeRetainedValue()
}
}
_ = withUnsafePointer(to: sourceBuffer) { src in
vImageConvert_AnyToAny(legacyConverter!,
src,
&legacyDestinationBuffer,
nil,
vImage_Flags(kvImageNoFlags))
}
var e = kvImageNoError
withUnsafePointer(to: sourceBuffer) { src in
withUnsafePointer(to: destinationBuffer) { dest in
e = vImageConverter_MustOperateOutOfPlace(legacyConverter!,
src,
dest,
vImage_Flags(kvImageNoFlags))
}
}
let legacyMustOperateOutOfPlace = e == kvImageOutOfPlaceOperationRequired
// Compare results
let destinationPixels: [UInt8] = arrayFromBuffer(buffer: destinationBuffer,
channelCount: 4,
count: pixels.count)
let legacyDestinationPixels: [UInt8] = arrayFromBuffer(buffer: legacyDestinationBuffer,
channelCount: 4,
count: pixels.count)
expectTrue(legacyDestinationPixels.elementsEqual(destinationPixels))
expectEqual(converter.sourceBufferCount, 1)
expectEqual(converter.destinationBufferCount, 1)
expectEqual(legacyMustOperateOutOfPlace, mustOperateOutOfPlace)
sourceBuffer.free()
destinationBuffer.free()
legacyDestinationBuffer.free()
}
//===----------------------------------------------------------------------===//
//
// MARK: Buffer
//
//===----------------------------------------------------------------------===//
Accelerate_vImageTests.test("vImage/IllegalSize") {
expectCrashLater()
let buffer = try! vImage_Buffer(width: -1, height: -1,
bitsPerPixel: 32)
}
Accelerate_vImageTests.test("vImage/IllegalSize") {
expectCrashLater()
let buffer = try! vImage_Buffer(width: 99999999, height: 99999999,
bitsPerPixel: 99999999)
}
Accelerate_vImageTests.test("vImage/InitWithInvalidImageFormat") {
let pixels: [UInt8] = (0 ..< width * height).map { _ in
return UInt8.random(in: 0 ..< 255)
}
let image = makePlanar8Image(from: pixels,
width: width,
height: height)!
let format = vImage_CGImageFormat(bitsPerComponent: 8,
bitsPerPixel: 32,
colorSpace: CGColorSpace(name: CGColorSpace.sRGB)!,
bitmapInfo: CGBitmapInfo(rawValue: 0))!
var error = kvImageNoError
expectCrashLater()
let buffer = try! vImage_Buffer(cgImage: image,
format: format)
}
Accelerate_vImageTests.test("vImage/CreateCGImage") {
let pixels: [UInt8] = (0 ..< width * height * 4).map { _ in
return UInt8.random(in: 0 ..< 255)
}
let image = makeRGBA8888Image(from: pixels,
width: width,
height: height)!
let buffer = try! vImage_Buffer(cgImage: image)
let format = vImage_CGImageFormat(cgImage: image)!
let bufferImage = try! buffer.createCGImage(format: format)
let imagePixels = imageToPixels(image: image)
let bufferImagePixels = imageToPixels(image: bufferImage)
expectTrue(imagePixels.elementsEqual(bufferImagePixels))
buffer.free()
}
Accelerate_vImageTests.test("vImage/CopyBadWidth") {
var source = try! vImage_Buffer(width: 10, height: 100, bitsPerPixel: 32)
var destination = try! vImage_Buffer(width: 20, height: 20, bitsPerPixel: 32)
expectCrashLater()
try! source.copy(destinationBuffer: &destination,
pixelSize: 4)
}
Accelerate_vImageTests.test("vImage/CopyBadHeight") {
var source = try! vImage_Buffer(width: 100, height: 10, bitsPerPixel: 32)
var destination = try! vImage_Buffer(width: 20, height: 20, bitsPerPixel: 32)
expectCrashLater()
try! source.copy(destinationBuffer: &destination,
pixelSize: 4)
}
Accelerate_vImageTests.test("vImage/Copy") {
let pixels: [UInt8] = (0 ..< width * height * 4).map { _ in
return UInt8.random(in: 0 ..< 255)
}
let image = makeRGBA8888Image(from: pixels,
width: width,
height: height)!
let source = try! vImage_Buffer(cgImage: image)
var destination = try! vImage_Buffer(width: widthi, height: heighti,
bitsPerPixel: 32)
try! source.copy(destinationBuffer: &destination,
pixelSize: 4)
let sourcePixels: [UInt8] = arrayFromBuffer(buffer: source,
channelCount: 4,
count: pixels.count)
let destinationPixels: [UInt8] = arrayFromBuffer(buffer: destination,
channelCount: 4,
count: pixels.count)
expectTrue(sourcePixels.elementsEqual(destinationPixels))
source.free()
destination.free()
}
Accelerate_vImageTests.test("vImage/InitializeWithFormat") {
let pixels: [UInt8] = (0 ..< width * height * 4).map { _ in
return UInt8.random(in: 0 ..< 255)
}
let image = makeRGBA8888Image(from: pixels,
width: width,
height: height)!
let format = vImage_CGImageFormat(cgImage: image)!
let buffer = try! vImage_Buffer(cgImage: image,
format: format)
let bufferPixels: [UInt8] = arrayFromBuffer(buffer: buffer,
channelCount: 4,
count: pixels.count)
expectTrue(bufferPixels.elementsEqual(pixels))
expectEqual(buffer.rowBytes, Int(width) * 4)
expectEqual(buffer.width, width)
expectEqual(buffer.height, height)
buffer.free()
}
Accelerate_vImageTests.test("vImage/Alignment") {
// New API
var alignment = try! vImage_Buffer.preferredAlignmentAndRowBytes(width: widthi,
height: heighti,
bitsPerPixel: 32)
// Legacy API
var legacyBuffer = vImage_Buffer()
let legacyAlignment = vImageBuffer_Init(&legacyBuffer,
height, width,
32,
vImage_Flags(kvImageNoAllocate))
expectEqual(alignment.alignment, legacyAlignment)
expectEqual(alignment.rowBytes, legacyBuffer.rowBytes)
legacyBuffer.free()
}
Accelerate_vImageTests.test("vImage/CreateBufferFromCGImage") {
let pixels: [UInt8] = (0 ..< width * height * 4).map { _ in
return UInt8.random(in: 0 ..< 255)
}
let image = makeRGBA8888Image(from: pixels,
width: width,
height: height)!
// New API
let buffer = try! vImage_Buffer(cgImage: image)
// Legacy API
let legacyBuffer: vImage_Buffer = {
var format = vImage_CGImageFormat(cgImage: image)!
var buffer = vImage_Buffer()
vImageBuffer_InitWithCGImage(&buffer,
&format,
nil,
image,
vImage_Flags(kvImageNoFlags))
return buffer
}()
let bufferPixels: [UInt8] = arrayFromBuffer(buffer: buffer,
channelCount: 4,
count: pixels.count)
let legacyBufferPixels: [UInt8] = arrayFromBuffer(buffer: legacyBuffer,
channelCount: 4,
count: pixels.count)
expectTrue(bufferPixels.elementsEqual(legacyBufferPixels))
expectEqual(buffer.width, legacyBuffer.width)
expectEqual(buffer.height, legacyBuffer.height)
expectEqual(buffer.rowBytes, legacyBuffer.rowBytes)
expectEqual(buffer.size, CGSize(width: Int(width),
height: Int(height)))
buffer.free()
free(legacyBuffer.data)
}
//===----------------------------------------------------------------------===//
//
// MARK: CVImageFormat
//
//===----------------------------------------------------------------------===//
Accelerate_vImageTests.test("vImage/MakeFromPixelBuffer") {
let pixelBuffer = makePixelBuffer(pixelFormat: kCVPixelFormatType_420YpCbCr8Planar)!
let format = vImageCVImageFormat.make(buffer: pixelBuffer)!
expectEqual(format.channels, [vImage.BufferType.luminance,
vImage.BufferType.Cb,
vImage.BufferType.Cr])
}
Accelerate_vImageTests.test("vImage/MakeFormat4444YpCbCrA8") {
let format = vImageCVImageFormat.make(format: .format4444YpCbCrA8,
matrix: kvImage_ARGBToYpCbCrMatrix_ITU_R_709_2.pointee,
chromaSiting: .center,
colorSpace: CGColorSpaceCreateDeviceRGB(),
alphaIsOpaqueHint: false)!
// test alphaIsOpaqueHint
expectEqual(format.alphaIsOpaqueHint, false)
format.alphaIsOpaqueHint = true
expectEqual(format.alphaIsOpaqueHint, true)
// test colorSpace
expectEqual(String(format.colorSpace!.name!), "kCGColorSpaceDeviceRGB")
format.colorSpace = CGColorSpace(name: CGColorSpace.extendedLinearSRGB)!
expectEqual(String(format.colorSpace!.name!), "kCGColorSpaceExtendedLinearSRGB")
// test channel names
let channels = format.channels
expectEqual(channels,
[vImage.BufferType.Cb,
vImage.BufferType.luminance,
vImage.BufferType.Cr,
vImage.BufferType.alpha])
let description = format.channelDescription(bufferType: channels.first!)
expectEqual(description?.min, 0)
expectEqual(description?.max, 255)
expectEqual(description?.full, 240)
expectEqual(description?.zero, 128)
}
Accelerate_vImageTests.test("vImage/MakeFormat420YpCbCr8Planar") {
let format = vImageCVImageFormat.make(format: .format420YpCbCr8Planar,
matrix: kvImage_ARGBToYpCbCrMatrix_ITU_R_709_2.pointee,
chromaSiting: .center,
colorSpace: CGColorSpaceCreateDeviceRGB(),
alphaIsOpaqueHint: false)!
// test chromaSiting
expectEqual(format.chromaSiting, vImageCVImageFormat.ChromaSiting.center)
format.chromaSiting = .dv420
expectEqual(format.chromaSiting, vImageCVImageFormat.ChromaSiting.dv420)
// test formatCode
expectEqual(format.formatCode, kCVPixelFormatType_420YpCbCr8Planar)
// test channelCount
expectEqual(format.channelCount, 3)
}
//===----------------------------------------------------------------------===//
//
// MARK: CGImageFormat
//
//===----------------------------------------------------------------------===//
Accelerate_vImageTests.test("vImage/CGImageFormatIllegalValues") {
let formatOne = vImage_CGImageFormat(bitsPerComponent: -1,
bitsPerPixel: 32,
colorSpace: CGColorSpaceCreateDeviceRGB(),
bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedFirst.rawValue))
let formatTwo = vImage_CGImageFormat(bitsPerComponent: 8,
bitsPerPixel: -1,
colorSpace: CGColorSpaceCreateDeviceRGB(),
bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedFirst.rawValue))
expectTrue(formatOne == nil)
expectTrue(formatTwo == nil)
}
Accelerate_vImageTests.test("vImage/CGImageFormatFromCGImage") {
let pixels: [UInt8] = (0 ..< width * height).map { _ in
return UInt8.random(in: 0 ..< 255)
}
let image = makePlanar8Image(from: pixels,
width: width,
height: height)!
var format = vImage_CGImageFormat(cgImage: image)!
var legacyFormat = vImage_CGImageFormat(bitsPerComponent: 8,
bitsPerPixel: 8,
colorSpace: Unmanaged.passRetained(CGColorSpaceCreateDeviceGray()),
bitmapInfo: CGBitmapInfo(rawValue: 0),
version: 0,
decode: nil,
renderingIntent: .defaultIntent)
expectTrue(vImageCGImageFormat_IsEqual(&format, &legacyFormat))
}
Accelerate_vImageTests.test("vImage/CGImageFormatLightweightInit") {
let colorspace = CGColorSpaceCreateDeviceRGB()
let renderingIntent = CGColorRenderingIntent.defaultIntent
let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedFirst.rawValue)
var format = vImage_CGImageFormat(bitsPerComponent: 8,
bitsPerPixel: 32,
colorSpace: colorspace,
bitmapInfo: bitmapInfo)!
var legacyFormat = vImage_CGImageFormat(bitsPerComponent: 8,
bitsPerPixel: 32,
colorSpace: Unmanaged.passRetained(colorspace),
bitmapInfo: bitmapInfo,
version: 0,
decode: nil,
renderingIntent: renderingIntent)
expectTrue(vImageCGImageFormat_IsEqual(&format, &legacyFormat))
expectTrue(format.componentCount == 4)
}
//===----------------------------------------------------------------------===//
//
// MARK: Helper Functions
//
//===----------------------------------------------------------------------===//
func makePixelBuffer(pixelFormat: OSType) -> CVPixelBuffer? {
var pixelBuffer: CVPixelBuffer? = nil
CVPixelBufferCreate(kCFAllocatorDefault,
1,
1,
pixelFormat,
[:] as CFDictionary?,
&pixelBuffer)
return pixelBuffer
}
func arrayFromBuffer<T>(buffer: vImage_Buffer,
channelCount: Int,
count: Int) -> Array<T> {
if (buffer.rowBytes == Int(buffer.width) * MemoryLayout<T>.stride * channelCount) {
let ptr = buffer.data.bindMemory(to: T.self,
capacity: count)
let buf = UnsafeBufferPointer(start: ptr, count: count)
return Array(buf)
} else {
var returnArray = [T]()
let perRowCount = Int(buffer.width) * MemoryLayout<T>.stride * channelCount
var ptr = buffer.data.bindMemory(to: T.self,
capacity: perRowCount)
for _ in 0 ..< buffer.height {
let buf = UnsafeBufferPointer(start: ptr, count: perRowCount)
returnArray.append(contentsOf: Array(buf))
ptr = ptr.advanced(by: buffer.rowBytes)
}
return returnArray
}
}
func imageToPixels(image: CGImage) -> [UInt8] {
let pixelCount = image.width * image.height
let pixelData = image.dataProvider?.data
let pixels: UnsafePointer<UInt8> = CFDataGetBytePtr(pixelData)
let buf = UnsafeBufferPointer(start: pixels, count: pixelCount)
return Array(buf)
}
func makePlanar8Image(from pixels: [UInt8],
width: UInt,
height: UInt) -> CGImage? {
if
let outputData = CFDataCreate(nil, pixels, pixels.count),
let cgDataProvider = CGDataProvider(data: outputData) {
return CGImage(width: Int(width),
height: Int(height),
bitsPerComponent: 8,
bitsPerPixel: 8,
bytesPerRow: Int(width),
space: CGColorSpaceCreateDeviceGray(),
bitmapInfo: CGBitmapInfo(rawValue: 0),
provider: cgDataProvider,
decode: nil,
shouldInterpolate: false,
intent: CGColorRenderingIntent.defaultIntent)
}
return nil
}
func makeRGBA8888Image(from pixels: [UInt8],
width: UInt,
height: UInt) -> CGImage? {
if
let outputData = CFDataCreate(nil, pixels, pixels.count),
let cgDataProvider = CGDataProvider(data: outputData) {
return CGImage(width: Int(width),
height: Int(height),
bitsPerComponent: 8,
bitsPerPixel: 8 * 4,
bytesPerRow: Int(width) * 4,
space: CGColorSpace(name: CGColorSpace.sRGB)!,
bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.last.rawValue),
provider: cgDataProvider,
decode: nil,
shouldInterpolate: false,
intent: CGColorRenderingIntent.defaultIntent)
}
return nil
}
}
runAllTests()