Tuesday, June 14, 2016

[iOS] How to zoom in iOS map more than zoom level 21

As we know you can only zoom in to zoom level 20 before iOS 9, zoom level 21 has been supported since iOS 9.

Actually you can zoom in the iOS map to zoom level 21 more,  in that case, the background map (building and road) will not be shown any more, but all labels are kept and the coordinate (latitude/longitude) system works properly on it as well, here is the steps to do it:

1. Add world wide overlay on top of map and road and bottom of labels
Overlay:
MKMapPoint corners[4];
        corners[0] = MKMapPointMake(MKMapRectGetMaxX(MKMapRectWorld), MKMapRectGetMaxY(MKMapRectWorld));
        corners[1] = MKMapPointMake(MKMapRectGetMinX(MKMapRectWorld), MKMapRectGetMaxY(MKMapRectWorld));
        corners[2] = MKMapPointMake(MKMapRectGetMinX(MKMapRectWorld), MKMapRectGetMinY(MKMapRectWorld));
        corners[3] = MKMapPointMake(MKMapRectGetMaxX(MKMapRectWorld), MKMapRectGetMinY(MKMapRectWorld));

        MKPolygon *instance = [MKPolygon polygonWithPoints:corners count:4];
Render:
MKPolygonRenderer *renderer = [[MKPolygonRenderer alloc] initWithPolygon:overlay];
        renderer.fillColor = [UIColor clearcolor];
        renderer.lineWidth = 0.0;

        renderer.strokeColor = renderer.fillColor

2. Add another overlay on top of it which can be zoom in/out (just like a PDF or something)


After finish that when you zoom in/out on the map you will see the altitude of camera could be as low as 6 meters, but the iOS map disappears once the altitude of camera less about 202 meters.

[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;
}