【问题标题】:Autodesk Forge Viewer Api Cannot load markups inside screenshotAutodesk Forge Viewer Api 无法在屏幕截图中加载标记
【发布时间】:2021-12-27 18:06:06
【问题描述】:

早安,

我正在使用最新的 Autodesk forge 查看器,并且我正在尝试截取同时呈现我的标记的屏幕截图。现在我的代码截图没有任何标记。下面是我的查看器代码。我正在加载标记核心和标记 Gui 扩展。请注意 onDocumentLoadSuccess(viewerDocument) 中的“takeSnapshot(viewer)”函数。该函数在初始化函数之前定义。

function takeSnapshot(target){
    $('#snipViewer').click( () => {
        target.getScreenShot(1600, 920, (blobURL) => {
            let snip = blobURL;
            $('#sniplink').attr("href", snip);
            $('#sniplink').html('Not Empty');
            $('#sniplink').css({"background-image": `url(${blobURL})`});
        });
    });        
}

//Autodesk Viewer Code

instance.data.showViewer = function showViewer(viewerAccessToken, viewerUrn){
    localStorage.setItem("viewerAccessTokentoken", viewerAccessToken);
    localStorage.setItem("viewerUrn", viewerUrn);  
    var viewer;
    var options = {
        env: 'AutodeskProduction',
        api: 'derivativeV2',
        getAccessToken: function(onTokenReady) {
            var token = viewerAccessToken;
            var timeInSeconds = 3600;
            onTokenReady(token, timeInSeconds);
        }
    };
    Autodesk.Viewing.Initializer(options, function() {
        let htmlDiv = document.getElementById('forgeViewer');
        viewer = new Autodesk.Viewing.GuiViewer3D(htmlDiv);
        let startedCode = viewer.start();
        viewer.setTheme("light-theme");
        viewer.loadExtension("Autodesk.CustomDocumentBrowser").then(() => {
            viewer.loadExtension("Autodesk.Viewing.MarkupsCore");
            viewer.loadExtension("Autodesk.Viewing.MarkupsGui");
        });
        if (startedCode > 0) {
            console.error('Failed to create a Viewer: WebGL not supported.');
            $("#loadingStatus").html("Failed to create a Viewer: WebGL not supported.");
            return;
        }
        console.log('Initialization complete, loading a model next...');
    });
    var documentId = `urn:` + viewerUrn;
    var derivativeId = `urn:` + instance.derivativeUrn;
    Autodesk.Viewing.Document.load(documentId, onDocumentLoadSuccess, onDocumentLoadFailure);
    function onDocumentLoadSuccess(viewerDocument) {
        var defaultModel = viewerDocument.getRoot().getDefaultGeometry();
        viewer.loadDocumentNode(viewerDocument, defaultModel);
        takeSnapshot(viewer);
    }
    function onDocumentLoadFailure() {
        console.error('Failed fetching Forge manifest');
        $("#loadingStatus").html("Failed fetching Forge manifest.");
    }
}

这篇文章我已经看过了:https://forge.autodesk.com/blog/screenshot-markups 我尝试过使用这种方法,但说明对我来说非常不清楚。 <div style="width:49vw; height:100vh;display:inline-block;"><canvas id="snapshot" style="position:absolute;"></canvas><button onclick="snaphot();" style="position:absolute;">Snapshot!</button></div>

这里的canvas元素是干什么用的?当我在初始化函数或屏幕截图函数中加载标记扩展时,我应该使用 renderToCanvas() 吗?有什么方法可以实现 renderToCanvas() 而不改变我已经在这里使用的太多东西吗?我不是查看器 API 方面的专家,所以如果你能帮助我,我将不胜感激,我是初学者,请不要跳过很多步骤。

非常感谢!

【问题讨论】:

    标签: autodesk-forge autodesk-viewer autodesk


    【解决方案1】:

    这里有一个更简化的逻辑,用于在 Forge Viewer 中生成带有标记的屏幕截图,并在下面进一步解释为什么需要这样做:

    function getViewerScreenshot(viewer) {
        return new Promise(function (resolve, reject) {
            const screenshot = new Image();
            screenshot.onload = () => resolve(screenshot);
            screenshot.onerror = err => reject(err);
            viewer.getScreenShot(viewer.container.clientWidth, viewer.container.clientHeight, function (blobURL) {
                screenshot.src = blobURL;
            });
        });
    }
    function addMarkupsToScreenshot(viewer, screenshot) {
        return new Promise(function (resolve, reject) {
            const markupCoreExt = viewer.getExtension('Autodesk.Viewing.MarkupsCore');
            const canvas = document.createElement('canvas');
            canvas.width = viewer.container.clientWidth;
            canvas.height = viewer.container.clientHeight;
            const context = canvas.getContext('2d');
            context.clearRect(0, 0, canvas.width, canvas.height);
            context.drawImage(screenshot, 0, 0, canvas.width, canvas.height);
            markupCoreExt.renderToCanvas(context, function () {
                resolve(canvas);
            });
        });
    }
    const screenshot = await getViewerScreenshot(viewer);
    const canvas = await addMarkupsToScreenshot(viewer, screenshot);
    const link = document.createElement('a');
    link.href = canvas.toDataURL();
    link.download = 'screenshot.png';
    link.click();
    

    基本上,标记扩展只能将其标记(而不是底层的 2D/3D 场景)渲染到现有的 <canvas> 元素中。这就是为什么这是一个多步骤的过程:

    1. 您使用 viewer.getScreenShot 渲染底层 2D/3D 场景,获取包含屏幕截图图像数据的 blob URL
    2. 您创建了一个新的<canvas> 元素
    3. 您将屏幕截图插入画布(在本例中,我们创建一个新的Image 实例并使用context.drawImage 将其渲染到画布中)
    4. 您调用扩展程序的 renderToCanvas,它将在屏幕截图图像的顶部 的画布中呈现标记

    【讨论】:

    • 感谢@PetrBroz 的解释,真的做得很好。我可以澄清一下 blobURL 吗?因此,当 renderToCanvas 被激活时,我们将标记呈现在屏幕截图的顶部。 bloblURL 更新了吗?据我了解,此方法只是创建一个包含我的标记的 html 元素。我的最终目标是截取带有标记的屏幕截图,并将其作为图像包含在评论部分,以便用户分享想法。这将需要一个可以随意共享的 URL,这会起作用还是我需要考虑一种新方法?谢谢你:)
    • blob URL 未更新。发生的情况是,我们获取 blob URL 并将其转换为 Image 类的实例。之后,我们创建一个空画布,将图像渲染到画布中,最后将标记渲染到画布中。
    • 我收到一个错误:未捕获(承诺中)类型错误:CanvasRenderingContext2D.drawImage:参数 1 无法转换为以下任何一种:HTMLImageElement、SVGImageElement、HTMLCanvasElement、HTMLVideoElement、ImageBitmap。你有什么想法?这是来自 .drawImage
    • 在调用.drawImage 之前检查screenshot 变量的类型。它应该是HTMLImageElement 的一个实例。
    猜你喜欢
    • 2021-02-21
    • 2020-06-06
    • 2021-02-10
    • 2021-09-30
    • 2020-05-20
    • 2018-05-24
    • 2021-05-30
    • 2019-11-14
    • 2020-01-06
    相关资源
    最近更新 更多