将图像二进制数据呈现到img或canvas标记中

render an image binary data into a img or canvas tag

本文关键字:canvas img 二进制 图像 数据      更新时间:2023-09-26

我有一个路由,我用它来请求图像,像这样:

/api/image

它返回文件数据的主体,类似于

����JFIF��C��C��� ��    
�����+�}Yϭ�F39M>���������>���;��ˋ��uXʽ�w�ڤx'-[2g��k�S���H���m
[�V?[_W����#��v��}6�[��F�F�%����n�...

我要做的是像这样:

<canvas>

然后我这样做了:

代码:

var canvas = $('canvas');
var blob = new Blob([file], {type: 'image/png'});
var url = URL.createObjectURL(blob);
var img = new Image;
var ctx = canvas.getContext('2d');
$(img).on('load',function(event) {
   ctx.drawImage(img, 0, 0);
   URL.revokeObjectURL(url);
}).each(function(){
     if(this.complete) { $(this).load() }
});
img.src = url;

我还直接将文件附加到图像源属性中,如:

img。SRC = 'data:image/png;base64,' + file

但是不工作

我得到的是资源没有找到,它抛出404错误:

> GET blob:http://localhost:3000/2a86de11-b565-4578-8ec1-2c20cbdae739 404 (Not Found)

我有点困惑,我做错了什么?

编辑:我刚刚做了这个:

var blob = new Blob([file], {type: 'image/png'});
var reader = new FileReader();
reader.onload = function (e) {
  suggestion.img.attr('src', e.target.result);
};
reader.readAsDataURL(blob);

但是它也不显示图像

好吧,您所显示的顶部数据是二进制的,因此,只是加上dataURL的东西是行不通的。您需要对二进制数据做一些不同的处理,或者返回实际的base64编码数据。

下面是一个复合示例。它表明:

  • 读取磁盘上的文件
  • 显示
  • 上传它
  • 使用GD创建修改后的副本,除非它是svg
  • 将其作为二进制数据发送回浏览器
  • 抓住它
  • 将其转换为blob,然后是dataURL
  • 在最终使用它设置图像的src属性之前。
  • base64编码,添加dataURL内容并输出。
  • 检索异地或跨协议图像并在画布上绘制而不污染它。

base64.php

<?php
    // usefull for images without CORS header
    if (isset($_GET['filename']) == true)
    {
        $filename = urldecode( $_GET['filename'] );
        $data = file_get_contents($filename);
        $finfo = new finfo(FILEINFO_MIME);
        $mimeType = $finfo->buffer($data);
        Header("Content-Type: $mimeType");                  // use the currently detected mime-type
        echo $data;
        die;
    }
    if (isset($_FILES['upload']) == true)
    {
        $alterResult = true;
        // GD wont load svgs :(
        if (strcmp(trim($_FILES['upload']['type']),"image/svg+xml") == 0)
            $alterResult = false;
        // expecting a form element with the type of 'file' and the name of 'upload' - accepting 1 file max
        $data = file_get_contents( $_FILES['upload']['tmp_name'] );
        // draw copy of image, invert the colours, guassian blur 5 times, draw inverted,bluury image beside unaltered copy
        if ($alterResult == true)
        {
            $mImage = imagecreatefromstring ($data);
            $output = imagecreatetruecolor(imagesx($mImage) * 2, imagesy($mImage));
            imagesavealpha ( $mImage , true);
            imagesavealpha ( $output , true);
            imagecopy($output, $mImage, 0, 0, 0, 0, imagesx($mImage) - 1, imagesy($mImage) - 1);
            imagefilter($mImage,IMG_FILTER_NEGATE);
            imagefilter($mImage,IMG_FILTER_GAUSSIAN_BLUR);
            imagefilter($mImage,IMG_FILTER_GAUSSIAN_BLUR);
            imagefilter($mImage,IMG_FILTER_GAUSSIAN_BLUR);
            imagefilter($mImage,IMG_FILTER_GAUSSIAN_BLUR);
            imagefilter($mImage,IMG_FILTER_GAUSSIAN_BLUR);
            imagecopy($output, $mImage, imagesx($mImage), 0, 0, 0, imagesx($mImage) - 1, imagesy($mImage) - 1);
            Header("Content-Type: image/png");
            imagepng($output);
            imagedestroy($mImage);
            imagedestroy($output);
            die;
        }
        // it's an svg, so just return byte-for-byte what we received
        else
        {
            $finfo = new finfo(FILEINFO_MIME);
            $mimeType = $finfo->buffer($data);
            $mimeType = preg_replace("/text'/plain/", "image/svg+xml", $mimeType);  // svgs are wrongly reported as text files
            Header("Content-Type: $mimeType");                  // use the currently detected mime-type
            echo $data;
            die;
        }
    }
?><!doctype html>
<html>
<head>
<script>
function byId(id){return document.getElementById(id)}
function newEl(tag){return document.createElement(tag)}
window.addEventListener('load',onDocLoaded);
function onDocLoaded(evt)
{
    byId('fileInput').addEventListener('change', onFileChosen);
    // cross origin test
    var can = newEl('canvas');
    var ctx = can.getContext('2d');
    var srcImg = byId('crossOrigin');
    can.width = srcImg.naturalWidth;
    can.height = srcImg.naturalHeight;
    ctx.drawImage(srcImg, 0,0);
    document.body.appendChild(can);
    console.log( can.toDataURL() );
}
function ajaxGet(url, onLoad, onError)
{
    var ajax = new XMLHttpRequest();
    ajax.onload = function(evt){onLoad(this);}
    ajax.onerror = function(evt){onError(this);}
    ajax.open("GET", url, true);
    ajax.send();
}
function ajaxGetBinary(url, onLoad, onError)
{
    var ajax = new XMLHttpRequest();
    ajax.responseType = 'arraybuffer';
    ajax.onload = function(evt){onLoad(this);}
    ajax.onerror = function(evt){onError(this);}
    ajax.open("GET", url, true);
    ajax.send();
}
function ajaxPostForm(url, formElem, onLoad, onError)
{
    var ajax = new XMLHttpRequest();
    ajax.open("POST", url, true);
    ajax.responseType = 'arraybuffer';
    ajax.onload = function(evt){onLoad(this);}
    ajax.onerror = function(evt){onError(this);}
    ajax.send( new FormData(formElem) );
}
function onFileChosen(evt)
{
    // just clear the images if no file selected
    if (this.files.length < 1)
    {
        byId('beforeImg').src = '';
        byId('afterImg').src = '';
        return;
    }
    var file = this.files[0];       // used to set the mime-type of the file when we get it back
    /*
        ==========Before upload/download==========
    */
    let fileReader = new FileReader();
    fileReader.onload = function(evt){byId('beforeImg').src=this.result;}
    fileReader.readAsDataURL(file); 
    /*
        ==========After upload/download==========
        send the file to the backend (also this source-file), then the back-end will read the temporary file and output it.
        we catch this binary output and make an image element with it
    */
    ajaxPostForm('<?php echo $_SERVER['PHP_SELF']; ?>', byId('mForm'), onPostOkay, function(){});
    function onPostOkay(ajax)
    {
        let arrayBuffer = ajax.response;
        if (arrayBuffer)
        {
            let byteArray = new Uint8Array(arrayBuffer);
            let blob = new Blob([byteArray], {type: file.type });
            byId('afterImg').src = URL.createObjectURL(blob);
        }
    }
}
</script>
<style>
.panel
{
    display: inline-block;
    padding: 8px;
    border-radius: 8px;
    border: solid 1px black;
    text-align: center;
}
</style>
</head>
<body>
    <!-- RESULT of below: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA......." -->
    <img id='crossOrigin' src='base64.php?filename=https%3A%2F%2Fmy.totalwellbeingdiet.com%2Fimg%2Fcsiro%2Flogos%2Fcsiro.png'/>
    <!-- RESULT of below: "Uncaught SecurityError: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported." -->
    <!-- <img id='crossOrigin' src='https://my.totalwellbeingdiet.com/img/csiro/logos/csiro.png'/> -->
    <form id='mForm' method='post' enctype="multipart/form-data">
        <input id='fileInput' type='file' name='upload'/>
    </form>
    <div class='panel'>
        <img id='beforeImg'/><br>
        <strong>Before upload</strong>
    </div>
    <div class='panel'>
        <img id='afterImg'/><br>
        <strong>After upload/mod/download</strong>
    </div>
</body>
</html>

你不应该自己构造blob, responseType应该是blob