Skip to content

Commit

Permalink
Add new enum PdfSize and Orientation for practical usecase.
Browse files Browse the repository at this point in the history
  • Loading branch information
fummicc1 committed Dec 3, 2023
1 parent d8b9fa0 commit 53ee925
Show file tree
Hide file tree
Showing 5 changed files with 319 additions and 26 deletions.
2 changes: 1 addition & 1 deletion .swiftpm/xcode/xcshareddata/xcschemes/Csv2ImgCmd.xcscheme
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@
isEnabled = "YES">
</CommandLineArgument>
<CommandLineArgument
argument = "-n https://raw.githubusercontent.com/fummicc1/csv2img/main/Fixtures/sample_1.csv"
argument = "-n https://raw.githubusercontent.com/fummicc1/csv2img/main/Fixtures/yolov5x6.csv"
isEnabled = "YES">
</CommandLineArgument>
<CommandLineArgument
Expand Down
34 changes: 27 additions & 7 deletions Sources/Csv2Img/Csv.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,26 +33,32 @@ public actor Csv {
///
/// `separator` is applied to each row and generate items per row.
/// `columns` is array of column whose type is ``Column``.
/// `Row` is array of row whose type is ``Row``
/// `rows` is array of row whose type is ``Row``
/// `exportType` is value of ``ExportType`` with default value `png`.
/// `pdfMetadata` is value of ``PDFMetadata`` with default value `nil`.
public init(
separator: String=",",
rawString: String? = nil,
encoding: String.Encoding = .utf8,
columns: [Csv.Column] = [],
rows: [Csv.Row] = [],
exportType: ExportType = .png
exportType: ExportType = .png,
pdfMetadata: PDFMetadata? = nil
) {
self.imageMarker = ImageMaker(
maximumRowCount: maximumRowCount,
fontSize: 12
)
self.pdfMetadata = pdfMetadata ?? PDFMetadata(
author: "Author",
title: "Title",
size: .a4,
orientation: .portrait
)
self.pdfMarker = PdfMaker(
maximumRowCount: maximumRowCount,
fontSize: 12,
metadata: PDFMetadata(
author: "Author",
title: "Title"
)
metadata: self.pdfMetadata
)
self.encoding = encoding
self.separator = separator
Expand Down Expand Up @@ -130,7 +136,14 @@ public actor Csv {

/// `exportType` determines export type. Please choose ``ExportType.png`` or ``ExportType.pdf``.
public var exportType: ExportType


/// `pdfMetadata` stores pdf metadata which is used when ``Csv2Img.Csv.ExportType`` is `.png`
private var pdfMetadata: PDFMetadata {
didSet {
pdfMarker.set(metadata: pdfMetadata)
}
}

/// ``maximumRowCount`` is the max number of Rows. this is fixed due to performance issue.
private let maximumRowCount: Int? = nil

Expand Down Expand Up @@ -627,4 +640,11 @@ extension Csv {
return nil
}
}

/**
- set ``PdfMetadata``
*/
public func update(pdfMetadata: PDFMetadata) {
self.pdfMetadata = pdfMetadata
}
}
25 changes: 18 additions & 7 deletions Sources/Csv2Img/PDFMetadata.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,27 @@ import Foundation

/// ``PDFMetadata`` is a struct which stores Metadata about output-pdf.
public struct PDFMetadata {

/// `author`. author of document.
public var author: String?
/// `title`. title of document.
public var title: String?

/**
- specify output pdf size with ``PdfSize``.
*/
public var size: PdfSize?
public var orientation: PdfSize.Orientation?

public init(
author: String,
title: String
author: String? = nil,
title: String? = nil,
size: PdfSize? = nil,
orientation: PdfSize.Orientation? = nil
) {
self.author = author
self.title = title
self.size = size
self.orientation = orientation
}

/// `author`. author of document.
public var author: String
/// `title`. title of document.
public var title: String
}
229 changes: 218 additions & 11 deletions Sources/Csv2Img/PdfMaker.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,16 @@ protocol PdfMakerType: Maker {
var latestOutput: PDFDocument? {
get
}
func setMetadata(
_ metadata: PDFMetadata
func set(
metadata: PDFMetadata
)
}

/// ``PdfMaker`` generate pdf from ``Csv`` (Work In Progress).
final class PdfMaker: PdfMakerType {

typealias Exportable = PDFDocument

init(
maximumRowCount: Int?,
fontSize: Double,
Expand All @@ -39,28 +39,49 @@ final class PdfMaker: PdfMakerType {
self.fontSize = fontSize
self.metadata = metadata
}

let maximumRowCount: Int?
private(
set
) var fontSize: Double
var metadata: PDFMetadata

var latestOutput: PDFDocument?

func set(
fontSize size: Double
) {
self.fontSize = size
}

/// generate png-image data from ``Csv``.
func make(
columns: [Csv.Column],
rows: [Csv.Row],
progress: @escaping (
Double
) -> Void
) throws -> PDFDocument {
return if let size = metadata.size, let orientation = metadata.orientation {
try make(
with: size,
orientation: orientation,
columns: columns,
rows: rows,
progress: progress
)
} else {
try make(with: fontSize, columns: columns, rows: rows, progress: progress)
}
}

func make(
with fontSize: Double,
columns: [Csv.Column],
rows: [Csv.Row],
progress: @escaping (
Double
) -> Void
) throws -> PDFDocument {
// NOTE: Anchor is bottom-left.
let horizontalSpace: Double = 8
Expand Down Expand Up @@ -313,8 +334,194 @@ final class PdfMaker: PdfMakerType {
return document
}

func setMetadata(
_ metadata: PDFMetadata
func make(
with pdfSize: PdfSize,
orientation: PdfSize.Orientation,
columns: [Csv.Column],
rows: [Csv.Row],
progress: @escaping (
Double
) -> Void
) throws -> PDFDocument {
let pageSize = pdfSize.size(
orientation: orientation
)

let totalRowCount = min(
maximumRowCount ?? rows.count,
rows.count
)
let rows = rows[..<totalRowCount].map {
$0
}

if rows.isEmpty {
throw PdfMakingError.emptyRows
}

let maxTextCount = rows.flatMap { $0.values }.map(\.count).max() ?? 0

set(fontSize: pageSize.width / Double(columns.count) / Double(maxTextCount) * 0.8)

let styles: [Csv.Column.Style] = columns.map(
\.style
)

let rowHeight = pageSize.height / Double(rows.count + 1)
let columnWidth = pageSize.width / Double(columns.count)
let lineWidth: Double = 1

let totalPageNumber = 1

var mediaBox = CGRect(
origin: .zero,
size: pageSize
)

let data = CFDataCreateMutable(
nil,
0
)!
let consumer = CGDataConsumer(
data: data
)!
guard let context = CGContext(
consumer: consumer,
mediaBox: &mediaBox,
nil
) else {
throw PdfMakingError.noContextAvailabe
}

let completeCount: Double = Double(
totalPageNumber
)
var completeFraction: Double = 0

var currentPageNumber: Int = 1
var startRowIndex: Int = 0
while currentPageNumber <= totalPageNumber {
let mediaBoxPerPage = CGRect(
origin: .zero,
size: pageSize
)
let coreInfo = [
kCGPDFContextTitle as CFString: metadata.title,
kCGPDFContextAuthor as CFString: metadata.author,
kCGPDFContextMediaBox: mediaBoxPerPage
] as [CFString : Any]
context.beginPDFPage(
coreInfo as CFDictionary
)

context.setFillColor(
CGColor(
red: 255/255,
green: 255/255,
blue: 255/255,
alpha: 1
)
)
context.fill(
CGRect(
origin: .zero,
size: CGSize(
width: pageSize.width,
height: pageSize.height
)
)
)

context.setLineWidth(
lineWidth
)
#if os(macOS)
context.setStrokeColor(
Color.separatorColor.cgColor
)
#elseif os(iOS)
context.setStrokeColor(
Color.separator.cgColor
)
#endif
context.setFillColor(
CGColor(
red: 33/255,
green: 33/255,
blue: 33/255,
alpha: 1
)
)

setColumnText(
context: context,
columns: columns,
boxWidth: Double(
columnWidth
),
boxHeight: Double(
rowHeight
),
totalHeight: Double(
pageSize.height
),
totalWidth: Double(
pageSize.width
)
)
setRowText(
context: context,
styles: styles,
rows: rows,
from: 0,
rowCountPerPage: rows.count,
columnHeight: Double(
rowHeight
),
width: Double(
columnWidth
),
height: Double(
rowHeight
),
totalWidth: Double(
pageSize.width
),
totalHeight: Double(
pageSize.height
)
)

context.drawPath(
using: .stroke
)

completeFraction += 1
progress(
completeFraction / completeCount
)

currentPageNumber += 1
startRowIndex += rows.count

context.endPDFPage()
}

#if os(iOS)
UIGraphicsEndPDFContext()
#endif

context.closePDF()

let document = PDFDocument(
data: data as Data
)!
self.latestOutput = document
return document
}

func set(
metadata: PDFMetadata
) {
self.metadata = metadata
}
Expand Down Expand Up @@ -420,7 +627,7 @@ extension PdfMaker {
}
}
}

private func setColumnText(
context: CGContext,
columns: [Csv.Column],
Expand Down
Loading

0 comments on commit 53ee925

Please sign in to comment.