Как добавить MKPolylines в MKSnapShotter в Swift 3?

Есть ли способ сделать снимок экрана mapView и включить ломаную линию? Я считаю, что мне нужно нарисовать CGPoint на изображении, которое возвращает MKSnapShotter, но я не уверен, как это сделать.

Текущий код

      func takeSnapshot(mapView: MKMapView, withCallback: (UIImage?, NSError?) -> ()) {
    let options = MKMapSnapshotOptions()
    options.region = mapView.region
    options.size = mapView.frame.size
    options.scale = UIScreen.main().scale

    let snapshotter = MKMapSnapshotter(options: options)


    snapshotter.start() { snapshot, error in
        guard snapshot != nil else {
            withCallback(nil, error)
            return
        }

        if let image = snapshot?.image{



            withCallback(image, nil)

            for coordinate in self.area {

                image.draw(at:snapshot!.point(for: coordinate))

            }

        }

    }
}

person Derivative    schedule 18.07.2016    source источник
comment
В видео Purpose Map Kit Apple демонстрирует, что если вы хотите включить аннотации в снимок, вам придется рисовать их вручную. (Сбивает с толку, да, но это то, что есть.) Я предполагаю, что то же самое верно и для наложений, таких как MKPolyline.   -  person Rob    schedule 19.07.2016
comment
Спасибо, я проверю это.   -  person Derivative    schedule 19.07.2016
comment
Итак, видео было информативным, но не особо помогло.   -  person Derivative    schedule 19.07.2016
comment
Я бы подумал, что демонстрация, ручная визуализация аннотаций на снимке, даст вам достаточно подсказок, как сделать то же самое с наложениями...   -  person Rob    schedule 19.07.2016


Ответы (3)


У меня была такая же проблема сегодня. После нескольких часов исследований, вот как я это решаю.

Следующие коды используются в Swift 3.

1. Создайте массив координат полилинии.

// initial this array with your polyline coordinates
var yourCoordinates = [CLLocationCoordinate2D]() 
yourCoorinates.append( coordinate 1 )
yourCoorinates.append( coordinate 2 )
...
// you can use any data structure you like

2. сделайте снимок как обычно, но задайте регион исходя из своих координат:

func takeSnapShot() {
    let mapSnapshotOptions = MKMapSnapshotOptions()

    // Set the region of the map that is rendered. (by polyline)
    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
        }
        // Don't just pass snapshot.image, pass snapshot itself!
        self.imageView.image = self.drawLineOnImage(snapshot: snapshot)
    }
}

3. Используйте snapshot.point() для рисования полилиний на снимке изображения.

func drawLineOnImage(snapshot: MKMapSnapshot) -> UIImage {
    let image = snapshot.image

    // for Retina screen
    UIGraphicsBeginImageContextWithOptions(self.imageView.frame.size, true, 0)

    // draw original image into the context
    image.draw(at: CGPoint.zero)

    // get the context for CoreGraphics
    let context = UIGraphicsGetCurrentContext()

    // set stroking width and color of the context
    context!.setLineWidth(2.0)
    context!.setStrokeColor(UIColor.orange.cgColor)

    // Here is the trick :
    // We use addLine() and move() to draw the line, this should be easy to understand.
    // The diificult part is that they both take CGPoint as parameters, and it would be way too complex for us to calculate by ourselves
    // Thus we use snapshot.point() to save the pain.
    context!.move(to: snapshot.point(for: yourCoordinates[0]))
    for i in 0...yourCoordinates.count-1 {
      context!.addLine(to: snapshot.point(for: yourCoordinates[i]))
      context!.move(to: snapshot.point(for: yourCoordinates[i]))
    }

    // apply the stroke to the context
    context!.strokePath()

    // get the image from the graphics context
    let resultImage = UIGraphicsGetImageFromCurrentImageContext()

    // end the graphics context 
    UIGraphicsEndImageContext()

    return resultImage!
}

Вот и все, надеюсь, это кому-то поможет.

Рекомендации

person user2875289    schedule 08.02.2017
comment
@user287589 user287589 Как рассчитать диапазон регионов, чтобы иметь вставки на снимке? - person Aymen HARRATH; 17.12.2018
comment
@AymenHARRATH Я не знаю. Извини - person user2875289; 19.12.2018
comment
Я попытался запустить этот фрагмент кода. Это дает мне следующую ошибку в этой строке: context!.setLineWidth(2.0) В сообщении об ошибке говорится: Неустранимая ошибка: неожиданно найдено nil при развертывании необязательного значения - person therealManUtdFan; 02.05.2019

Что не так с:

snapshotter.start( completionHandler: { snapshot, error in
  guard snapshot != nil else {
    withCallback(nil, error)
    return
  }

  if let image = snapshot?.image {
    withCallback(image, nil)

    for coordinate in self.area {
      image.draw(at:snapshot!.point(for: coordinate))
    }

  }
})
person Yohst    schedule 04.11.2016
comment
В итоге я просто сохранил координаты в массиве, а затем отобразил их на карте, созданной в другом представлении. - person Derivative; 04.11.2016

Если вам просто нужна копия изображения, которое пользователь видит в MKMapView, помните, что это подкласс UIView, и поэтому вы можете сделать это...

public extension UIView {
    public var snapshot: UIImage? {
        get {
            UIGraphicsBeginImageContextWithOptions(self.bounds.size, false, UIScreen.main.scale)
            self.drawHierarchy(in: self.bounds, afterScreenUpdates: true)
            let image = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
            return image
        }
    }
}

// ...
if let img = self.mapView.snapshot {
    // Do something
}
person Grimxn    schedule 12.09.2018