KMPrintPresenter.swift 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086
  1. //
  2. // KMPrintPresenter.swift
  3. // PDF Master
  4. //
  5. // Created by lizhe on 2022/12/21.
  6. //
  7. import Cocoa
  8. import PDFKit
  9. //MARK: CPDFKit page 方法无法使用 暂时使用系统方法
  10. class KMPrintPresenter: NSObject {
  11. lazy var printData: KMPrintModel = KMPrintModel() {
  12. didSet {
  13. self.reloadData()
  14. }
  15. }
  16. var document: CPDFDocument?
  17. fileprivate weak var delegate: KMPrintPresenterDeleage?
  18. /**
  19. 初始化presenter 绑定数据
  20. */
  21. func initPresenter(delegate: KMPrintPresenterDeleage, data: KMPrintModel, document: CPDFDocument) {
  22. self.delegate = delegate
  23. self.document = document
  24. self.printData = data
  25. // DispatchQueue.main.async {
  26. // let pdfDocument = self.updatePrintDocument(documentURL: document.documentURL, data: self.printData)
  27. // self.printData.url = pdfDocument.documentURL
  28. // }
  29. }
  30. /**
  31. 刷新数据
  32. */
  33. func reloadData() {
  34. guard let document = document else { return }
  35. let pdfDocument = self.updatePrintDocument(documentURL: document.documentURL, data: self.printData)
  36. self.printData.url = pdfDocument.documentURL
  37. }
  38. /**
  39. @abstract 解除绑定
  40. */
  41. func free() {
  42. delegate = nil
  43. }
  44. }
  45. protocol KMPrintPresenterDeleage: NSObject {
  46. func showData(presenter: KMPrintPresenter, document: CPDFDocument)
  47. }
  48. protocol KMPrintPresenterDocument: NSObject {}
  49. extension KMPrintPresenter: KMPrintPresenterDocument {
  50. /**
  51. @abstract 获取打印document
  52. @param url 源文件url
  53. @param data 数据
  54. @retrun document
  55. */
  56. func updatePrintDocument(documentURL: URL, data: KMPrintModel) -> CPDFDocument {
  57. // 获取基本参数
  58. let printModel: KMPrintModel = data
  59. //获取总page
  60. let pages = self.fetchPages(documentURL, printModel.page)
  61. //绘制PDF
  62. let filePath = self.drawPages(nil, printModel, pages)
  63. let result = CPDFDocument(url: URL(fileURLWithPath: filePath))!
  64. if self.delegate != nil {
  65. self.delegate?.showData(presenter: self, document: result)
  66. }
  67. KMPrint("保存地址" + filePath)
  68. return result
  69. }
  70. /**
  71. @abstract 插入page
  72. @param paperSet 纸张设置
  73. @param pageSet page设置
  74. @param pages page数组
  75. */
  76. func drawPages(_ toFilePath: String?,
  77. _ printModel: KMPrintModel,
  78. _ pages: [KMPrintDrawPage]) -> String {
  79. /**
  80. 参数
  81. */
  82. //纸张大小
  83. let paperSize: CGSize = self.fetchPaperSize(printModel.paper)
  84. //总页数
  85. let paperCount: Int = self.fetchTotalPaperCount(paperSize, pages, printModel.page)
  86. //每页page数
  87. let pageOfPaperCount: Int = self.fetchPageOfPaper(printModel.page)
  88. //获取每张纸的page
  89. let drawPages: [[KMPrintDrawPage]] = self.fetchDrawPages(paperSize, printModel.page, paperCount, pageOfPaperCount, pages)
  90. //导出地址
  91. let filePath = KMPrintPresenter.fetchSaveFilePath(toFilePath)
  92. /**
  93. 绘制每张纸的内容
  94. */
  95. //创建画布
  96. let context: CGContext = self.createContext(filePath, paperSize)
  97. for drawPage in drawPages {
  98. context.beginPDFPage(nil)
  99. self.drawPageToContext(context, drawPage, printModel)
  100. context.endPDFPage()
  101. }
  102. context.closePDF()
  103. return filePath
  104. }
  105. /**
  106. 获取绘制的pages
  107. @pageModel page参数
  108. @param paperCount 纸张数量
  109. @param pageOfPaperCount 每张纸的page数量
  110. @param pages 所有page数量
  111. */
  112. func fetchDrawPages(_ paperSize: CGSize, _ pageModel: KMPrintPageModel,_ paperCount: Int, _ pageOfPaperCount: Int, _ pages: [KMPrintDrawPage]) -> [[KMPrintDrawPage]] {
  113. guard pages.count != 0 else {
  114. return []
  115. }
  116. //一个page重复获取次数
  117. var pageRepetitionCount = 1
  118. if (pageModel.operation.type == .poster) {
  119. if (pageModel.operation.poster.type == .tile) {
  120. pageRepetitionCount = Int(pageModel.operation.poster.tilePoint.x * pageModel.operation.poster.tilePoint.y)
  121. } else if (pageModel.operation.poster.type == .breakUp) {
  122. pageRepetitionCount = Int(pageModel.operation.pageOfPaper.point.x * pageModel.operation.pageOfPaper.point.y)
  123. }
  124. }
  125. var drawPages:[[KMPrintDrawPage]] = []
  126. for i in 0...(paperCount - 1) {
  127. //获取多页page
  128. var tempPags: [KMPrintDrawPage] = []
  129. for j in 0...(pageOfPaperCount - 1) {
  130. if pageModel.operation.type == .pamphlet {
  131. let pageIndex = i / pageRepetitionCount
  132. if (pageIndex * pageOfPaperCount + j < pages.count) {
  133. let pageIndex = i / pageRepetitionCount
  134. let originDrawPage = (pages[pageIndex * pageOfPaperCount + j])
  135. let drawPage = KMPrintDrawPage()
  136. drawPage.page = originDrawPage.page
  137. var pageCropRect = self.fetchPageCropRect(paperSize,i % pageRepetitionCount, pageModel, drawPage)
  138. var pageShowRect = pageCropRect
  139. drawPage.cropRect = pageCropRect
  140. drawPage.showRect = pageShowRect
  141. tempPags.append(drawPage)
  142. } else {
  143. tempPags.append(KMPrintDrawPage())
  144. }
  145. } else {
  146. let pageIndex = i / pageRepetitionCount
  147. if (pageIndex * pageOfPaperCount + j < pages.count) {
  148. let originDrawPage = (pages[pageIndex * pageOfPaperCount + j])
  149. let drawPage = KMPrintDrawPage()
  150. drawPage.page = originDrawPage.page
  151. var pageCropRect = self.fetchPageCropRect(paperSize,i % pageRepetitionCount, pageModel, drawPage)
  152. var pageShowRect = pageCropRect
  153. if (pageModel.operation.type == .poster) {
  154. if (pageModel.operation.poster.type == .tile) {
  155. pageShowRect = self.fetchPageShowRect(paperSize, i % pageRepetitionCount, pageModel, drawPage)
  156. } else if (pageModel.operation.poster.type == .breakUp) {
  157. pageShowRect = pageCropRect
  158. }
  159. }
  160. drawPage.cropRect = pageCropRect
  161. drawPage.showRect = pageShowRect
  162. tempPags.append(drawPage)
  163. }
  164. }
  165. }
  166. drawPages.append(tempPags)
  167. }
  168. return drawPages
  169. }
  170. /**
  171. 获取pages
  172. @param type 页面类型
  173. @param contentType annoation类型
  174. @param selectPages 当type 为custom时 传入选中page的下标
  175. */
  176. static func fetchSaveFilePath(_ filePath: String?) -> String {
  177. var saveFilePath = filePath ?? ""
  178. if saveFilePath.count == 0 {
  179. saveFilePath = NSTemporaryDirectory() + "/PDFMasterTest/test2.pdf"
  180. }
  181. if !FileManager.default.fileExists(atPath: NSTemporaryDirectory() + "/PDFMasterTest") {
  182. try?FileManager.default.createDirectory(atPath: NSTemporaryDirectory() + "/PDFMasterTest", withIntermediateDirectories: true)
  183. }
  184. if FileManager.default.fileExists(atPath: saveFilePath) {
  185. try?FileManager.default.removeItem(atPath: saveFilePath)
  186. }
  187. return saveFilePath
  188. }
  189. /**
  190. 获取pages
  191. @param type 页面类型
  192. @param contentType annoation类型
  193. @param selectPages 当type 为custom时 传入选中page的下标
  194. */
  195. static func creatDocument(_ url: URL) -> CPDFDocument {
  196. if FileManager.default.fileExists(atPath: NSTemporaryDirectory() + "/PDFMasterTest") {
  197. try?FileManager.default.createDirectory(atPath: NSTemporaryDirectory() + "/PDFMasterTest", withIntermediateDirectories: true)
  198. }
  199. let document = CPDFDocument(url: url)!
  200. // document.importPages(IndexSet(integer: 0), from: document, at: 0)
  201. let count = document.pageCount
  202. for _ in 0...(count - 1) {
  203. document.removePage(at: 0)
  204. }
  205. return document
  206. }
  207. /**
  208. 获取pages
  209. @param type 页面类型
  210. @param contentType annoation类型
  211. @param selectPages 当type 为custom时 传入选中page的下标
  212. */
  213. func fetchPages(_ documentURL: URL, _ pageModel: KMPrintPageModel) -> [KMPrintDrawPage] {
  214. let document = PDFDocument.init(url: documentURL)!
  215. var pageIndexs: [Int] = []
  216. let range = pageModel.range
  217. let contentType = pageModel.contentType
  218. let reversePrintOrder = range.reversePrintOrder
  219. switch range.type {
  220. case .allPage:
  221. for index in 0...document.pageCount - 1 {
  222. pageIndexs.append(index)
  223. }
  224. case .evenPage:
  225. for index in 0...document.pageCount - 1 {
  226. if index % 2 == 0 {
  227. pageIndexs.append(index)
  228. }
  229. }
  230. case .oddPage:
  231. for index in 0...document.pageCount - 1 {
  232. if index % 2 != 0 {
  233. pageIndexs.append(index)
  234. }
  235. }
  236. case .currentPage:
  237. pageIndexs.append(0)
  238. case .custom:
  239. pageIndexs.append(0)
  240. default:
  241. pageIndexs.append(0)
  242. }
  243. var pagesArray: [KMPrintDrawPage] = []
  244. for index in pageIndexs {
  245. let page = document.page(at: index)!
  246. let drawPage = KMPrintDrawPage()
  247. drawPage.page = page
  248. self.dealPageContent(contentType, [drawPage])
  249. if reversePrintOrder {
  250. pagesArray.insert(drawPage, at: 0)
  251. } else {
  252. pagesArray.append(drawPage)
  253. }
  254. }
  255. return pagesArray
  256. }
  257. /**
  258. 处理page annoation 内容
  259. @param contentType annoation类型
  260. @param pages page
  261. */
  262. func dealPageContent (_ contentType: KMPrintContentType, _ pages: [KMPrintDrawPage]) -> Void {
  263. for page in pages {
  264. let annoations: [PDFAnnotation] = page.page.annotations
  265. //内容处理
  266. switch contentType {
  267. case .document:
  268. for annoation in annoations {
  269. annoation.page!.removeAnnotation(annoation)
  270. }
  271. case .documentAndStamp:
  272. for annoation in annoations {
  273. if !self.isAnnoationStamp(type: annoation.type!) {
  274. annoation.page!.removeAnnotation(annoation)
  275. }
  276. }
  277. case .documentAndMarkup:
  278. for annoation in annoations {
  279. if !self.isAnnoationMarkup(type: annoation.type!) {
  280. annoation.page!.removeAnnotation(annoation)
  281. }
  282. }
  283. case .documentAndForm:
  284. for annoation in annoations {
  285. if !self.isAnnoationForm(type: annoation.type!) {
  286. annoation.page!.removeAnnotation(annoation)
  287. }
  288. }
  289. default:
  290. KMPrint("未找到")
  291. break
  292. }
  293. }
  294. }
  295. /**
  296. @abstract 获取context
  297. @param size纸张大小
  298. */
  299. func createContext(_ saveFilePath: String, _ size: CGSize) -> CGContext {
  300. var mediaBox: CGRect = NSMakeRect(0, 0, size.width, size.height)
  301. let url = CFURLCreateWithFileSystemPath(nil, saveFilePath as CFString, .cfurlposixPathStyle, false)
  302. let content: CGContext = CGContext.init(url!, mediaBox: &mediaBox, nil)!
  303. return content
  304. }
  305. /**
  306. @abstract 绘制page
  307. @param context
  308. @pages page数组 [CPDFPage]
  309. */
  310. func drawPageToContext(_ context: CGContext, _ pages: [KMPrintDrawPage], _ data: KMPrintModel, _ drawPageRect: CGRect = NSZeroRect) {
  311. //左下角有坐标系原点
  312. /**
  313. paper
  314. */
  315. let paperSize: CGSize = self.fetchPaperSize(data.paper)//纸张大小
  316. let paperItemSize: CGSize = self.fetchPaperItemSize(data.paper) //页面paper大小(去除边框)
  317. let paperInset: NSEdgeInsets = data.paper.info.inset //绘制paper大小
  318. let border: Bool = data.page.operation.multipage.isBorder //是否存在边框
  319. /**
  320. page
  321. */
  322. let pageOrder: KMPrintPageOperation.Multipage.Order = .horizontal //页面顺序
  323. let pageSize: CGSize = self.fetchPageItemSize(data.page, paperItemSize) //page大小
  324. let showModel: KMPrintPageOperation.Size = self.fetchShowModel(data.page)
  325. let autoRotate = self.fetchAutoRotate(data.page)
  326. let autoSize: Bool = self.fetchAutoSize(data.page)
  327. //行列
  328. let columnAndRow = self.fetchPageColumnAndRow(data.page) //行 列数量
  329. let columnAndRowSpace = CGPoint(x: data.page.operation.multipage.lineSpacing, y: data.page.operation.multipage.columnsSpacing) //行 列之间的空间
  330. for i in 0..<Int(columnAndRow.x) {
  331. for j in 0..<(Int(columnAndRow.y)) {
  332. let index = j + i * Int(columnAndRow.y)
  333. if index < pages.count {
  334. //参数
  335. let page: KMPrintDrawPage = pages[index]
  336. let rect = page.showRect
  337. //裁剪当前Page
  338. page.page.setBounds(page.cropRect, for: .cropBox)
  339. let pageItemSize = rect.size
  340. let rotate = page.page.rotation
  341. var scale = self.fetchPageScale(page, pageSize, autoRotate, autoSize)
  342. if data.page.operation.type == .size {
  343. if showModel.model == .custom {
  344. scale *= showModel.scale
  345. } else if showModel.model == .full {
  346. scale = 1
  347. }
  348. } else if (data.page.operation.type == .poster) {
  349. if (data.page.operation.poster.type == .tile) {
  350. scale = data.page.operation.poster.scale
  351. }
  352. } else if (data.page.operation.type == .pamphlet) {
  353. let margin = data.page.operation.pamphlet.margin
  354. let tempSize = CGSizeMake((pageSize.width - margin) / 2, pageSize.height)
  355. scale = min(tempSize.width / pageSize.width, tempSize.height / pageSize.height)
  356. }
  357. //当前item的自身中心点
  358. let center = CGPoint(x: (pageSize.width - pageItemSize.width * scale) / 2.0 ,
  359. y: (pageSize.height - pageItemSize.height * scale) / 2.0)
  360. var origin = rect.origin
  361. //多页Page自动旋转
  362. // if autoSize {
  363. switch pageOrder {
  364. case .horizontal:
  365. origin.x = (pageSize.width + columnAndRowSpace.x) * CGFloat(i) + paperInset.left + center.x
  366. //页面内容高度 + 下边的行间距 - 第几个cell的高度 +居中
  367. origin.y = paperSize.height - (pageSize.height + columnAndRowSpace.y) * (CGFloat(j) + 1) + center.y + columnAndRowSpace.y
  368. case .horizontalReverseSequence:
  369. origin.x = paperSize.width - (pageSize.width + columnAndRowSpace.x) * (CGFloat(i) + 1) + center.x + columnAndRowSpace.x
  370. origin.y = paperSize.height - (pageSize.height + columnAndRowSpace.y) * (CGFloat(j) + 1) + center.y + paperInset.bottom + columnAndRowSpace.y
  371. case .vertical:
  372. origin.x = (pageSize.width + columnAndRowSpace.x) * CGFloat(i) + paperInset.left + center.x
  373. origin.y = paperSize.height - (pageSize.height + columnAndRowSpace.y) * (CGFloat(j) + 1) + center.y + paperInset.bottom + columnAndRowSpace.y
  374. case .verticalReverseSequence:
  375. origin.x = paperSize.width - (pageSize.width + columnAndRowSpace.x) * (CGFloat(i) + 1) + center.x + columnAndRowSpace.x
  376. origin.y = paperSize.height - (pageSize.height + columnAndRowSpace.y) * (CGFloat(j) + 1) + center.y + paperInset.bottom + columnAndRowSpace.y
  377. default:
  378. KMPrint("未找到")
  379. break
  380. }
  381. // }
  382. NSGraphicsContext.current = NSGraphicsContext(cgContext: context, flipped: false)
  383. NSGraphicsContext.saveGraphicsState()
  384. //平移
  385. context.translateBy(x: origin.x, y: origin.y)
  386. //缩放
  387. context.scaleBy(x: CGFloat(scale), y: CGFloat(scale))
  388. page.page.draw(with: PDFDisplayBox.cropBox, to: context)
  389. page.page.transform(context, for: PDFDisplayBox.cropBox)
  390. if border {
  391. var dirtyRect = rect
  392. //CGRectMake(origin.x, origin.y, 100, 100)
  393. if rotate == 90 ||
  394. rotate == 270 {
  395. dirtyRect = NSMakeRect(dirtyRect.origin.x, dirtyRect.origin.y, dirtyRect.size.height, dirtyRect.size.width)
  396. }
  397. context.addRect(dirtyRect)
  398. context.setStrokeColor(red: 0, green: 0, blue: 0, alpha: 1.0)
  399. context.strokePath()
  400. }
  401. NSGraphicsContext.restoreGraphicsState()
  402. // page.setBounds(NSRect(x: 0, y: 0, width: pageRect.size.width, height: pageRect.size.height), for: .cropBox)
  403. }
  404. }
  405. }
  406. }
  407. func drawLabelTextContextSize(context: CGContext) {
  408. let pageSize = CGSize(width: 0, height: 0)
  409. let KBlankA4W = pageSize.width
  410. let KBlankA4H = pageSize.height
  411. var contextString: String
  412. // if let labelString = PDFPrint.labelString, !labelString.isEmpty {
  413. // contextString = labelString
  414. // } else {
  415. let date = Date()
  416. let formatter = DateFormatter()
  417. formatter.dateFormat = "YYYY-MM-dd hh:mm:ss"
  418. contextString = "(\("1"),\("1")) \("filePath.lastPathComponent") \(formatter.string(from: date))"
  419. // }
  420. let fontSize = 12.0 * (max(KBlankA4W, KBlankA4H) / 842)
  421. let font = NSFont.systemFont(ofSize: fontSize)
  422. let color = NSColor.black
  423. var size = NSSize.zero
  424. var style = NSMutableParagraphStyle()
  425. style.alignment = .center
  426. style.lineBreakMode = .byCharWrapping
  427. var attributes = [NSAttributedString.Key: Any]()
  428. attributes[.paragraphStyle] = style
  429. attributes[.foregroundColor] = color
  430. attributes[.font] = font
  431. size = contextString.boundingRect(with: CGSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude),
  432. options: [.usesLineFragmentOrigin, .usesFontLeading],
  433. attributes: attributes).size
  434. // if PDFPrint.splitType == .pageNumber {
  435. contextString.draw(in: CGRect(x: 10 + 10,
  436. y: KBlankA4H - 10 + size.height,
  437. width: size.width, height: size.height),
  438. withAttributes: attributes)
  439. // } else {
  440. // contextString.draw(in: CGRect(x: PDFPrint.edgeInsets.left + 10,
  441. // y: KBlankA4H - PDFPrint.edgeInsets.top + size.height,
  442. // width: size.width, height: size.height),
  443. // withAttributes: attributes)
  444. // }
  445. }
  446. }
  447. protocol KMPrintPresenterPage {}
  448. extension KMPrintPresenter: KMPrintPresenterPage {
  449. /**
  450. 获取pages
  451. @param type 页面类型
  452. @param contentType annoation类型
  453. @param selectPages 当type 为custom时 传入选中page的下标
  454. */
  455. func fetchPageCropRect(_ paperSize: CGSize, _ index: Int, _ pageModel: KMPrintPageModel, _ page: KMPrintDrawPage) -> CGRect {
  456. var newRect = page.page.bounds(for: .cropBox)
  457. if (pageModel.operation.type == .poster) {
  458. let originSize = newRect.size
  459. var cropPoint = CGPoint(x: 1, y: 1)
  460. var scale = 1.0
  461. if (pageModel.operation.poster.type == .tile) {
  462. cropPoint = pageModel.operation.poster.tilePoint
  463. // scale = pageModel.operation.poster.scale
  464. } else if (pageModel.operation.poster.type == .breakUp) {
  465. cropPoint = pageModel.operation.pageOfPaper.point
  466. }
  467. let width = originSize.width / cropPoint.x
  468. let height = originSize.height / cropPoint.y
  469. let column: Int = Int(cropPoint.x) //行
  470. let row: Int = Int(cropPoint.y) //列
  471. for i in 0...column - 1 {
  472. for j in 0...row - 1 {
  473. if i + j + i * (row - 1) == index {
  474. newRect.origin.x = CGFloat(i) * width * scale
  475. newRect.origin.y = ((originSize.height - CGFloat(j) * height - height)) * scale
  476. newRect.size.width = width * scale
  477. newRect.size.height = height * scale
  478. return newRect
  479. }
  480. }
  481. }
  482. }
  483. return newRect
  484. }
  485. func fetchPageShowRect(_ paperSize: CGSize, _ index: Int, _ pageModel: KMPrintPageModel, _ page: KMPrintDrawPage) -> CGRect {
  486. var newRect = NSZeroRect
  487. var pageRect = CGRect(x: 0, y: 0, width: paperSize.width, height: paperSize.height)
  488. if (pageModel.operation.type == .poster) {
  489. let pageSize = page.page.bounds(for: .cropBox)
  490. var cropPoint = CGPoint(x: 1, y: 1)
  491. var scale = 1.0
  492. if (pageModel.operation.poster.type == .tile) {
  493. cropPoint = pageModel.operation.poster.tilePoint
  494. scale = pageModel.operation.poster.scale
  495. } else if (pageModel.operation.poster.type == .breakUp) {
  496. cropPoint = pageModel.operation.pageOfPaper.point
  497. }
  498. if (cropPoint.x == 1 && cropPoint.y == 1) {
  499. } else {
  500. let originPaperSize = CGSize(width: paperSize.width * cropPoint.x, height: paperSize.height * cropPoint.y)
  501. let pageWidth = pageSize.width * scale
  502. let pageHeight = pageSize.height * scale
  503. let pageOrigin = CGPoint(x: (originPaperSize.width - pageWidth) / 2, y: (originPaperSize.height - pageHeight) / 2)
  504. let width = originPaperSize.width / cropPoint.x
  505. let height = originPaperSize.height / cropPoint.y
  506. let column: Int = Int(cropPoint.x) //行
  507. let row: Int = Int(cropPoint.y) //列
  508. for i in 0...column - 1 {
  509. for j in 0...row - 1 {
  510. if i + j + i * (row - 1) == index {
  511. newRect.origin.x = CGFloat(i) * width
  512. newRect.origin.y = ((originPaperSize.height - CGFloat(j) * height - height))
  513. newRect.size.width = width
  514. newRect.size.height = height
  515. if (pageOrigin.x > newRect.origin.x) {
  516. pageRect.origin.x = pageOrigin.x
  517. pageRect.size.width = newRect.size.width - pageOrigin.x
  518. } else if (originPaperSize.width - pageOrigin.x > newRect.origin.x) {
  519. pageRect.origin.x = 0
  520. pageRect.size.width = newRect.size.width - pageOrigin.x
  521. } else {
  522. pageRect.origin.x = 0
  523. pageRect.size.width = newRect.size.width
  524. }
  525. if (originPaperSize.height - pageOrigin.y < newRect.origin.y + newRect.size.height) {
  526. pageRect.origin.y = 0
  527. pageRect.size.height = newRect.size.height - pageOrigin.y
  528. } else if (pageOrigin.y > newRect.origin.y) {
  529. pageRect.origin.y = pageOrigin.y
  530. pageRect.size.height = newRect.size.height - pageOrigin.y
  531. } else {
  532. pageRect.origin.y = newRect.origin.y - pageOrigin.y
  533. pageRect.size.height = newRect.size.height
  534. }
  535. return pageRect
  536. }
  537. }
  538. }
  539. }
  540. }
  541. return pageRect
  542. }
  543. func fetchPageColumnAndRow(_ pageModel: KMPrintPageModel) -> CGPoint {
  544. var point = NSZeroPoint
  545. let pageOrder: KMPrintPageOperation.Multipage.Order = pageModel.operation.multipage.orderType //页面顺序
  546. switch pageModel.operation.type {
  547. case .multipage:
  548. point.x = pageModel.operation.pageOfPaper.point.x
  549. point.y = pageModel.operation.pageOfPaper.point.y
  550. case .pamphlet:
  551. point.x = 1
  552. point.y = 2
  553. default:
  554. point.x = 1
  555. point.y = 1
  556. }
  557. //如果是横向参数需切换
  558. if pageOrder == .horizontal ||
  559. pageOrder == .horizontalReverseSequence {
  560. let temp = point.x
  561. point.x = point.y
  562. point.y = temp
  563. }
  564. return point
  565. }
  566. func fetchAutoRotate(_ pageModel: KMPrintPageModel) -> Bool {
  567. var autoRotate = false
  568. switch pageModel.operation.type {
  569. case .multipage:
  570. autoRotate = pageModel.operation.isAutoRotate
  571. case .pamphlet:
  572. autoRotate = pageModel.operation.isAutoRotate
  573. default:
  574. autoRotate = false
  575. }
  576. return autoRotate
  577. }
  578. func fetchAutoSize(_ pageModel: KMPrintPageModel) -> Bool {
  579. var autoSize = false
  580. switch pageModel.operation.type {
  581. case .size:
  582. autoSize = true
  583. default:
  584. autoSize = false
  585. }
  586. return autoSize
  587. }
  588. func fetchShowModel(_ pageModel: KMPrintPageModel) -> KMPrintPageOperation.Size {
  589. var model = KMPrintPageOperation.Size()
  590. switch pageModel.operation.type {
  591. case .size:
  592. model = pageModel.operation.size
  593. default:
  594. model = KMPrintPageOperation.Size()
  595. }
  596. return model
  597. }
  598. func fetchPageItemSize(_ pageModel: KMPrintPageModel, _ paperSize: CGSize) -> CGSize {
  599. var size = NSZeroSize
  600. let columnAndRow = self.fetchPageColumnAndRow(pageModel) //行 列数量
  601. let lineSpacing = pageModel.operation.multipage.lineSpacing
  602. let columnsSpacing = pageModel.operation.multipage.columnsSpacing
  603. let columnAndRowSpace = CGPoint(x: lineSpacing, y: columnsSpacing) //行 列之间的空间
  604. //page大小
  605. if pageModel.operation.type == .multipage {
  606. size = CGSize(width: (paperSize.width - CGFloat((columnAndRow.x - 1)) * CGFloat(columnAndRowSpace.x)) / columnAndRow.x,
  607. height: (paperSize.height - CGFloat((columnAndRow.y - 1)) * CGFloat(columnAndRowSpace.y)) / columnAndRow.y)
  608. } else {
  609. size = CGSize(width: (paperSize.width - CGFloat((columnAndRow.x - 1)) * CGFloat(columnAndRowSpace.x)) / columnAndRow.x,
  610. height: (paperSize.height - CGFloat((columnAndRow.y - 1)) * CGFloat(columnAndRowSpace.y)) / columnAndRow.y)
  611. }
  612. return size
  613. }
  614. func fetchPageScale(_ page: KMPrintDrawPage, _ pageItemSize: CGSize, _ autoRotate: Bool, _ autoSize: Bool) -> CGFloat {
  615. var scale = 1.0
  616. let originSize = page.page.bounds(for: .cropBox)
  617. var rotate = page.page.rotation
  618. //取出page横竖时能显示的最大Rect
  619. if autoRotate {
  620. //page旋转度数为0度或者180度时,在指定的大小内,能显示的比例
  621. let scale1 = min(pageItemSize.width / originSize.width, pageItemSize.height / originSize.height)
  622. //page旋转度数为90度或者270度时,在指定的大小内,能显示的比例
  623. let scale2 = min(pageItemSize.width / originSize.height, pageItemSize.height / originSize.width)
  624. scale = max(scale1, scale2)
  625. if scale1 > scale2 {
  626. //高为竖直排列时,显示最大,则需将page时90度或者270度需要进行旋转
  627. if rotate == 90 || rotate == 270 {
  628. rotate = rotate - 90
  629. }
  630. } else {
  631. //宽为竖直排列时,显示最大,则需将page时0度或者180度需要进行旋转
  632. if rotate == 0 || rotate == 180 {
  633. rotate = rotate - 90
  634. }
  635. }
  636. } else {
  637. scale = min(pageItemSize.width / originSize.width, pageItemSize.height / originSize.height)
  638. }
  639. if (autoSize) {
  640. } else {
  641. scale = min(scale, 1)
  642. }
  643. return scale
  644. }
  645. func fetchPageRotate(_ page: KMPrintDrawPage, _ pageItemSize: CGSize, _ autoRotate: Bool) -> CGFloat {
  646. var scale = 1.0
  647. let originSize = page.page.bounds(for: .cropBox)
  648. var rotate = page.page.rotation
  649. //取出page横竖时能显示的最大Rect
  650. if autoRotate {
  651. //page旋转度数为0度或者180度时,在指定的大小内,能显示的比例
  652. let scale1 = min(pageItemSize.width / originSize.width, pageItemSize.height / originSize.height)
  653. //page旋转度数为90度或者270度时,在指定的大小内,能显示的比例
  654. let scale2 = min(pageItemSize.width / originSize.height, pageItemSize.height / originSize.width)
  655. scale = max(scale1, scale2)
  656. if scale1 > scale2 {
  657. //高为竖直排列时,显示最大,则需将page时90度或者270度需要进行旋转
  658. if rotate == 90 || rotate == 270 {
  659. rotate = rotate - 90
  660. }
  661. } else {
  662. //宽为竖直排列时,显示最大,则需将page时0度或者180度需要进行旋转
  663. if rotate == 0 || rotate == 180 {
  664. rotate = rotate - 90
  665. }
  666. }
  667. } else {
  668. scale = min(pageItemSize.width / originSize.width, pageItemSize.height / originSize.height)
  669. }
  670. return scale
  671. }
  672. func fetchPageLite(pageModel: KMPrintPageModel) {
  673. }
  674. }
  675. protocol KMPrintPresenterPaper {}
  676. extension KMPrintPresenter: KMPrintPresenterPaper {
  677. /**
  678. 获取每张纸的page
  679. @param type 页面类型
  680. @param contentType annoation类型
  681. @param selectPages 当type 为custom时 传入选中page的下标
  682. */
  683. func fetchPageOfPaper(_ pageModel: KMPrintPageModel) -> Int {
  684. var count = 1
  685. switch pageModel.operation.type {
  686. case .multipage:
  687. count = Int(pageModel.operation.pageOfPaper.point.x * pageModel.operation.pageOfPaper.point.y)
  688. case .poster:
  689. count = Int(pageModel.operation.pageOfPaper.point.x * pageModel.operation.pageOfPaper.point.y)
  690. case .pamphlet:
  691. count = 2
  692. default:
  693. count = 1
  694. }
  695. return count
  696. }
  697. /**
  698. 获取总纸张数
  699. @param pages page总数
  700. @param contentType annoation类型
  701. @param selectPages 当type 为custom时 传入选中page的下标
  702. */
  703. func fetchTotalPaperCount (_ paperSize: CGSize, _ pages: [KMPrintDrawPage], _ pageModel: KMPrintPageModel) -> Int {
  704. var count = 1
  705. let pageOfPaper = self.fetchPageOfPaper(pageModel)
  706. switch pageModel.operation.type {
  707. case .multipage:
  708. count = Int(ceilf(Float(pages.count / pageOfPaper)))
  709. case .poster:
  710. if (pageModel.operation.poster.type == .tile) {
  711. //1 2 4 9 16
  712. let scale = pageModel.operation.poster.scale
  713. let pageSize = pages.first?.page.bounds(for: .cropBox).size ?? paperSize
  714. let point = self.fetchPosterPageCount(paperSize: paperSize, pageSize: pageSize, scale: scale)
  715. pageModel.operation.poster.tilePoint = point
  716. count = Int((point.x * point.y)) * pages.count
  717. } else if (pageModel.operation.poster.type == .breakUp) {
  718. count = Int((pageModel.operation.pageOfPaper.point.x * pageModel.operation.pageOfPaper.point.y)) * pages.count
  719. } else {
  720. count = Int(ceilf(Float(pages.count / pageOfPaper)))
  721. }
  722. case .pamphlet: do {
  723. let temp = pages.count%2
  724. if temp == 0 {
  725. count = pages.count / 2
  726. } else {
  727. count = pages.count / 2 + 1
  728. }
  729. }
  730. default:
  731. count = Int(ceilf(Float(pages.count / pageOfPaper)))
  732. }
  733. return count
  734. }
  735. func fetchPosterPageCount(paperSize: CGSize, pageSize: CGSize, scale: CGFloat) -> CGPoint {
  736. var xCount: Int = 1
  737. var yCount: Int = 1
  738. var contain: Bool = true
  739. while (contain) {
  740. if (pageSize.width * scale < CGFloat(xCount) * paperSize.width &&
  741. pageSize.height * scale < CGFloat(yCount) * paperSize.height) {
  742. contain = false
  743. break
  744. }
  745. //增加行数 和 列数
  746. if xCount == yCount {
  747. xCount += 1
  748. } else {
  749. yCount += 1
  750. }
  751. }
  752. return CGPoint(x: xCount, y: yCount)
  753. }
  754. /**
  755. 获取pages
  756. @param type 页面类型
  757. @param contentType annoation类型
  758. @param selectPages 当type 为custom时 传入选中page的下标
  759. */
  760. func fetchPaperSize(_ paperModel: KMPrintPaperModel) -> CGSize {
  761. var paperSize = KMPrintPaperInfo.KMPaperType.paperSize(type: paperModel.info.type, unit: .px)
  762. let direction = paperModel.direction
  763. if direction == .vertical {
  764. paperSize = CGSize(width: paperSize.width, height: paperSize.height)
  765. } else if direction == .horizontal {
  766. paperSize = CGSize(width: paperSize.height, height: paperSize.width)
  767. }
  768. return paperSize
  769. }
  770. func fetchPaperItemSize(_ paperModel: KMPrintPaperModel) -> CGSize {
  771. var paperSize = self.fetchPaperSize(paperModel)
  772. let paperInset = paperModel.info.inset
  773. paperSize = CGSize(width: paperSize.width - paperInset.left - paperInset.right,
  774. height: paperSize.height - paperInset.bottom - paperInset.top)
  775. return paperSize
  776. }
  777. }
  778. protocol KMPrintPresenterDraw {}
  779. extension KMPrintPresenter: KMPrintPresenterDraw {
  780. // -(void)drawCutMarkContext:(CGContextRef)context contextSize:(CGSize)size
  781. // {
  782. // CGContextSetStrokeColorWithColor(context, [NSColor blackColor].CGColor);
  783. // CGContextSetLineWidth(context, 1.0);
  784. // CGContextSetLineCap(context, kCGLineCapSquare);
  785. //
  786. // if(self.columnIndex == 1 && self.lineIndex == 1) {
  787. // [self drawLeftBottomCutMarks:context size:size];
  788. // [self drawRightTopCutMarks:context size:size];
  789. // [self drawRightBottomCutMarks:context size:size];
  790. // } else if (self.lineIndex == 1 && self.columnIndex == self.vertArray.count) {
  791. // [self drawLeftTopCutMarks:context size:size];
  792. // [self drawRightTopCutMarks:context size:size];
  793. // [self drawRightBottomCutMarks:context size:size];
  794. // } else if (self.columnIndex == 1 && self.lineIndex == self.hourArray.count) {
  795. // [self drawLeftTopCutMarks:context size:size];
  796. // [self drawLeftBottomCutMarks:context size:size];
  797. // [self drawRightBottomCutMarks:context size:size];
  798. // } else if (self.columnIndex == self.vertArray.count && self.hourArray.count == self.lineIndex) {
  799. // [self drawLeftTopCutMarks:context size:size];
  800. // [self drawLeftBottomCutMarks:context size:size];
  801. // [self drawRightTopCutMarks:context size:size];
  802. // } else {
  803. // [self drawLeftTopCutMarks:context size:size];
  804. // [self drawLeftBottomCutMarks:context size:size];
  805. // [self drawRightTopCutMarks:context size:size];
  806. // [self drawRightBottomCutMarks:context size:size];
  807. // }
  808. // //绘制完成
  809. // CGContextStrokePath(context);
  810. // }
  811. //
  812. // //左上角切割标记
  813. // -(void)drawLeftTopCutMarks:(CGContextRef)context size:(CGSize)size
  814. // {
  815. // CGFloat KBlankA4H =size.height;
  816. // CGPoint point_LeftTop = CGPointZero;
  817. //
  818. // if (self.PDFPrint.splitType == kKMPDFPosterSplitType_PageNumber) {
  819. // point_LeftTop.x = self.PDFPrint.fullPageEdgeInsets.left;
  820. // } else {
  821. // point_LeftTop.x = self.PDFPrint.edgeInsets.left;
  822. // }
  823. //
  824. // point_LeftTop.y = KBlankA4H - self.PDFPrint.edgeInsets.top;
  825. //
  826. // CGContextMoveToPoint(context, 10,point_LeftTop.y);
  827. // CGContextAddLineToPoint(context,point_LeftTop.x, point_LeftTop.y);
  828. //
  829. // CGContextMoveToPoint(context, point_LeftTop.x - 10,KBlankA4H -10);
  830. // CGContextAddLineToPoint(context,point_LeftTop.x - 10,point_LeftTop.y);
  831. // }
  832. //
  833. // //右上角切割标记
  834. // -(void)drawRightTopCutMarks:(CGContextRef)context size:(CGSize)size
  835. // {
  836. // CGFloat KBlankA4W =size.width;
  837. // CGFloat KBlankA4H =size.height;
  838. //
  839. // CGPoint point_RightTop = CGPointZero;//右上角
  840. //
  841. // if (self.PDFPrint.splitType == kKMPDFPosterSplitType_PageNumber) {
  842. // point_RightTop.x = KBlankA4W - self.PDFPrint.fullPageEdgeInsets.right;
  843. // point_RightTop.y = KBlankA4H - self.PDFPrint.fullPageEdgeInsets.top;
  844. // } else {
  845. // point_RightTop.x = KBlankA4W - self.PDFPrint.edgeInsets.right;
  846. // point_RightTop.y = KBlankA4H - self.PDFPrint.edgeInsets.top;
  847. // }
  848. //
  849. // CGContextMoveToPoint(context,point_RightTop.x,point_RightTop.y);
  850. // CGContextAddLineToPoint(context,KBlankA4W - 10,point_RightTop.y);
  851. //
  852. // CGContextMoveToPoint(context,point_RightTop.x + 10,KBlankA4H - 10);
  853. // CGContextAddLineToPoint(context,point_RightTop.x + 10,point_RightTop.y);
  854. // }
  855. //
  856. // //左下角切割标记
  857. // -(void)drawLeftBottomCutMarks:(CGContextRef)context size:(CGSize)size
  858. // {
  859. // CGPoint point_LeftBottom = CGPointZero;//左下角
  860. // if (self.PDFPrint.splitType == kKMPDFPosterSplitType_PageNumber) {
  861. // point_LeftBottom.x = self.PDFPrint.fullPageEdgeInsets.left;
  862. // point_LeftBottom.y = self.PDFPrint.fullPageEdgeInsets.bottom;
  863. // } else {
  864. // point_LeftBottom.x = self.PDFPrint.edgeInsets.left;
  865. // point_LeftBottom.y = self.PDFPrint.edgeInsets.bottom;
  866. // }
  867. //
  868. // //左下角
  869. // CGContextMoveToPoint(context, 10,point_LeftBottom.y);
  870. // CGContextAddLineToPoint(context,point_LeftBottom.x, point_LeftBottom.y);
  871. //
  872. // CGContextMoveToPoint(context, point_LeftBottom.x- 10,10);
  873. // CGContextAddLineToPoint(context,point_LeftBottom.x - 10,point_LeftBottom.y);
  874. // }
  875. //
  876. // //右下角切割标记
  877. // -(void)drawRightBottomCutMarks:(CGContextRef)context size:(CGSize)size
  878. // {
  879. // CGFloat KBlankA4W =size.width;
  880. //
  881. // CGPoint point_RightBottom = CGPointZero;//右下角
  882. // if (self.PDFPrint.splitType == kKMPDFPosterSplitType_PageNumber) {
  883. // point_RightBottom.x = KBlankA4W - self.PDFPrint.fullPageEdgeInsets.right;
  884. // point_RightBottom.y = self.PDFPrint.fullPageEdgeInsets.bottom;
  885. // } else {
  886. // point_RightBottom.x = KBlankA4W - self.PDFPrint.edgeInsets.right;
  887. // point_RightBottom.y = self.PDFPrint.edgeInsets.bottom;
  888. // }
  889. //
  890. // CGContextMoveToPoint(context,KBlankA4W - 10,point_RightBottom.y);
  891. // CGContextAddLineToPoint(context,point_RightBottom.x,point_RightBottom.y);
  892. //
  893. // CGContextMoveToPoint(context,point_RightBottom.x+ 10,10);
  894. // CGContextAddLineToPoint(context,point_RightBottom.x+ 10,point_RightBottom.y);
  895. // }
  896. func drawString(_ pageModel: KMPrintPageModel, _ contextSize: CGSize) {
  897. var string = pageModel.operation.poster.tags.first ?? ""
  898. // if string.isEmpty {
  899. // string =
  900. // }
  901. }
  902. //
  903. // - (void)drawLabelTextContextSize:(CGSize)contextSize
  904. // {
  905. // CGFloat KBlankA4W =contextSize.width;
  906. // CGFloat KBlankA4H =contextSize.height;
  907. //
  908. // NSString *contextString = nil;
  909. // if (self.PDFPrint.labelString && self.PDFPrint.labelString.length > 0) {
  910. // contextString = self.PDFPrint.labelString;
  911. // } else {
  912. // NSDate *date = [NSDate date];
  913. // NSDateFormatter *formatter = [[[NSDateFormatter alloc] init] autorelease];
  914. // [formatter setDateFormat:@"YYYY-MM-dd hh:mm:ss"];
  915. // contextString = [NSString stringWithFormat:@"(%ld,%ld) %@ %@",self.columnIndex,self.lineIndex,[self.filePath lastPathComponent],[formatter stringFromDate:date]];
  916. // }
  917. //
  918. // CGFloat fontSize = 12.0 * (MAX(KBlankA4W, KBlankA4H)/842);
  919. // NSFont *font = [NSFont systemFontOfSize:fontSize];
  920. // NSColor *color = [NSColor blackColor];
  921. //
  922. // NSSize size = NSZeroSize;
  923. // NSMutableParagraphStyle *style = [[[NSMutableParagraphStyle alloc] init] autorelease];
  924. // [style setAlignment:NSCenterTextAlignment];
  925. // [style setLineBreakMode:NSLineBreakByCharWrapping];
  926. // NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
  927. // [dictionary setObject:style forKey:NSParagraphStyleAttributeName];
  928. // [dictionary setObject:color forKey:NSForegroundColorAttributeName];
  929. // [dictionary setObject:font forKey:NSFontAttributeName];
  930. // size = [contextString boundingRectWithSize:CGSizeMake(MAXFLOAT, MAXFLOAT)
  931. // options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading
  932. // attributes:dictionary].size;
  933. //
  934. // if (self.PDFPrint.splitType == kKMPDFPosterSplitType_PageNumber) {
  935. // [contextString drawInRect:CGRectMake(self.PDFPrint.fullPageEdgeInsets.left +10,
  936. // KBlankA4H - self.PDFPrint.fullPageEdgeInsets.top + size.height,
  937. // size.width, size.height)
  938. // withAttributes:dictionary];
  939. // } else {
  940. // [contextString drawInRect:CGRectMake(self.PDFPrint.edgeInsets.left +10,
  941. // KBlankA4H - self.PDFPrint.edgeInsets.top + size.height,
  942. // size.width, size.height)
  943. // withAttributes:dictionary];
  944. // }
  945. //
  946. // }
  947. }
  948. protocol KMPrintPresenterPrivate {}
  949. extension KMPrintPresenter: KMPrintPresenterPrivate {
  950. func isAnnoationStamp(type: String) -> Bool {
  951. let annotationStamp: [String] = ["Square", "Stamp"]
  952. return annotationStamp.contains(type)
  953. }
  954. func isAnnoationMarkup(type: String) -> Bool {
  955. let annotationStamp: [String] = ["Widget", "Freehand", "Highlight", "Underline", "Squiggly", "Circle", "StrikeOut", "Ink"]
  956. return annotationStamp.contains(type)
  957. }
  958. func isAnnoationForm(type: String) -> Bool {
  959. let annotationStamp: [String] = ["FreeText"]
  960. return annotationStamp.contains(type)
  961. }
  962. }
  963. protocol KMPrintPresenterProtocol: NSObject {
  964. }
  965. ///**
  966. // @abstract 获取context
  967. // @param size纸张大小
  968. // */
  969. //func createContext(_ saveFilePath: String, size: CGSize) -> CGContext {
  970. // let s = CGSize(width: nearbyint(size.width), height: nearbyint(size.height))
  971. // let rep = NSBitmapImageRep.init(bitmapDataPlanes: nil,
  972. // pixelsWide: Int(s.width),
  973. // pixelsHigh: Int(s.height),
  974. // bitsPerSample: 8,
  975. // samplesPerPixel: 4,
  976. // hasAlpha: true,
  977. // isPlanar: false,
  978. // colorSpaceName: NSColorSpaceName.calibratedRGB,
  979. // bytesPerRow: 0,
  980. // bitsPerPixel: 0)!
  981. // let context: CGContext = NSGraphicsContext.init(bitmapImageRep: rep)!.cgContext
  982. // return context
  983. //}