Files
Nextcloud-Cookbook-iOS/Nextcloud Cookbook iOS Client/RecipeExport/RecipeExporter.swift
2025-05-26 15:52:24 +02:00

157 lines
5.8 KiB
Swift

//
// RecipeToPDF.swift
// Nextcloud Cookbook iOS Client
//
// Created by Vincent Meilinger on 08.01.24.
//
import Foundation
import TPPDF
import SwiftUI
class RecipeExporter {
func createPDF(recipe: CookbookApiRecipeDetailV1, image: UIImage?) -> URL? {
let document = PDFDocument(format: .a4)
let titleStyle = PDFTextStyle(name: "title", font: UIFont.boldSystemFont(ofSize: 18), color: .black)
let headerStyle = PDFTextStyle(name: "header", font: UIFont.boldSystemFont(ofSize: 16), color: .darkGray)
let textStyle = PDFTextStyle(name: "text", font: UIFont.systemFont(ofSize: 14), color: .black)
let titleSection = PDFSection(columnWidths: [0.5, 0.5])
if let image = image, let resizedImage = cropAndResizeImage(image: image, targetHeight: 150) {
let pdfImg = PDFImage(
image: resizedImage,
size: resizedImage.size,
options: [.rounded],
cornerRadius: 5
)
titleSection.columns[0].add(image: pdfImg)
}
// Title
titleSection.columns[1].add(textObject: PDFSimpleText(text: recipe.name, style: titleStyle))
// Description
if !recipe.description.isEmpty {
titleSection.columns[1].add(space: 10)
titleSection.columns[1].add(textObject: PDFSimpleText(text: recipe.description, style: textStyle))
}
// Time
if let prepTime = recipe.prepTime, let prepTimeString = DurationComponents.ptToText(prepTime) {
let prepString = "Preparation time: \(prepTimeString)"
titleSection.columns[1].add(space: 10)
titleSection.columns[1].add(textObject: PDFSimpleText(text: prepString, style: textStyle))
}
if let cookTime = recipe.cookTime, let cookTimeString = DurationComponents.ptToText(cookTime) {
let cookString = "Cooking time: \(cookTimeString)"
titleSection.columns[1].add(space: 10)
titleSection.columns[1].add(textObject: PDFSimpleText(text: cookString, style: textStyle))
}
document.add(section: titleSection)
// Ingredients
var ingr = ""
for ingredient in recipe.recipeIngredient {
ingr.append("\(ingredient)\n")
}
let section = PDFSection(columnWidths: [0.5, 0.5])
section.columns[0].add(textObject: PDFSimpleText(text: ingr, style: textStyle))
document.add(space: 20)
document.add(section: section)
// Instructions
var instr = ""
for instruction in recipe.recipeInstructions {
instr += instruction + "\n\n"
}
document.add(space: 10)
document.add(textObject: PDFSimpleText(text: instr, style: textStyle))
// Generate PDF
let generator = PDFGenerator(document: document)
do {
return try generator.generateURL(filename: "\(recipe.name).pdf")
} catch {
return nil
}
}
func createText(recipe: CookbookApiRecipeDetailV1) -> String {
var recipeString = ""
recipeString.append("" + recipe.name + "\n")
recipeString.append(recipe.description + "\n\n")
for ingredient in recipe.recipeIngredient {
recipeString.append("" + ingredient + "\n")
}
recipeString.append("\n")
var counter = 1
for instruction in recipe.recipeInstructions {
recipeString.append("\(counter). " + instruction + "\n")
counter += 1
}
return recipeString
}
func createJson(recipe: CookbookApiRecipeDetailV1) -> Data? {
return JSONEncoder.safeEncode(recipe)
}
}
private extension RecipeExporter {
func resizeImage(image: UIImage, targetHeight: CGFloat) -> UIImage? {
let size = image.size
let heightRatio = targetHeight / size.height
let newSize = CGSize(width: size.width * heightRatio, height: targetHeight)
let renderer = UIGraphicsImageRenderer(size: newSize)
let resizedImage = renderer.image { (context) in
image.draw(in: CGRect(origin: .zero, size: newSize))
}
return resizedImage
}
func cropAndResizeImage(image: UIImage, targetHeight: CGFloat) -> UIImage? {
let originalSize = image.size
let targetAspectRatio = 4.0 / 3.0
var cropRect: CGRect
// Calculate the rect to crop to 4:3
if originalSize.width / originalSize.height > targetAspectRatio {
// Image is wider than 4:3, crop width
let croppedWidth = originalSize.height * targetAspectRatio
let cropX = (originalSize.width - croppedWidth) / 2.0
cropRect = CGRect(x: cropX, y: 0, width: croppedWidth, height: originalSize.height)
} else {
// Image is narrower than 4:3, crop height
let croppedHeight = originalSize.width / targetAspectRatio
let cropY = (originalSize.height - croppedHeight) / 2.0
cropRect = CGRect(x: 0, y: cropY, width: originalSize.width, height: croppedHeight)
}
// Crop the image
guard let croppedCGImage = image.cgImage?.cropping(to: cropRect) else { return nil }
let croppedImage = UIImage(cgImage: croppedCGImage)
// Resize the cropped image
let resizeRatio = targetHeight / croppedImage.size.height
let resizedSize = CGSize(width: croppedImage.size.width * resizeRatio, height: targetHeight)
let renderer = UIGraphicsImageRenderer(size: resizedSize)
let resizedImage = renderer.image { (context) in
croppedImage.draw(in: CGRect(origin: .zero, size: resizedSize))
}
return resizedImage
}
}