减少iOS CoreGraphics中渲染PDF的文件大小

减少iOS CoreGraphics中渲染PDF的文件大小,ios,iphone,swift,pdf,Ios,Iphone,Swift,Pdf,在我的应用程序中,我用多张图片(10到15张图片)创建一个PDF,并通过电子邮件发送。我的问题是创建的PDF太大了,即使我使用JPG图像。这些图像是收据或发票的照片 我的调试器向我显示了以下有关要放入PDF的图像的信息(这些图像是通过iPhone 6上的内置摄像头拍摄的) 我已经为创建PDF文件编写了一个协议扩展。这是我的密码: protocol RendersPdf { var realm: Realm { get } func renderPdf() -> URL? }

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

我的调试器向我显示了以下有关要放入PDF的图像的信息(这些图像是通过iPhone 6上的内置摄像头拍摄的)

我已经为创建PDF文件编写了一个协议扩展。这是我的密码:

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点是2倍,iPhone 6:1点是3倍)。

您需要设置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
}
}
类ViewController:UIViewController{
重写func viewDidLoad(){
super.viewDidLoad()
//选择您想要的尺码或使用您自己的尺码
设MB_10=10485760
设MB_5=5242880
设MB_3=3145728
让图像:[UIImage]=[]//NSData{
如果质量>0{
guard let PdfilePath=NSSearchPathForDirectoriesInDomains(.documentDirectory、.userDomainMask,true).first?.appending(“someName.pdf”)else{
打印(“创建pdf路径时出错”)
归零
}
var largestmagesize=CGSize.zero
对于图像中的图像{
如果image.size.width>largestImageSize.width{
largestImageSize.width=image.size.width
}
如果image.size.height>largestImageSize.height{
largestImageSize.height=image.size.height
}
}
设pdfData=NSMutableData()
UIGraphicsBeginPDDFContextToData(pdfData,CGRect(x:0,y:0,宽度:largestImageSize.width,高度:largestImageSize.height),无)
let context=UIGraphicsGetCurrentContext()
对于图像中的图像{
UIGraphicsBeginPDFPage()
UIGraphicsPushContext(上下文!)
如果质量!=100{
guard let imageData=UIImageJPEG表示(图像、CGFloat(质量)/100.0)其他{
打印(“减小图像大小时出错”)
归零
}
guard let newImage=UIImage(数据:imageData)else{
打印(“从数据创建图像时出错”)
归零
}
newImage.draw(在:CGPoint.zero处)
}否则{
image.draw(在:CGPoint.zero处)
}
UIGraphicsPopContext()
}
UIGraphicsSendPdfContext();
如果(pdfData.length>maxSize){
打印(“将质量降低到\(质量-10)”)
return self.createPDF(图像:图像,最大尺寸:最大尺寸,质量:质量-10)
}
if!pdfData.write(toFile:pdfFilePath,原子性:true){
打印(“写入PdfilePath失败”)
}
返回NSData(内容文件:pdfFilePath)
}
归零
}
}

hii@LoVo您的最大尺寸是多少answer@DilipTiwari我在开始时定义了3个静态值,3MB、5MB和10MB(全部为Int)但是你可以选择你喜欢的任何文件大小作为最大文件大小。Hi@productioncoder你有什么解决方案吗?我想我对图像使用了极高的压缩率。这大大减少了大小
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
}
}