Take a screenshot of the map.

Use case
GIS users may want to export a screenshot of a map to enable sharing as an image or printing.
How to use the sample
Pan and zoom to find an interesting location. Press Take screenshot, and a screenshot image will display over the map. Note that there may be a small delay if the map is still rendering when you push the button.
How it works
- The
exportImagefunction is executed on theMapView. - Once the asynchronous task completes, a
QImageis returned. - QML cannot directly render a
QImage. Instead, a QML Image Provider must be created for generating an in-memory URL to the returnedQImage. This is done with the following steps:
- Subclass
QQuickImageProvider. - Reimplement the
requestImagefunction. - Add an image provider to the
QQmlEngineinstance usingQQmlEngine::addImageProvider. - Create a
Q_PROPERTYthat returns the image URL from the Image Provider. - Bind the QML Image to the image URL property. When this property changes, it will automatically trigger the
requestImagefunction and return the URL to the image.
Relevant API
- GeoView::exportImage
Tags
capture, export, image, print, screen capture, screenshot, share, shot
Sample code
// [WriteFile Name=TakeScreenshot, Category=Maps]// [Legal]// Copyright 2018 Esri.//// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at// http://www.apache.org/licenses/LICENSE-2.0//// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License.// [Legal]
#ifdef PCH_BUILD#include "pch.hpp"#endif // PCH_BUILD
// sample headers#include "MapImageProvider.h"#include "TakeScreenshot.h"
// ArcGIS Maps SDK headers#include "Map.h"#include "MapQuickView.h"#include "MapTypes.h"
// Qt headers#include <QFuture>#include <QQmlContext>#include <QUuid>
using namespace Esri::ArcGISRuntime;
TakeScreenshot::TakeScreenshot(QQuickItem* parent /* = nullptr */): QQuickItem(parent){}
void TakeScreenshot::init(){ // Register the map view for QML qmlRegisterType<MapQuickView>("Esri.Samples", 1, 0, "MapView"); qmlRegisterType<TakeScreenshot>("Esri.Samples", 1, 0, "TakeScreenshotSample");}
void TakeScreenshot::componentComplete(){ QQuickItem::componentComplete();
// find QML MapView component m_mapView = findChild<MapQuickView*>("mapView");
// Create a map using the imagery basemap m_map = new Map(BasemapStyle::ArcGISImageryStandard, this);
// Set map to map view m_mapView->setMap(m_map);
// Get the image provider from the QML Engine QQmlEngine* engine = QQmlEngine::contextForObject(this)->engine(); m_imageProvider = dynamic_cast<MapImageProvider*>(engine->imageProvider(MapImageProvider::imageProviderId()));}
// Q_INVOKABLE function to kick off the export image asynchronous taskvoid TakeScreenshot::captureScreenshot(){ m_mapView->exportImageAsync().then(this, [this](QImage img) { // convert the QUuid into a QString const QString imageId = QUuid().createUuid().toString(QUuid::WithoutBraces); // add the image to the provider m_imageProvider->addImage(imageId, img); // update the URL with the unique id m_mapImageUrl = QString("image://%1/%2").arg(MapImageProvider::imageProviderId(), imageId); // emit the signal to trigger the QML Image to update emit mapImageUrlChanged(); });}
QUrl TakeScreenshot::mapImageUrl() const{ return m_mapImageUrl;}// [WriteFile Name=TakeScreenshot, Category=Maps]// [Legal]// Copyright 2018 Esri.//// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at// http://www.apache.org/licenses/LICENSE-2.0//// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License.// [Legal]
#ifndef TAKESCREENSHOT_H#define TAKESCREENSHOT_H
// Qt headers#include <QQuickItem>
namespace Esri::ArcGISRuntime{class Map;class MapQuickView;}
class MapImageProvider;
class TakeScreenshot : public QQuickItem{ Q_OBJECT
Q_PROPERTY(QUrl mapImageUrl READ mapImageUrl NOTIFY mapImageUrlChanged)
public: explicit TakeScreenshot(QQuickItem* parent = nullptr); ~TakeScreenshot() override = default;
void componentComplete() override; static void init(); Q_INVOKABLE void captureScreenshot();
signals: void mapImageUrlChanged();
private: Esri::ArcGISRuntime::Map* m_map = nullptr; Esri::ArcGISRuntime::MapQuickView* m_mapView = nullptr; MapImageProvider* m_imageProvider = nullptr; QUrl m_mapImageUrl;
private: QUrl mapImageUrl() const;};
#endif // TAKESCREENSHOT_H// [Legal]// Copyright 2018 Esri.//// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at// http://www.apache.org/licenses/LICENSE-2.0//// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License.// [Legal]
// sample headers#include "MapImageProvider.h"
// Qt headers#include <QQuickImageProvider>
MapImageProvider::MapImageProvider() : QQuickImageProvider(QQuickImageProvider::Image){}
// reimplemented function for QML to request Images from the providerQImage MapImageProvider::requestImage(const QString& id, QSize* size, const QSize &requestedSize){ Q_UNUSED(size) Q_UNUSED(requestedSize) return m_images[id];}
// helper to add images to the the providervoid MapImageProvider::addImage(const QString& id, const QImage& img){ m_images[id] = img;}
// static function to return the image provider idQString MapImageProvider::imageProviderId(){ return QStringLiteral("mapimageprovider");}// [Legal]// Copyright 2018 Esri.//// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at// http://www.apache.org/licenses/LICENSE-2.0//// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License.// [Legal]
// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License.
#ifndef MAPIMAGEPROVIDER_H#define MAPIMAGEPROVIDER_H
// Qt headers#include <QImage>#include <QMap>#include <QQuickImageProvider>
class MapImageProvider : public QQuickImageProvider{
public: MapImageProvider(); ~MapImageProvider() override = default;
public: QImage requestImage(const QString& id, QSize* size, const QSize& requestedSize) override; void addImage(const QString& id, const QImage& img); static QString imageProviderId();
private: QMap<QString, QImage> m_images;};
#endif // MAPIMAGEPROVIDER_H// [WriteFile Name=TakeScreenshot, Category=Maps]// [Legal]// Copyright 2018 Esri.//// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at// http://www.apache.org/licenses/LICENSE-2.0//// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License.// [Legal]
import QtQuickimport QtQuick.Controlsimport Esri.Samples
TakeScreenshotSample { id: rootRectangle clip: true width: 800 height: 600
// Declare a MapView MapView { id: mapView anchors.fill: parent objectName: "mapView"
Component.onCompleted: { // Set the focus on MapView to initially enable keyboard navigation forceActiveFocus(); }
Button { anchors { horizontalCenter: parent.horizontalCenter bottom: mapView.attributionTop margins: 10 } text: "Take screenshot" onClicked: { captureScreenshot(); busyIndicator.visible = true; } } }
onMapImageUrlChanged: { imageRect.visible = true; busyIndicator.visible = false; }
Rectangle { id: imageRect anchors.fill: parent visible: false Rectangle { anchors.fill: parent color: "#60000000" }
Image { id: mapImage anchors.centerIn: parent width: parent.width * 0.75 height: parent.height * 0.75 source: mapImageUrl // bind to the property exposed by TakeScreenshot
Rectangle { anchors { right: parent.right top: parent.top margins: 10 } width: 28 height: width color: "lightgray" radius: 50
Image { anchors.centerIn: parent width: parent.width * 0.95 height: parent.height * 0.95 source: "qrc:/Samples/Maps/TakeScreenshot/close.png" }
MouseArea { anchors.fill: parent onClicked: imageRect.visible = false; } } } }
BusyIndicator { id: busyIndicator anchors.centerIn: parent visible: false }}