[darwin][ios][macos] map snapshotter - add MGLMapSnapshot wrapper

This commit is contained in:
Ivo van Dongen
2017-10-09 19:50:21 +03:00
committed by Ivo van Dongen
parent dde1a92291
commit 3cdb249c70
5 changed files with 94 additions and 30 deletions

View File

@@ -69,23 +69,42 @@ MGL_EXPORT
@end
/**
An image generated by a snapshotter object.
*/
@interface MGLMapSnapshot : NSObject
#if TARGET_OS_IPHONE
/**
A block to processes the result or error of a snapshot request.
@param snapshot The `UIImage` that was generated or `nil` if an error occurred.
@param error The error that occured or `nil` when successful.
Converts the specified map coordinate to a point in the coordinate space of the image.
*/
typedef void (^MGLMapSnapshotCompletionHandler)(UIImage* _Nullable snapshot, NSError* _Nullable error);
- (CGPoint)pointForCoordinate:(CLLocationCoordinate2D)coordinate;
/**
The image of the map’s content.
*/
@property(nonatomic, readonly) UIImage *image;
#else
/**
Converts the specified map coordinate to a point in the coordinate space of the image.
*/
- (NSPoint)pointForCoordinate:(CLLocationCoordinate2D)coordinate;
/**
The image of the map’s content.
*/
@property(nonatomic, readonly) NSImage *image;
#endif
@end
/**
A block to processes the result or error of a snapshot request.
@param snapshot The `NSImage` that was generated or `nil` if an error occurred.
@param error The eror that occured or `nil` when succesful.
@param snapshot The `MGLMapSnapshot` that was generated or `nil` if an error occurred.
@param error The error that occured or `nil` when successful.
*/
typedef void (^MGLMapSnapshotCompletionHandler)(NSImage* _Nullable snapshot, NSError* _Nullable error);
#endif
typedef void (^MGLMapSnapshotCompletionHandler)(MGLMapSnapshot* _Nullable snapshot, NSError* _Nullable error);
/**
An immutable utility object for capturing map-based images.
@@ -93,20 +112,18 @@ typedef void (^MGLMapSnapshotCompletionHandler)(NSImage* _Nullable snapshot, NSE
### Example
```swift
var camera = MGLMapCamera()
camera.centerCoordinate = CLLocationCoordinate2D(latitude: 37.7184, longitude: -122.4365)
camera.pitch = 20
let camera = MGLMapCamera(lookingAtCenter: CLLocationCoordinate2D(latitude: 37.7184, longitude: -122.4365), fromDistance: 100, pitch: 20, heading: 0)
var options = MGLMapSnapshotOptions(styleURL: MGLStyle.satelliteStreetsStyleURL(), camera: camera, size: CGSize(width: 320, height: 480))
let options = MGLMapSnapshotOptions(styleURL: MGLStyle.satelliteStreetsStyleURL(), camera: camera, size: CGSize(width: 320, height: 480))
options.zoomLevel = 10
var snapshotter = MGLMapSnapshotter(options: options)
snapshotter.start { (image, error) in
if error {
// error handler
} else {
// image handler
}
let snapshotter = MGLMapSnapshotter(options: options)
snapshotter.start { (snapshot, error) in
if error != nil {
// error handler
} else {
// image handler
}
}
```
*/
@@ -141,7 +158,8 @@ MGL_EXPORT
/**
The zoom level.
The default zoom level is 0. This overwrites the camera zoom level if set.
The default zoom level is 0. If this property is non-zero and the camera property
is non-nil, the camera’s altitude is ignored in favor of this property’s value.
*/
@property (nonatomic) double zoomLevel;
@@ -169,7 +187,7 @@ MGL_EXPORT
map ID (`mapbox://styles/{user}/{style`}), or a path to a local file relative
to the application’s resource path. Specify `nil` for the default style.
*/
@property (nonatomic) NSURL* styleURL;
@property (nonatomic, nullable) NSURL *styleURL;
/**
The size of the output image, measured in points.

View File

@@ -49,6 +49,33 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64;
@end
@interface MGLMapSnapshot()
- (instancetype)initWithImage:(nullable MGLImage *)image scale:(CGFloat)scale pointForFn:(mbgl::MapSnapshotter::PointForFn)pointForFn;
@property (nonatomic) CGFloat scale;
@end
@implementation MGLMapSnapshot {
mbgl::MapSnapshotter::PointForFn _pointForFn;
}
- (instancetype)initWithImage:(nullable MGLImage *)image scale:(CGFloat)scale pointForFn:(mbgl::MapSnapshotter::PointForFn)pointForFn
{
self = [super init];
if (self) {
_pointForFn = std::move(pointForFn);
_scale = scale;
_image = image;
}
return self;
}
- (CGPoint)pointForCoordinate:(CLLocationCoordinate2D)coordinate
{
mbgl::ScreenCoordinate sc = _pointForFn(MGLLatLngFromLocationCoordinate2D(coordinate));
return CGPointMake(sc.x * self.scale, sc.y * self.scale);
}
@end
@interface MGLMapSnapshotter()
@property (nonatomic) MGLMapSnapshotOptions *options;
@end
@@ -117,7 +144,7 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64;
_loading = true;
dispatch_async(queue, ^{
_snapshotCallback = std::make_unique<mbgl::Actor<mbgl::MapSnapshotter::Callback>>(*mbgl::Scheduler::GetCurrent(), [=](std::exception_ptr mbglError, mbgl::PremultipliedImage image) {
_snapshotCallback = std::make_unique<mbgl::Actor<mbgl::MapSnapshotter::Callback>>(*mbgl::Scheduler::GetCurrent(), [=](std::exception_ptr mbglError, mbgl::PremultipliedImage image, mbgl::MapSnapshotter::PointForFn pointForFn) {
_loading = false;
if (mbglError) {
NSString *description = @(mbgl::util::toString(mbglError).c_str());
@@ -171,7 +198,8 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64;
// Dispatch result to origin queue
dispatch_async(queue, ^{
completion(compositedImage, nil);
MGLMapSnapshot* snapshot = [[MGLMapSnapshot alloc] initWithImage:compositedImage scale:self.options.scale pointForFn:pointForFn];
completion(snapshot, nil);
});
});
}
@@ -189,7 +217,7 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64;
- (NSURL *)styleURL
{
NSString *styleURLString = @(_mbglMapSnapshotter->getStyleURL().c_str());
return styleURLString && styleURLString.length > 0 ? [NSURL URLWithString:styleURLString] : nil;
return styleURLString.length ? [NSURL URLWithString:styleURLString] : nil;
}
- (void)setStyleURL:(NSURL *)url

View File

@@ -278,6 +278,24 @@ class MGLDocumentationExampleTests: XCTestCase, MGLMapViewDelegate {
//#-end-example-code
}
func testMGLMapSnapshotter() {
//#-example-code
let camera = MGLMapCamera(lookingAtCenter: CLLocationCoordinate2D(latitude: 37.7184, longitude: -122.4365), fromDistance: 100, pitch: 20, heading: 0)
let options = MGLMapSnapshotOptions(styleURL: MGLStyle.satelliteStreetsStyleURL(), camera: camera, size: CGSize(width: 320, height: 480))
options.zoomLevel = 10
let snapshotter = MGLMapSnapshotter(options: options)
snapshotter.start { (snapshot, error) in
if error != nil {
// error handler
} else {
// image handler
}
}
//#-end-example-code
}
// For testMGLMapView().
func myCustomFunction() {}
}

View File

@@ -51,11 +51,11 @@
// Create and start the snapshotter
MGLMapSnapshotter* snapshotter = [[MGLMapSnapshotter alloc] initWithOptions:options];
[snapshotter startWithCompletionHandler: ^(UIImage *image, NSError *error) {
[snapshotter startWithCompletionHandler: ^(MGLMapSnapshot* snapshot, NSError *error) {
if (error) {
NSLog(@"Could not load snapshot: %@", [error localizedDescription]);
} else {
imageView.image = image;
imageView.image = snapshot.image;
}
}];

View File

@@ -167,7 +167,7 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
// Create and start the snapshotter
snapshotter = [[MGLMapSnapshotter alloc] initWithOptions:options];
[snapshotter startWithCompletionHandler:^(NSImage *image, NSError *error) {
[snapshotter startWithCompletionHandler:^(MGLMapSnapshot *snapshot, NSError *error) {
if (error) {
NSLog(@"Could not load snapshot: %@", error.localizedDescription);
} else {
@@ -182,7 +182,7 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
NSURL *fileURL = panel.URL;
NSBitmapImageRep *bitmapRep;
for (NSImageRep *imageRep in image.representations) {
for (NSImageRep *imageRep in snapshot.image.representations) {
if ([imageRep isKindOfClass:[NSBitmapImageRep class]]) {
bitmapRep = (NSBitmapImageRep *)imageRep;
break; // stop on first bitmap rep we find
@@ -190,7 +190,7 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
}
if (!bitmapRep) {
bitmapRep = [NSBitmapImageRep imageRepWithData:image.TIFFRepresentation];
bitmapRep = [NSBitmapImageRep imageRepWithData:snapshot.image.TIFFRepresentation];
}
CFStringRef uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (__bridge CFStringRef)fileURL.pathExtension, NULL /* inConformingToUTI */);