|
|
@@ -460,57 +460,42 @@ extension Kingfisher where Base: Image {
|
|
|
let h = Int(size.height)
|
|
|
let rowBytes = Int(CGFloat(cgImage.bytesPerRow))
|
|
|
|
|
|
- let inDataPointer = UnsafeMutablePointer<UInt8>.allocate(capacity: rowBytes * Int(h))
|
|
|
- inDataPointer.initialize(to: 0)
|
|
|
- defer {
|
|
|
- inDataPointer.deinitialize()
|
|
|
- inDataPointer.deallocate(capacity: rowBytes * Int(h))
|
|
|
- }
|
|
|
-
|
|
|
- let bitmapInfo = cgImage.bitmapInfo.fixed
|
|
|
- guard let context = CGContext(data: inDataPointer,
|
|
|
- width: w,
|
|
|
- height: h,
|
|
|
- bitsPerComponent: cgImage.bitsPerComponent,
|
|
|
- bytesPerRow: rowBytes,
|
|
|
- space: cgImage.colorSpace ?? CGColorSpaceCreateDeviceRGB(),
|
|
|
- bitmapInfo: bitmapInfo.rawValue) else
|
|
|
- {
|
|
|
+ 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)
|
|
|
+ }
|
|
|
+
|
|
|
+ guard let context = beginContext() else {
|
|
|
assertionFailure("[Kingfisher] Failed to create CG context for blurring image.")
|
|
|
return base
|
|
|
}
|
|
|
+ defer { endContext() }
|
|
|
|
|
|
- context.draw(cgImage, in: CGRect(x: 0, y: 0, width: w, height: h))
|
|
|
-
|
|
|
+ #if !os(macOS)
|
|
|
+ context.scaleBy(x: 1.0, y: -1.0)
|
|
|
+ context.translateBy(x: 0, y: -size.height)
|
|
|
+ #endif
|
|
|
|
|
|
- var inBuffer = vImage_Buffer(data: inDataPointer, height: vImagePixelCount(h), width: vImagePixelCount(w), rowBytes: rowBytes)
|
|
|
+ context.draw(cgImage, in: CGRect(x: 0, y: 0, width: w, height: h))
|
|
|
|
|
|
- let outDataPointer = UnsafeMutablePointer<UInt8>.allocate(capacity: rowBytes * Int(h))
|
|
|
- outDataPointer.initialize(to: 0)
|
|
|
- defer {
|
|
|
- outDataPointer.deinitialize()
|
|
|
- outDataPointer.deallocate(capacity: rowBytes * Int(h))
|
|
|
- }
|
|
|
+ var inBuffer = createEffectBuffer(context)
|
|
|
|
|
|
- var outBuffer = vImage_Buffer(data: outDataPointer, height: vImagePixelCount(h), width: vImagePixelCount(w), rowBytes: rowBytes)
|
|
|
+ guard let outContext = beginContext() else {
|
|
|
+ assertionFailure("[Kingfisher] Failed to create CG context for blurring image.")
|
|
|
+ return base
|
|
|
+ }
|
|
|
+ defer { endContext() }
|
|
|
+ var outBuffer = createEffectBuffer(outContext)
|
|
|
|
|
|
for _ in 0 ..< iterations {
|
|
|
vImageBoxConvolve_ARGB8888(&inBuffer, &outBuffer, nil, 0, 0, UInt32(targetRadius), UInt32(targetRadius), nil, vImage_Flags(kvImageEdgeExtend))
|
|
|
(inBuffer, outBuffer) = (outBuffer, inBuffer)
|
|
|
}
|
|
|
|
|
|
- guard let outContext = CGContext(data: inDataPointer,
|
|
|
- width: w,
|
|
|
- height: h,
|
|
|
- bitsPerComponent: cgImage.bitsPerComponent,
|
|
|
- bytesPerRow: rowBytes,
|
|
|
- space: cgImage.colorSpace ?? CGColorSpaceCreateDeviceRGB(),
|
|
|
- bitmapInfo: bitmapInfo.rawValue) else
|
|
|
- {
|
|
|
- assertionFailure("[Kingfisher] Failed to create CG context for blurring image.")
|
|
|
- return base
|
|
|
- }
|
|
|
-
|
|
|
#if os(macOS)
|
|
|
let result = outContext.makeImage().flatMap { fixedForRetinaPixel(cgImage: $0, to: size) }
|
|
|
#else
|
|
|
@@ -615,13 +600,13 @@ extension Kingfisher where Base: Image {
|
|
|
return base
|
|
|
}
|
|
|
let colorSpace = CGColorSpaceCreateDeviceRGB()
|
|
|
- let bitmapInfo = imageRef.bitmapInfo.fixed
|
|
|
-
|
|
|
- guard let context = CGContext(data: nil, width: imageRef.width, height: imageRef.height, bitsPerComponent: 8, bytesPerRow: 0, space: colorSpace, bitmapInfo: bitmapInfo.rawValue) else {
|
|
|
+ guard let context = beginContext() else {
|
|
|
assertionFailure("[Kingfisher] Decoding fails to create a valid context.")
|
|
|
return base
|
|
|
}
|
|
|
|
|
|
+ defer { endContext() }
|
|
|
+
|
|
|
let rect = CGRect(x: 0, y: 0, width: imageRef.width, height: imageRef.height)
|
|
|
context.draw(imageRef, in: rect)
|
|
|
let decompressedImageRef = context.makeImage()
|
|
|
@@ -721,24 +706,48 @@ extension CGSizeProxy {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-extension CGBitmapInfo {
|
|
|
- var fixed: CGBitmapInfo {
|
|
|
- var fixed = self
|
|
|
- let alpha = (rawValue & CGBitmapInfo.alphaInfoMask.rawValue)
|
|
|
- if alpha == CGImageAlphaInfo.none.rawValue {
|
|
|
- fixed.remove(.alphaInfoMask)
|
|
|
- fixed = CGBitmapInfo(rawValue: fixed.rawValue | CGImageAlphaInfo.noneSkipFirst.rawValue)
|
|
|
- } else if !(alpha == CGImageAlphaInfo.noneSkipFirst.rawValue) || !(alpha == CGImageAlphaInfo.noneSkipLast.rawValue) {
|
|
|
- fixed.remove(.alphaInfoMask)
|
|
|
- fixed = CGBitmapInfo(rawValue: fixed.rawValue | CGImageAlphaInfo.premultipliedFirst.rawValue)
|
|
|
- }
|
|
|
- return fixed
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
extension Kingfisher where Base: Image {
|
|
|
|
|
|
+ func beginContext() -> CGContext? {
|
|
|
+ #if os(macOS)
|
|
|
+ guard let rep = NSBitmapImageRep(
|
|
|
+ bitmapDataPlanes: nil,
|
|
|
+ pixelsWide: Int(size.width),
|
|
|
+ pixelsHigh: Int(size.height),
|
|
|
+ bitsPerSample: cgImage?.bitsPerComponent ?? 8,
|
|
|
+ samplesPerPixel: 4,
|
|
|
+ hasAlpha: true,
|
|
|
+ isPlanar: false,
|
|
|
+ colorSpaceName: NSCalibratedRGBColorSpace,
|
|
|
+ bytesPerRow: 0,
|
|
|
+ bitsPerPixel: 0) else
|
|
|
+ {
|
|
|
+ assertionFailure("[Kingfisher] Image representation cannot be created.")
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+ rep.size = size
|
|
|
+ NSGraphicsContext.saveGraphicsState()
|
|
|
+ guard let context = NSGraphicsContext(bitmapImageRep: rep) else {
|
|
|
+ assertionFailure("[Kingfisher] Image contenxt cannot be created.")
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+
|
|
|
+ NSGraphicsContext.setCurrent(context)
|
|
|
+ return context.cgContext
|
|
|
+ #else
|
|
|
+ UIGraphicsBeginImageContextWithOptions(size, false, scale)
|
|
|
+ return UIGraphicsGetCurrentContext()
|
|
|
+ #endif
|
|
|
+ }
|
|
|
+
|
|
|
+ func endContext() {
|
|
|
+ #if os(macOS)
|
|
|
+ NSGraphicsContext.restoreGraphicsState()
|
|
|
+ #else
|
|
|
+ UIGraphicsEndImageContext()
|
|
|
+ #endif
|
|
|
+ }
|
|
|
+
|
|
|
func draw(cgImage: CGImage?, to size: CGSize, draw: ()->()) -> Image {
|
|
|
#if os(macOS)
|
|
|
guard let rep = NSBitmapImageRep(
|
|
|
@@ -791,36 +800,6 @@ extension Kingfisher where Base: Image {
|
|
|
#endif
|
|
|
}
|
|
|
|
|
|
-
|
|
|
-extension CGContext {
|
|
|
- static func createARGBContext(from imageRef: CGImage) -> CGContext? {
|
|
|
-
|
|
|
- let w = imageRef.width
|
|
|
- let h = imageRef.height
|
|
|
- let bytesPerRow = w * 4
|
|
|
- let colorSpace = CGColorSpaceCreateDeviceRGB()
|
|
|
-
|
|
|
- let data = malloc(bytesPerRow * h)
|
|
|
- defer {
|
|
|
- free(data)
|
|
|
- }
|
|
|
-
|
|
|
- let bitmapInfo = imageRef.bitmapInfo.fixed
|
|
|
-
|
|
|
- // Create the bitmap context. We want pre-multiplied ARGB, 8-bits
|
|
|
- // per component. Regardless of what the source image format is
|
|
|
- // (CMYK, Grayscale, and so on) it will be converted over to the format
|
|
|
- // specified here.
|
|
|
- return CGContext(data: data,
|
|
|
- width: w,
|
|
|
- height: h,
|
|
|
- bitsPerComponent: imageRef.bitsPerComponent,
|
|
|
- bytesPerRow: bytesPerRow,
|
|
|
- space: colorSpace,
|
|
|
- bitmapInfo: bitmapInfo.rawValue)
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
extension Double {
|
|
|
var isEven: Bool {
|
|
|
return truncatingRemainder(dividingBy: 2.0) == 0
|