// // KMPrintPresenter_C.swift // PDF Reader Pro // // Created by lizhe on 2022/12/21. // // import Cocoa class KMPrintPresenter_C: NSObject { lazy var printData: KMPrintModel! = KMPrintModel() var document: CPDFDocument? fileprivate weak var delegate: KMPrintPresenter_CDeleage? /** 初始化presenter */ func initPresenter(delegate: KMPrintPresenter_CDeleage, data: KMPrintModel, document: CPDFDocument) { self.delegate = delegate self.printData = data self.updatePrintDocument(documentURL: document.documentURL, data: self.printData) } func reloadData() { self.updatePrintDocument(documentURL: self.document!.documentURL, data: self.printData) } /** @abstract 解除绑定 */ func free() { delegate = nil } } protocol KMPrintPresenter_CDeleage: NSObject { func showData(presenter: KMPrintPresenter_C, document: CPDFDocument) } protocol KMPrintPresenter_CDocument: NSObject {} extension KMPrintPresenter_C: KMPrintPresenter_CDocument { /** @abstract 获取打印document @param url 源文件url @param data 数据 @retrun document */ func updatePrintDocument(documentURL: URL, data: KMPrintModel) -> CPDFDocument { /** 获取基本参数 */ let printModel: KMPrintModel = data /** 绘制document */ //创建预览document let previewDocument = self.creatDocument(url: documentURL) //获取总page let pages = self.fetchPages(documentURL: documentURL, range: printModel.page.range) //插入page let insertSuccess = self.insertPages(document: previewDocument, printModel: printModel, pages: pages) if insertSuccess { KMPrint("插入成功") } else { KMPrint("插入失败") } //重置document let filePath = self.saveDocument(document: previewDocument) if self.delegate != nil { self.delegate?.showData(presenter: self, document: previewDocument) } KMPrint("保存地址" + filePath) return previewDocument } /** @abstract 插入page @param paperSet 纸张设置 @param pageSet page设置 @param pages page数组 */ func insertPages(document: CPDFDocument, printModel: KMPrintModel, pages: [CPDFPage]) -> Bool { //每张纸包含的apge数量 var pageOfPaperCount: Int = 1 switch printModel.page.operation.type { case .multipage: pageOfPaperCount = Int(printModel.page.operation.pageOfPaper.point.x * printModel.page.operation.pageOfPaper.point.y) case .poster: pageOfPaperCount = Int(printModel.page.operation.pageOfPaper.point.x * printModel.page.operation.pageOfPaper.point.y) default: pageOfPaperCount = 1 } //总页数 let count: Int = Int(ceil(Double(pages.count / pageOfPaperCount))) let size = printModel.page.operation.size var insertPages: [CPDFPage] = [] for i in 0...count { //获取多页page var drawPages: [CPDFPage] = [] for j in 0...pageOfPaperCount { if i * pageOfPaperCount + j < pages.count { let drawPage = pages[i * pageOfPaperCount + j] drawPages.append(drawPage) } } //TODO: 暂时屏蔽 let insertPage = KMPrintPage_C.init() insertPage.pages = drawPages insertPage.data = printModel insertPage.setBounds(CGRect(x: 0, y: 0, width: printModel.paper.info.size.width, height: printModel.paper.info.size.height), for: CPDFDisplayBox.mediaBox) insertPage.drawBlock = { [weak self] box, context, pages, data in //绘制page self?.drawPageToContext(context: context, pages: pages, data: data) } insertPages.append(insertPage) } var result = true if insertPages.count != 0 { for index in 0...insertPages.count - 1 { let page = insertPages[index] var success = false if (printModel.page.range.reversePrintOrder) { success = document.insertPageObject(page, at: 0) } else { success = document.insertPageObject(page, at: UInt(index)) } if success { KMPrint("插入成功") } else { KMPrint("插入失败") result = false } } } // var result = true // if pages.count != 0 { // for index in 0...pages.count - 1 { // let page = pages[index] // let success = document.insertPageObject(page, at: UInt(index)) // if success { // print("插入成功") // } else { // print("插入失败") // result = false // } // } // } return result } func creatDocument(url: URL) -> CPDFDocument { if FileManager.default.fileExists(atPath: NSTemporaryDirectory() + "/PDFReaderProTest") { try?FileManager.default.createDirectory(atPath: NSTemporaryDirectory() + "/PDFReaderProTest", withIntermediateDirectories: true) } let document = CPDFDocument(url: url)! // document.importPages(IndexSet(integer: 0), from: document, at: 0) let count = document.pageCount for _ in 0...count { document.removePage(at: 0) } return document } func saveDocument(document: CPDFDocument) -> String { let filePath = NSTemporaryDirectory() + "/PDFReaderProTest/test2.pdf" if FileManager.default.fileExists(atPath: filePath) { try?FileManager.default.removeItem(atPath: filePath) } let url: URL = NSURL(string: filePath)! as URL var success = document.write(to: url) if !success { success = NSData(data: document.dataRepresentation()).write(to: url, atomically: true) } if success { KMPrint("保存成功" + filePath) } else { KMPrint("保存失败") } return filePath } /** 获取pages @param type 页面类型 @param selectPages 当type 为custom时 传入选中page的下标 */ func fetchPages(documentURL: URL, range: KMPrintPageRange) -> [CPDFPage] { let document = CPDFDocument.init(url: documentURL)! if document.pageCount < 1 { let page: CPDFPage = document.page(at: 0) return [page] } else { var pagesArray: [CPDFPage] = [] switch range.type { case .allPage: for index in 0...document.pageCount - 1 { let page: CPDFPage = document.page(at: index)! pagesArray.append(page) } case .evenPage: for index in 0...document.pageCount - 1 { if index % 2 == 0 { let page: CPDFPage = document.page(at: index)! pagesArray.append(page) } } case .oddPage: for index in 0...document.pageCount - 1 { if index % 2 != 0 { let page: CPDFPage = document.page(at: index)! pagesArray.append(page) } } // case .currentPage: // let page = self.pdfView.currentPage() // if page != nil { // pagesArray.append(page!) // } else { // print("page不存在") // } case .custom: for index in range.selectPages { let page: CPDFPage = document.page(at: UInt(index - 1)) pagesArray.append(page) } default: KMPrint("无匹配选项") } return pagesArray } } /** @abstract 获取context @param size纸张大小 */ func createContext(size: CGSize) -> CGContext { let s = CGSize(width: nearbyint(size.width), height: nearbyint(size.height)) let rep = NSBitmapImageRep.init(bitmapDataPlanes: nil, pixelsWide: Int(s.width), pixelsHigh: Int(s.height), bitsPerSample: 8, samplesPerPixel: 4, hasAlpha: true, isPlanar: false, colorSpaceName: NSColorSpaceName.calibratedRGB, bytesPerRow: 0, bitsPerPixel: 0)! let context: CGContext = NSGraphicsContext.init(bitmapImageRep: rep)!.cgContext return context } /** @abstract 绘制page @param context @pages page数组 [CPDFPage] */ func drawPageToContext(context: CGContext, pages: [CPDFPage], data: KMPrintModel) { /** paper */ let paperDirection: KMPrintPaperDirectionType = .vertical //打印方向 let paperSize: CGSize = CGSize(width: 595, height: 842) //页面paper大小 var dealPaperSize: CGSize = paperSize //页面paper大小 let paperInset: NSEdgeInsets = NSEdgeInsets(top: 0, left: 0, bottom: 0, right: 0) //绘制paper大小 var columnCount: Int = 2 //行 var rowCount: Int = 2 //列 let columnSpace: CGFloat = 2.0 //行间距 let rowSpace: CGFloat = 2.0 //列间距 let border: Bool = true /** page */ let pageOrder: KMPrintPageOperation.Multipage.Order = .horizontal //页面顺序 var pageSize: CGSize = CGSize(width: 100, height: 100) //page大小 let contentType: KMPrintContentType = .document var scale: Float = 1.0 //缩放尺寸 let autoRotate: Bool = false /** 计算 */ if paperDirection == .horizontal { dealPaperSize = CGSize(width: dealPaperSize.height, height: dealPaperSize.width) } //减去inset dealPaperSize = CGSize(width: dealPaperSize.width - paperInset.left - paperInset.right, height: dealPaperSize.height - paperInset.bottom - paperInset.top) //计算page尺寸(减去page之间的间隙) pageSize = CGSize(width: (dealPaperSize.width - CGFloat((columnCount - 1)) * CGFloat(columnSpace)) / CGFloat(columnCount), height: (dealPaperSize.height - CGFloat((rowCount - 1)) * CGFloat(rowSpace)) / CGFloat(rowCount)) //如果是横向参数需切换 if pageOrder == .horizontal || pageOrder == .horizontalReverseSequence { let temp = columnCount columnCount = rowCount rowCount = temp } for i in 0...columnCount { for j in 0...rowCount { let index = j + i * columnCount if index < pages.count { //参数 let page = pages[index] let rect = page.bounds(for: CPDFDisplayBox.cropBox) let originSize = rect.size var dealSize = originSize var rotate = page.rotation var annoations: [CPDFAnnotation] = page.annotations //处理 switch contentType { case .document: annoations.removeAll() case .documentAndStamp: for annoation in annoations { if !(annoation.isKind(of: CPDFStampAnnotation.self)) { annoation.page.removeAnnotation(annoation) } } case .documentAndMarkup: for annoation in annoations { if !(annoation.isKind(of: CPDFMarkupAnnotation.self)) { annoation.page.removeAnnotation(annoation) } } default: break } if rotate == 90 || rotate == 270 { dealSize = CGSize(width: originSize.height, height: originSize.width) } //取出page横竖时能显示的最大Rect if autoRotate { //page旋转度数为0度或者180度时,在指定的大小内,能显示的比例 let scale1 = Float(min(pageSize.width / originSize.width, pageSize.height / originSize.height)) //page旋转度数为90度或者270度时,在指定的大小内,能显示的比例 let scale2 = Float(min(pageSize.width / originSize.height, pageSize.height / originSize.width)) scale = max(scale1, scale2) if scale1 > scale2 { //高为竖直排列时,显示最大,则需将page时90度或者270度需要进行旋转 if rotate == 90 || rotate == 270 { rotate = rotate - 90 } } else { //宽为竖直排列时,显示最大,则需将page时0度或者180度需要进行旋转 if rotate == 0 || rotate == 180 { rotate = rotate - 90 } } if rotate == 90 || rotate == 270 { dealSize = CGSize(width: originSize.height, height: originSize.width) } else { dealSize = CGSize(width: originSize.width, height: originSize.height) } } else { scale = Float(min(pageSize.width / dealSize.width, pageSize.height / dealSize.height)) } scale = min(scale, 1) //居中 let spaceX: CGFloat = (pageSize.width - dealSize.width * CGFloat(scale)) / 2 let spaceY: CGFloat = (pageSize.height - dealSize.height * CGFloat(scale))/2 var translateX: CGFloat = 0.0 var translateY: CGFloat = 0.0 switch pageOrder { case .horizontal: translateX = (pageSize.width + columnSpace) + CGFloat(j) + paperInset.left + spaceX //页面内容高度 + 下边的行间距 - 第几个cell的高度 +居中 translateY = dealPaperSize.height + paperInset.bottom - (pageSize.height + rowSpace) * (CGFloat(i) + 1) + spaceY + rowSpace case .horizontalReverseSequence: translateX = dealPaperSize.width + paperInset.left - (pageSize.width + columnSpace) * (CGFloat(j) + 1) + spaceX + columnSpace translateY = dealPaperSize.height - (pageSize.height + rowSpace) * (CGFloat(i) + 1) + spaceY + paperInset.bottom + rowSpace case .vertical: translateX = (pageSize.width + columnSpace) * CGFloat(i) + paperInset.left + spaceX translateY = dealPaperSize.height - (pageSize.height + rowSpace) * (CGFloat(j) + 1) + spaceY + paperInset.bottom + rowSpace case .verticalReverseSequence: translateX = dealPaperSize.width + paperInset.left - (pageSize.width + columnSpace) * (CGFloat(i) + 1) + spaceX + columnSpace translateY = dealPaperSize.height - (pageSize.height + rowSpace) * (CGFloat(j) + 1) + spaceY + paperInset.bottom + rowSpace } context.saveGState() //平移 context.translateBy(x: translateX, y: translateY) //缩放 context.scaleBy(x: CGFloat(scale), y: CGFloat(scale)) page.draw(with: CPDFDisplayBox.cropBox, to: context) page.transform(context, for: CPDFDisplayBox.cropBox) if border { var dirtyRect = rect if rotate == 90 || rotate == 270 { dirtyRect = NSMakeRect(dirtyRect.origin.x, dirtyRect.origin.y, dirtyRect.size.height, dirtyRect.size.width) } context.addRect(dirtyRect) context.setStrokeColor(red: 0.0, green: 0.0, blue: 0.0, alpha: 1.0) context.strokePath() } context.restoreGState() } } } } } protocol KMPrintPresenter_CProtocol: NSObject { }