提问人:Jabed Dhali 提问时间:11/15/2023 最后编辑:Jabed Dhali 更新时间:11/18/2023 访问量:21
UIGraphicsBeginImageContext 阴影输出与 SwiftUI 视图阴影修饰符不同
UIGraphicsBeginImageContext shadow output is not same as SwiftUI view shadow modifier
问:
我想将一个图像拟合到另一个具有阴影效果的图像上。首先,我按如下方式构建 swiftUI 视图,然后尝试使用 UIGraphicsBeginImageContext 获得相同的输出。但不幸的是,这里发现了问题:输出图像中的阴影模糊与视图不同。我正在寻找合适的解决方案。
struct ContentView: View {
@State private var imageRect : CGRect = .zero
@State private var shadowBlur = 40.0
@State private var shadowX = 100.0
@State private var shadowY = 100.0
var body: some View {
VStack {
GeometryReader(content: { geometry in
ZStack {
Image("background")
.resizable()
.scaledToFit()
.overlay {
Image("foreground")
.resizable()
.scaledToFit()
.shadow(color: Color.red, radius: CGFloat(shadowBlur), x: shadowX, y: shadowY)
}
.clipped()
.background(GeometryGetter(rect: $imageRect))
}
.frame(width: geometry.size.width, height: geometry.size.height)
})
Button("Click") {
let fgImage = UIImage(named: "foreground")!
let bgImage = UIImage(named: "background")!
let scale = bgImage.size.width / imageRect.width
let fgFrame = fgImage.size.scaleSizeToFit(in: bgImage.size)
let fggImage = fgImage.resize(targetSize: fgFrame)
UIGraphicsBeginImageContext(bgImage.size)
bgImage.draw(at: CGPoint.zero)
let context = UIGraphicsGetCurrentContext()
context?.setShadow(offset: CGSize(width: shadowX * scale, height: shadowY * scale), blur: shadowBlur * scale, color: UIColor.red.cgColor)
let imageDrawPoint = CGPoint(x: bgImage.size.width/2.0 - fggImage.size.width / 2.0, y: bgImage.size.height/2.0 - fggImage.size.height / 2.0)
fggImage.draw(at: imageDrawPoint)
let outputImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
print("SUCCESS")
}
}
}
}
extension UIImage {
func resize(targetSize: CGSize) -> UIImage {
let image = self.toCIImage()
let scaleX = targetSize.width / image.extent.size.width
let scaleY = targetSize.height / image.extent.size.height
let scaleTransform = CGAffineTransform(scaleX: scaleX, y: scaleY)
let scaledImage = image.transformed(by: scaleTransform)
return scaledImage.toUIImage()
}
}
extension CGSize {
func scaleSizeToFit(in canvas: CGSize) -> CGSize {
let widthScale = canvas.width / self.width
let heightScale = canvas.height / self.height
let scale = min(widthScale, heightScale)
let scaledSize = CGSize(width: self.width * scale, height: self.height * scale)
return scaledSize
}
}
struct GeometryGetter: View {
@Binding var rect: CGRect
var body: some View {
GeometryReader { (g) -> Path in
print("width: \(g.size.width), height: \(g.size.height)")
DispatchQueue.main.async {
self.rect = g.frame(in: .global)
}
return Path()
}
}
}
答:
1赞
DonMag
11/18/2023
#1
由于自动图像缩放,这可能无法为您提供确切的屏幕内容,但它会更接近......
您需要设置阴影模糊值以匹配屏幕缩放系数,因此请更改:
context?.setShadow(offset: CGSize(width: shadowX * scale, height: shadowY * scale),
blur: shadowBlur * scale,
color: UIColor.red.cgColor)
自:
context?.setShadow(offset: CGSize(width: shadowX * scale, height: shadowY * scale),
blur: shadowBlur * scale * UIScreen.main.scale,
color: UIColor.red.cgColor)
另一种选择是将视图本身()呈现为 -- 搜索会得到很多例子。ZStack
UIImage
How to convert a SwiftUI view to a UIImage
评论
GeometryGetter(rect: $imageRect)
fgImage.size.scaleSizeToFit(in: bgImage.size)
fgImage.resize(targetSize: fgFrame)