swiftairprintios18uiprintpagerenderer

When I try to print with AirPrinter printablerect scale 3x in iOS 18 where it print proper in iOS 17?


I have develop functionality to print tags via iOS application. Till iOS 17 it's print properly but after updating to iOS 18 it scale more then 3x.

iOS 17 Name tag rect paperRect: (0.0, 0.0, 266.51338582677164, 175.748031496063) before adjustedPrintableRect: (8.588976377952747, 4.365354330708661, 249.33543307086615, 167.01732283464568)

iOS 18 Name tag rect paperRect: (0.0, 0.0, 841.8897637795276, 595.2755905511812) before adjustedPrintableRect: (39.99685039370081, 18.0, 783.8929133858268, 559.2755905511812)

class AirprintLabelRenderer: UIPrintPageRenderer {
    
    private let imagesToRender: [UIImage]
    
    init(imagesToRender: [UIImage]) {
        self.imagesToRender = imagesToRender
        super.init()
    }
    
    override var numberOfPages: Int {
        return imagesToRender.count
    }

    override func drawPage(at pageIndex: Int, in printableRect: CGRect) {
        print("printableRect: \(printableRect)")
        imagesToRender[pageIndex].draw(in: printableRect)
    }
}

class AirprintTagPrinter: NSObject, TagPrinter {

    var identifier: String {
        return printer.url.absoluteString
    }
    
    let displayName: String
    let printerType = TagPrinterType.airprint
    
    private let printer: UIPrinter
    
    init(name: String, printer: UIPrinter) {
        self.displayName = name
        self.printer = printer
    }

    func toPrinter(jobs: [TagPrintJob], callBack: @escaping TagPrinter.TagPrinterPrintCallback) {
        //Airprint has to be pushed to the main thread because of the way the labels are created (via nibs and UIImages)
        DispatchQueue.main.async {
            let printingItems = jobs.compactMap { self.buildItem(for: $0) }
            guard printingItems.count > 0 else {
                callBack(AirprintPrinterResult(successfulJobs: jobs, error: nil))
                return
            }
            
            let controller = UIPrintInteractionController.shared
            controller.showsNumberOfCopies = false
            controller.printInfo = self.buildPrinterInfo()
            controller.printPageRenderer = AirprintLabelRenderer(imagesToRender: printingItems)
            controller.delegate = self
            controller.print(to: self.printer) { (controller, completed, error) in
                if let error = error {
                    Logger.error("An error occurred printing to airprinter: \(error)")
                    callBack(AirprintPrinterResult(successfulJobs: [], error: error))
                } else {
                    callBack(AirprintPrinterResult(successfulJobs: jobs, error: error))
                }
            }
        }
    }
    
    private func buildItem(for job: TagPrintJob) -> UIImage? {
        var viewToTransform: UIView?
        switch job {
        case let testJob as TestTagPrintJob:
            let testTag = TestTagAirPrintLabel.loadFromNib(named: "TestTagAirPrintLabel")
            testTag?.setupUI(from: testJob)
            viewToTransform = testTag
        case let nameJob as NameTagPrintJob:
            let nameTag = NameTagAirPrintLabel.loadFromNib(named: "NameTagAirPrintLabel")
            nameTag?.setupUI(from: nameJob)
            viewToTransform = nameTag
        default:
            viewToTransform = nil
        }
        return viewToTransform?.toImage(size: CGSize(width: 550, height: 420))
    }
    
    private func buildPrinterInfo() -> UIPrintInfo {
        let printInfo = UIPrintInfo.printInfo()
        printInfo.outputType = .photoGrayscale
        printInfo.jobName = "AirPrint"
        printInfo.orientation = .landscape
        printInfo.duplex = .none
        return printInfo
    }
}

extension AirprintTagPrinter: UIPrintInteractionControllerDelegate {

    func printInteractionController(_ printInteractionController: UIPrintInteractionController, chooseCutterBehavior availableBehaviors: [Any]) -> UIPrinter.CutterBehavior {
        return .cutAfterEachJob
    }
}

Solution

  • To solve this problem I have changed only one line. which is following.

    From:

    controller.printPageRenderer = AirprintLabelRenderer(imagesToRender: printingItems)
    

    To:

    controller.printingItems = printingItems