将PDF转换为图像-Swift iOS

时间:2019-01-31 06:10:13

标签: ios swift cgpdfdocument

我正在尝试将PDF文件及其所有页面转换为png图像。

我将下面的代码放在一起,以填充该线程上的示例 How to convert PDF to PNG efficiently?

运行代码时,它在pdf文件源(sourceURL)上崩溃,肯定在那里有一个文件。当我打印sourceURl时,它会将URL打印到文件中。

崩溃表明找到了nil-我的理解是这意味着找不到文件?即使我可以实际看到并打开文件,也可以将URL打印到文件中。

有人可以指出我在做什么错吗?

代码:

func convertPDFtoPNG() {
    let sourceURL = pptURL
    print("pptURL:", pptURL!)
    let destinationURL = pngURL
    let urls = try? convertPDF(at: sourceURL!, to: destinationURL!, fileType: .png, dpi: 200)
}
func convertPDF(at sourceURL: URL, to destinationURL: URL, fileType: ImageFileType, dpi: CGFloat = 200) throws -> [URL] {
    let pdfDocument: CGPDFDocument! = CGPDFDocument(sourceURL as CFURL)!  //Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value

    let colorSpace = CGColorSpaceCreateDeviceRGB()
    let bitmapInfo = CGImageAlphaInfo.noneSkipLast.rawValue

    var urls = [URL](repeating: URL(fileURLWithPath : "/"), count: pdfDocument.numberOfPages)
    DispatchQueue.concurrentPerform(iterations: pdfDocument.numberOfPages) { i in

        let pdfPage = pdfDocument.page(at: i + 1)!

        let mediaBoxRect = pdfPage.getBoxRect(.mediaBox)
        let scale = dpi / 72.0
        let width = Int(mediaBoxRect.width * scale)
        let height = Int(mediaBoxRect.height * scale)

        let context = CGContext(data: nil, width: width, height: height, bitsPerComponent: 8, bytesPerRow: 0, space: colorSpace, bitmapInfo: bitmapInfo)!
        context.interpolationQuality = .high
        context.fill(CGRect(x: 0, y: 0, width: width, height: height))
        context.scaleBy(x: scale, y: scale)
        context.drawPDFPage(pdfPage)

        let image = context.makeImage()!
        let imageName = sourceURL.deletingPathExtension().lastPathComponent
        let imageURL = destinationURL.appendingPathComponent("\(imageName)-Page\(i+1).\(fileType.fileExtention)")

        let imageDestination = CGImageDestinationCreateWithURL(imageURL as CFURL, fileType.uti, 1, nil)!
        CGImageDestinationAddImage(imageDestination, image, nil)
        CGImageDestinationFinalize(imageDestination)

        urls[i] = imageURL
    }
    return urls
}

2 个答案:

答案 0 :(得分:0)

确保您的pptURL是文件url。
URL(string: "path/to/pdf")URL(fileURLWithPath: "path/to/pdf")是不同的东西,并且在启动URL时必须使用最后一个。

输出应以“ file:///”前缀开头,例如

  

file:/// Users / dev / Library / Developer / CoreSimulator / Devices / 4FF18699-D82F-4308-88D6-44E3C11C955A / data / Containers / Bundle / Application / 8F230041-AC15-45D9-863F-5778B565B12F / myApp。 app / example.pdf

答案 1 :(得分:0)


import Foundation
import Photos
// 1: 目前主要用来操作pdf转为图片
// 2: 图片保存到自定义相册中
struct HBPhotosAlbumHelperUtil {
    static let shared = HBPhotosAlbumHelperUtil()
    // url链接的pdf转为image
    // pageNumber :表示pdf的对应的页面,默认为第一页
    func drawToImagePDFFromURL(pdfurl url: String?, pageNumber index: Int = 1, scaleX scalex: CGFloat = 1.0, scaleY scaley: CGFloat = -1.0) -> UIImage? {
        guard let pdfUrl = url, pdfUrl.count > 0, let formatterUrl = pdfUrl.urlValue else {
            return nil
        }
        guard let document = CGPDFDocument(formatterUrl as CFURL) else {
            return nil
        }
        guard let page = document.page(at: index) else {
            return nil
        }
        let pageRect = page.getBoxRect(.mediaBox)
        if #available(iOS 10.0, *) {
            let renderGraph = UIGraphicsImageRenderer(size: pageRect.size)
            let drawImage = renderGraph.image { context in
                UIColor.white.set()
                context.fill(pageRect)
                context.cgContext.translateBy(x: 0.0, y: pageRect.size.height)
                context.cgContext.scaleBy(x: scalex, y: scaley)
                context.cgContext.drawPDFPage(page)
            }
            return drawImage
        } else {
            UIGraphicsBeginImageContextWithOptions(pageRect.size, false, 1.0)
            let context = UIGraphicsGetCurrentContext()
            context?.setFillColor(UIColor.white.cgColor)
            context?.fill(pageRect)
            context?.translateBy(x: 0.0, y: pageRect.size.height)
            context?.scaleBy(x: scalex, y: scaley)
            context?.drawPDFPage(page)
            let pdfImage = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
            return pdfImage
        }
    }
}

// 用来表示保存图片到自定义相册或者系统相册的操作结果
enum HBPhotosAlbumUtilResult {
    case success, error, denied
}

extension HBPhotosAlbumHelperUtil {
    // 请求获取操作系统相册权限
    // 返回true说明已经得到授权
    static var photoAlbumAuthorized: Bool {
        return PHPhotoLibrary.authorizationStatus() == .authorized || PHPhotoLibrary.authorizationStatus() == .notDetermined
    }

    // 保存图片到自定义相册中
    func saveImageToCustomAlbum(saveImage markImage: UIImage, customAlbumName albumName: String = "丰巢管家电子发票", completion: ((_ result: HBPhotosAlbumUtilResult) -> Void)?) {
        guard HBPhotosAlbumHelperUtil.photoAlbumAuthorized else {
            completion?(.denied)
            return
        }
        var assetAlbum: PHAssetCollection?
        // 如果相册名称为空,则图片默认保存到系统相册里面
        if albumName.isEmpty {
            let assetCollection = PHAssetCollection.fetchAssetCollections(with: .smartAlbum, subtype: .smartAlbumUserLibrary,
                                                                          options: nil)
            assetAlbum = assetCollection.firstObject
        } else {
            // 获取指定的相册是否存在
            let assetList = PHAssetCollection.fetchAssetCollections(with: .album, subtype: .any, options: nil)
            assetList.enumerateObjects { albumOption, _, stop in
                let assetCollection = albumOption
                if albumName == assetCollection.localizedTitle {
                    assetAlbum = assetCollection
                    stop.initialize(to: true)
                }
            }
            // 自定义相册不存在就创建
            if assetAlbum == nil {
                PHPhotoLibrary.shared().performChanges({
                    PHAssetCollectionChangeRequest.creationRequestForAssetCollection(withTitle: albumName)
                }) { _, _ in
                    self.saveImageToCustomAlbum(saveImage: markImage, customAlbumName: albumName, completion: completion)
                }
            }
        }
        // 保存图片
        PHPhotoLibrary.shared().performChanges({
            let result = PHAssetChangeRequest.creationRequestForAsset(from: markImage)
            if !albumName.isEmpty {
                if let assetPlaceHolder = result.placeholderForCreatedAsset,
                    let lastAssetAlbum = assetAlbum,
                    let albumChangeRequset = PHAssetCollectionChangeRequest(for:
                        lastAssetAlbum) {
                    albumChangeRequset.addAssets([assetPlaceHolder] as NSArray)
                }
            }
        }) { isSuccess, _ in
            guard isSuccess else {
                completion?(.error)
                return
            }
            completion?(.success)
        }
    }
}



extension String {
    /// URL legalization
    public var urlValue: URL? {
        if let url = URL(string: self) {
            return url
        }
        var set = CharacterSet()
        set.formUnion(.urlHostAllowed)
        set.formUnion(.urlPathAllowed)
        set.formUnion(.urlQueryAllowed)
        set.formUnion(.urlFragmentAllowed)

        return self.addingPercentEncoding(withAllowedCharacters: set).flatMap { URL(string: $0) }
    }
 }


You can use the api like this:

// Use this way to achieve pdf to image
HBPhotosAlbumHelperUtil.shared.drawToImagePDFFromURL(pdfurl: "link to pdf file")


// In this way, you can save pictures to the system custom album.
HBPhotosAlbumHelperUtil.shared.saveImageToCustomAlbum(saveImage: UIImage()) { (result) in

        }