Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding a header image and a PDFTable in the document header cuts off the top of the table #318

Open
brendand opened this issue Dec 16, 2022 · 3 comments

Comments

@brendand
Copy link
Contributor

ℹ Please fill out this template when filing an issue.
All lines beginning with an ℹ symbol instruct you with what info we expect. You can delete those lines once you've filled in the info.

What did you do?

I added a banner image to the document's .headerLeft and a table in the .headerLeft. The table has an Image to the left and Text to the right of the image.

document.add(.headerLeft, image: bannerPDFImage)

document.add(.headerLeft, table: headerTable)

What did you expect to happen?

I expected to see the full image and text beneath the banner image. Instead, there's a gap between the banner image and table below, with the top of the table cut off.

What happened instead?

image

TPPDF Environment

TPPDF version: 2.5.3
Xcode version: 14.2
Swift version: 5.7

Demo Code / Project

From the TableExampleFactory.swift file:


//
//  TableExampleFactory.swift
//  TPPDF_Example
//
//  Created by Philip Niedertscheider on 16.12.19.
//  Copyright © 2022 techprimate GmbH. All rights reserved.
//

#if os(iOS)
import UIKit
#elseif os(macOS)
import AppKit
#endif

import TPPDF

class TableExampleFactory: ExampleFactory {

    func generateDocument() -> [PDFDocument] {
        let document = PDFDocument(format: .a4)

		let headerStyle = PDFTableStyleDefaults.none

		let headerTable = PDFTable(rows: 1, columns: 2)
		headerTable.widths = [0.1, 0.9]
		headerTable.style = headerStyle
		
		var tableContent : [[PDFTableContentable]] = [[PDFTableContentable]]()
		var rowContent : [PDFTableContentable] = [PDFTableContentable]()
		
		if #available(macOS 12.0, *) {

			let bannerImage = Image(named: "Business Logo Banner.jpg")
			if let bannerImage = bannerImage {
				let bannerPDFImage = PDFImage(image: bannerImage)
				document.add(.headerLeft, image: bannerPDFImage)
			}
			
			var formIcon = Image(systemSymbolName: "doc.plaintext", accessibilityDescription: "")
			formIcon?.resizingMode = .tile
			var config = NSImage.SymbolConfiguration(textStyle: .largeTitle,
													 scale: .large)
			config = config.applying(NSImage.SymbolConfiguration.preferringMulticolor())
			formIcon = formIcon?.withSymbolConfiguration(config)
			if let formIcon = formIcon {
				rowContent.append(formIcon)
			} else {
				rowContent.append("")
			}
			
			headerStyle.contentStyle = PDFTableCellStyle(
				
				borders: PDFTableCellBorders(left: PDFLineStyle(type: .none),
											 top: PDFLineStyle(type: .none),
											 right: PDFLineStyle(type: .none),
											 bottom: PDFLineStyle(type: .none)),
				
				font: Font.systemFont(ofSize: 28, weight: .light)
			)
			
			rowContent.append("Test Header Text Content")
			
			tableContent.append(rowContent)
			headerTable.content = tableContent
			headerTable.rows.allCellsAlignment = .left
			document.add(.headerLeft, table: headerTable)
			
		} else {
			// Fallback on earlier versions
		}

		
        // Create a table
        var table = PDFTable(rows: 34, columns: 4)

        // Tables can contain Strings, Numbers, Images or nil, in case you need an empty cell.
        // If you add a unknown content type, an assertion will be thrown and the rendering will stop.
        table.content = [
            [nil, "Name",      "Image",                        "Description"],
            [1,   "Waterfall", Image(named: "Image-1.jpg")!, "Water flowing down stones."],
            [2,   "Forrest",   Image(named: "Image-2.jpg")!, "Sunlight shining through the leafs."],
            [3,   "Fireworks", Image(named: "Image-3.jpg")!, "Fireworks exploding into 100.000 stars"],
            [4,   "Fields",    Image(named: "Image-4.jpg")!, "Crops growing big and providing food."],
            [1,   "Waterfall", Image(named: "Image-1.jpg")!, "Water flowing down stones."],
            [2,   "Forrest",   Image(named: "Image-2.jpg")!, "Sunlight shining through the leafs."],
            [3,   "Fireworks", Image(named: "Image-3.jpg")!, "Fireworks exploding into 100.000 stars"],
            [4,   "Fields",    Image(named: "Image-4.jpg")!, "Crops growing big and providing food."],
			[1,   "Waterfall", Image(named: "Image-1.jpg")!, "Water flowing down stones."],
			[2,   "Forrest",   Image(named: "Image-2.jpg")!, "Sunlight shining through the leafs."],
			[3,   "Fireworks", Image(named: "Image-3.jpg")!, "Fireworks exploding into 100.000 stars"],
			[4,   "Fields",    Image(named: "Image-4.jpg")!, "Crops growing big and providing food."],
			[1,   "Waterfall", Image(named: "Image-1.jpg")!, "Water flowing down stones."],
			[2,   "Forrest",   Image(named: "Image-2.jpg")!, "Sunlight shining through the leafs."],
			[3,   "Fireworks", Image(named: "Image-3.jpg")!, "Fireworks exploding into 100.000 stars"],
			[4,   "Fields",    Image(named: "Image-4.jpg")!, "Crops growing big and providing food."],
			[1,   "Waterfall", Image(named: "Image-1.jpg")!, "Water flowing down stones."],
			[2,   "Forrest",   Image(named: "Image-2.jpg")!, "Sunlight shining through the leafs."],
			[3,   "Fireworks", Image(named: "Image-3.jpg")!, "Fireworks exploding into 100.000 stars"],
			[4,   "Fields",    Image(named: "Image-4.jpg")!, "Crops growing big and providing food."],
			[1,   "Waterfall", Image(named: "Image-1.jpg")!, "Water flowing down stones."],
			[2,   "Forrest",   Image(named: "Image-2.jpg")!, "Sunlight shining through the leafs."],
			[3,   "Fireworks", Image(named: "Image-3.jpg")!, "Fireworks exploding into 100.000 stars"],
			[4,   "Fields",    Image(named: "Image-4.jpg")!, "Crops growing big and providing food."],
			[1,   "Waterfall", Image(named: "Image-1.jpg")!, "Water flowing down stones."],
			[2,   "Forrest",   Image(named: "Image-2.jpg")!, "Sunlight shining through the leafs."],
			[3,   "Fireworks", Image(named: "Image-3.jpg")!, "Fireworks exploding into 100.000 stars"],
			[4,   "Fields",    Image(named: "Image-4.jpg")!, "Crops growing big and providing food."],
			[1,   "Waterfall", Image(named: "Image-1.jpg")!, "Water flowing down stones."],
			[2,   "Forrest",   Image(named: "Image-2.jpg")!, "Sunlight shining through the leafs."],
			[3,   "Fireworks", Image(named: "Image-3.jpg")!, "Fireworks exploding into 100.000 stars"],
			[4,   "Fields",    Image(named: "Image-4.jpg")!, "Crops growing big and providing food."],

            [nil, nil,         nil,                            "Many beautiful places"]
        ]
        table.rows.allRowsAlignment = [.center, .left, .center, .right]

        // The widths of each column is proportional to the total width, set by a value between 0.0 and 1.0, representing percentage.

        table.widths = [
            0.1, 0.25, 0.35, 0.3
        ]

        // To speed up table styling, use a default and change it

        let style = PDFTableStyleDefaults.simple

        // Change standardized styles
        style.footerStyle = PDFTableCellStyle(
            colors: (
                fill: Color(red: 0.171875,
                              green: 0.2421875,
                              blue: 0.3125,
                              alpha: 1.0),
                text: Color.white
            ),
            borders: PDFTableCellBorders(left: PDFLineStyle(type: .full),
                                         top: PDFLineStyle(type: .full),
                                         right: PDFLineStyle(type: .full),
                                         bottom: PDFLineStyle(type: .full)),

            font: Font.systemFont(ofSize: 10)
        )

        // Simply set the amount of footer and header rows

        style.columnHeaderCount = 1
        style.footerCount = 1

        table.style = style

        // Style each cell individually
        table[1,1].style = PDFTableCellStyle(colors: (fill: Color.yellow, text: Color.black))

        // Set table padding and margin
        table.padding = 5.0
        table.margin = 10.0

        // In case of a linebreak during rendering we want to have table headers on each page.

        table.showHeadersOnEveryPage = true

        document.add(table: table)

        // Another table:

        table = PDFTable(rows: 50, columns: 4)
        table.widths = [0.1, 0.3, 0.3, 0.3]
        table.margin = 10
        table.padding = 10
        table.showHeadersOnEveryPage = false
        table.style.columnHeaderCount = 3

        for row in 0..<table.size.rows {
            table[row, 0].content = "\(row)".asTableContent
            for column in 1..<table.size.columns {
                table[row, column].content = "\(row),\(column)".asTableContent
            }
        }

        for i in stride(from: 3, to: 48, by: 3) {
            table[rows: i...(i + 2), column: 1].merge(with: PDFTableCell(content: Array(repeating: "\(i),1", count: 3).joined(separator: "\n").asTableContent,
                                                           alignment: .center))
        }
        for i in stride(from: 4, to: 47, by: 3) {
            table[rows: i...(i + 2), column: 2].merge(with: PDFTableCell(content: Array(repeating: "\(i),2", count: 3).joined(separator: "\n").asTableContent,
                                                           alignment: .center))
        }
        for i in stride(from: 5, to: 48, by: 3) {
            table[rows: i...(i + 2), column: 3].merge(with: PDFTableCell(content: Array(repeating: "\(i),3", count: 3).joined(separator: "\n").asTableContent,
                                                           alignment: .center))
        }

        table[rows: 0..<2, column: 2].merge()
        table[rows: 1..<3, column: 3].merge()

        document.add(table: table)

        return [document]
    }
}

and here's the banner image I added to the project for testing purposes.

Business Logo Banner

@brendand
Copy link
Contributor Author

brendand commented Dec 16, 2022

So I discovered if I make a small change to the TPPDF framework code, the table in the header lines up. I still don't know what's causing the gap between the header banner image and the table in the header. I would think there should be no gap and the whole header should be a bit shorter.

On line 62 of PDFTableObject.swift, I added 10 to that line's y parameter:

let origin = CGPoint(x: tableOrigin.x + originX, y: verticalOrigins[node.position.row] + 10)

image

I don't know why it solves the problem at the moment, but it does. I still think the position of the table is too low. Or at least I should be able to control the gap between the table and the header image.

@brendand
Copy link
Contributor Author

Well, although that fixes the header issue, the content cells all get a gap between rows too, so that's no good.

@brendand
Copy link
Contributor Author

It would seem that the table top is getting cut off because I have style.columHeaderCount = 0. So it seems the code expects every PDFTable to have a header. In this case I'm using a PDFTable simply to draw an icon to the left of the text.

Is there a better way to do that inside the header? I tried with an attributed string and an NSTextAttachment, but it got stripped out when the PDF was generated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant