ios: colored and clickable qr code with logo (#1885)
* ios: colored and clickable qr code with logo * size of circle * same padding as in android * add padding to logo --------- Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
5082f5b4a4
commit
8a445ece90
@@ -133,7 +133,7 @@ func imageHasAlpha(_ img: UIImage) -> Bool {
|
||||
context.draw(cgImage, in: CGRect(x: 0, y: 0, width: cgImage.width, height: cgImage.height))
|
||||
if let data = context.data {
|
||||
let data = data.assumingMemoryBound(to: UInt8.self)
|
||||
let size = cgImage.width * cgImage.height
|
||||
let size = cgImage.width * cgImage.height * 4
|
||||
var i = 0
|
||||
while i < size {
|
||||
if data[i] < 255 { return true }
|
||||
@@ -203,3 +203,51 @@ func dropImagePrefix(_ s: String) -> String {
|
||||
private func dropPrefix(_ s: String, _ prefix: String) -> String {
|
||||
s.hasPrefix(prefix) ? String(s.dropFirst(prefix.count)) : s
|
||||
}
|
||||
|
||||
extension UIImage {
|
||||
func replaceColor(_ from: UIColor, _ to: UIColor) -> UIImage {
|
||||
if let cgImage = cgImage {
|
||||
let colorSpace = CGColorSpaceCreateDeviceRGB()
|
||||
let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedFirst.rawValue)
|
||||
if let context = CGContext(data: nil, width: cgImage.width, height: cgImage.height, bitsPerComponent: 8, bytesPerRow: cgImage.width * 4, space: colorSpace, bitmapInfo: bitmapInfo.rawValue) {
|
||||
context.draw(cgImage, in: CGRect(x: 0, y: 0, width: cgImage.width, height: cgImage.height))
|
||||
if let data = context.data {
|
||||
var fromAlpha: CGFloat = 0
|
||||
var fromRed: CGFloat = 0
|
||||
var fromGreen: CGFloat = 0
|
||||
var fromBlue: CGFloat = 0
|
||||
var toAlpha: CGFloat = 0
|
||||
var toRed: CGFloat = 0
|
||||
var toGreen: CGFloat = 0
|
||||
var toBlue: CGFloat = 0
|
||||
from.getRed(&fromRed, green: &fromGreen, blue: &fromBlue, alpha: &fromAlpha)
|
||||
to.getRed(&toRed, green: &toGreen, blue: &toBlue, alpha: &toAlpha)
|
||||
let fAlpha = UInt8(UInt8(fromAlpha * 255))
|
||||
let fRed = UInt8(fromRed * 255)
|
||||
let fGreen = UInt8(fromGreen * 255)
|
||||
let fBlue = UInt8(fromBlue * 255)
|
||||
let tAlpha = UInt8(toAlpha * 255)
|
||||
let tRed = UInt8(toRed * 255)
|
||||
let tGreen = UInt8(toGreen * 255)
|
||||
let tBlue = UInt8(toBlue * 255)
|
||||
let data = data.assumingMemoryBound(to: UInt8.self)
|
||||
let size = cgImage.width * cgImage.height * 4
|
||||
var i = 0
|
||||
while i < size {
|
||||
if data[i] == fAlpha && data[i + 1] == fRed && data[i + 2] == fGreen && data[i + 3] == fBlue {
|
||||
data[i + 0] = tAlpha
|
||||
data[i + 1] = tRed
|
||||
data[i + 2] = tGreen
|
||||
data[i + 3] = tBlue
|
||||
}
|
||||
i += 4
|
||||
}
|
||||
}
|
||||
if let img = context.makeImage() {
|
||||
return UIImage(cgImage: img)
|
||||
}
|
||||
}
|
||||
}
|
||||
return self
|
||||
}
|
||||
}
|
||||
@@ -30,17 +30,42 @@ struct MutableQRCode: View {
|
||||
|
||||
struct QRCode: View {
|
||||
let uri: String
|
||||
@State private var image: UIImage?
|
||||
var withLogo: Bool = true
|
||||
var tintColor = UIColor(red: 0.023, green: 0.176, blue: 0.337, alpha: 1)
|
||||
@State private var image: UIImage? = nil
|
||||
@State private var makeScreenshotBinding: () -> Void = {}
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
if let image = image {
|
||||
qrCodeImage(image)
|
||||
}
|
||||
GeometryReader { geo in
|
||||
ZStack {
|
||||
if withLogo {
|
||||
let w = geo.size.width
|
||||
Image("icon-light")
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
.frame(width: w * 0.16, height: w * 0.16)
|
||||
.frame(width: w * 0.165, height: w * 0.165)
|
||||
.background(.white)
|
||||
.clipShape(Circle())
|
||||
}
|
||||
}
|
||||
.onAppear {
|
||||
makeScreenshotBinding = {
|
||||
showShareSheet(items: [makeScreenshot(geo.frame(in: .local).origin, geo.size)])
|
||||
}
|
||||
}
|
||||
.frame(width: geo.size.width, height: geo.size.height)
|
||||
}
|
||||
}
|
||||
.onTapGesture(perform: makeScreenshotBinding)
|
||||
.onAppear {
|
||||
image = image ?? generateImage(uri)
|
||||
image = image ?? generateImage(uri)?.replaceColor(UIColor.black, tintColor)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,6 +88,20 @@ private func generateImage(_ uri: String) -> UIImage? {
|
||||
return nil
|
||||
}
|
||||
|
||||
extension View {
|
||||
func makeScreenshot(_ origin: CGPoint? = nil, _ targetSize: CGSize? = nil) -> UIImage {
|
||||
let controller = UIHostingController(rootView: self.edgesIgnoringSafeArea(.all))
|
||||
let targetSize = targetSize ?? controller.view.intrinsicContentSize
|
||||
let view = controller.view
|
||||
view?.bounds = CGRect(origin: origin ?? .zero, size: targetSize)
|
||||
view?.backgroundColor = .clear
|
||||
let renderer = UIGraphicsImageRenderer(size: targetSize)
|
||||
return renderer.image { _ in
|
||||
view?.drawHierarchy(in: controller.view.bounds, afterScreenUpdates: true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct QRCode_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
QRCode(uri: "https://simplex.chat/invitation#/?v=1&smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FFe5ICmvrm4wkrr6X1LTMii-lhBqLeB76%23MCowBQYDK2VuAyEAdhZZsHpuaAk3Hh1q0uNb_6hGTpuwBIrsp2z9U2T0oC0%3D&e2e=v%3D1%26x3dh%3DMEIwBQYDK2VvAzkAcz6jJk71InuxA0bOX7OUhddfB8Ov7xwQIlIDeXBRZaOntUU4brU5Y3rBzroZBdQJi0FKdtt_D7I%3D%2CMEIwBQYDK2VvAzkA-hDvk1duBi1hlOr08VWSI-Ou4JNNSQjseY69QyKm7Kgg1zZjbpGfyBqSZ2eqys6xtoV4ZtoQUXQ%3D")
|
||||
|
||||
Reference in New Issue
Block a user