在Javascript中将base64转换为文件

8
目标是将base64字符串转换为可发送的jpg文件,无法使用html输入类型文件,但必须以相同格式提供。我在文件生成方面有一些困惑(我在客户端移动应用程序上)。以下是我拥有的内容:
 file = "data:image/jpg;base64,#{imageData}"

imageData是base64编码字符串。

有一种方法可以将其转换为有效的文件吗?


你的问题的第一句和最后一句不同(jpg vs html file)。也许你应该考虑编辑你的问题,使其不再含糊。话虽如此,我过去在使用Chrome时曾经使用过fileWriter对象。(不知道其他浏览器现在是否支持它)http://www.html5rocks.com/en/tutorials/file/filesystem/ - enhzflep
编辑过了,我认为不再含糊。我之前已经阅读过那篇文章,但是我还没有找到将字符串转换为文件实例的方法。感谢您的回复。 - Imnl
1个回答

3

免责声明:产生了一个无效结果(接近但无效)

上周我做了相反的事情,即将图像作为二进制数据加载(以规避在本地主机上运行文件的要求)。

在此过程中,我:

  • 加载了文件
  • 对其进行了base64转换
  • 向base64字符串添加了前导信息
  • 将构造的字符串设置为img元素的src

这个方法完全可行。读完你的问题后,我尝试简单地反向这个过程。然而,在某个地方我失败了。确实正确地从图像中提取了数据,但在之后的某个地方(我认为是在调用atob解码时)数据被破坏了。

保存的文件大小不符合预期,在“%PNG”前面添加了一个额外的字符,并且文件中间缺少一些数据。说实话,我感到非常困惑。

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

1. 读取文件并将数据放入一个element中的代码

// 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;
    }
}

尝试从图像/画布中获取数据,并使用程序员提供的文件名强制下载它。
<!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>

非常感谢您的回复,我已经尝试过了,正如您所说,问题出在atob函数上,它无法正确地转换base64。 - Imnl

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接