user979331
user979331

Reputation: 11951

CGContext renders text upside down

I am rendering a NSAttributedString with CGContext, however when it renders the text is upside down :(

This is what I came up with:

override func draw(with box: PDFDisplayBox, in context: CGContext) {

        UIGraphicsPushContext(context)
        context.saveGState()

        let paragraphStyle = NSMutableParagraphStyle()
        paragraphStyle.alignment = .center

        let attributes = [
            NSAttributedString.Key.paragraphStyle: paragraphStyle,
            NSAttributedString.Key.font: UIFont.systemFont(ofSize: 80.0),
            NSAttributedString.Key.foregroundColor: UIColor.red
        ]

        NSAttributedString(string: self.widgetStringValue!, attributes: attributes).draw(in: self.bounds)


        context.restoreGState()
        UIGraphicsPopContext()

    }

I have tried adding this:

context.translateBy(x: 0.0, y: bounds.height)  
context.scaleBy(x: 1.0, y: -1.0)

But then the text does not appear on my screen at all :(

What am I doing wrong?

UPDATE

As requested here is my full TextAnnotation class:

class TextAnnotation:  PDFAnnotation {

    var currentText: String?

    override init(bounds: CGRect, forType annotationType: PDFAnnotationSubtype, withProperties properties: [AnyHashable : Any]?) {
        super.init(bounds: bounds, forType: annotationType, withProperties: properties)

        self.widgetFieldType = PDFAnnotationWidgetSubtype(rawValue: PDFAnnotationWidgetSubtype.text.rawValue)

        self.font = UIFont.systemFont(ofSize: 80)

        self.isMultiline = true

        self.widgetStringValue = "Text Here"

        self.currentText = self.widgetStringValue!
    }

    override func draw(with box: PDFDisplayBox, in context: CGContext) {
        UIGraphicsPushContext(context)
        context.saveGState()

        let pageBounds = bounds
        context.translateBy(x: 0, y: pageBounds.height)
        context.scaleBy(x: 1, y: -1)

        let paragraphStyle = NSMutableParagraphStyle()
        paragraphStyle.alignment = .center

        let attributes: [NSAttributedString.Key: Any] = [
            .paragraphStyle: paragraphStyle,
            .font: UIFont.systemFont(ofSize: 80),
            .foregroundColor: UIColor.red
        ]

        widgetStringValue!.draw(in: pageBounds, withAttributes: attributes)

        context.restoreGState()
        UIGraphicsPopContext()
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

}

Upvotes: 2

Views: 576

Answers (2)

Swindler
Swindler

Reputation: 810

In my case, I was subclassing a PDFAnnotation. The key was using the correct y-value (which was a pain to figure out) for the translateBy call in my draw method:

override func draw(with box: PDFDisplayBox, in context: CGContext) {
    let text = NSString(string: "Hello!")

    UIGraphicsPushContext(context)
    context.saveGState()

    context.translateBy(x: 0, y: bounds.height + (2 * bounds.minY))
    context.scaleBy(x: 1, y: -1.0)
    text.draw(in: bounds.offsetBy(dx: 2, dy: 0), withAttributes: attributes)

    context.restoreGState()
    UIGraphicsPopContext()
}

Upvotes: 2

Rob
Rob

Reputation: 438232

In a PDFAnnotation, you should just add the translateBy(x:y:) and scaledBy(x:y:) as you’ve discussed:

override func draw(with box: PDFDisplayBox, in context: CGContext) {
    UIGraphicsPushContext(context)
    context.saveGState()

    context.translateBy(x: 0, y: bounds.height)
    context.scaleBy(x: 1, y: -1)

    let paragraphStyle = NSMutableParagraphStyle()
    paragraphStyle.alignment = .center

    let attributes: [NSAttributedString.Key: Any] = [
        .paragraphStyle:  paragraphStyle,
        .font:            UIFont.systemFont(ofSize: 80),
        .foregroundColor: UIColor.red
    ]

    widgetStringValue?.draw(in: bounds, withAttributes: attributes)

    context.restoreGState()
    UIGraphicsPopContext()
}

In a PDFPage you should use bounds(for:) to get the bounds within that PDFDisplayBox, and then use translateBy(x:y:) and scaledBy(x:y:) as you’ve discussed:

override func draw(with box: PDFDisplayBox, to context: CGContext) {
    UIGraphicsPushContext(context)
    context.saveGState()

    let pageBounds = bounds(for: box)
    context.translateBy(x: 0, y: pageBounds.height)
    context.scaleBy(x: 1, y: -1)

    let paragraphStyle = NSMutableParagraphStyle()
    paragraphStyle.alignment = .center

    let attributes: [NSAttributedString.Key: Any] = [
        .paragraphStyle:  paragraphStyle,
        .font:            UIFont.systemFont(ofSize: 80),
        .foregroundColor: UIColor.red
    ]

    text.draw(in: pageBounds, withAttributes: attributes)

    context.restoreGState()
    UIGraphicsPopContext()
}

Upvotes: 0

Related Questions