Tuesday, June 14, 2016

[iOS] Convert a PDF to Image

Drawing PDF is piece of cake, not much CUP and Memory, but drawing a bitmap image that's memory consuming thing, so please be careful when you covert it on a iPhone.

1. Covert a PDF to image
-(NSData *)extractFromPdf:(NSURL *)url forRect:(CGRect)rect {
    //===============================================================
    // Load the PDF in memory once
    //===============================================================
    if (![url.absoluteString isEqualToString:self.pdfUrl.absoluteString]) {
        [self releasePdfResource];
    
        CGPDFDocumentRef pdfRef = CGPDFDocumentCreateWithURL((__bridge CFURLRef)url);
        if (CGPDFDocumentGetNumberOfPages(pdfRef) == 0) {
            CGPDFDocumentRelease(pdfRef);
            return nil;
        }
        
        self.pdfUrl = url;
        pdf = pdfRef;
        pdfPage = CGPDFDocumentGetPage(pdfRef, 1);
    }
    
    //===============================================================
    // Draw PDF to layer
    //===============================================================
    CGSize layerSize = CGSizeMake(rect.origin.x + rect.size.width, rect.origin.y + rect.size.height);
    CGContextRef bitmapContext = PWCreateBitmapContext(rect.size.width, rect.size.height);
    CGLayerRef layer = CGLayerCreateWithContext(bitmapContext, layerSize, NULL);
    CGContextRef layerContext = CGLayerGetContext(layer);
    CGContextSaveGState (layerContext);
    CGContextDrawPDFPage(layerContext, pdfPage);
    CGContextRestoreGState (layerContext);
    
    // Draw layer to bitmap
    CGContextSaveGState (bitmapContext);
    CGRect tileRect = CGRectMake(-rect.origin.x,
                                 -rect.origin.y,
                                 rect.origin.x + rect.size.width,
                                 rect.origin.y + rect.size.height);
    
    CGContextDrawLayerInRect(bitmapContext, tileRect, layer);
    CGLayerRelease(layer);
    CGContextRestoreGState (bitmapContext);

    //===============================================================
    // Release
    //===============================================================
    CGImageRef bitmap = CGBitmapContextCreateImage(bitmapContext);
    UIImage *image = [UIImage imageWithCGImage:bitmap];
    CGImageRelease(bitmap);
    CGContextRelease (bitmapContext);
    
    NSData *imageData = UIImagePNGRepresentation(image);
    return imageData;

}


2. Covert a PDF to image with scale and rotation

-(NSData *)extractFromPdf:(NSURL *)url
                  forRect:(CGRect)rect
         withScalePdfSize:(CGSize)scalePdfSize
            rotationAngle:(float)rotation {
    //===============================================================
    // Load the PDF in memory once
    //===============================================================
    if (![url.absoluteString isEqualToString:self.pdfUrl.absoluteString]) {
        [self releasePdfResource];
    
        CGPDFDocumentRef pdfRef = CGPDFDocumentCreateWithURL((__bridge CFURLRef)url);
        if (CGPDFDocumentGetNumberOfPages(pdfRef) == 0) {
            CGPDFDocumentRelease(pdfRef);
            return nil;
        }
        
        self.pdfUrl = url;
        pdf = pdfRef;
        pdfPage = CGPDFDocumentGetPage(pdfRef, 1);
    }
    
    //===============================================================
    // Prepare affine transform
    //===============================================================
    CGRect originalPdfRect = CGPDFPageGetBoxRect(pdfPage, kCGPDFCropBox);
    CGFloat scaleFactorWidth = scalePdfSize.width/originalPdfRect.size.width;
    CGFloat scaleFactorHeight = scalePdfSize.height/originalPdfRect.size.height;
    /*
     x
     |
     |
     |**************
     |*            *
     |*            *
     |*            *
     |**************------y
     (0, 0)
     
     After rotate, move left with a distance of sin(angle)*height
                *
              *   *
           |*       *
          *|          *
        *  |        *
      *    |      *
        *  |    *
         * |  * (angle)
     -+++++*--------------y
           (0, 0)
     */
    CGAffineTransform centerTransform;
    double angle = rotation * M_PI / 180;
    if (rotation < 0) {
        centerTransform = CGAffineTransformMakeTranslation(-sin(angle)*originalPdfRect.size.height*scaleFactorHeight, 0);
    } else {
        centerTransform = CGAffineTransformMakeTranslation(0, sin(angle)*originalPdfRect.size.width*scaleFactorWidth);
    }
    CGAffineTransform rotateTransform = CGAffineTransformRotate(centerTransform, -angle);
    CGAffineTransform scaleTransform = CGAffineTransformScale(rotateTransform, scaleFactorWidth, scaleFactorHeight);
    
    //===============================================================
    // Create bitmap context and alloc the size of memory
    //===============================================================
    int pixelsWide = rect.size.width+rect.origin.x;
    int pixelsHigh = rect.size.height+rect.origin.y;
    CGContextRef bitmapContext = PWCreateBitmapContext(pixelsWide, pixelsHigh);
    if (bitmapContext== NULL) {
        return NULL;
    }
    
    //===============================================================
    // Draw PDF to layer
    //===============================================================
    CGLayerRef layer = CGLayerCreateWithContext(bitmapContext, rect.size, NULL);
    CGContextRef layerContext = CGLayerGetContext(layer);
    CGContextSaveGState (layerContext);
    CGContextConcatCTM(layerContext, scaleTransform);
    CGContextDrawPDFPage(layerContext, pdfPage);
    CGContextRestoreGState (layerContext);
    
    // Draw layer to bitmap
    CGContextSaveGState (bitmapContext);
    CGContextDrawLayerInRect(bitmapContext, rect, layer);
    CGContextRestoreGState (bitmapContext);
    
    //===============================================================
    // Release
    //===============================================================
    CGLayerRelease(layer);
    CGImageRef bitmap = CGBitmapContextCreateImage(bitmapContext);
    UIImage *image = [UIImage imageWithCGImage:bitmap];
    NSData *imageData = UIImagePNGRepresentation(image);
    CGImageRelease(bitmap);
    CGContextRelease (bitmapContext);
    
    return imageData;
}




No comments:

Post a Comment