diff --git a/printing/ios/printing/Sources/printing/PrintJob.swift b/printing/ios/printing/Sources/printing/PrintJob.swift index af87b263..ee3bf7a5 100644 --- a/printing/ios/printing/Sources/printing/PrintJob.swift +++ b/printing/ios/printing/Sources/printing/PrintJob.swift @@ -40,6 +40,7 @@ public class PrintJob: UIPrintPageRenderer, UIPrintInteractionControllerDelegate private var dynamic = false private var currentSize: CGSize? private var forceCustomPrintPaper = false + private var fitToPage = false public init(printing: PrintingPlugin, index: Int) { self.printing = printing @@ -49,13 +50,30 @@ public class PrintJob: UIPrintPageRenderer, UIPrintInteractionControllerDelegate } override public func drawPage(at pageIndex: Int, in _: CGRect) { - let ctx = UIGraphicsGetCurrentContext() - let page = pdfDocument?.page(at: pageIndex + 1) - ctx?.scaleBy(x: 1.0, y: -1.0) - ctx?.translateBy(x: 0.0, y: -paperRect.size.height) - if page != nil { - ctx?.drawPDFPage(page!) + guard let ctx = UIGraphicsGetCurrentContext(), + let page = pdfDocument?.page(at: pageIndex + 1) else { return } + + let pdfRect = page.getBoxRect(.mediaBox) + + ctx.saveGState() + ctx.scaleBy(x: 1.0, y: -1.0) + ctx.translateBy(x: 0.0, y: -paperRect.size.height) + + if fitToPage { + let scaleX = paperRect.width / pdfRect.width + let scaleY = paperRect.height / pdfRect.height + let scale = min(scaleX, scaleY) + let scaledWidth = pdfRect.width * scale + let scaledHeight = pdfRect.height * scale + let offsetX = (paperRect.width - scaledWidth) / 2 + let offsetY = (paperRect.height - scaledHeight) / 2 + + ctx.translateBy(x: offsetX, y: offsetY) + ctx.scaleBy(x: scale, y: scale) } + + ctx.drawPDFPage(page) + ctx.restoreGState() } func cancelJob(_ error: String?) { @@ -170,10 +188,11 @@ public class PrintJob: UIPrintPageRenderer, UIPrintInteractionControllerDelegate return bestPaper } - func printPdf(name: String, withPageSize size: CGSize, andMargin margin: CGRect, withPrinter printerID: String?, dynamically dyn: Bool, outputType type: UIPrintInfo.OutputType, forceCustomPrintPaper: Bool = false) { + func printPdf(name: String, withPageSize size: CGSize, andMargin margin: CGRect, withPrinter printerID: String?, dynamically dyn: Bool, outputType type: UIPrintInfo.OutputType, forceCustomPrintPaper: Bool = false, fitToPage: Bool = false) { currentSize = size dynamic = dyn self.forceCustomPrintPaper = forceCustomPrintPaper + self.fitToPage = fitToPage let printing = UIPrintInteractionController.isPrintingAvailable if !printing { diff --git a/printing/ios/printing/Sources/printing/PrintingPlugin.swift b/printing/ios/printing/Sources/printing/PrintingPlugin.swift index 57641ece..391d18da 100644 --- a/printing/ios/printing/Sources/printing/PrintingPlugin.swift +++ b/printing/ios/printing/Sources/printing/PrintingPlugin.swift @@ -77,6 +77,7 @@ public class PrintingPlugin: NSObject, FlutterPlugin { let printJob = PrintJob(printing: self, index: args["job"] as! Int) let dynamic = args["dynamic"] as! Bool let forceCustomPrintPaper = args["forceCustomPrintPaper"] as! Bool + let fitToPage = args["fitToPage"] as? Bool ?? false let outputType: UIPrintInfo.OutputType switch args["outputType"] as! Int { @@ -107,7 +108,8 @@ public class PrintingPlugin: NSObject, FlutterPlugin { withPrinter: printer, dynamically: dynamic, outputType: outputType, - forceCustomPrintPaper: forceCustomPrintPaper) + forceCustomPrintPaper: forceCustomPrintPaper, + fitToPage: fitToPage) result(NSNumber(value: 1)) } else if call.method == "sharePdf" { let object = args["doc"] as! FlutterStandardTypedData diff --git a/printing/lib/printing_web.dart b/printing/lib/printing_web.dart index 124f1505..af5eb506 100644 --- a/printing/lib/printing_web.dart +++ b/printing/lib/printing_web.dart @@ -159,6 +159,7 @@ class PrintingPlugin extends PrintingPlatform { bool usePrinterSettings, OutputType outputType, bool forceCustomPrintPaper, + bool fitToPage, ) async { late Uint8List result; try { diff --git a/printing/lib/src/interface.dart b/printing/lib/src/interface.dart index 4336eda1..89bd56b5 100644 --- a/printing/lib/src/interface.dart +++ b/printing/lib/src/interface.dart @@ -69,6 +69,7 @@ abstract class PrintingPlatform extends PlatformInterface { bool usePrinterSettings, OutputType outputType, bool forceCustomPrintPaper, + bool fitToPage, ); /// Enumerate the available printers on the system. diff --git a/printing/lib/src/method_channel.dart b/printing/lib/src/method_channel.dart index 9882d683..a6acc315 100644 --- a/printing/lib/src/method_channel.dart +++ b/printing/lib/src/method_channel.dart @@ -180,6 +180,7 @@ class MethodChannelPrinting extends PrintingPlatform { bool usePrinterSettings, OutputType outputType, bool forceCustomPrintPaper, + bool fitToPage, ) async { final job = _printJobs.add( onCompleted: Completer(), @@ -200,6 +201,7 @@ class MethodChannelPrinting extends PrintingPlatform { 'usePrinterSettings': usePrinterSettings, 'outputType': outputType.index, 'forceCustomPrintPaper': forceCustomPrintPaper, + 'fitToPage': fitToPage, }; await _channel.invokeMethod('printPdf', params); diff --git a/printing/lib/src/printing.dart b/printing/lib/src/printing.dart index caa6ae75..30b088ff 100644 --- a/printing/lib/src/printing.dart +++ b/printing/lib/src/printing.dart @@ -49,6 +49,11 @@ mixin Printing { /// Use value `true` to use [format] as custom paper size, when the printer /// driver will not allows the user to use papers which are actually supported by the printer. /// (Supported platforms: iOS) + /// + /// Set [fitToPage] to true to scale the PDF content to fit the paper size + /// while preserving aspect ratio. Without this, the PDF is rendered at its + /// native point size which may not match the selected paper. + /// (Supported platforms: iOS) static Future layoutPdf({ required LayoutCallback onLayout, String name = 'Document', @@ -57,6 +62,7 @@ mixin Printing { bool usePrinterSettings = false, OutputType outputType = OutputType.generic, bool forceCustomPrintPaper = false, + bool fitToPage = false, }) { return PrintingPlatform.instance.layoutPdf( null, @@ -67,6 +73,7 @@ mixin Printing { usePrinterSettings, outputType, forceCustomPrintPaper, + fitToPage, ); } @@ -164,6 +171,7 @@ mixin Printing { bool usePrinterSettings = false, OutputType outputType = OutputType.generic, bool forceCustomPrintPaper = false, + bool fitToPage = false, }) { return PrintingPlatform.instance.layoutPdf( printer, @@ -174,6 +182,7 @@ mixin Printing { usePrinterSettings, outputType, forceCustomPrintPaper, + fitToPage, ); } diff --git a/printing/test/printing_test.dart b/printing/test/printing_test.dart index d18333c1..a6b8c89b 100644 --- a/printing/test/printing_test.dart +++ b/printing/test/printing_test.dart @@ -99,6 +99,7 @@ class MockPrinting extends Mock bool usePrinterSettings, OutputType outputType, bool forceCustomPrintPaper, + bool fitToPage, ) async => true; @override