diff options
Diffstat (limited to 'platform/darwin/src/MGLMapSnapshotter.mm')
-rw-r--r-- | platform/darwin/src/MGLMapSnapshotter.mm | 267 |
1 files changed, 146 insertions, 121 deletions
diff --git a/platform/darwin/src/MGLMapSnapshotter.mm b/platform/darwin/src/MGLMapSnapshotter.mm index 346666cf80..967706ac2e 100644 --- a/platform/darwin/src/MGLMapSnapshotter.mm +++ b/platform/darwin/src/MGLMapSnapshotter.mm @@ -61,6 +61,7 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64; @implementation MGLMapSnapshot { mbgl::MapSnapshotter::PointForFn _pointForFn; } + - (instancetype)initWithImage:(nullable MGLImage *)image scale:(CGFloat)scale pointForFn:(mbgl::MapSnapshotter::PointForFn)pointForFn { self = [super init]; @@ -80,7 +81,7 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64; @end @interface MGLMapSnapshotter() -@property (nonatomic) MGLMapSnapshotOptions *options; + @end @implementation MGLMapSnapshotter { @@ -88,46 +89,16 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64; std::shared_ptr<mbgl::ThreadPool> _mbglThreadPool; std::unique_ptr<mbgl::MapSnapshotter> _mbglMapSnapshotter; std::unique_ptr<mbgl::Actor<mbgl::MapSnapshotter::Callback>> _snapshotCallback; + NS_ARRAY_OF(MGLAttributionInfo *) *_attributionInfo; } - (instancetype)initWithOptions:(MGLMapSnapshotOptions *)options { self = [super init]; if (self) { - _options = options; + [self setOptions:options]; _loading = false; - - mbgl::DefaultFileSource *mbglFileSource = [MGLOfflineStorage sharedOfflineStorage].mbglFileSource; - _mbglThreadPool = mbgl::sharedThreadPool(); - - std::string styleURL = std::string([options.styleURL.absoluteString UTF8String]); - - // Size; taking into account the minimum texture size for OpenGL ES - // For non retina screens the ratio is 1:1 MGLSnapshotterMinimumPixelSize - mbgl::Size size = { - static_cast<uint32_t>(MAX(options.size.width, MGLSnapshotterMinimumPixelSize)), - static_cast<uint32_t>(MAX(options.size.height, MGLSnapshotterMinimumPixelSize)) - }; - - float pixelRatio = MAX(options.scale, 1); - - // Camera options - mbgl::CameraOptions cameraOptions; - if (CLLocationCoordinate2DIsValid(options.camera.centerCoordinate)) { - cameraOptions.center = MGLLatLngFromLocationCoordinate2D(options.camera.centerCoordinate); - } - cameraOptions.angle = MAX(0, options.camera.heading) * mbgl::util::DEG2RAD; - cameraOptions.zoom = MAX(0, options.zoomLevel); - cameraOptions.pitch = MAX(0, options.camera.pitch); - - // Region - mbgl::optional<mbgl::LatLngBounds> coordinateBounds; - if (!MGLCoordinateBoundsIsEmpty(options.coordinateBounds)) { - coordinateBounds = MGLLatLngBoundsFromCoordinateBounds(options.coordinateBounds); - } - - // Create the snapshotter - _mbglMapSnapshotter = std::make_unique<mbgl::MapSnapshotter>(*mbglFileSource, *_mbglThreadPool, styleURL, size, pixelRatio, cameraOptions, coordinateBounds); + } return self; } @@ -167,14 +138,7 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64; [infos growArrayByAddingAttributionInfosFromArray:tileSetInfos]; } - CGSize attributionBackgroundSize = CGSizeMake(10, 0); - for (MGLAttributionInfo *info in infos) { - if (info.isFeedbackLink) { - continue; - } - attributionBackgroundSize.width += [info.title size].width + 10; - attributionBackgroundSize.height = MAX([info.title size].height, attributionBackgroundSize.height); - } + _attributionInfo = infos; if (mbglError) { NSString *description = @(mbgl::util::toString(mbglError).c_str()); @@ -198,11 +162,29 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64; dispatch_queue_t workQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_async(workQueue, ^{ #if TARGET_OS_IPHONE - UIImage *logoImage = [UIImage imageNamed:@"mapbox" inBundle:[NSBundle mgl_frameworkBundle] compatibleWithTraitCollection:nil]; + MGLAttributionInfoStyle attributionInfoStyle = MGLAttributionInfoStyleLong; + for (NSUInteger styleValue = MGLAttributionInfoStyleLong; styleValue >= MGLAttributionInfoStyleShort; styleValue--) { + attributionInfoStyle = (MGLAttributionInfoStyle)styleValue; + CGSize attributionSize = [self attributionSizeWithLogoStyle:attributionInfoStyle sourceAttributionStyle:attributionInfoStyle]; + if (attributionSize.width <= mglImage.size.width) { + break; + } + } + + UIImage *logoImage = [self logoImageWithStyle:attributionInfoStyle]; + CGSize attributionBackgroundSize = [self attributionTextSizeWithStyle:attributionInfoStyle]; CGRect logoImageRect = CGRectMake(MGLLogoImagePosition.x, mglImage.size.height - (MGLLogoImagePosition.y + logoImage.size.height), logoImage.size.width, logoImage.size.height); - CGRect attributionBackgroundFrame = CGRectMake(mglImage.size.width - 10 - attributionBackgroundSize.width, - logoImageRect.origin.y + (logoImageRect.size.height / 2) - (attributionBackgroundSize.height / 2) + 1, + CGPoint attributionOrigin = CGPointMake(mglImage.size.width - 10 - attributionBackgroundSize.width, + logoImageRect.origin.y + (logoImageRect.size.height / 2) - (attributionBackgroundSize.height / 2) + 1); + if (!logoImage) { + CGSize defaultLogoSize = [self mapboxLongStyleLogo].size; + logoImageRect = CGRectMake(0, mglImage.size.height - (MGLLogoImagePosition.y + defaultLogoSize.height), 0, defaultLogoSize.height); + attributionOrigin = CGPointMake(10, logoImageRect.origin.y + (logoImageRect.size.height / 2) - (attributionBackgroundSize.height / 2) + 1); + } + + CGRect attributionBackgroundFrame = CGRectMake(attributionOrigin.x, + attributionOrigin.y, attributionBackgroundSize.width, attributionBackgroundSize.height); CGPoint attributionTextPosition = CGPointMake(attributionBackgroundFrame.origin.x + 10, @@ -231,20 +213,39 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64; [blurredAttributionBackground drawInRect:attributionBackgroundFrame]; - [self drawAttributionText:infos origin:attributionTextPosition]; + [self drawAttributionTextWithStyle:attributionInfoStyle origin:attributionTextPosition]; UIImage *compositedImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); #else - NSImage *logoImage = [[NSImage alloc] initWithContentsOfFile:[[NSBundle mgl_frameworkBundle] pathForResource:@"mapbox" ofType:@"pdf"]]; - NSImage *sourceImage = mglImage; - NSSize targetSize = NSMakeSize(self.options.size.width, self.options.size.height); NSRect targetFrame = NSMakeRect(0, 0, targetSize.width, targetSize.height); + + MGLAttributionInfoStyle attributionInfoStyle = MGLAttributionInfoStyleLong; + for (NSUInteger styleValue = MGLAttributionInfoStyleLong; styleValue >= MGLAttributionInfoStyleShort; styleValue--) { + attributionInfoStyle = (MGLAttributionInfoStyle)styleValue; + CGSize attributionSize = [self attributionSizeWithLogoStyle:attributionInfoStyle sourceAttributionStyle:attributionInfoStyle]; + if (attributionSize.width <= mglImage.size.width) { + break; + } + } + + NSImage *logoImage = [self logoImageWithStyle:attributionInfoStyle]; + CGSize attributionBackgroundSize = [self attributionTextSizeWithStyle:attributionInfoStyle]; + NSImage *sourceImage = mglImage; + CGRect logoImageRect = CGRectMake(MGLLogoImagePosition.x, MGLLogoImagePosition.y, logoImage.size.width, logoImage.size.height); - CGRect attributionBackgroundFrame = CGRectMake(targetFrame.size.width - 10 - attributionBackgroundSize.width, - MGLLogoImagePosition.y + 1, + CGPoint attributionOrigin = CGPointMake(targetFrame.size.width - 10 - attributionBackgroundSize.width, + MGLLogoImagePosition.y + 1); + if (!logoImage) { + CGSize defaultLogoSize = [self mapboxLongStyleLogo].size; + logoImageRect = CGRectMake(0, MGLLogoImagePosition.y, 0, defaultLogoSize.height); + attributionOrigin = CGPointMake(10, attributionOrigin.y); + } + + CGRect attributionBackgroundFrame = CGRectMake(attributionOrigin.x, + attributionOrigin.y, attributionBackgroundSize.width, attributionBackgroundSize.height); CGPoint attributionTextPosition = CGPointMake(attributionBackgroundFrame.origin.x + 10, @@ -261,7 +262,9 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64; [sourceImageRep drawInRect: targetFrame]; - [logoImage drawInRect:logoImageRect]; + if (logoImage) { + [logoImage drawInRect:logoImageRect]; + } NSBitmapImageRep *attributionBackground = [[NSBitmapImageRep alloc] initWithFocusedViewRect:attributionBackgroundFrame]; @@ -271,7 +274,7 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64; [blurredAttributionBackground drawInRect:attributionBackgroundFrame]; - [self drawAttributionText:infos origin:attributionTextPosition]; + [self drawAttributionTextWithStyle:attributionInfoStyle origin:attributionTextPosition]; [compositedImage unlockFocus]; @@ -290,15 +293,16 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64; }); } -- (void)drawAttributionText:(NSArray *)attributionInfo origin:(CGPoint)origin +- (void)drawAttributionTextWithStyle:(MGLAttributionInfoStyle)attributionInfoStyle origin:(CGPoint)origin { - for (MGLAttributionInfo *info in attributionInfo) { + for (MGLAttributionInfo *info in _attributionInfo) { if (info.isFeedbackLink) { continue; } - [info.title drawAtPoint:origin]; + NSAttributedString *attribution = [info titleWithStyle:attributionInfoStyle]; + [attribution drawAtPoint:origin]; - origin.x += [info.title size].width + 10; + origin.x += [attribution size].width + 10; } } @@ -324,10 +328,8 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64; MGLImage *image; #if TARGET_OS_IPHONE - image = [UIImage imageWithCGImage:cgimg]; #else - image = [[NSImage alloc] initWithCGImage:cgimg size:[backgroundImage extent].size]; #endif @@ -335,87 +337,110 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64; return image; } -- (void)cancel +- (MGLImage *)logoImageWithStyle:(MGLAttributionInfoStyle)style { - _snapshotCallback.reset(); - _mbglMapSnapshotter.reset(); -} - -- (NSURL *)styleURL -{ - NSString *styleURLString = @(_mbglMapSnapshotter->getStyleURL().c_str()); - return styleURLString.length ? [NSURL URLWithString:styleURLString] : nil; + MGLImage *logoImage; + switch (style) { + case MGLAttributionInfoStyleLong: + logoImage = [self mapboxLongStyleLogo]; + break; + case MGLAttributionInfoStyleMedium: +#if TARGET_OS_IPHONE + logoImage = [UIImage imageNamed:@"mapbox_helmet" inBundle:[NSBundle mgl_frameworkBundle] compatibleWithTraitCollection:nil]; +#else + logoImage = [[NSImage alloc] initWithContentsOfFile:[[NSBundle mgl_frameworkBundle] pathForResource:@"mapbox_helmet" ofType:@"pdf"]]; +#endif + break; + case MGLAttributionInfoStyleShort: + logoImage = nil; + break; + } + return logoImage; } -- (void)setStyleURL:(NSURL *)url +- (MGLImage *)mapboxLongStyleLogo { - _mbglMapSnapshotter->setStyleURL(std::string([url.absoluteString UTF8String])); + MGLImage *logoImage; +#if TARGET_OS_IPHONE + logoImage =[UIImage imageNamed:@"mapbox" inBundle:[NSBundle mgl_frameworkBundle] compatibleWithTraitCollection:nil]; +#else + logoImage = [[NSImage alloc] initWithContentsOfFile:[[NSBundle mgl_frameworkBundle] pathForResource:@"mapbox" ofType:@"pdf"]]; +#endif + return logoImage; } -- (CGSize)size +- (CGSize)attributionSizeWithLogoStyle:(MGLAttributionInfoStyle)logoStyle sourceAttributionStyle:(MGLAttributionInfoStyle)attributionStyle { - mbgl::Size size = _mbglMapSnapshotter->getSize(); - return CGSizeMake(size.width, size.height); + MGLImage *logoImage = [self logoImageWithStyle:logoStyle]; + + CGSize attributionBackgroundSize = [self attributionTextSizeWithStyle:attributionStyle]; + + CGSize attributionSize = CGSizeZero; + + if (logoImage) { + attributionSize.width = MGLLogoImagePosition.x + logoImage.size.width + 10; + } + attributionSize.width = attributionSize.width + 10 + attributionBackgroundSize.width + 10; + attributionSize.height = MAX(logoImage.size.height, attributionBackgroundSize.height); + + return attributionSize; } -- (void)setSize:(CGSize)size +- (CGSize)attributionTextSizeWithStyle:(MGLAttributionInfoStyle)attributionStyle { - _mbglMapSnapshotter->setSize({ - static_cast<uint32_t>(MAX(size.width, MGLSnapshotterMinimumPixelSize)), - static_cast<uint32_t>(MAX(size.height, MGLSnapshotterMinimumPixelSize)) - }); + CGSize attributionBackgroundSize = CGSizeMake(10, 0); + for (MGLAttributionInfo *info in _attributionInfo) { + if (info.isFeedbackLink) { + continue; + } + CGSize attributionSize = [info titleWithStyle:attributionStyle].size; + attributionBackgroundSize.width += attributionSize.width + 10; + attributionBackgroundSize.height = MAX(attributionSize.height, attributionBackgroundSize.height); + } + + return attributionBackgroundSize; } -- (MGLMapCamera *)camera +- (void)cancel { - mbgl::CameraOptions cameraOptions = _mbglMapSnapshotter->getCameraOptions(); - CGFloat pitch = *cameraOptions.pitch; - CLLocationDirection heading = mbgl::util::wrap(*cameraOptions.angle, 0., 360.); - CLLocationDistance distance = MGLAltitudeForZoomLevel(*cameraOptions.zoom, pitch, cameraOptions.center->latitude(), [self size]); - return [MGLMapCamera cameraLookingAtCenterCoordinate:MGLLocationCoordinate2DFromLatLng(*cameraOptions.center) - fromDistance:distance - pitch:pitch - heading:heading]; + _snapshotCallback.reset(); + _mbglMapSnapshotter.reset(); } -- (void)setCamera:(MGLMapCamera *)camera +- (void)setOptions:(MGLMapSnapshotOptions *)options { + _options = options; + mbgl::DefaultFileSource *mbglFileSource = [MGLOfflineStorage sharedOfflineStorage].mbglFileSource; + _mbglThreadPool = mbgl::sharedThreadPool(); + + std::string styleURL = std::string([options.styleURL.absoluteString UTF8String]); + + // Size; taking into account the minimum texture size for OpenGL ES + // For non retina screens the ratio is 1:1 MGLSnapshotterMinimumPixelSize + mbgl::Size size = { + static_cast<uint32_t>(MAX(options.size.width, MGLSnapshotterMinimumPixelSize)), + static_cast<uint32_t>(MAX(options.size.height, MGLSnapshotterMinimumPixelSize)) + }; + + float pixelRatio = MAX(options.scale, 1); + + // Camera options mbgl::CameraOptions cameraOptions; - CLLocationCoordinate2D center; - if (CLLocationCoordinate2DIsValid(camera.centerCoordinate)) { - cameraOptions.center = MGLLatLngFromLocationCoordinate2D(camera.centerCoordinate); - center = camera.centerCoordinate; - } else { - // Center is optional, but always set. - center = MGLLocationCoordinate2DFromLatLng(*_mbglMapSnapshotter->getCameraOptions().center); + if (CLLocationCoordinate2DIsValid(options.camera.centerCoordinate)) { + cameraOptions.center = MGLLatLngFromLocationCoordinate2D(options.camera.centerCoordinate); } + cameraOptions.angle = MAX(0, options.camera.heading) * mbgl::util::DEG2RAD; + cameraOptions.zoom = MAX(0, options.zoomLevel); + cameraOptions.pitch = MAX(0, options.camera.pitch); - cameraOptions.angle = MAX(0, camera.heading) * mbgl::util::DEG2RAD; - cameraOptions.zoom = MAX(0, MGLZoomLevelForAltitude(camera.altitude, camera.pitch, center.latitude, [self size])); - cameraOptions.pitch = MAX(0, camera.pitch); -} - -- (double)zoomLevel -{ - mbgl::CameraOptions cameraOptions = _mbglMapSnapshotter->getCameraOptions(); - return MGLAltitudeForZoomLevel(*cameraOptions.zoom, *cameraOptions.pitch, cameraOptions.center->latitude(), [self size]); -} - -- (void)setZoomLevel:(double)zoomLevel -{ - mbgl::CameraOptions cameraOptions = _mbglMapSnapshotter->getCameraOptions(); - cameraOptions.zoom = zoomLevel; - _mbglMapSnapshotter->setCameraOptions(cameraOptions); -} - -- (MGLCoordinateBounds)coordinateBounds -{ - return MGLCoordinateBoundsFromLatLngBounds(_mbglMapSnapshotter->getRegion()); -} - -- (void)setCoordinateBounds:(MGLCoordinateBounds)coordinateBounds -{ - _mbglMapSnapshotter->setRegion(MGLLatLngBoundsFromCoordinateBounds(coordinateBounds)); + // Region + mbgl::optional<mbgl::LatLngBounds> coordinateBounds; + if (!MGLCoordinateBoundsIsEmpty(options.coordinateBounds)) { + coordinateBounds = MGLLatLngBoundsFromCoordinateBounds(options.coordinateBounds); + } + + // Create the snapshotter + _mbglMapSnapshotter = std::make_unique<mbgl::MapSnapshotter>(*mbglFileSource, *_mbglThreadPool, styleURL, size, pixelRatio, cameraOptions, coordinateBounds); } @end |