ios - 在 iOS CoreGraphics 中减小渲染 PDF 的文件大小

标签 ios iphone swift pdf

在我的应用程序中,我用多张图片(10 到 15 张图片)创建了一个 PDF,并通过电子邮件发送。我的问题是创建的 PDF 太大了,即使我使用 JPG 图像。图片是收据或发票的照片。

我的调试器向我显示了有关我要放入 PDF 中的图像的以下信息(它们是使用 iPhone 6 上的内置相机拍摄的)

print("UIScreen.main.scale = \(UIScreen.main.scale)") //prints 2
print("image.size = \(image.size)") //prints (2448.0, 3264.0)
print("image.scale = \(image.scale)") //prints image.scale = 1

let imgDataJpg: NSData = NSData(data: UIImageJPEGRepresentation(image, 0.5)!)
let imageSizeJpg = Double(imgDataJpg.length)

print("image size on disk in KB: %f ", imageSizeJpg / 1024.0) //prints 899.5888671875

我已经编写了用于创建 PDF 文件的协议(protocol)扩展。这是我的代码:

protocol RendersPdf {
    var realm: Realm { get }
    func renderPdf() -> URL?
}
extension RendersPdf {

//this is the default size of a PDF page
fileprivate var pageFrame: CGRect {
    get {
        return CGRect(x: 0, y: 0, width: 612, height: 792)
    }
}

func renderPdf(images: [UIImage]) -> URL? {
    let pdfUrl = startPdf()
    let context = UIGraphicsGetCurrentContext()
    defer {
        UIGraphicsEndPDFContext()
    }
    for image in images {
        draw(image: image)
    }   
}
func startPdf() -> URL {
    let pdfUrl = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("somePdfName").appendingPathExtension("pdf")

    let success = UIGraphicsBeginPDFContextToFile(pdfUrl.path, CGRect.zero, nil)
    assert(success, "could not create pdf graphics context")
    return pdfUrl
}
fileprivate func draw(image: UIImage) {
    UIGraphicsBeginPDFPageWithInfo(pageFrame, nil)
    let imageFrame = pageFrame
    image.draw(in: imageFrame)   
}
fileprivate func resize(image: UIImage) -> UIImage {

    UIGraphicsBeginImageContextWithOptions(pageFrame.size, false, 0.0);
    image.draw(in: CGRect(x: 0, y: 0, width: pageFrame.size.width, height: pageFrame.size.height))
    let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext() ?? image
    UIGraphicsEndImageContext()
    return newImage   
}
}

如果我有 11 张图片,我的 PDF 会变得 11MB 大,所以我尝试使用上面的调整大小功能手动调整图像大小来缩小它。但是,PDF 变得更大,在我的情况下高达 32MB(这怎么可能,我把图像变小了?)

如何减小生成的 PDF 的文件大小?如何确保该解决方案适用于不同的屏幕分辨率(iPhone 6:1 点在 iPhone 6+ 1 上为 2px点是 3px)。

最佳答案

您需要设置 pdf 的最大文件大小,并根据此大小降低图像质量。检查此示例,并根据需要随意使用和修改它:

class ViewController: UIViewController {

override func viewDidLoad() {
    super.viewDidLoad()

    //choose the size you want or use your own size
    let MB_10 = 10485760
    let MB_5 = 5242880
    let MB_3 = 3145728

    let images : [UIImage] = [] //<---- insert your images here

    if self.createPDF(images: images, maxSize: MB_5, quality: 100) != nil {
        print("worked check pdfFilePath")
    }
}

func createPDF(images:[UIImage], maxSize:Int, quality:Int) -> NSData? {
    if quality > 0 {
        guard let pdfFilePath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first?.appending("someName.pdf") else {
            print("Error creating pdf path")
            return nil
        }

        var largestImageSize = CGSize.zero

        for image in images {
            if image.size.width > largestImageSize.width {
                largestImageSize.width = image.size.width
            }

            if image.size.height > largestImageSize.height {
                largestImageSize.height = image.size.height
            }
        }

        let pdfData = NSMutableData()
        UIGraphicsBeginPDFContextToData(pdfData, CGRect(x: 0, y: 0, width: largestImageSize.width, height: largestImageSize.height), nil)

        let context = UIGraphicsGetCurrentContext()

        for image in images {
            UIGraphicsBeginPDFPage()
            UIGraphicsPushContext(context!)

            if quality != 100 {
                guard let imageData = UIImageJPEGRepresentation(image, CGFloat(quality) / 100.0) else {
                    print("Error reducing image size")
                    return nil
                }
                guard let newImage = UIImage(data: imageData) else {
                    print("Error creating image from data")
                    return nil
                }
                newImage.draw(at: CGPoint.zero)
            } else {
                image.draw(at: CGPoint.zero)
            }
            UIGraphicsPopContext()
        }

        UIGraphicsEndPDFContext();

        if (pdfData.length > maxSize) {
            print("reduces quality to \(quality - 10)")
            return self.createPDF(images: images, maxSize: maxSize, quality: quality - 10)
        }

        if !pdfData.write(toFile: pdfFilePath, atomically: true) {
            print("write to pdfFilePath failed")
        }

        return NSData(contentsOfFile: pdfFilePath)
    }

    return nil
}
}

关于ios - 在 iOS CoreGraphics 中减小渲染 PDF 的文件大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41663432/

相关文章:

ios - Unwind segue (D->B) 不释放 C

ios - 带有 qos_class_user_interactive 的 global_queue

iphone - 如何将 UITabBarItem 标题更改为另一个 UITabBarItem 的标题?

iphone - 如何将模拟器与测试工具集成?

swift - 如何使用分支和边界的方法解决问题?

ios - 使用苹果在权限消息中缺少应用名称登录

ios - 如何通过 ViewControllers 管理和释放内存

ios - 未找到架构 x86_64 的符号 - iOS

ios - 自定义模态转换解除动画运行不同步

iphone - 如何: iPhone Web Service call to WCF Service with Certificate Authentication