2025-04-08 14:38:46 +04:00

117 lines
4.3 KiB
Swift

import UIKit
import Accelerate
private func imageBuffer(from data: UnsafeMutableRawPointer!, width: vImagePixelCount, height: vImagePixelCount, rowBytes: Int) -> vImage_Buffer {
return vImage_Buffer(data: data, height: vImagePixelCount(height), width: vImagePixelCount(width), rowBytes: rowBytes)
}
public func blurredImage(_ image: UIImage, radius: CGFloat, iterations: Int = 3) -> UIImage? {
guard let cgImage = image.cgImage, let providerData = cgImage.dataProvider?.data else {
return nil
}
if image.size.width <= 0.0 || image.size.height <= 0 || radius <= 0 {
return image
}
var boxSize = UInt32(radius)
if boxSize % 2 == 0 {
boxSize += 1
}
let bytes = cgImage.bytesPerRow * cgImage.height
let inData = malloc(bytes)
var inBuffer = imageBuffer(from: inData, width: vImagePixelCount(cgImage.width), height: vImagePixelCount(cgImage.height), rowBytes: cgImage.bytesPerRow)
let outData = malloc(bytes)
var outBuffer = imageBuffer(from: outData, width: vImagePixelCount(cgImage.width), height: vImagePixelCount(cgImage.height), rowBytes: cgImage.bytesPerRow)
let tempSize = vImageBoxConvolve_ARGB8888(&inBuffer, &outBuffer, nil, 0, 0, boxSize, boxSize, nil, vImage_Flags(kvImageEdgeExtend + kvImageGetTempBufferSize))
let tempData = malloc(tempSize)
defer {
free(inData)
free(outData)
free(tempData)
}
let source = CFDataGetBytePtr(providerData)
memcpy(inBuffer.data, source, bytes)
for _ in 0 ..< iterations {
vImageBoxConvolve_ARGB8888(&inBuffer, &outBuffer, tempData, 0, 0, boxSize, boxSize, nil, vImage_Flags(kvImageEdgeExtend))
let temp = inBuffer.data
inBuffer.data = outBuffer.data
outBuffer.data = temp
}
let context = cgImage.colorSpace.flatMap {
CGContext(data: inBuffer.data, width: cgImage.width, height: cgImage.height, bitsPerComponent: cgImage.bitsPerComponent, bytesPerRow: cgImage.bytesPerRow, space: $0, bitmapInfo: cgImage.bitmapInfo.rawValue)
}
let blurredCGImage = context?.makeImage()
if let blurredCGImage = blurredCGImage {
return UIImage(cgImage: blurredCGImage, scale: image.scale, orientation: image.imageOrientation)
} else {
return nil
}
}
public func verticalBlurredImage(_ image: UIImage, radius: CGFloat, iterations: Int = 3) -> UIImage? {
guard let cgImage = image.cgImage, let providerData = cgImage.dataProvider?.data else {
return nil
}
if image.size.width <= 0.0 || image.size.height <= 0 || radius <= 0 {
return image
}
var boxSize = UInt32(radius)
if boxSize % 2 == 0 {
boxSize += 1
}
let bytes = cgImage.bytesPerRow * cgImage.height
let inData = malloc(bytes)
var inBuffer = imageBuffer(from: inData, width: vImagePixelCount(cgImage.width), height: vImagePixelCount(cgImage.height), rowBytes: cgImage.bytesPerRow)
let outData = malloc(bytes)
var outBuffer = imageBuffer(from: outData, width: vImagePixelCount(cgImage.width), height: vImagePixelCount(cgImage.height), rowBytes: cgImage.bytesPerRow)
let tempSize = vImageBoxConvolve_ARGB8888(&inBuffer, &outBuffer, nil, 0, 0, boxSize, 1, nil, vImage_Flags(kvImageEdgeExtend + kvImageGetTempBufferSize))
let tempData = malloc(tempSize)
defer {
free(inData)
free(outData)
free(tempData)
}
let source = CFDataGetBytePtr(providerData)
memcpy(inBuffer.data, source, bytes)
for _ in 0 ..< iterations {
vImageBoxConvolve_ARGB8888(&inBuffer, &outBuffer, tempData, 0, 0, boxSize, 1, nil, vImage_Flags(kvImageEdgeExtend))
let temp = inBuffer.data
inBuffer.data = outBuffer.data
outBuffer.data = temp
}
let context = cgImage.colorSpace.flatMap {
CGContext(data: inBuffer.data, width: cgImage.width, height: cgImage.height, bitsPerComponent: cgImage.bitsPerComponent, bytesPerRow: cgImage.bytesPerRow, space: $0, bitmapInfo: cgImage.bitmapInfo.rawValue)
}
let blurredCGImage = context?.makeImage()
if let blurredCGImage = blurredCGImage {
return UIImage(cgImage: blurredCGImage, scale: image.scale, orientation: image.imageOrientation)
} else {
return nil
}
}