Estoy tratando de crear una instantánea de un MKMapView en iOS7 aplicación de la misma manera se recomienda en todas partes anteriores versiones de iOS:

- (UIImage*) renderMapViewToImage
{
   UIGraphicsBeginImageContextWithOptions(mapView.frame.size, NO, 0.0);
   [mapView.layer renderInContext:UIGraphicsGetCurrentContext()];
   UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
   UIGraphicsEndImageContext(); 
   return image;
}

Sin embargo, la imagen devuelta es un rectángulo negro con azul actual ubicación de punto en la parte superior de la misma.
He intentado usar diferentes subcapas de la mapView así, pero el resultado es siempre el mismo.

¿Alguien sabe cómo tomar MKMapView instantáneas en iOS7 ?

  • ¿por qué están pasando 0.0 como opciones de contexto ? debe ser de 1.0 o 2.0 para pantallas de retina …
  • Cero está bien. Como la documentación de UIGraphicsBeginImageContextWithOptions dice, «Si especifica un valor de 0.0, el factor de escala se establece el factor de escala de la pantalla principal.»
InformationsquelleAutor Michael | 2013-09-13

3 Comentarios

  1. 117

    Puede utilizar MKMapSnapshotter y agarrar el image de la resultante MKMapSnapshot. Ver la discusión de la WWDC 2013 sesión de vídeo, Poner Map Kit en Perspectiva.

    Por ejemplo:

    MKMapSnapshotOptions *options = [[MKMapSnapshotOptions alloc] init];
    options.region = self.mapView.region;
    options.scale = [UIScreen mainScreen].scale;
    options.size = self.mapView.frame.size;
    
    MKMapSnapshotter *snapshotter = [[MKMapSnapshotter alloc] initWithOptions:options];
    [snapshotter startWithCompletionHandler:^(MKMapSnapshot *snapshot, NSError *error) {
        UIImage *image = snapshot.image;
        NSData *data = UIImagePNGRepresentation(image);
        [data writeToFile:[self snapshotFilename] atomically:YES];
    }];

    Habiendo dicho eso, la renderInContext solución que funciona para mí. Hay notas acerca de que sólo hacía que en la cola principal en iOS7, pero aún así parece que funciona. Pero MKMapSnapshotter parece la solución más apropiada para iOS7.


    Si desea incluir algunas anotaciones en la instantánea, usted tiene que dibujar manualmente (!). Esto se discute en detalle en la final de la Poner Map Kit en Perspectiva de vídeo. Tengo que decir que este es uno de los menos elegante implementaciones que he visto de Apple aconsejar. De todos modos, en iOS, podría parecerse:

    MKMapSnapshotOptions *options = [[MKMapSnapshotOptions alloc] init];
    options.region = self.mapView.region;
    options.scale = [UIScreen mainScreen].scale;
    options.size = self.mapView.frame.size;
    MKMapSnapshotter *snapshotter = [[MKMapSnapshotter alloc] initWithOptions:options];
    [snapshotter startWithQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) completionHandler:^(MKMapSnapshot *snapshot, NSError *error) {
    //get the image associated with the snapshot
    UIImage *image = snapshot.image;
    //Get the size of the final image
    CGRect finalImageRect = CGRectMake(0, 0, image.size.width, image.size.height);
    //Get a standard annotation view pin. Clearly, Apple assumes that we'll only want to draw standard annotation pins!
    MKAnnotationView *pin = [[MKPinAnnotationView alloc] initWithAnnotation:nil reuseIdentifier:@""];
    UIImage *pinImage = pin.image;
    //ok, let's start to create our final image
    UIGraphicsBeginImageContextWithOptions(image.size, YES, image.scale);
    //first, draw the image from the snapshotter
    [image drawAtPoint:CGPointMake(0, 0)];
    //now, let's iterate through the annotations and draw them, too
    for (id<MKAnnotation>annotation in self.mapView.annotations)
    {
    CGPoint point = [snapshot pointForCoordinate:annotation.coordinate];
    if (CGRectContainsPoint(finalImageRect, point)) //this is too conservative, but you get the idea
    {
    CGPoint pinCenterOffset = pin.centerOffset;
    point.x -= pin.bounds.size.width / 2.0;
    point.y -= pin.bounds.size.height / 2.0;
    point.x += pinCenterOffset.x;
    point.y += pinCenterOffset.y;
    [pinImage drawAtPoint:point];
    }
    }
    //grab the final image
    UIImage *finalImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    //and save it
    NSData *data = UIImagePNGRepresentation(finalImage);
    [data writeToFile:[self snapshotFilename] atomically:YES];
    }];

    Para MacOS aplicación, ver el video para obtener más información, pero la técnica es básicamente la misma (el mecanismo para la creación de las imágenes es ligeramente diferente).

    • Gracias por la excelente respuesta! Funciona ahora. renderInContext todavía no funciona para mí, pero esa es otra historia.
    • Es allí cualquier manera de representar un pin de anotación con MKMapSnapshotter?
    • Al final de el video que hago referencia en mi respuesta, Apple paseos que precisamente a través de esta técnica. Es fea. Estoy sorprendido de que ellos piensan que esto es aceptable la aplicación. De todos modos, he incluido una versión aquí y actualizado mi respuesta en consecuencia. Tendrás que modificarlo si no se utiliza pin anotaciones, si usted tiene MKUserAnnotation, etc., pero esto debe apuntar en la dirección correcta.
    • Gran respuesta! Yo no ir hasta el final de la Manzana del video, y no puedo estar más de acuerdo: esto no es elegante en todo. La idea de este fresco nueva API es no confiar en el Contexto de la Imagen de la representación y el uso de MapKit Api adicionales. Pero funciona y se ve como un encanto. He aquí un screeshot: dl.dropboxusercontent.com/u/2452151/Permalink/…
    • Gracias, funcionó bien. Hay alguien intentó con la costumbre de anotación de imagen?
    • No lo he hecho, pero no debería ser peor que el anterior.
    • Sí, sólo una línea más para agregar pin archivo de imagen, y para quien no lo he probado, agregar @ 2x para el nombre de archivo para la pantalla retina. Gracias de nuevo 🙂
    • Me hizo el trabajo en el uso personalizado de las vistas de anotación. Básicamente yo «duplicar» el drawRect y tiene que devolver una imagen en su lugar. Necesita un poco de ajuste con respecto a las coordenadas, pero no es demasiado trabajo.
    • muchas gracias. especialmente para la anotación parte!
    • Se puede hacer esto sin tener una instancia de un MapView?
    • Eso es correcto, no de la vista del mapa que se necesita. Claramente, usted tendría que establecer la camera o region de la MKMapSnapshotOptions de alguna otra manera (la de arriba sólo utiliza la region de la vista de mapa), pero sí, MKMapSnapshotter funciona perfectamente bien sin una vista de mapa. De hecho, a menudo se usa precisamente por esa razón, cuando usted no quiere a la sobrecarga de la vista de mapa y una estática interpretación es aceptable.
    • desde que uso startWithQueue: con un fondo de cola, no es seguro para usar: MKAnnotationView *pin = [[MKPinAnnotationView alloc] initWithAnnotation:nil reuseIdentifier:@»»]; en el de devolución de llamada.
    • Yo no creo que es verdad. Tomé esta directamente desde Apple demo. Allí, en realidad, se limita la representación de vista de las opciones disponibles desde el fondo de colas y creo que este es uno de ellos.
    • Excelente explicación…

  2. 4

    Para Swift 3

    Aquí es una forma rápida de 3 versión modificada de este artículo:
    Representar un Mapa como una Imagen utilizando MapKit

    El siguiente código le permite la instantánea de una región basada en tanto el Punto(1 de coordenadas) y Polilínea(varios coordenadas)

    func takeSnapShot() {
    let mapSnapshotOptions = MKMapSnapshotOptions()
    //Set the region of the map that is rendered. (by one specified coordinate)
    //let location = CLLocationCoordinate2DMake(24.78423, 121.01836) //Apple HQ
    //let region = MKCoordinateRegionMakeWithDistance(location, 1000, 1000)
    //Set the region of the map that is rendered. (by polyline)
    //var yourCoordinates = [CLLocationCoordinate2D]()  <- initinal this array with your polyline coordinates
    let polyLine = MKPolyline(coordinates: &yourCoordinates, count: yourCoordinates.count)
    let region = MKCoordinateRegionForMapRect(polyLine.boundingMapRect)
    mapSnapshotOptions.region = region
    //Set the scale of the image. We'll just use the scale of the current device, which is 2x scale on Retina screens.
    mapSnapshotOptions.scale = UIScreen.main.scale
    //Set the size of the image output.
    mapSnapshotOptions.size = CGSize(width: IMAGE_VIEW_WIDTH, height: IMAGE_VIEW_HEIGHT)
    //Show buildings and Points of Interest on the snapshot
    mapSnapshotOptions.showsBuildings = true
    mapSnapshotOptions.showsPointsOfInterest = true
    let snapShotter = MKMapSnapshotter(options: mapSnapshotOptions)
    snapShotter.start() { snapshot, error in
    guard let snapshot = snapshot else {
    return
    }
    self.imageView.image = snapshot.image
    }
    }
  3. 2

    Para iOS 10 y por encima de puede utilizar UIGraphicsImageRenderer clase para representar cualquier vista de la imagen (en caso de que si usted no desea utilizar MKMapSnapshotter, ya que estoy usando MapBox).

    let render = UIGraphicsImageRenderer(size: self.mapView.bounds.size)
    let image = render.image { ctx in
    self.mapView.drawHierarchy(in: self.mapView.bounds, afterScreenUpdates: true)
    }

    Resultado:

    Instantánea de MKMapView en iOS7

Dejar respuesta

Please enter your comment!
Please enter your name here