// // CGImage.swift // Mastodon // // Created by MainasuK Cirno on 2021-3-31. // import CoreImage extension CGImage { // Reference // https://www.itu.int/dms_pubrec/itu-r/rec/bt/R-REC-BT.709-6-201506-I!!PDF-E.pdf // Luma Y = 0.2126R + 0.7152G + 0.0722B var brightness: CGFloat? { let context = CIContext() // default with metal accelerate let ciImage = CIImage(cgImage: self) let rec709Image = context.createCGImage( ciImage, from: ciImage.extent, format: .RGBA8, colorSpace: CGColorSpace(name: CGColorSpace.itur_709) // BT.709 a.k.a Rec.709 ) guard let image = rec709Image, image.bitsPerPixel == 32, let data = rec709Image?.dataProvider?.data, let pointer = CFDataGetBytePtr(data) else { return nil } let length = CFDataGetLength(data) guard length > 0 else { return nil } var luma: CGFloat = 0.0 for i in stride(from: 0, to: length, by: 4) { let r = pointer[i] let g = pointer[i + 1] let b = pointer[i + 2] let Y = 0.2126 * CGFloat(r) + 0.7152 * CGFloat(g) + 0.0722 * CGFloat(b) luma += Y } luma /= CGFloat(width * height) return luma } } #if canImport(SwiftUI) && DEBUG import SwiftUI import UIKit class BrightnessView: UIView { let label = UILabel() let imageView = UIImageView() override init(frame: CGRect) { super.init(frame: frame) let stackView = UIStackView() stackView.axis = .horizontal stackView.translatesAutoresizingMaskIntoConstraints = false addSubview(stackView) NSLayoutConstraint.activate([ stackView.topAnchor.constraint(equalTo: topAnchor), stackView.leadingAnchor.constraint(equalTo: leadingAnchor), stackView.trailingAnchor.constraint(equalTo: trailingAnchor), stackView.bottomAnchor.constraint(equalTo: bottomAnchor), ]) stackView.distribution = .fillEqually stackView.addArrangedSubview(imageView) stackView.addArrangedSubview(label) imageView.contentMode = .scaleAspectFill imageView.layer.masksToBounds = true label.textAlignment = .center label.numberOfLines = 0 } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } func setImage(_ image: UIImage) { imageView.image = image guard let brightness = image.cgImage?.brightness, let style = image.domainLumaCoefficientsStyle else { label.text = "" return } let styleDescription: String = { switch style { case .light: return "Light" case .dark: return "Dark" case .unspecified: fallthrough @unknown default: return "Unknown" } }() label.text = styleDescription + "\n" + "\(brightness)" } } struct CGImage_Brightness_Previews: PreviewProvider { static var previews: some View { Group { UIViewPreview(width: 375) { let view = BrightnessView() view.setImage(.placeholder(color: .black)) return view } .previewLayout(.fixed(width: 375, height: 44)) UIViewPreview(width: 375) { let view = BrightnessView() view.setImage(.placeholder(color: .gray)) return view } .previewLayout(.fixed(width: 375, height: 44)) UIViewPreview(width: 375) { let view = BrightnessView() view.setImage(.placeholder(color: .separator)) return view } .previewLayout(.fixed(width: 375, height: 44)) UIViewPreview(width: 375) { let view = BrightnessView() view.setImage(.placeholder(color: .red)) return view } .previewLayout(.fixed(width: 375, height: 44)) UIViewPreview(width: 375) { let view = BrightnessView() view.setImage(.placeholder(color: .green)) return view } .previewLayout(.fixed(width: 375, height: 44)) UIViewPreview(width: 375) { let view = BrightnessView() view.setImage(.placeholder(color: .blue)) return view } .previewLayout(.fixed(width: 375, height: 44)) UIViewPreview(width: 375) { let view = BrightnessView() view.setImage(.placeholder(color: .secondarySystemGroupedBackground)) return view } .previewLayout(.fixed(width: 375, height: 44)) } } } #endif