Skip to content

Commit

Permalink
Do not trust image color space and bitmap info
Browse files Browse the repository at this point in the history
Force use an alpha based rgb
  • Loading branch information
onevcat committed Jul 16, 2024
1 parent 2239ba5 commit e4d98dc
Showing 1 changed file with 22 additions and 28 deletions.
50 changes: 22 additions & 28 deletions Sources/Image/ImageDrawing.swift
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ extension KingfisherWrapper where Base: KFCrossPlatformImage {
/// > This method is only applicable to CG-based images. The current image scale is preserved.
/// > For any non-CG-based image, the `base` image itself is returned.
public func blurred(withRadius radius: CGFloat) -> KFCrossPlatformImage {
guard let cgImage = cgImage, let colorSpace = cgImage.colorSpace else {
guard let cgImage = cgImage else {
assertionFailure("[Kingfisher] Blur only works for CG-based image.")
return base
}
Expand Down Expand Up @@ -332,40 +332,34 @@ extension KingfisherWrapper where Base: KFCrossPlatformImage {
iterations = 3
}

let inProvider = cgImage.dataProvider
func createEffectBuffer(_ context: CGContext) -> vImage_Buffer {
let data = context.data
let width = vImagePixelCount(context.width)
let height = vImagePixelCount(context.height)
let rowBytes = context.bytesPerRow

return vImage_Buffer(data: data, height: height, width: width, rowBytes: rowBytes)
}

let width = vImagePixelCount(cgImage.width)
let height = vImagePixelCount(cgImage.height)
let rowBytes = cgImage.bytesPerRow

let inBitmapData = inProvider?.data
guard let inputContext = CGContext.fresh(cgImage: cgImage) else {
return base
}
inputContext.draw(cgImage, in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
var inBuffer = createEffectBuffer(inputContext)

let inData = UnsafeMutableRawPointer(mutating: CFDataGetBytePtr(inBitmapData))
var inBuffer = vImage_Buffer(data: inData, height: height, width: width, rowBytes: rowBytes)
guard let outContext = CGContext.fresh(cgImage: cgImage) else {
return base
}
var outBuffer = createEffectBuffer(outContext)

let outData = malloc(cgImage.bytesPerRow * cgImage.height)
defer { free(outData) }
var outBuffer = vImage_Buffer(data: outData, height: height, width: width, rowBytes: rowBytes)

for _ in 0 ..< iterations {
let flag = vImage_Flags(kvImageEdgeExtend)
vImageBoxConvolve_ARGB8888(
&inBuffer, &outBuffer, nil, 0, 0, UInt32(targetRadius), UInt32(targetRadius), nil, flag)
// Next inBuffer should be the outButter of current iteration
(inBuffer, outBuffer) = (outBuffer, inBuffer)
}
guard let outContext = CGContext(
data: outBuffer.data,
width: cgImage.width,
height: cgImage.height,
bitsPerComponent: cgImage.bitsPerComponent,
bytesPerRow: cgImage.bytesPerRow,
space: colorSpace,
bitmapInfo: cgImage.bitmapInfo.rawValue
) ?? .fallback(data: outBuffer.data, cgImage: cgImage) else {
assertionFailure("[Kingfisher] Creating CG context failed.")
return base
}

#if os(macOS)
let result = outContext.makeImage().flatMap {
fixedForRetinaPixel(cgImage: $0, to: size)
Expand Down Expand Up @@ -696,9 +690,9 @@ extension KingfisherWrapper where Base: KFCrossPlatformImage {
}

extension CGContext {
fileprivate static func fallback(data: UnsafeMutableRawPointer?, cgImage: CGImage) -> CGContext? {
return CGContext(
data: data,
fileprivate static func fresh(cgImage: CGImage) -> CGContext? {
CGContext(
data: nil,
width: cgImage.width,
height: cgImage.height,
bitsPerComponent: 8,
Expand Down

0 comments on commit e4d98dc

Please sign in to comment.