swiftuiuigraphicsimagerenderer

ImageRenderer omits curved text - Bug?


I am using the CrookedText library to generate curved text around a circle.

My app is supposed to print the image that is generated via ImageRenderer, but fails to include the curved text, although it is properly rendered on the screen when I present the same view:

Here's an image with the current result (top image) and the expected output (bottom image):

upper part - renderedImage, lower part original

The code:

struct CardPresenterView: View {
    
    @State private var renderedImage = Image(systemName: "photo")
    
    var body: some View {
        VStack() {
            Spacer()
            OptionView()
            Spacer()
            renderedImage
                .shadow(radius: 10)
            Spacer()
            CardView()
               .aspectRatio(2/3, contentMode: .fit)
            
           Spacer()
               ShareLink("Export", item: renderedImage, preview: SharePreview(Text("Shared image"), image: renderedImage))
        }
        .onAppear { render() }
    }
    
    @MainActor func render() {
         let renderer = ImageRenderer(content: CardView().aspectRatio(2/3, contentMode: .fit))
         if let uiImage = renderer.uiImage {
             renderedImage = Image(uiImage: uiImage)
         }
     }
}

I cannot explain this behavior, is this an XCode bug?


Solution

  • If the library would be using a Canvas to draw the curved text then, according to the ImageRenderer documentation, it should work. So it must be drawing it in some way which is not compatible with ImageRenderer.

    You could try using CurvedText from this answer instead. This is a SwiftUI solution for curved text (it was my answer). Doing it this way, the rendered version seems to work fine, as the following (improvised) version of CardView demonstrates. The values for .trim and .rotationEffect were found with a little trial and error:

    struct CardView: View {
        var body: some View {
            ZStack {
                Circle()
                    .fill(.yellow)
                    .frame(width: 300, height: 300)
                Circle()
                    .trim(from: 0, to: 0.28)
                    .stroke(.red, lineWidth: 40)
                    .rotationEffect(.degrees(-0.58 * 360))
                    .padding(20)
                Circle()
                    .trim(from: 0, to: 0.32)
                    .stroke(.red, lineWidth: 40)
                    .rotationEffect(.degrees(-0.2 * 360))
                    .padding(20)
    
                // See https://stackoverflow.com/a/77280669/20386264
                CurvedText(string: "The quick brown fox", radius: 130)
                    .font(.title2)
                    .offset(y: -130)
                    .rotationEffect(.degrees(-0.19 * 360))
                CurvedText(string: "jumps over the lazy dog", radius: 130)
                    .font(.title2)
                    .offset(y: -130)
                    .rotationEffect(.degrees(0.21 * 360))
            }
        }
    }
    

    Screenshot