Select to view content in your preferred language

How to save screenshot of AGSMapView

4831
14
Jump to solution
02-20-2013 09:59 PM
HumzaAkhtar
Deactivated User
Hi,

I am developing an iOS app using ArcGIS api and I wanted to put a feature of saving screenshot of the map. However using the normal rendering procedure results in a blank image. I am using the self.mapview.layers to access the layer before I save the current context as an image.  Below are some lines of code from my app which does the function of saving screenshots.


     UIGraphicsBeginImageContextWithOptions(self.mapview.frame.size,NO, 0.0);
[self.mapview.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *screenshot = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImageWriteToSavedPhotosAlbum(screenshot,self,@selector(image:didFinishSavingWithError:contextInfo:),nil);

There is another thread here which marks this code as the final answer but in the latest api 10.1, this just results in a blank image which is quite confusing for me.

I would appreciate if some one can help me deal with this.

thanks and Regards
H Akhtar
0 Kudos
14 Replies
baidynathpanda
Emerging Contributor
If you are developing a enterprise application better use the UIGetScreenImage() API. (Don't use if you are developing a app for publishing to appstore)

I was facing the same issue but what I did was:
1)Captured the complete screen shot using this API
2)Cropped the image only to the MAP area.(If you have both Orientation support then add conditions for all four)

Its working perfect for me. 🙂
0 Kudos
HumzaAkhtar
Deactivated User
Humza,
I have tried that but maybe I am putting it in the wrong spot or doing something else wrong.  I am attaching my code for both calling the get image process and the process itself.  Any help would be greatly appreciated. 
Calling
-(void) PrintPermitFinal
{
CAEAGLLayer *eaglLayer = (CAEAGLLayer *) self.mapView.layer;
    eaglLayer.drawableProperties = @{
                                     kEAGLDrawablePropertyRetainedBacking: [NSNumber numberWithBool:YES],
kEAGLDrawablePropertyColorFormat: kEAGLColorFormatRGBA8
                                     };
// reset buttons
    [selfsettoInitialMapView];
// create image and pdf
    UIImage *screenshot = [[UIImage alloc] initWithData:[self getImage]];
// use clip path Rect to clip image to right size
CGImageRef imageref = CGImageCreateWithImageInRect([screenshot CGImage], clipRect);
    screenshot = [UIImage imageWithCGImage:imageref];
//save image to photo album for testing only
    UIImageWriteToSavedPhotosAlbum(screenshot,self,@selector(image:didFinishSavingWithError:contextInfo:),nil);
//Send Image to Dictionary
if (AppDelagate.PermitImages == nil)
    {
AppDelagate.PermitImages = [[NSMutableDictionaryalloc] init];
    }
NSString *Key= [selfCreatePermitID:[AppDelagate.GraphicToPrint.allAttributesvalueForKey:@"Full_Name"] AndAddress:[AppDelagate.GraphicToPrint.allAttributesvalueForKey:@"Owner_Address"]];
    [AppDelagate.PermitImages setObject:screenshot forKey:Key];
self.tabBarController.selectedViewController = [self.tabBarController.viewControllersobjectAtIndex:1];
}

Getting the image virtually unchanged from Bernese
- (NSData *)getImage
{
    GLint width;

    GLint height;

glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &width);

glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &height);

    NSInteger myDataLength = width * height * 4;

// allocate array and read pixels into it.
    GLubyte *buffer = (GLubyte *) malloc(myDataLength);
    glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer);

// gl renders "upside down" so swap top to bottom into new array.
// there's gotta be a better way, but this works.
    GLubyte *buffer2 = (GLubyte *) malloc(myDataLength);
    for(int y = 0; y < height; y++)
    {
        for(int x = 0; x < width * 4; x++)
        {
            buffer2[((height - 1) - y) * width * 4 + x] = buffer[y * 4 * width + x];
        }
    }

// make data provider with data.
    CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, buffer2, myDataLength, NULL);

// prep the ingredients
    int bitsPerComponent = 8;
    int bitsPerPixel = 32;
    int bytesPerRow = 4 * width;
CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;
CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;

// make the cgimage
    CGImageRef imageRef = CGImageCreate(width, height, bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpaceRef, bitmapInfo, provider, NULL, NO, renderingIntent);

// then make the uiimage from that
    UIImage *myImage = [[UIImage alloc] initWithCGImage:imageRef];
    NSData *iDat = UIImageJPEGRepresentation(myImage, 0);
    CGImageRelease(imageRef);
CGDataProviderRelease(provider);
    CGColorSpaceRelease(colorSpaceRef);
    free(buffer);
    free(buffer2);
    return iDat;
}

Cheers,
Jeff



Hi Jeff,

does your print method gets called after user has pressed some button to take screenshot of the map ? if yes then kindly remove the first two lines of the code in print method and add them to a initialization method like didopenwebmap() or didloadmap() or your selfsettoInitialMapView() method  and try again. Also please make sure that before you take the screenshot there should be no popup being displayed on the map.

Regards
0 Kudos
Yu_ChingYu
Emerging Contributor
Hi,

I have the same issue as you have and still looking for solution.

Any suggestion will welcome!
0 Kudos
JeffGiesler
Deactivated User
Humza,Thanks for the suggestion.  I moved the first lines to my print button and now it works.Thanks,Jeff
0 Kudos
Yu_ChingYu
Emerging Contributor
Thanks for your suggestion!!
It works!! This is my code.

1. place
CAEAGLLayer *eaglLayer = (CAEAGLLayer *) theMap.layer;
    eaglLayer.drawableProperties = @{
                                     kEAGLDrawablePropertyRetainedBacking: [NSNumber numberWithBool:YES],
                                     kEAGLDrawablePropertyColorFormat: kEAGLColorFormatRGBA8
                                     };

on ,y viewDidLoad() function block.

2. call the
- (NSData *)getImage
{
    GLint width;

    GLint height;

glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &width);

glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &height);

    NSInteger myDataLength = width * height * 4;

// allocate array and read pixels into it.
    GLubyte *buffer = (GLubyte *) malloc(myDataLength);
    glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer);

// gl renders "upside down" so swap top to bottom into new array.
// there's gotta be a better way, but this works.
    GLubyte *buffer2 = (GLubyte *) malloc(myDataLength);
    for(int y = 0; y < height; y++)
    {
        for(int x = 0; x < width * 4; x++)
        {
            buffer2[((height - 1) - y) * width * 4 + x] = buffer[y * 4 * width + x];
        }
    }

// make data provider with data.
    CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, buffer2, myDataLength, NULL);

// prep the ingredients
    int bitsPerComponent = 8;
    int bitsPerPixel = 32;
    int bytesPerRow = 4 * width;
CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;
CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;

// make the cgimage
    CGImageRef imageRef = CGImageCreate(width, height, bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpaceRef, bitmapInfo, provider, NULL, NO, renderingIntent);

// then make the uiimage from that
    UIImage *myImage = [[UIImage alloc] initWithCGImage:imageRef];
    NSData *iDat = UIImageJPEGRepresentation(myImage, 0);
    CGImageRelease(imageRef);
CGDataProviderRelease(provider);
    CGColorSpaceRelease(colorSpaceRef);
    free(buffer);
    free(buffer2);
    return iDat;
}

function on my button click event.
3. Get the picture without blank.

Thank you so much!!
0 Kudos