1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798 |
- // _____ _
- // |_ _| |_ _ _ ___ ___ _ __ __ _
- // | | | ' \| '_/ -_) -_) ' \/ _` |_
- // |_| |_||_|_| \___\___|_|_|_\__,_(_)
- //
- // Threema iOS Client
- // Copyright (c) 2019-2020 Threema GmbH
- //
- // This program is free software: you can redistribute it and/or modify
- // it under the terms of the GNU Affero General Public License, version 3,
- // as published by the Free Software Foundation.
- //
- // This program is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- // GNU Affero General Public License for more details.
- //
- // You should have received a copy of the GNU Affero General Public License
- // along with this program. If not, see <https://www.gnu.org/licenses/>.
- import Foundation
- @objc class ThreemaQRCodeGenerator: NSObject {
- @objc class func generate(qrString: String, dimension: Int) -> UIImage? {
- guard let qrFilter = CIFilter(name: "CIQRCodeGenerator") else { return nil }
- let qrData = qrString.data(using: String.Encoding.ascii)
- qrFilter.setValue(qrData, forKey: "inputMessage")
- let scale = dimension/39
- let qrTransform = CGAffineTransform.init(scaleX: CGFloat(scale), y: CGFloat(scale))
- guard let qrImage = qrFilter.outputImage?.transformed(by: qrTransform) else { return nil }
-
- guard let logo = BundleUtil.imageNamed("QRLogo").cgImage else {
- return convert(cmage: qrImage)
- }
- guard let threemaQr: CIImage = qrImage.combined(with: CIImage(cgImage: logo)) else {
- return convert(cmage: qrImage)
- }
- return convert(cmage: threemaQr)
- }
-
- class func convert(cmage:CIImage) -> UIImage {
- let context:CIContext = CIContext.init(options: nil)
- let cgImage:CGImage = context.createCGImage(cmage, from: cmage.extent)!
- let image:UIImage = UIImage.init(cgImage: cgImage)
- return image
- }
- }
- extension CIImage {
- /// Inverts the colors and creates a transparent image by converting the mask to alpha.
- /// Input image should be black and white.
- var transparent: CIImage? {
- return inverted?.blackTransparent
- }
-
- /// Inverts the colors.
- var inverted: CIImage? {
- guard let invertedColorFilter = CIFilter(name: "CIColorInvert") else { return nil }
-
- invertedColorFilter.setValue(self, forKey: "inputImage")
- return invertedColorFilter.outputImage
- }
-
- /// Converts all black to transparent.
- var blackTransparent: CIImage? {
- guard let blackTransparentFilter = CIFilter(name: "CIMaskToAlpha") else { return nil }
- blackTransparentFilter.setValue(self, forKey: "inputImage")
- return blackTransparentFilter.outputImage
- }
-
- /// Applies the given color as a tint color.
- func tinted(using color: UIColor) -> CIImage?
- {
- guard
- let transparentQRImage = transparent,
- let filter = CIFilter(name: "CIMultiplyCompositing"),
- let colorFilter = CIFilter(name: "CIConstantColorGenerator") else { return nil }
-
- let ciColor = CIColor(color: color)
- colorFilter.setValue(ciColor, forKey: kCIInputColorKey)
- let colorImage = colorFilter.outputImage
-
- filter.setValue(colorImage, forKey: kCIInputImageKey)
- filter.setValue(transparentQRImage, forKey: kCIInputBackgroundImageKey)
-
- return filter.outputImage!
- }
-
- /// Combines the current image with the given image centered.
- func combined(with image: CIImage) -> CIImage? {
- guard let combinedFilter = CIFilter(name: "CISourceOverCompositing") else { return nil }
- let centerTransform = CGAffineTransform(translationX: extent.midX - (image.extent.size.width / 2), y: extent.midY - (image.extent.size.height / 2))
- combinedFilter.setValue(image.transformed(by: centerTransform), forKey: "inputImage")
- combinedFilter.setValue(self, forKey: "inputBackgroundImage")
- return combinedFilter.outputImage!
- }
- }
|