【问题标题】:How can I draw an image from the HTML5 File API on Canvas?如何从 Canvas 上的 HTML5 File API 绘制图像?
【发布时间】:2011-07-21 12:08:21
【问题描述】:

我想在画布上绘制使用 HTML5 File API 打开的图像。

handleFiles(e) 方法中,我可以使用e.target.files[0] 访问文件,但我无法使用drawImage 直接绘制该图像。如何从 HTML5 画布上的 File API 绘制图像?

这是我使用的代码:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<script>
window.onload = function() {
    var input = document.getElementById('input');
    input.addEventListener('change', handleFiles);
}

function handleFiles(e) {
    var ctx = document.getElementById('canvas').getContext('2d');
    ctx.drawImage(e.target.files[0], 20,20);
    alert('the image is drawn');
}
</script>
</head>
<body>
<h1>Test</h1>
<input type="file" id="input"/>
<canvas width="400" height="300" id="canvas"/>
</body>
</html>

【问题讨论】:

    标签: javascript canvas drawimage fileapi


    【解决方案1】:

    您有一个不是图像的File 实例。

    要获取图像,请使用new Image()src 必须是引用所选 File 的 URL。您可以使用URL.createObjectURL 获取引用Blob 的URL(File 也是Blob):http://jsfiddle.net/t7mv6/86/

    var ctx = document.getElementById('canvas').getContext('2d');
    var img = new Image;
    img.onload = function() {
        ctx.drawImage(img, 20,20);
        alert('the image is drawn');
    }
    img.src = URL.createObjectURL(e.target.files[0]);
    

    注意:请务必在完成后撤销对象 url,否则会泄漏内存。如果你没有做太疯狂的事情,你可以在img.onload 函数中添加一个URL.revokeObjectURL(img.src)

    参考资料:

    【讨论】:

    • 请在src之前附加onloadload 事件可以在这两行之间触发。 (如果图像被缓存等)
    • @Raynos:谢谢。 (虽然在这种情况下文件加载速度一定非常快......)
    • 出于好奇,您能否参考它所说的“将.src 设置为 Blob/文件”应该在 HTML5 规范中工作?我有一个小问题,这可能是一个专有扩展。它恰好在 Chrome / FF6 中工作(没有 Opera、IE10 或 Saf nightlies 来测试)
    • @Raynos:我的错,我看错了。看起来这回答了你的疑问:w3.org/TR/FileAPI/#dfn-readAsDataURLSet the result attribute to be blob's data content represented as a Data URL [DataURL]; on getting, the result attribute returns the (complete) data of blob as a Data URL。显然Data URL可以设置为Image的src;这将加载正常。
    【解决方案2】:

    Live Example

    function handleFiles(e) {
        var ctx = document.getElementById('canvas').getContext('2d');
        var url = URL.createObjectURL(e.target.files[0]);
        var img = new Image();
        img.onload = function() {
            ctx.drawImage(img, 20, 20);    
        }
        img.src = url;   
    }
    

    window.URL.createObjectUrldocs

    您也可以改用FileReader 来创建对象 URL。

    FileReader 的浏览器支持稍好一些。

    FileReader 方法适用于 FF6 / Chrome。我不确定将Img.src 设置为Blob 是否有效且跨浏览器。

    创建对象 url 是正确的方法。

    编辑:

    正如评论中提到的window.URL 支持,而离线似乎在 FF6/Chrome 中不可用。

    【讨论】:

    • 这有效,但仅限在线。如果我在 Chrome 中使用本地 .html 文件尝试此操作,它将不起作用。
    • FileReader 方法在本地也不起作用...谢谢。
    • @Jonas 可能是权限问题。如果默认情况下它们被阻止,我不会感到惊讶。打开它可能会发现一些不起眼的标志。
    • @Jonas 似乎晦涩的标志是 chrome 的 --allow-file-access-from-files.Reference
    【解决方案3】:

    这是一个使用FileReadercomplete example (Fiddle)(Raynos 提到它具有更好的浏览器支持)。在此示例中,我还缩放 Canvas 以适合图像。

    在现实生活中的示例中,您可能会将图像缩放到某个最大值,这样您的表单就不会爆炸;-)。这是example with scaling (Fiddle)

    var URL = window.webkitURL || window.URL;
    
    window.onload = function() {
        var input = document.getElementById('input');
        input.addEventListener('change', handleFiles, false);
        
        // set original canvas dimensions as max
        var canvas = document.getElementById('canvas');
        canvas.dataMaxWidth = canvas.width;
        canvas.dataMaxHeight = canvas.height;
    }
    
    function handleFiles(e) {
        var ctx = document.getElementById('canvas').getContext('2d');
        var reader  = new FileReader();
        var file = e.target.files[0];
        // load to image to get it's width/height
        var img = new Image();
        img.onload = function() {
            // setup scaled dimensions
            var scaled = getScaledDim(img, ctx.canvas.dataMaxWidth, ctx.canvas.dataMaxHeight);
            // scale canvas to image
            ctx.canvas.width = scaled.width;
            ctx.canvas.height = scaled.height;
            // draw image
            ctx.drawImage(img, 0, 0
                , ctx.canvas.width, ctx.canvas.height
            );
        }
        // this is to setup loading the image
        reader.onloadend = function () {
            img.src = reader.result;
        }
        // this is to read the file
        reader.readAsDataURL(file);
    }
    
    // returns scaled dimensions object
    function getScaledDim(img, maxWidth, maxHeight) {
        var scaled = {
            ratio: img.width / img.height,
            width: img.width,
            height: img.height
        }
        if (scaled.width > maxWidth) {
            scaled.width = maxWidth;
            scaled.height = scaled.width / scaled.ratio;
        }
        if (scaled.height > maxHeight) {
            scaled.height = maxHeight;
            scaled.width = scaled.height / scaled.ratio;
        }
        return scaled;
    }
    canvas {
        border:1px solid black
    }
    <input type="file" id="input"/>
    <div>
        <canvas width="400" height="300" id="canvas"/>
    </div>

    【讨论】:

    • 答案应该在问题中显示代码,而不仅仅是在外部链接中。
    • @HereticMonkey 我认为 2015 年 stackO 上没有该选项?,但我添加了代码。
    • 我早在 2015 年就在 Stack Overflow。那时您也可以在答案中添加代码。也许不在代码片段中,但您绝对可以添加代码:P。
    猜你喜欢
    • 2014-10-20
    • 2011-08-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-10
    • 2015-06-16
    • 2018-07-16
    相关资源
    最近更新 更多