【问题标题】: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']);开头??

标签: javascript php html jquery canvas


【解决方案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']
  • 感谢您的帮助!但是这种方法仍然没有帮助我。第一个屏幕截图只是一个白色画布。 :(
  • 在我删除了那部分(上面提到的)之后,它每次都能正常工作?!
  • 如果我改变你上面描述的方法,那么第一个屏幕截图仍然只是一个白色的画布,其余的屏幕截图都是从原始截图中裁剪出来的。我决定不改变方法,而是试图弄清楚为什么第一个屏幕截图被加载为白色画布。
猜你喜欢
  • 2015-06-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多