如何使用JavaScript将图像转换为Base64字符串?

733

我需要将我的图片转换为Base64字符串,以便将图片发送到服务器。

是否有适用于此的JavaScript文件?否则,我该如何进行转换?


5
你的形象来源是哪里? - TJHeuvel
6
以下是翻译的内容:如何在 JavaScript 中获取图像数据?我正在尝试从一个图像中获取像素数据,以便通过 Canvas 对其进行处理。有没有一种方法可以在 JavaScript 中获取图像的像素数据?谢谢! - duri
1
JS和jQ:https://dev59.com/questions/T2Mm5IYBdhLWcg3wT9qU - Roko C. Buljan
https://idkblogs.com/js/31/Convert-image-file-into-base64-in-javascript - Shubham Verma
21个回答

1184

您可以选择多种方法:

1. 方法:FileReader

通过XMLHttpRequest将图像作为Blob加载,并使用FileReader API (readAsDataURL())将其转换为dataURL

function toDataURL(url, callback) {
  var xhr = new XMLHttpRequest();
  xhr.onload = function() {
    var reader = new FileReader();
    reader.onloadend = function() {
      callback(reader.result);
    }
    reader.readAsDataURL(xhr.response);
  };
  xhr.open('GET', url);
  xhr.responseType = 'blob';
  xhr.send();
}

toDataURL('https://www.gravatar.com/avatar/d50c83cc0c6523b4d3f6085295c953e0', function(dataUrl) {
  console.log('RESULT:', dataUrl)
})

这个代码示例也可以使用 WHATWG fetch API 实现:

const toDataURL = url => fetch(url)
  .then(response => response.blob())
  .then(blob => new Promise((resolve, reject) => {
    const reader = new FileReader()
    reader.onloadend = () => resolve(reader.result)
    reader.onerror = reject
    reader.readAsDataURL(blob)
  }))


toDataURL('https://www.gravatar.com/avatar/d50c83cc0c6523b4d3f6085295c953e0')
  .then(dataUrl => {
    console.log('RESULT:', dataUrl)
  })

这些方法:

  • 具有更好的压缩效果
  • 也适用于其他文件类型

浏览器支持:

提示:要转换本地文件,您可以使用live-server。一旦在包含要转换的图片的文件夹上启动它,在浏览器中打开url并使用开发者控制台即可将图像转换为base64。


2. 方法:Canvas (适用于旧版浏览器)

将图像加载到Image对象中,将其绘制到一个不受污染的画布上,然后将画布转换回dataURL。

function toDataURL(src, callback, outputFormat) {
  var img = new Image();
  img.crossOrigin = 'Anonymous';
  img.onload = function() {
    var canvas = document.createElement('CANVAS');
    var ctx = canvas.getContext('2d');
    var dataURL;
    canvas.height = this.naturalHeight;
    canvas.width = this.naturalWidth;
    ctx.drawImage(this, 0, 0);
    dataURL = canvas.toDataURL(outputFormat);
    callback(dataURL);
  };
  img.src = src;
  if (img.complete || img.complete === undefined) {
    img.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";
    img.src = src;
  }
}

toDataURL(
  'https://www.gravatar.com/avatar/d50c83cc0c6523b4d3f6085295c953e0',
  function(dataUrl) {
    console.log('RESULT:', dataUrl)
  }
)

详见

支持的输入格式:

image/pngimage/jpegimage/jpgimage/gifimage/bmpimage/tiffimage/x-iconimage/svg+xmlimage/webpimage/xxx

支持的输出格式:

image/pngimage/jpegimage/webp(chrome)

浏览器支持:


方法三:从本地文件系统读取图片

若想要转换来自用户文件系统的图片,则需要采用不同的方法。使用FileReader API

function encodeImageFileAsURL(element) {
  var file = element.files[0];
  var reader = new FileReader();
  reader.onloadend = function() {
    console.log('RESULT', reader.result)
  }
  reader.readAsDataURL(file);
}
<input type="file" onchange="encodeImageFileAsURL(this)" />


80
我在 Chrome 上无法使用:来自 **** 站点的图片因为跨域资源共享政策被阻止加载:请求的资源没有设置 'Access-Control-Allow-Origin' 头信息。因此,来源为 'http://fiddle.jshell.net' 的站点被禁止访问。 - DickieBoy
7
以防万一其他人遇到同样的问题,这个例程在返回的字符串中包含了 "data:image/jpg;base64," 头部,因此您不需要将其附加。 - Chris Rae
2
警告2:某些东西会干扰内容。在某个地方,数据有可能被损坏/更改(尽管可能不是很严重),至少在我使用Firefox 35浏览器查看某些图像时会发生这种情况,与PHP在同一图像上创建的base64不同。 - hanshenrik
2
是的,没错。由于我们实际上是将图像绘制到画布元素(https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/drawImage),然后将其转换为数据URL(https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toDataURL),因此可能会丢失一些数据。 - HaNdTriX
3
方法:FileReader(2)比方法Canvas更快,已在大型照片上进行测试。希望对某些人有所帮助。 - Max
显示剩余32条评论

231
你可以使用HTML5 <canvas>来实现:
创建一个画布,将你的图像加载到其中,然后使用 toDataURL() 方法获取Base64表示的图像(实际上是一个data: URL,但它包含了Base64编码的图像)。

3
toDataURL方法是否像xhr一样可以控制诸如done/fail/always之类的回调函数? - Jeroen Ooms
我们能否将2个或更多的画布提取为单个PNG文件? - techie_28
18
这种方法在CORS违规的情况下会失败。除此之外,这个解决方案应该能回答这个问题。 - Revanth Kumar
2
我们都知道将二进制转换为base64会占用更多的数据,但是如果不使用reader.readAsDataURL,使用canvas来获取base64可能会增加更多的数据,因为在使用toDataURL时,您可能还会失去所有图像压缩。除非您希望每个图像都被转换为特定格式。当您使用canvas时,您也会失去所有元数据,例如:EXIF、旋转、相机、地理位置等。 - Endless
指示不清楚。尝试复制粘贴此答案,得到“您:找不到函数”的错误提示。 - lmat - Reinstate Monica
显示剩余2条评论

101

这段代码可以将你的字符串、图片甚至视频文件转换成Base64编码的字符串数据。

<input id="inputFileToLoad" type="file" onchange="encodeImageFileAsURL();" />
<div id="imgTest"></div>
<script type='text/javascript'>
  function encodeImageFileAsURL() {

    var filesSelected = document.getElementById("inputFileToLoad").files;
    if (filesSelected.length > 0) {
      var fileToLoad = filesSelected[0];

      var fileReader = new FileReader();

      fileReader.onload = function(fileLoadedEvent) {
        var srcData = fileLoadedEvent.target.result; // <--- data: base64

        var newImage = document.createElement('img');
        newImage.src = srcData;

        document.getElementById("imgTest").innerHTML = newImage.outerHTML;
        alert("Converted Base64 version is " + document.getElementById("imgTest").innerHTML);
        console.log("Converted Base64 version is " + document.getElementById("imgTest").innerHTML);
      }
      fileReader.readAsDataURL(fileToLoad);
    }
  }
</script>


5
这不仅非常棒,而且可以绕过跨域来源问题!使用它,您可以允许用户提供自己的图像或来自URL的图像(因为Windows会自行获取它),将它们绘制在画布上,并在能够使用.toDataURL()等方法的同时处理它们。 非常感谢! - ElDoRado1239
你好,如何将此应用于从远程URL加载的图像而不会遇到跨域问题?谢谢。 - guthik
有时候在Chrome 78.0.3904.97中可以工作,但其他时候会导致选项卡崩溃。 - Dshiz

51

基本上,如果您的图像是

<img id='Img1' src='someurl'>

然后您可以像这样进行转换:

var c = document.createElement('canvas');
var img = document.getElementById('Img1');
c.height = img.naturalHeight;
c.width = img.naturalWidth;
var ctx = c.getContext('2d');

ctx.drawImage(img, 0, 0, c.width, c.height);
var base64String = c.toDataURL();

9
很遗憾,这只适用于本地图像,如果您尝试使用远程图像(从网络上选择一个),则会在(Firefox)控制台中写入“SecurityError:The operation is insecure”。 - user2677034
3
它可能适用于其他图像,但取决于该站点的CORS设置,并且必须指定为 <img id='Img1' src='someurl' crossorigin='anonymous'> - Mike
在Firefox上,您可以暂时禁用该安全功能。前往“about:config”并将属性“privacy.file_unique_origin”更改为false。 - Manuel Romeiro

27

这是我所做的:

// Author James Harrington 2014
function base64(file, callback){
  var coolFile = {};
  function readerOnload(e){
    var base64 = btoa(e.target.result);
    coolFile.base64 = base64;
    callback(coolFile)
  };

  var reader = new FileReader();
  reader.onload = readerOnload;

  var file = file[0].files[0];
  coolFile.filetype = file.type;
  coolFile.size = file.size;
  coolFile.filename = file.name;
  reader.readAsBinaryString(file);
}

这是使用它的方法

base64( $('input[type="file"]'), function(data){
  console.log(data.base64)
})

8
btoa是一种编码方法,可将ASCII字符编码为Base64格式。 - Alexander Mills
7
为什么JavaScript中的atob和btoa这样命名?JavaScript中的atob()函数用于将ASCII编码的字符串转换为二进制数据,而btoa()函数则将二进制数据编码为ASCII字符串。它们的名称来自于“ASCII to binary”和“binary to ASCII”的缩写,即a对应ASCII,b对应Binary。这些函数最初是在Netscape Navigator 2上引入的,这也是最早支持JavaScript的浏览器之一。 - James Harrington

25

我发现最安全可靠的方法是使用FileReader()

示例:图像转Base64

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
  </head>
  <body>
    <input id="myinput" type="file" onchange="encode();" />
    <div id="dummy">
    </div>
    <div>
      <textarea style="width:100%;height:500px;" id="txt">
      </textarea>
    </div>
    <script>
      function encode() {
        var selectedfile = document.getElementById("myinput").files;
        if (selectedfile.length > 0) {
          var imageFile = selectedfile[0];
          var fileReader = new FileReader();
          fileReader.onload = function(fileLoadedEvent) {
            var srcData = fileLoadedEvent.target.result;
            var newImage = document.createElement('img');
            newImage.src = srcData;
            document.getElementById("dummy").innerHTML = newImage.outerHTML;
            document.getElementById("txt").value = document.getElementById("dummy").innerHTML;
          }
          fileReader.readAsDataURL(imageFile);
        }
      }
    </script>
  </body>
</html>

更新 - 为@AnniekJ请求添加注释的相同代码:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
  </head>
  <body>
    <input id="myinput" type="file" onchange="encode();" />
    <div id="dummy">
    </div>
    <div>
      <textarea style="width:100%;height:500px;" id="txt">
      </textarea>
    </div>
    <script>
      function encode() {
        // Get the file objects that was selected by the user from myinput - a file picker control
        var selectedfile = document.getElementById("myinput").files;
        // Check that the user actually selected file/s from the "file picker" control
        // Note - selectedfile is an array, hence we check it`s length, when length of the array
        // is bigger than 0 than it means the array containes file objects
        if (selectedfile.length > 0) {
          // Set the first file object inside the array to this variable
          // Note: if multiple files are selected we can itterate on all of the selectedfile array  using a for loop - BUT in order to not make this example complicated we only take the first file object that was selected
          var imageFile = selectedfile[0];
          // Set a filereader object to asynchronously read the contents of files (or raw data buffers) stored on the            user's computer, using File or Blob objects to specify the file or data to read. 
          var fileReader = new FileReader();
          // We declare an event of the fileReader class (onload event) and we register an anonimous function that will be executed when the event is raised. it is "trick" we preapare in order for the onload event to be raised after the last line of this code will be executed (fileReader.readAsDataURL(imageFile);) - please read about events in javascript if you are not familiar with "Events" 
          fileReader.onload = function(fileLoadedEvent) {
            // AT THIS STAGE THE EVENT WAS RAISED
            // Here we are getting the file contents - basiccaly the base64 mapping
            var srcData = fileLoadedEvent.target.result;
            // We create an image html element dinamically in order to display the image
            var newImage = document.createElement('img');
            // We set the source of the image we created
            newImage.src = srcData;
            // ANOTHER TRICK TO EXTRACT THE BASE64 STRING
            // We set the outer html of the new image to the div element
            document.getElementById("dummy").innerHTML = newImage.outerHTML;
            // Then we take the inner html of the div and we have the base64 string
            document.getElementById("txt").value = document.getElementById("dummy").innerHTML;
          }
          // This line will raise the fileReader.onload event - note we are passing the file object here as an argument to the function of the event  
          fileReader.readAsDataURL(imageFile);
        }
      }
    </script>
  </body>
</html>

嗨,我正在寻找一种将Powerpoint AddIn中的图像转换为base64的方法(否则我无法将它们添加到幻灯片中),并找到了您的回复。您能否向我解释一下您在这里做什么?我对此还不是很了解,所以我不太明白整个FileReader。只是为了提供一些背景:我有一个名为selectedImages的字符串,其中包含.png文件,并且我想将它们转换为base64文件,然后能够将它们添加到Powerpoint幻灯片中。 - AnniekJ
@AnniekJ 请查看我的更新答案,每行代码上方都有注释。 - Jonathan Applebaum

11
如果您有一个文件对象,这个简单的函数将会起作用:
function getBase64 (file, callback) {

    const reader = new FileReader();

    reader.addEventListener('load', () => callback(reader.result));

    reader.readAsDataURL(file);
}

使用示例:

getBase64(fileObjectFromInput, function(base64Data){
    console.log("Base64 of file is", base64Data); // Here you can have your code which uses Base64 for its operation, // file to Base64 by oneshubh
});

如果我将reader.result作为请求体发送到WebAPI,那么在API端是否能够使用byte[]类型来消费它? - CredibleAshok
尝试使用reader.readAsArrayBuffer(file),它会给你一个字节数组。如果您正在使用Java,则可以在那里将base64转换为字节数组,请参考以下示例:https://dev59.com/aVgQ5IYBdhLWcg3w-o1w - Shubham

9

我最终使用了一个返回Promisefunction

const getImg64 = async() => {
  const convertImgToBase64URL = (url) => {
  console.log(url)
    return new Promise((resolve, reject) => {
      const img = new Image();
      img.crossOrigin = 'Anonymous';
      img.onload = () => {
          let canvas = document.createElement('CANVAS')
          const ctx = canvas.getContext('2d')
          canvas.height = img.height;
          canvas.width = img.width;
          ctx.drawImage(img, 0, 0);
          const dataURL = canvas.toDataURL();
          canvas = null;
          resolve(dataURL)
      }
      img.src = url;
    })
  }
  //for the demonstration purposes I used proxy server to avoid cross origin error
  const proxyUrl = 'https://cors-anywhere.herokuapp.com/'
  const image = await convertImgToBase64URL(proxyUrl+'https://image.shutterstock.com/image-vector/vector-line-icon-hello-wave-260nw-1521867944.jpg')
  console.log(image)
}
getImg64()


你可以在任何异步函数中使用这种方法。然后,你只需要await转换后的图像并继续执行指令。


我有一个类似的解决方案,它有效了,谢谢! - SalahAdDin

8

这里是使用JavaScript Promise的方法。

const getBase64 = (file) => new Promise(function (resolve, reject) {
    let reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onload = () => resolve(reader.result)
    reader.onerror = (error) => reject('Error: ', error);
})


现在,在事件处理程序中使用它。
const _changeImg = (e) => {
        const file = e.target.files[0];
        let encoded;
        getBase64(file)
          .then((result) => {
            encoded = result;
           })
          .catch(e => console.log(e))
    }

2
如果您只想更改预览图像,请使用URL.createObjectURL(file) - Endless

8
uploadProfile(e) {

    let file = e.target.files[0];
    let reader = new FileReader();

    reader.onloadend = function() {
        console.log('RESULT', reader.result)
    }
    reader.readAsDataURL(file);
}

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