Reputation: 74
Im rendering pdf from html content with help of UIPrintPageRenderer, unfortunately sometimes occurs bug, when one element is divided on to parts on different pages. Is there any way to avoid id?
My code and screenshots below:
UIPrintPageRenderer inheritance to specify pdf details.
public class CustomPrintPageRenderer: UIPrintPageRenderer {
fileprivate let offsetX: CGFloat = 40.0
fileprivate let offsetY: CGFloat = 12.0
fileprivate let kHeaderHeight: CGFloat = 36
fileprivate let kFooterHeight: CGFloat = 36
fileprivate let debugFrame = false
fileprivate var name: String?
fileprivate var policy: String?
init(name: String, policy: String, content: String) {
self.name = name
self.policy = policy
super.init()
// Set the page frame.
setValue(NSValue(cgRect: App.A4Rect), forKey: "paperRect")
// Set the printing area frame.
setValue(NSValue(cgRect: App.A4Rect.insetBy(dx: 0, dy: 0)), forKey: "printableRect")
headerHeight = kHeaderHeight
footerHeight = kFooterHeight
// Create formatter
let formatter = UIMarkupTextPrintFormatter(markupText: content)
formatter.perPageContentInsets = UIEdgeInsets(top: kHeaderHeight + 15, left: 36, bottom: 0, right: 36)
addPrintFormatter(formatter, startingAtPageAt: 0)
}
override public func drawHeaderForPage(at pageIndex: Int, in headerRect: CGRect) {
if let name = name as NSString?, let policy = policy as NSString? {
add(name: name, policy: policy, in: headerRect)
}
addLogo(in: headerRect)
if debugFrame {
let path = UIBezierPath(rect: headerRect)
UIColor.red.set()
path.stroke()
}
}
override public func drawFooterForPage(at pageIndex: Int, in footerRect: CGRect) {
addPageNumber(at: pageIndex, in: footerRect)
if debugFrame {
let path = UIBezierPath(rect: footerRect)
UIColor.red.set()
path.stroke()
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// MARK: -
extension CustomPrintPageRenderer {
fileprivate func addLogo(in headerRect: CGRect) {
let image = #imageLiteral(resourceName: "mss-logo")
let desiredHeight: CGFloat = 40
let newWidth = (desiredHeight * image.size.width) / image.size.height
let imageSize = CGSize(width: newWidth, height: desiredHeight)
let imageRect = CGRect(
x: headerRect.width - imageSize.width - offsetX,
y: headerRect.height - imageSize.height + offsetY,
width: imageSize.width,
height: imageSize.height)
image.draw(in: imageRect)
}
fileprivate func add(name: NSString, policy: NSString, in headerRect: CGRect) {
let text = "\(policy) - \(name)"
let font = UIFont(name: "HelveticaNeue", size: 12.0)
let textSize = getTextSize(text: text as String, font: font!)
let pointX = offsetX
let pointY = headerRect.height - textSize.height
let attributes = [NSAttributedStringKey.font: font!, NSAttributedStringKey.foregroundColor: Color.lightGray]
text.draw(at: CGPoint(x: pointX, y: pointY), withAttributes: attributes)
}
fileprivate func addPageNumber(at pageIndex: Int, in footerRect: CGRect) {
let footerText: NSString = "Page \(pageIndex + 1) of \(numberOfPages)" as NSString
let font = UIFont(name: "HelveticaNeue", size: 12.0)
let textSize = getTextSize(text: footerText as String, font: font!)
let pointX = footerRect.width - textSize.width - offsetX
let pointY = footerRect.origin.y + footerRect.height - textSize.height - 25
let attributes = [NSAttributedStringKey.font: font!]
footerText.draw(at: CGPoint(x: pointX, y: pointY), withAttributes: attributes)
}
fileprivate func getTextSize(text: String, font: UIFont!, textAttributes: [NSAttributedStringKey: AnyObject]! = nil) -> CGSize {
let testLabel = UILabel(frame: CGRect(x: 0.0, y: 0.0, width: paperRect.width, height: footerHeight))
if let attributes = textAttributes {
testLabel.attributedText = NSAttributedString(string: text, attributes: attributes)
}
else {
testLabel.text = text
testLabel.font = font!
}
testLabel.sizeToFit()
return testLabel.frame.size
}
}
** Alert html **
HTML I use to compose alert and add it to pdf.
<tr>
<td></td>
</tr>
<tr>
<div>
<td class="alert" colspan="2">#TEXT#</td>
</div>
</tr>
<tr>
<td></td>
</tr>
** And pdf drawing **
This is how I draw pdf with CustomPrintPageRenderer.
fileprivate func drawPDFUsingPrintPageRenderer(printPageRenderer: UIPrintPageRenderer) -> NSData! {
let data = NSMutableData()
UIGraphicsBeginPDFContextToData(data, App.A4Rect, nil)
for i in 0 ..< printPageRenderer.numberOfPages {
UIGraphicsBeginPDFPage()
printPageRenderer.drawPage(at: i, in: UIGraphicsGetPDFContextBounds())
}
UIGraphicsEndPDFContext()
return data
}
Will be much appreciated for any help!
Upvotes: 0
Views: 506
Reputation: 1755
@media print {
.pagebreak-before:first-child { display: block; page-break-before: avoid; }
.pagebreak-before { display: block; page-break-before: always; }
button {
page-break-inside: avoid;
}
}
Then you probably use those in a class element. Use page break-before for images, etc.
Upvotes: 1