UILabel text duplicates in PDF when containing a certain character

时间:2018-12-19 11:11:49

标签: ios pdf uikit uilabel

I'm generating a PDF something like:

  1. UIGraphicsBeginPDFContextToFile
  2. layer.render(in: context)
  3. UIGraphicsEndPDFContext

Yesterday, I found a fix to make all text vector-based (basically this answer https://stackoverflow.com/a/9056861/897465).

That worked really well, text is vectors and searchable, etc.

Except for one irritating thing.

Everytime a UILabel contains the character "Å", the text is kind of duplicated in the PDF, like the image below. Probably there are other characters as well the would cause this. enter image description here

I've got a small example that demonstrates it below. If you run this in the simulator you'll get a pdf in /tmp/test.pdf where you can see the issue yourself.

I guess I should file a rdar, but I would really like some good workaround (good meaning not checking if label.text contains "Å"). Since I don't think this is something Apple would fix, considering the whole workaround to begin with (PDFLabel).

import UIKit

class PDFLabel: UILabel {

    override func draw(_ layer: CALayer, in ctx: CGContext) {
        let isPDF = !UIGraphicsGetPDFContextBounds().isEmpty
        if !layer.shouldRasterize && isPDF {
            draw(bounds)
        } else {
            super.draw(layer, in: ctx)
        }
    }

}

func generatePDFWith(_ texts: [String]) {
    let paper = CGRect(origin: .zero, size: CGSize(width: 876, height: 1239))

    UIGraphicsBeginPDFContextToFile("/tmp/test.pdf", paper, [
        kCGPDFContextCreator as String: "SampleApp"
    ])

    texts.forEach { text in
        UIGraphicsBeginPDFPage()
        let v = UIView()
        let label = PDFLabel()
        label.text = text
        label.textColor = .black

        v.translatesAutoresizingMaskIntoConstraints = false
        label.translatesAutoresizingMaskIntoConstraints = false

        v.addSubview(label)
        v.widthAnchor.constraint(equalToConstant: 500).isActive = true
        v.heightAnchor.constraint(equalToConstant: 500).isActive = true

        label.centerXAnchor.constraint(equalTo: v.centerXAnchor).isActive = true
        label.centerYAnchor.constraint(equalTo: v.centerYAnchor).isActive = true

        v.setNeedsLayout()
        v.layoutIfNeeded()
        v.layer.render(in: UIGraphicsGetCurrentContext()!)
    }

    UIGraphicsEndPDFContext();
    print("Done!")
}

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        generatePDFWith([
            "Ångavallen",
            "Hey Whatsapp?",
            "Änglavallen",
            "Örebro",
            "Råå",
            "RÅÅ",
            "Å",
            "Ål",
        ])
    }

}

EDIT: Little progress in debugging, it seems that the draw function gets called two times, and the first time it is drawn a little "off" if it has an "Å" (probably any character larger than the box).

So this fixed it for me (however ugly it may be):

class PDFLabel: UILabel {

    var count = 0

    override func draw(_ layer: CALayer, in ctx: CGContext) {
        let isPDF = !UIGraphicsGetPDFContextBounds().isEmpty
        if isPDF {
            if count > 0 { draw(bounds) }
            count += 1
        } else if !layer.shouldRasterize {
            draw(bounds)
        } else {
            super.draw(layer, in: ctx)
        }
    }

}

0 个答案:

没有答案