macOS Swift生成PDF时如何缩放图片并保留画质?
问题:macOS Ventura下Swift脚本生成PDF时画质丢失
我有一个命令行Swift脚本,用于将一系列像素尺寸相近的图片生成PDF。脚本会将图片标准化,让每张图片作为PDF页面时拥有相同的英寸高宽(比如把扫描的6×9英寸文档的所有图片统一为该尺寸)。由于图片校正和页面老化,各图片像素差异可达3.5%,不标准化会出现留白。
以下是核心缩放逻辑代码,其中height和width为PDF文档期望的英寸高宽:
// 获取当前每英寸像素数 let imageRep = image.representations[0] let originalWidth = CGFloat(imageRep.pixelsWide) let originalHeight = CGFloat(imageRep.pixelsHigh) let pixelsPerInch = originalWidth*72.0/imageRep.size.width // 计算水平缩放比例 let inchesWide = originalWidth/pixelsPerInch let scaleX = width/inchesWide // 计算垂直缩放比例 let inchesHigh = originalHeight/pixelsPerInch let scaleY = height/inchesHigh // 标准化图片,使其添加到PDF时拥有正确的英寸尺寸 let pageSize = NSSize(width:image.size.width*scaleX, height:image.size.height*scaleY) let normalizedImage = NSImage(size:pageSize, flipped:false) { (resizedRect) -> Bool in image.draw(in:resizedRect) return true }
系统版本差异问题
- 在macOS Monterey系统中,脚本可正常缩放尺寸且不改变底层图片质量:比如10.4MB的图片生成的PDF约为10.6MB,修改尺寸仅调整PDF显示尺寸,文件大小基本不变。
- 升级到macOS 13.3.1(Ventura)后,缩放尺寸正确但画质大幅下降:同样10.4MB的图片生成的PDF仅3.5MB,文本几乎无法辨认。
临时方案的局限性
脚本现在会根据NSImage的缩放调整画质,而之前不会。目前尝试过两种临时方案,但都存在问题:
- 增大尺寸可提升可读性,但PDF打开时尺寸过大;
- 直接修改原图片的
size属性,但图片不再标准化,会出现留白。
通过对比发现,代码创建的normalizedImage和从文件生成的image在设置.size时表现不同,推测问题与图片来源有关。需求是将每张扫描图片标准化为精确的英寸尺寸,同时保留原始图片的画质。
测试用精简脚本
// 从一系列图片创建PDF import PDFKit class PDFCreator { let images: [NSImage] var document = PDFDocument() init(images: [NSImage]) { self.images = images } public func create() { // 将图片添加到PDF for var image in self.images { print("添加…", image.name()!, image.size) image = self.normalizeImage(image: image) // 添加到PDF文档 guard let page = PDFPage(image: image) else { print("无法添加", image.name()!, "到文档。") exit(0); } self.document.insert(page, at: self.document.pageCount) } // 保存PDF到文件 print("保存PDF为", outputPath) let fileURL = NSURL.fileURL(withPath: outputPath) self.document.write(to: fileURL) } // 将图片调整为合适的英寸宽高,同时保留画质 private func normalizeImage(image: NSImage) -> NSImage { if width <= 0 || height <= 0 { return image } // 获取当前每英寸像素数 let imageRep = image.representations[0] let originalWidth = CGFloat(imageRep.pixelsWide) let originalHeight = CGFloat(imageRep.pixelsHigh) let pixelsPerInch = originalWidth*72.0/imageRep.size.width // 计算水平缩放比例 let inchesWide = originalWidth/pixelsPerInch let scaleX = width/inchesWide // 计算垂直缩放比例 let inchesHigh = originalHeight/pixelsPerInch let scaleY = height/inchesHigh // 标准化图片,使其添加到PDF时拥有正确的英寸尺寸 let pageSize = NSSize(width:image.size.width*scaleX, height:image.size.height*scaleY) let normalizedImage = NSImage(size:pageSize, flipped:false) { (resizedRect) -> Bool in image.draw(in:resizedRect) return true } return normalizedImage } } // NSImage无法自行解析别名 func resolvePath(path: String) -> URL { do { let file = NSURL.fileURL(withPath: path) return try URL(resolvingAliasFileAt: file) } catch { print("无法找到文件", path) exit(0) } } // 设置默认值并读取图片 let outputPath = "test.pdf" var pages:[NSImage] = [] let width:CGFloat = 5.625 let height:CGFloat = 8.125 for file in CommandLine.arguments[1...] { let resolvedPath = resolvePath(path:file) let image = NSImage(byReferencing: resolvedPath) image.setName(resolvedPath.lastPathComponent) pages.append(image) } if pages == [] { print("至少需要一张图片。");exit(0) } // 创建PDF let pdf = PDFCreator(images: pages) pdf.create()
内容的提问来源于stack exchange,提问作者Jerry Stratton
相关产品推荐
相关产品推荐

