I have a goal to convert View to Image using SwiftUI.
From the first image I have a look that is exactly what I want.
Link picture View will be convert to an Image:
but when I convert the display to an image, the background object and the sticker (Santa's hat) size and position are messed up, even though I've made it neat and fit exactly what I want. the following is the result of the image:
View results that have been converted into an Image:
This is my Code View
import SwiftUI
struct SnapshotView: View {
@ObservedObject var effectData: EffectViewModel
@ObservedObject var eraseModel: EraseViewModel
@ObservedObject var stickerData: StickerViewModel
@Binding var image: UIImage?
@Binding var isActive: Bool
@Binding var isEffectAvailable: Bool
@Binding var sliderValueBlur: Double
init(image: Binding<UIImage?>, isActive: Binding<Bool>,
isEffectAvailable: Binding<Bool>,
sliderValueBlur: Binding<Double>,
effectData: ObservedObject<EffectViewModel>,
eraseModel: ObservedObject<EraseViewModel>,
stickerData: ObservedObject<StickerViewModel>) {
_image = image
_isActive = isActive
_isEffectAvailable = isEffectAvailable
_sliderValueBlur = sliderValueBlur
_effectData = effectData
_eraseModel = eraseModel
_stickerData = stickerData
}
var body: some View {
GeometryReader { geo in
VStack {
ZStack(alignment: .center) {
if isEffectAvailable {
VStack {
Image(uiImage: self.effectData.modelEffect!.image_effect)
.resizable()
.scaledToFit()
.frame(width: geo.size.width, alignment: .center)
.position(self.effectData.modelEffect!.position_effect)
.scaleEffect(self.effectData.modelEffect!.currentScale)
.mask(
Image(uiImage: image!)
.resizable()
.scaledToFit()
.frame(width: geo.size.width, alignment: .center)
)
.blur(radius: CGFloat(self.effectData.modelEffect!.valueBlur))
.opacity(self.effectData.modelEffect!.opacity_effect)
}
.background(
ZStack {
Image(uiImage: image!)
.resizable()
.scaledToFit()
.frame(width: geo.size.width, alignment: .top)
.blur(radius: CGFloat(sliderValueBlur)*4)
}
.border(Color.black, width: 1)
)
} else {
ZStack {
Image(uiImage: image!)
.resizable()
.scaledToFit()
.frame(width: geo.size.width, alignment: .top)
.blur(radius: CGFloat(sliderValueBlur)*4)
}
.border(Color.black, width: 1)
}
Image(uiImage: self.eraseModel.inputImage)
.resizable()
.scaledToFit()
.frame(width: geo.size.width, alignment: .center)
.overlay(
VStack {
ForEach(stickerData.selectedSticker.indices, id: \.self) { index in
ZStack(alignment: .bottomTrailing) {
Image(uiImage: stickerData.selectedSticker[index].image)
.resizable()
.frame(width: stickerData.selectedSticker[index].width, height: stickerData.selectedSticker[index].height, alignment: .center)
.scaleEffect(stickerData.selectedSticker[index].scale)
.overlay(
Rectangle()
.stroke(Color.gray, lineWidth: stickerData.selectedSticker[index].isEditing ? 4 : 0)
)
}
.frame(width: 130, height: 130, alignment: .center)
.position(stickerData.selectedSticker[index].position)
.scaleEffect(stickerData.selectedSticker[index].scale)
}
}
)
}
}
}
}
}
And this is the function I use to convert View to Image
extension UIView {
var renderedImage: UIImage {
// rect of capure
let rect = self.bounds
// create the context of bitmap
UIGraphicsBeginImageContextWithOptions(rect.size, false, 0.0)
let context: CGContext = UIGraphicsGetCurrentContext()!
self.layer.render(in: context)
// get a image from current context bitmap
let capturedImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return capturedImage
}
}
extension View {
func takeScreenshot(origin: CGPoint, size: CGSize) -> UIImage {
let window = UIWindow(frame: CGRect(origin: origin, size: size))
let hosting = UIHostingController(rootView: self)
hosting.view.frame = window.frame
window.addSubview(hosting.view)
window.makeKeyAndVisible()
return hosting.view.renderedImage
}
}
Usage example:
Button(action: {
let viewSnapshot = SnapshotView(image: self.$image, isActive: self.$isActive, isEffectAvailable: self.$isEffectAvailable, sliderValueBlur: self.$sliderValueBlur, effectData: self._effectData, eraseModel: self._eraseModel, stickerData: self._stickerData)
let saveImage = viewSnapshot.takeScreenshot(origin: geo.frame(in: .global).origin, size: self.image!.size)
UIImageWriteToSavedPhotosAlbum(saveImage, nil, nil, nil)
}, label: {
Text("SAVE")
.foregroundColor(.white)
})
Maybe you can help me, what's wrong here