画布中的图像未正确保存

Posted

技术标签:

【中文标题】画布中的图像未正确保存【英文标题】:Image from canvas is not saved correctly 【发布时间】:2021-06-23 05:50:21 【问题描述】:

祝所有用户美好的一天! 我的问题是我在画布上呈现的屏幕截图未正确保存。 使用js在画布上显示屏幕截图

function retrieveImageFromClipboardAsBlob(pasteEvent, callback)
    if(pasteEvent.clipboardData == false)
        if(typeof(callback) == "function")
            callback(undefined);
        
    ;
    var items = pasteEvent.clipboardData.items;
    if(items == undefined)
        if(typeof(callback) == "function")
            callback(undefined);
        
    ;
    for (var i = 0; i < items.length; i++) 
        if (items[i].type.indexOf("image") == -1) continue;
        var blob = items[i].getAsFile();

        if(typeof(callback) == "function")
            callback(blob);
        
    


window.addEventListener("paste", function(e)
    retrieveImageFromClipboardAsBlob(e, function(imageBlob)
        if(imageBlob)
            var canvas = document.getElementById("mycanvas");
            var ctx = canvas.getContext('2d');
            var img = new Image();
            img.onload = function()
                canvas.width = this.width;
                canvas.height = this.height;
                ctx.drawImage(img, 0, 0);
            ;
            var URLObj = window.URL || window.webkitURL;
            img.src = URLObj.createObjectURL(imageBlob);
        
    );

    var cnv = document.getElementById("mycanvas");
    var sendCanvas = function (cnv) 
        var imgs = cnv.toDataURL('image/png').replace('data:image/png;base64,','');
        var sender = new XMLHttpRequest();
        sender.open('POST', '/temp.php', true);
        sender.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
        sender.onreadystatechange = function () 
            if (sender.readyState == 4) 
        ;
        sender.send('imgs='+imgs);
    ;
    sendCanvas(cnv);
, false);

首先,屏幕截图在画布上绘制,然后发送到 php 处理程序。 我的 html 表单有:

<canvas id="mycanvas">
<?php
    $imgs = str_replace(' ', '+', $_POST['imgs']);
    $imgs = base64_decode($imgs);
    $shootname = "screenshot".rand().".png";
    $screendir = "/mnt/ElmaFiles/".$shootname;
    file_put_contents($screendir, $imgs);
    $screennames .= $shootname.",";
?>
<p><input type="submit" name="submit1" class="btn success"></p>
<script src="//ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"</script>
<script src="/script11.js"></script>

在我的理解中,当我按下 ctrl + v 时,文件应该被保存到指定的文件夹中。但它并不是真的那样工作。 比如我传输了3张截图,但是我的文件夹里保存了5张截图:

请帮助我理解我的错误在哪里? 非常感谢您! 忘了补充:保存5张截图时,只能打开第三张和第四张,其余的都写了“格式不正确”之类的错误

【问题讨论】:

注意typeof(callback)中不需要括号,可以改为typeof callback @luekbaja 感谢您的建议,我最近开始学习网络语言。但这并没有解决我的问题:( temp.php 是做什么的?那应该保存文件吗?您可以添加其中的内容吗?或者您是否满意它可以正常工作? @ProfessorAbronsius 对不起。没注意到我错了。我的 html 表单是 temp.php OK - 所以你将 AJAX 请求发送到同一页面?那是显示的那段代码 - 以$imgs = str_replace(' ', '+', $_POST['imgs']);开头?? 【参考方案1】:

我对上面的内容做了一点重写,希望能帮助解决你遇到的一些问题。

应该明确定位将图像保存到磁盘的 PHP,以便尝试为常规 GET 请求调用 $_POST['imgs'] 不会导致问题。要将二进制数据发送到服务器而不是 XMLHttpRequest,请改用 fetch ~ 一个相当强大的 api。

<?php

    error_reporting( E_ALL );
    ini_set( 'display_errors', 1 );
    
    if( $_SERVER['REQUEST_METHOD']=='POST' && !empty( $_POST['imgs'] ) )
        ob_clean();
        
        $decoded=base64_decode( $_POST['imgs'] );
        
        #edit directory to suit. This is a sub-folder to where the script is currently running.
        $dir=sprintf('%s/images/tmp',__DIR__);
        
        
        
        $filename=sprintf('screenshot%s.png', rand() );
        $targetfile=sprintf('%s%s%s', realpath($dir), DIRECTORY_SEPARATOR, $filename );
        file_put_contents( $targetfile, $decoded );
        
        exit( $filename );
    
?>
<!DOCTYPE html>
<html lang='en'>
    <head>
        <meta charset='utf-8' />
        <title></title>
        <script>
            document.addEventListener('DOMContentLoaded',()=>
            
                function getBlob(evt,callback)
                    if( evt.clipboardData == false || evt.clipboardData.items=='undefined' )
                        return false;
                    ;
                    let items = evt.clipboardData.items;
                    for( let i=0; i < items.length; i++)
                        let item=items[i];
                        if( ~item.type.indexOf('image') )callback( item.getAsFile() );
                    
                

                window.addEventListener('paste', function(e)
                    let canvas = document.querySelector('canvas');
                    let ctxt = canvas.getContext('2d');
                    
                    const callback=function( blob )
                        if( blob )
                            let img = new Image();
                                img.onload = function()
                                    canvas.width=this.width;
                                    canvas.height=this.height;
                                    ctxt.drawImage( img, 0, 0 );
                                ;
                                img.src = URL.createObjectURL(blob);
                            return true;
                        
                        return false;
                    ;
                    
                    getBlob( e, callback );
                    
                    let fd=new FormData();
                        fd.append('imgs', canvas.toDataURL('image/png').replace('data:image/png;base64,',''));
                        
                    fetch( location.href, method:'post', body:fd )
                        .then( r=>r.text() )
                        .then( text=>
                            console.info('Screenshot %s saved',text )
                        )
                );
            );
        </script>
    </head>
    <body>
        <canvas></canvas>
    </body>
</html>

【讨论】:

谢谢!它真的很有帮助。但是,进入画布的第一个屏幕截图仍然是空的。其余的屏幕截图创建没有问题。 真的吗?似乎工作正常...啊~发现一个小错误。将str_replace(' ', '+', $_POST['imgs'] ) 更改为简单的$_POST['imgs'] 感谢您的帮助!但是这种方法仍然没有帮助我。第一个屏幕截图只是一个白色画布。 :( 在我删除了那部分(上面提到的)之后,它每次都能正常工作?! 如果我改变你上面描述的方法,那么第一个屏幕截图仍然只是一个白色的画布,其余的屏幕截图都是从原始截图中裁剪出来的。我决定不改变方法,而是试图弄清楚为什么第一个屏幕截图被加载为白色画布。

以上是关于画布中的图像未正确保存的主要内容,如果未能解决你的问题,请参考以下文章

将图像加载到画布上并放大/缩小并移动它以适应并保存画布上的内容

如何将画布保存为html5中的图像?

使用 C# 和 jQuery 将画布保存到图像

Javascript:将画布另存为图像 ==>“未捕获的类型错误:未定义不是函数”

在 Android 中的图像上保存画布绘图

如何将使用 InkCanvas 在画布上完成的工作保存到 UWP C# 中的图像文件?