// 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(iOS 9999, macOS 9999, tvOS 9999, watchOS 9999, *) { 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 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(buffer: vImage_Buffer, channelCount: Int, count: Int) -> Array { if (buffer.rowBytes == Int(buffer.width) * MemoryLayout.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.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 = 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()