Wednesday, November 18, 2015

How To: Pre-Process Tilemap Overlays in MKMapView

Hi all.

Time for another tutorial. Recently I was trying to modify a tilemap returned from a typical public map overlay server (such as - basically I needed a way to change black areas of the tile into transparent so that I could nicely overlay it on top of MKMapView. I searched for this for a while, found some solutions but did not really work as I wanted. Some examples used MKTileOverlayRenderer. Somehow that gave me weird results that I do not understand.

Note: In this tutorial there are no downloadable project since it is a straight forward MKTileOverlay subclassing usage. (But, if u really need a sample project, do shout in the comment section).

In your custom MKTileOverlay, you return the URL to load according to map rect using the normal URLForTilePath as usual. Then in the loadTileAtPath method, you process the *data variable.

Here is the example of the method:

- (void)loadTileAtPath:(MKTileOverlayPath)path result:(void (^)(NSData *, NSError *))result
    if (!result)
        NSURLRequest *request = [NSURLRequest requestWithURL:[self URLForTilePath:path]];
        [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
            if ([data length]<335) {
            } else {
                    CGSize sz = CGSizeMake(256,256);
                    CGRect rect = CGRectMake(0,0,256,256);
                    UIImage *img = [UIImage imageWithData:data];
                    CGContextRef context = UIGraphicsGetCurrentContext();
                    [img drawInRect:rect];
                    UInt8 *dat = CGBitmapContextGetData(context);
                    // int numComponents = 4;
                    long dataLength = CGBitmapContextGetHeight(context) * CGBitmapContextGetBytesPerRow(context);
                    int  Comp1, Comp2, Comp3, Comp4;
                    Comp1 = 0;
                    Comp2 = 1;
                    Comp3 = 2;
                    Comp4 = 3;

                    // This processes each pixels and convert the map to greyscale.

                    for(int index=0;index<dataLength;index+=4){
                        int aRed = dat[index+Comp1];
                        int aGrn = dat[index+Comp2];
                        int aBlu = dat[index+Comp3];
                        float grey = (aRed+aGrn+aBlu)/3.0;
                        dat[index+Comp1] = grey;
                         dat[index+Comp2] = grey;
                         dat[index+Comp3] = grey;
                    UIImage *tileImage = UIGraphicsGetImageFromCurrentImageContext();
                    NSData *tileData = UIImagePNGRepresentation(tileImage);
                    result(tileData,nil); // return new data



As in the method above: Take *data and convert it to UIImage. Create a graphic context to draw on. Draw the map on that context. Then further manipulate the context pixels by pixels. Finally get the resulting image from the modified context and return as result.

Normal original openstreetmap tile (unmodified) loaded unto MKMapView as MKTileOverlay:

Change to grey (pixels to grey code given in the method above):

Change to invert color:

Change to High Saturation

Note: The air pollution markers are on another MKTileOverlay.

All these 4 map styles came from a single tileserver (

Do take note that each time a tile (of size 256x256) is loaded, your custom class will process it with CoreGraphics with the code given. It is wise to keep the processing simple and too heavy burden on processor.

Saturday, October 3, 2015

LONG LIVE XIBs!!!! Create an iOS app without storyboards in XCode

Are you one of those devs who don't like Storyboard? I didn't even bother to learn about Storyboards and how to use them. Call me stubborn noob that's ok. But I am so used to programmatically create things on XCode so storyboards are not my thang.

So how do you do this with latest XCode? If you go to New Project LO AND BEHOLD no such thing as a project without storyboards. All of them has storyboards. Unless you go with the absolute empty project.

What I will show you is how to select a Single View Project and then make it run without Storyboard. Let's go! First go to menu File -- New -- Project... and select Single View Application. Then follow the following steps: 

Well, obviously, first thing to do it is to delete the storyboard!

2. Delete the "Main" text in Main Interface under General Tab in the target.

3. Right click your project in the left panel and select New File... and goto iOS - User interface - View and click Next. Give the xib name "ViewController" (basically same name as your viewcontroller.m and h).

4. Click on your newly created XIB file. Click on the File's Owner (yellow box), then click on the Identity Inspector tab, and type "ViewController" in the Class field.  (see the red boxes highlighted in the image below)

5. Then click on the View part of XIB file and click on the  Connections Inspector tab and connect the Referencing Outlet to the File's Owner and select "view".

6. Click your AppDelegate.h, and add these codes:

(see the red box highlights).

6. Then click on AppDelegate.m and add these codes in the appDidFinishLaunching method:

That's all and you should be able to run the app and it will show an empty white View.


Related Posts Plugin for WordPress, Blogger...