102 lines
3.8 KiB
Swift
Executable File
102 lines
3.8 KiB
Swift
Executable File
//
|
|
// Swiftfin is subject to the terms of the Mozilla Public
|
|
// License, v2.0. If a copy of the MPL was not distributed with this
|
|
// file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
|
//
|
|
// Copyright (c) 2022 Jellyfin & Jellyfin Contributors
|
|
//
|
|
|
|
import UIKit
|
|
|
|
public extension BlurHash {
|
|
func cgImage(size: CGSize) -> CGImage? {
|
|
let width = Int(size.width)
|
|
let height = Int(size.height)
|
|
let bytesPerRow = width * 3
|
|
|
|
guard let data = CFDataCreateMutable(kCFAllocatorDefault, bytesPerRow * height) else { return nil }
|
|
CFDataSetLength(data, bytesPerRow * height)
|
|
|
|
guard let pixels = CFDataGetMutableBytePtr(data) else { return nil }
|
|
|
|
for y in 0 ..< height {
|
|
for x in 0 ..< width {
|
|
var c: (Float, Float, Float) = (0, 0, 0)
|
|
|
|
for j in 0 ..< numberOfVerticalComponents {
|
|
for i in 0 ..< numberOfHorizontalComponents {
|
|
let basis = cos(Float.pi * Float(x) * Float(i) / Float(width)) * cos(Float.pi * Float(y) * Float(j) / Float(height))
|
|
let component = components[j][i]
|
|
c += component * basis
|
|
}
|
|
}
|
|
|
|
let intR = UInt8(linearTosRGB(c.0))
|
|
let intG = UInt8(linearTosRGB(c.1))
|
|
let intB = UInt8(linearTosRGB(c.2))
|
|
|
|
pixels[3 * x + 0 + y * bytesPerRow] = intR
|
|
pixels[3 * x + 1 + y * bytesPerRow] = intG
|
|
pixels[3 * x + 2 + y * bytesPerRow] = intB
|
|
}
|
|
}
|
|
|
|
let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.none.rawValue)
|
|
|
|
guard let provider = CGDataProvider(data: data) else { return nil }
|
|
guard let cgImage = CGImage(
|
|
width: width,
|
|
height: height,
|
|
bitsPerComponent: 8,
|
|
bitsPerPixel: 24,
|
|
bytesPerRow: bytesPerRow,
|
|
space: CGColorSpaceCreateDeviceRGB(),
|
|
bitmapInfo: bitmapInfo,
|
|
provider: provider,
|
|
decode: nil,
|
|
shouldInterpolate: true,
|
|
intent: .defaultIntent
|
|
) else { return nil }
|
|
|
|
return cgImage
|
|
}
|
|
|
|
func cgImage(numberOfPixels: Int = 1024, originalSize size: CGSize) -> CGImage? {
|
|
let width: CGFloat
|
|
let height: CGFloat
|
|
if size.width > size.height {
|
|
width = floor(sqrt(CGFloat(numberOfPixels) * size.width / size.height) + 0.5)
|
|
height = floor(CGFloat(numberOfPixels) / width + 0.5)
|
|
} else {
|
|
height = floor(sqrt(CGFloat(numberOfPixels) * size.height / size.width) + 0.5)
|
|
width = floor(CGFloat(numberOfPixels) / height + 0.5)
|
|
}
|
|
return cgImage(size: CGSize(width: width, height: height))
|
|
}
|
|
|
|
func image(size: CGSize) -> UIImage? {
|
|
guard let cgImage = cgImage(size: size) else { return nil }
|
|
return UIImage(cgImage: cgImage)
|
|
}
|
|
|
|
func image(numberOfPixels: Int = 1024, originalSize size: CGSize) -> UIImage? {
|
|
guard let cgImage = cgImage(numberOfPixels: numberOfPixels, originalSize: size) else { return nil }
|
|
return UIImage(cgImage: cgImage)
|
|
}
|
|
}
|
|
|
|
@objc
|
|
public extension UIImage {
|
|
convenience init?(blurHash string: String, size: CGSize, punch: Float = 1) {
|
|
guard let blurHash = BlurHash(string: string),
|
|
let cgImage = blurHash.punch(punch).cgImage(size: size) else { return nil }
|
|
self.init(cgImage: cgImage)
|
|
}
|
|
|
|
convenience init?(blurHash string: String, numberOfPixels: Int = 1024, originalSize size: CGSize, punch: Float = 1) {
|
|
guard let blurHash = BlurHash(string: string),
|
|
let cgImage = blurHash.punch(punch).cgImage(numberOfPixels: numberOfPixels, originalSize: size) else { return nil }
|
|
self.init(cgImage: cgImage)
|
|
}
|
|
}
|