Marlon Brando aka Ben
Marlon Brando aka Ben

Reputation: 933

Why app Terminates due to memory waring when convert pdf page to high quality image in ios, swift in real device

I'm trying to get the image(high quality) of each pdf page. I'm using below code running through a for loop until page count and it works.

    guard let document = CGPDFDocument(pdfurl as CFURL) else { return }
    guard let page = document.page(at: i) else { return }
    let dpi: CGFloat = 300.0/72.0
    let pagerect = page.getBoxRect(.mediaBox)
    print(pagebounds)
    print(pagerect)
    let render = UIGraphicsImageRenderer(size: CGSize(width: pagerect.size.width * dpi, height: pagerect.size.height * dpi))

    let imagedata = render.jpegData(withCompressionQuality: 0.5, actions: { cnv in
        UIColor.white.set()
        cnv.fill(pagerect)
        cnv.cgContext.translateBy(x: 0.0, y: pagerect.size.height * dpi)
        cnv.cgContext.scaleBy(x: dpi, y: -dpi)
        cnv.cgContext.drawPDFPage(page)
    })
    let image = UIImage(data: imagedata)

I'm getting following issues with this ...

How can I avoid this memory warning and get the quality image form pdf page. hope any help. have a nice day.

Upvotes: 3

Views: 535

Answers (2)

Alexander Panshin
Alexander Panshin

Reputation: 11

If you are facing this issue then try this:

           autoreleasepool {
                guard let page = document.page(at: i) else { return }
                
                // Fetch the page rect for the page we want to render.
                let pageRect = page.getBoxRect(.mediaBox)
                var dpi: CGFloat = 1.0
                if pageRect.size.width > pageRect.size.height {
                    dpi = 3508.0 / pageRect.size.width
                } else {
                    dpi = 3508.0 / pageRect.size.height
                }
                //dpi = 300
                let format = UIGraphicsImageRendererFormat()
                format.scale = 1
                let renderer = UIGraphicsImageRenderer(size: CGSize(width: pageRect.size.width * dpi, height: pageRect.size.height * dpi), format: format)
                let imagedata = renderer.jpegData(withCompressionQuality: 1.0, actions: { cnv in
                    UIColor.white.set()
                    cnv.fill(pageRect)
                    cnv.cgContext.translateBy(x: 0.0, y: pageRect.size.height * dpi)
                    cnv.cgContext.scaleBy(x: dpi, y: -dpi)
                    cnv.cgContext.drawPDFPage(page)
                })
                let image = UIImage(data: imagedata)
                
            }

autoreleasepool - for permanent memory clearing

scale - so that images for different devices are not created, which increases their resolution by 2 or 3 times

changed the way to increase dpi as it can be initially more or less than 72

Upvotes: 1

Joshi
Joshi

Reputation: 873

1) sometimes the image is nil.

  • Is there a reason that you are generating a jpeg data then converting to UIImage VS directly creating an uiimage (using func image(actions: (UIGraphicsImageRendererContext) -> Void) -> UIImage)?
  • If you really need to use the jpeg method, then don't directly instantiate from UIImage(data:), use CGImage's init?(jpegDataProviderSource source: CGDataProvider, decode: UnsafePointer<CGFloat>?, shouldInterpolate: Bool, intent: CGColorRenderingIntent) then use UIImage(cgImage:) to get your UIImage instance

2) When this runs, the usage of memory is very high

  • Are you storing all images created per each page? If yes, then if you have a pdf of high number of pages then you will consume max memory at some point because of accumulated images. Why don't you store to disk each image created then releasing it afterwards so you don't accumulate the memory of storing all pages in memory.
  • Sharing the loop(assuming there is a loop) outside of this snippet could help solve your issue more

Upvotes: 0

Related Questions