Question
I have an iOS app that takes an html file, turns it into a PDF, and displays it to a WebKit web view. I have a weird problem where the bottom table cell gets cut off when I display to PDF. The weird thing is that the bottom table is only cut off when the text is centered. If it is left-aligned, everything works fine. Why does this happen?
Please note that I am not looking for a work around solution. Rather, I am seeking to understand why this happens. Is this a bug in iOS? Or did I miss something?
Overview
In the image below, there are two tables <table>
. One table is large, has a reddish (coral) background, and has a height of 505px. The other table is below the first with a white background (height is not set). Both have some text. The text is centered for both tables.
The navbar title shows the details of the current view. For example, as shown in the image below, a title of PDF Landscape 505 means that the view shows a PDF in landscape dimensions with a main table height of 505px.
The Problem
The problem arises when I increase the height by 10px. In the image below, the main table height is 515px and the lower table is now cut off.
Take the exact same html and css code and change only the text-alignment to be left-aligned. Now the lower table is not cut off anymore. I also changed the background color to green for distinction. Green means that text is left-aligned. Red means that text is centered.
The following image shows a main-table height of 745px and still the lower table is not cut off because it is left-aligned.
Code
Below is the html code used for this test.
<!DOCTYPE html>
<html>
<head>
<title>#COLOR#</title>
<meta charset="utf-8">
<style>
table, th, td {
border-collapse: collapse;
border: 3px solid black;
text-align: #ALIGN#;
}
table.main-table {
width: 1012px;
height: #HEIGHT#px;
background-color: #COLOR#;
}
table.bottom-table {
width: 1012px;
}
</style>
</head>
<body>
<table class="main-table">
<tr><td>Hello World.</td></tr>
</table>
<table class="bottom-table">
<tr><td>This text gets cut off when centered. It does *not* get cut when left-aligned.</td></tr>
</table>
</body>
</html>
In MyViewController
, the getHTML()
function pulls the html source from sample.html
. The function then replaces #ALIGN#
, #COLOR#
, and #HEIGHT#
with their respective values.
func getHTML() -> String? {
let htmlPath: String? = Bundle.main.path(forResource: htmlResource, ofType: "html")
guard let path = htmlPath else { return nil }
do {
// Load the HTML template code into a String variable.
var html = try String(contentsOfFile: path)
html = html.replacingOccurrences(of: "#HEIGHT#", with: tableHeight.description)
html = html.replacingOccurrences(of: "#COLOR#", with: colorState.rawValue)
html = html.replacingOccurrences(of: "#ALIGN#", with: alignState.rawValue)
return html
} catch {
print("Error: " + error.localizedDescription)
}
return nil
}
The PDFBuilder class handles the PDF creation with one function:
static func exportHTMLToPDF(html: String, frame: CGRect) -> Data {
// Set a printable frame and inset
let pageFrame = frame
let insetRect = pageFrame.insetBy(dx: 10.0, dy: 10.0)
// Create a UIPrintPageRenderer and set the paperRect and printableRect using above values.
let pageRenderer = UIPrintPageRenderer()
pageRenderer.setValue(pageFrame, forKey: "paperRect")
pageRenderer.setValue(insetRect, forKey: "printableRect")
// Create a printFormatter and pass the HTML code as a string.
let printFormatter = UIMarkupTextPrintFormatter(markupText: html)
// Add the printFormatter to the pageRenderer
pageRenderer.addPrintFormatter(printFormatter, startingAtPageAt: 0)
// This data var is where the PDF will be stored once created.
let data = NSMutableData()
// This is where the PDF gets drawn.
UIGraphicsBeginPDFContextToData(data, pageFrame, nil)
UIGraphicsBeginPDFPage()
pageRenderer.drawPage(at: 0, in: UIGraphicsGetPDFContextBounds())
print("bounds: " + UIGraphicsGetPDFContextBounds().debugDescription)
UIGraphicsEndPDFContext()
return data as Data
}
This project is also on Github: https://github.com/starkindustries/PrintPDFTest
Troubleshooting Steps Taken
App Notes
The top toolbar has two buttons: green and red. Green makes the text left-aligned. Red makes the text centered.
The bottom toolbar has five buttons: rewind, html, portrait, landscape, and fast forward. The rewind button reduces the main table's height by 10px. Fast forward increases the height by 10px. The html button shows the html view. Portrait and landscape show PDF's in their respective orientations.
I had many troubles with PDF rendering in order to keep the exact same aspect and size then my HTML file once transformed (mostly because of resolution translation problems).
The best and simpliest workaround that I found is to encapsulate the content in a container that exactly fit the height of the document. You can use the media query to apply your css code only on the print result if you want to display your source html file.
table, th, td {
border-collapse: collapse;
border: 3px solid black;
text-align: center;
}
table.main-table {
width: 1012px;
height: 515px;
background-color: #f4f4f4;
}
table.bottom-table {
width: 1012px;
}
@media print {
.main-container{
height:1100px;/* adjust the height to fit your PDF document*/
}
}
<div class="main-container">
<table class="main-table">
<tr><td>Hello World.</td></tr>
</table>
<table class="bottom-table">
<tr><td>This text gets cut off when centered. It does *not* get cut when left-aligned.</td></tr>
</table>
</div>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With