mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
121 lines
4.5 KiB
Swift
121 lines
4.5 KiB
Swift
import UIKit
|
|
import Accelerate
|
|
import Display
|
|
|
|
private func generateHistogram(cgImage: CGImage) -> ([[vImagePixelCount]], Int)? {
|
|
var sourceBuffer = vImage_Buffer()
|
|
defer {
|
|
free(sourceBuffer.data)
|
|
}
|
|
|
|
var cgImageFormat = vImage_CGImageFormat(
|
|
bitsPerComponent: UInt32(cgImage.bitsPerComponent),
|
|
bitsPerPixel: UInt32(cgImage.bitsPerPixel),
|
|
colorSpace: Unmanaged.passUnretained(cgImage.colorSpace!),
|
|
bitmapInfo: cgImage.bitmapInfo,
|
|
version: 0,
|
|
decode: nil,
|
|
renderingIntent: .defaultIntent
|
|
)
|
|
|
|
let noFlags = vImage_Flags(kvImageNoFlags)
|
|
var error = vImageBuffer_InitWithCGImage(&sourceBuffer, &cgImageFormat, nil, cgImage, noFlags)
|
|
assert(error == kvImageNoError)
|
|
|
|
if cgImage.alphaInfo == .premultipliedLast {
|
|
error = vImageUnpremultiplyData_RGBA8888(&sourceBuffer, &sourceBuffer, noFlags)
|
|
} else if cgImage.alphaInfo == .premultipliedFirst {
|
|
error = vImageUnpremultiplyData_ARGB8888(&sourceBuffer, &sourceBuffer, noFlags)
|
|
}
|
|
assert(error == kvImageNoError)
|
|
|
|
let histogramBins = (0...3).map { _ in
|
|
return [vImagePixelCount](repeating: 0, count: 256)
|
|
}
|
|
var mutableHistogram: [UnsafeMutablePointer<vImagePixelCount>?] = histogramBins.map {
|
|
return UnsafeMutablePointer<vImagePixelCount>(mutating: $0)
|
|
}
|
|
error = vImageHistogramCalculation_ARGB8888(&sourceBuffer, &mutableHistogram, noFlags)
|
|
assert(error == kvImageNoError)
|
|
|
|
let alphaBinIndex = [.last, .premultipliedLast].contains(cgImage.alphaInfo) ? 3 : 0
|
|
return (histogramBins, alphaBinIndex)
|
|
}
|
|
|
|
public func imageHasTransparency(_ cgImage: CGImage) -> Bool {
|
|
guard cgImage.bitsPerComponent == 8, cgImage.bitsPerPixel == 32 else {
|
|
return false
|
|
}
|
|
guard [.first, .last, .premultipliedFirst, .premultipliedLast].contains(cgImage.alphaInfo) else {
|
|
return false
|
|
}
|
|
if let (histogramBins, alphaBinIndex) = generateHistogram(cgImage: cgImage) {
|
|
let opaqueCount: vImagePixelCount = histogramBins[alphaBinIndex][255]
|
|
var transparentCount: vImagePixelCount = 0
|
|
for i in 0 ..< 255 {
|
|
transparentCount += histogramBins[alphaBinIndex][i]
|
|
}
|
|
let totalCount = opaqueCount + transparentCount
|
|
return Double(transparentCount) / Double(totalCount) > 0.05
|
|
}
|
|
return false
|
|
}
|
|
|
|
private func scaledDrawingContext(_ cgImage: CGImage, maxSize: CGSize) -> DrawingContext {
|
|
var size = CGSize(width: cgImage.width, height: cgImage.height)
|
|
if (size.width > maxSize.width && size.height > maxSize.height) {
|
|
size = size.aspectFilled(maxSize)
|
|
}
|
|
let context = DrawingContext(size: size, scale: 1.0, clear: true)
|
|
context.withFlippedContext { context in
|
|
context.draw(cgImage, in: CGRect(origin: CGPoint(), size: size))
|
|
}
|
|
return context
|
|
}
|
|
|
|
public func imageRequiresInversion(_ cgImage: CGImage) -> Bool {
|
|
guard cgImage.bitsPerComponent == 8, cgImage.bitsPerPixel == 32 else {
|
|
return false
|
|
}
|
|
guard [.first, .last, .premultipliedFirst, .premultipliedLast].contains(cgImage.alphaInfo) else {
|
|
return false
|
|
}
|
|
|
|
let context = scaledDrawingContext(cgImage, maxSize: CGSize(width: 128.0, height: 128.0))
|
|
if let cgImage = context.generateImage()?.cgImage, let (histogramBins, alphaBinIndex) = generateHistogram(cgImage: cgImage) {
|
|
var hasAlpha = false
|
|
for i in 0 ..< 255 {
|
|
if histogramBins[alphaBinIndex][i] > 0 {
|
|
hasAlpha = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if hasAlpha {
|
|
var matching: Int = 0
|
|
var total: Int = 0
|
|
for y in 0 ..< Int(context.size.height) {
|
|
for x in 0 ..< Int(context.size.width) {
|
|
var saturation: CGFloat = 0.0
|
|
var brightness: CGFloat = 0.0
|
|
var alpha: CGFloat = 0.0
|
|
if context.colorAt(CGPoint(x: x, y: y)).getHue(nil, saturation: &saturation, brightness: &brightness, alpha: &alpha) {
|
|
if alpha < 1.0 {
|
|
hasAlpha = true
|
|
}
|
|
|
|
if alpha > 0.0 {
|
|
total += 1
|
|
if saturation < 0.1 && brightness < 0.25 {
|
|
matching += 1
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return CGFloat(matching) / CGFloat(total) > 0.85
|
|
}
|
|
}
|
|
return false
|
|
}
|