2
votes

I've created several UIViews inside of a UIScrollView that resize dynamically based on values I type into Height and Width text fields. Once the UIView resizes I save the contents of the UIScrollView as PDF data.

I find that the dimensions of the UIView within the PDF (when measured in Adobe Illustrator) are always rounded to a third.

For example:

1.5 -> 1.333

1.75 -> 1.666

I check the constant values each time before the constraints are updated and they are accurate. Can anyone explain why the UIViews have incorrect dimensions once rendered as a PDF?

@IBAction func updateDimensions(_ sender: Any) {

        guard let length = NumberFormatter().number(from:
            lengthTextField.text ?? "") else { return }

        guard let width = NumberFormatter().number(from:
            widthTextField.text ?? "") else { return }

        guard let height = NumberFormatter().number(from:
            heightTextField.text ?? "") else { return }

        let flapHeight = CGFloat(truncating: width)/2

        let lengthFloat = CGFloat(truncating: length)
        let widthFloat = CGFloat(truncating: width)
        let heightFloat = CGFloat(truncating: height)

        UIView.animate(withDuration: 0.3) {
            self.faceAWidthConstraint.constant = lengthFloat
            self.faceAHeightConstraint.constant = heightFloat
            self.faceBWidthConstraint.constant = widthFloat
            self.faceA1HeightConstraint.constant = flapHeight
            self.view.layoutIfNeeded()
        }
    }

    func createPDFfrom(aView: UIView, saveToDocumentsWithFileName fileName: String)
    {
        let pdfData = NSMutableData()
        UIGraphicsBeginPDFContextToData(pdfData, aView.bounds, nil)
        UIGraphicsBeginPDFPage()

        guard let pdfContext = UIGraphicsGetCurrentContext() else { return }

        aView.layer.render(in: pdfContext)
        UIGraphicsEndPDFContext()

        if let documentDirectories = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first {
            let documentsFileName = documentDirectories + "/" + fileName
            debugPrint(documentsFileName)
            pdfData.write(toFile: documentsFileName, atomically: true)
        }
    }
1

1 Answers

1
votes

You should not be using layer.render(in:) to render your pdf. The reason its always a third is because you must be on a 3x device (it would be 1/2 on a 2x device and simply 1 on a 1x device), so there are 3 pixels per point. When iOS converts your constraints to pixels, then best it can do is round to the nearest third because its picking an integer pixel. The pdf can have much higher pixel density (or use vector art with infinite) resolution, so instead of using layer.render(in:), which is dumping pixels in the rasterized vector layer into your PDF, you should actually draw the contents into the PDF context manually (ie use UIBezier curve, UIImage.draw, etc). This will allow the pdf to capture the full resolution of any rasterized images you have and will allow it to capture any vectors you use without degrading them into rasterized pixels that are constrained by the device screen that you happen to be on.