在 Javascript 中将 base64 转换为文件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/22589680/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 23:25:45  来源:igfitidea点击:

Convert a base64 to a file in Javascript

javascriptfilecross-browserclient-side

提问by Imnl

The goal is to transform a base64 string into a sendable jpg file, I cant use the html input type file but i have to serve in the same format. I am bit lost with file generation. (I am on a client side mobile app).

目标是将 base64 字符串转换为可发送的 jpg 文件,我不能使用 html 输入类型文件,但我必须以相同的格式提供服务。我对文件生成有点迷茫。(我在客户端移动应用程序上)。

This is what i have:

这就是我所拥有的:

 file = "data:image/jpg;base64,#{imageData}"

imageData is the base64 string

imageData 是 base64 字符串

There is a way to transform this into a valid file?

有没有办法将其转换为有效文件?

回答by enhzflep

Disclaimer: Produces an invalid result (close, but invalid)

免责声明:产生无效结果(关闭,但无效)

I've done the reverse earlier last week - that is, load an image as binary data (to get around the requirement to run file from localhost).

上周早些时候我做了相反的事情 - 即,将图像作为二进制数据加载(以解决从本地主机运行文件的要求)。

In it, I:

其中,我:

  • loaded the file
  • base64 converted it
  • added a pre-amble to the base64 string
  • set the constructed string to be the src of an img element
  • 加载文件
  • base64 转换了它
  • 向 base64 字符串添加了前导码
  • 将构造的字符串设置为 img 元素的 src

This worked just fine. Upon reading your question, I tried to simply reverse the process. I was however, unsuccessfull somewhere. The data is extracted from the image correctly, then somewhere afterwards (I think in the call to atob that un-encodes it) the data is messed-up.

这工作得很好。阅读您的问题后,我试图简单地颠倒这个过程。然而,我在某处不成功。数据是从图像中正确提取的,然后在之后的某个地方(我认为在调用 atob 时对其进行了取消编码)数据被弄乱了。

The saved files are an unexpected size, have an added char before "%PNG" and have some missing data in the middle of the file. I'm rather perplexed at this point, to be honest.

保存的文件大小意外,在“%PNG”之前添加了一个字符,并且文件中间有一些丢失的数据。老实说,我在这一点上很困惑。

Anyhow, here's the code I've tried:

无论如何,这是我尝试过的代码:

1. Code to read a file and stuff the data into an element

1. 读取文件并将数据填充到元素中的代码

// fileVar is an object as returned by <input type='file'>
// imgElem is an <img> element - (doesn't need to be added to the DOM)
function loadImgFromFile(fileVar, imgElem)
{
    var fileReader = new FileReader();
    fileReader.onload = onFileLoaded;
    fileReader.readAsBinaryString(fileVar);
    function onFileLoaded(fileLoadedEvent)
    {
        var result,data;
        data = fileLoadedEvent.target.result;
        result = "data:";
        result += fileVar.type;
        result += ";base64,";
        result += btoa(data);
        imgElem.src = result;
    }
}

2. Attempt to grab data from an image/canvas and force the download of it using a programmer-supplied filename.

2. 尝试从图像/画布中获取数据并使用程序员提供的文件名强制下载它。

<!doctype html>
<html>
<head>
<script>
function byId(e){return document.getElementById(e)}
function newEl(tag){return document.createElement(tag)}
window.addEventListener('load', onPageLoaded, false);

function onPageLoaded(evt)
{
    var imgElem = byId('srcImg');
    imgElem.onload = function(){saveImgAsFile( byId('srcImg'), "myImage.png" );};

        // simple result of canvas.toDataURL() called on a 5x5 pixel image of a '+'
    imgElem.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHklEQVQIW2NkQID/QCYjiAsmoABFEMRBAThVYmgHAAhoBQWHhfyYAAAAAElFTkSuQmCC"; 

    // use the below line instead of the one above, if you wish to assign an actual image file, rather than the result of call to canvas.toDataURL()
    // the base64 string allows me to keep it all in the one file, also, to run if opened via a double-click, rather than having to run from localhost
//  imgElem.src = "img/1x1.png";
}

function saveImgAsFile(imgElem, fileName)
{
    // get a base64 encoded string from an image element
    var srcElem = imgElem;
    var dstCanvas = newEl('canvas');
    dstCanvas.width = srcElem.naturalWidth;
    dstCanvas.height = srcElem.naturalHeight;
    var ctx = dstCanvas.getContext('2d');
    ctx.drawImage(srcElem,0,0);
    var imgSrcStr = dstCanvas.toDataURL();

    // extract the image type
    var colonPos = imgSrcStr.indexOf(":");
    var semiColonPos = imgSrcStr.indexOf(";");
    var imgType = imgSrcStr.slice(colonPos+1, semiColonPos);
    console.log("image type: " + imgType);

    // extract the image data
    var commaPos = imgSrcStr.indexOf(',');
    var base64ImgString = imgSrcStr.slice(commaPos + 1);
    console.log("Data: " + base64ImgString);

    // holds the data that is actually written to disk for this image
    //** I think the error occurs during this step **//
    var unencodedImage = atob(base64ImgString);

    var imgFileAsBlob = new Blob( [unencodedImage], {type: imgType} );
    var fileNameToUse = fileName;

    var downloadLink = newEl('a');
    downloadLink.download = fileNameToUse;
    downloadLink.innerHTML = "Download File";
    if (window.webkitURL != null)
    {
        // Chrome allows the link to be clicked
        // without actually adding it to the DOM.
        downloadLink.href = window.webkitURL.createObjectURL(imgFileAsBlob);
    }
    else
    {
        // Firefox requires the link to be added to the DOM
        // before it can be clicked.
        downloadLink.href = window.URL.createObjectURL(imgFileAsBlob);
        downloadLink.onclick = destroyClickedElement;
        downloadLink.style.display = "none";
        document.body.appendChild(downloadLink);
    }
    downloadLink.click();
}

/*

function saveTextAsFile()
{
    var textToWrite = "This is just some random content";
    var textFileAsBlob = new Blob([textToWrite], {type:'text/plain'})
    var fileNameToSaveAs = "myFile.txt";

    var downloadLink = document.createElement("a");
    downloadLink.download = fileNameToSaveAs;
    downloadLink.innerHTML = "Download File";
    if (window.webkitURL != null)
    {
        // Chrome allows the link to be clicked
        // without actually adding it to the DOM.
        downloadLink.href = window.webkitURL.createObjectURL(textFileAsBlob);
    }
    else
    {
        // Firefox requires the link to be added to the DOM
        // before it can be clicked.
        downloadLink.href = window.URL.createObjectURL(textFileAsBlob);
        downloadLink.onclick = destroyClickedElement;
        downloadLink.style.display = "none";
        document.body.appendChild(downloadLink);
    }
    downloadLink.click();
}
*/
function destroyClickedElement(event)
{
    document.body.removeChild(event.target);
}
</script>
</head>
<body>
    <img id='srcImg'/>
</body>
</html>