canvas和base64

base64是二进制数据的一个编码格式,就像utf8一样的东西

他跟json一样,也是前后端交互能够相互识别的数据,他更多的是用来传递文件数据

在js里生成base64的API有两个,一个是FileReader,一个是画布canvas

FileReader

<input type="file" onchange="change(this.files[0])">
function change(file){
   var fr = new FileReader()
   fr.onload = function(e) {
      // 这个就是base64
      console.log( e.target.result );
   }
   // 这个方法传参是一个Blob类型的格式
   fr.readAsDataURL(file)
}

canvas
我们使用画布是为了获取画布上的内容
画布的输入是图片,然后对这个图片进行剪切,打水印什么的
画布上的内容的输出格式是base64

// 这个image就是输入
// 除了new,也可以直接取页面上的标签
var image = new Image();

image.onload = function () {
   var w = image.width;
   var h = image.height;
   var canvas = document.createElement('canvas');
   var ctx = canvas.getContext("2d");
   canvas.width = w;
   canvas.height = h;
   ctx.drawImage(image, 0, 0, w, h);
   // 可以在这里添加水印或者合并图片什么的
   ...
   // 把画布的内容转成base64,这个就是输出
   var base64 = canvas.toDataURL('image/jpeg');
   console.log(base64)
}
// 这个src可以是图片地址,也可以是上面fileReader的base64
image.src = "xxx.jpg";

如果画布想要压缩图片

// 压缩比例
var bili = 0.7;
var base64 = canvas.toDataURL('image/jpeg',bili);

画布的兼容
画布的api是非常不友好的

  1. 跨域问题(往下看有解决方案)
  2. ios系统的画布小得过分(所以有些需求要做网页版的ps的千万别接)
  3. 拍照还会旋转(往下看有解决方案)

关于画布跨域
张大神的跨域的解决方案

// 不管画布的输入,即图片的来源是new Image() 还是 document.querySelector()
// 如果图片是外链,产生了跨域,那画布会报错
// Uncaught DOMException: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.
// Tainted canvases 【被污染的画布】
// 解决方案是先让后端开启图片支持跨域CORS
// 然后在new Image() 或者 document.querySelector() 之后加上
img.crossOrigin=""

画布太小,不能获得base64
解决方案是不通过画布获得base64,可以通过请求图片地址,修改响应头获得blob 格式文件,然后让fileReader把blob转成base64,缺点是请求不允许跨域,上代码

function getBase64(imgUrl) {
   window.URL = window.URL || window.webkitURL;
   var xhr = new XMLHttpRequest();
   xhr.open("get", imgUrl, true);
   // 至关重要
   xhr.responseType = "blob";
   xhr.onload = function () {
    if (this.status == 200) {
         //得到一个blob对象
         var blob = this.response;
         console.log("blob", blob)
         //  至关重要
         let fr = new FileReader();
         fr.onloadend = function (e) {
          let base64 = e.target.result;
          console.log(base64)
         };
         fr.readAsDataURL(blob);
         var img = document.createElement("img");
         img.onload = function (e) {
          window.URL.revokeObjectURL(img.src); // 清除释放
         };
         let src = window.URL.createObjectURL(blob);
         console.log(src)
         img.src = src;
         document.getElementById("xxx").appendChild(img);
    }
  }
  xhr.send();
}
getBase64("xx.png")

关于blob
上面使用到了blob的知识
从input onchange中返回的图片对象其实就是一个File对象。
而Blob对象是一个用来包装二进制文件的容器,File继承于Blob。
FileReader是用来读取内存中的文件的API,支持File和Blob两种格式。

FileReader和URL.createObjectURL的区别
资料来自掘金网友

区别一

  • 通过FileReader.readAsDataURL(file)可以获取一段data:base64的字符串
  • 通过URL.createObjectURL(blob)可以获取当前文件的一个内存URL

区别二

  • createObjectURL是同步执行(立即的)
  • FileReader.readAsDataURL是异步执行(过一段时间)

区别三

  • createObjectURL返回一段带hash的url,并且一直存储在内存中,直到document触发了unload事件(例如:document close)或者执行revokeObjectURL来释放。
  • FileReader.readAsDataURL则返回包含很多字符的base64,并会比blob url消耗更多内存,但是在不用的时候会自动从内存中清除(通过垃圾回收机制)

区别三

  • createObjectURL支持从IE10往上的所有现代浏览器
  • FileReader.readAsDataURL同样支持从IE10往上的所有现代浏览器

拍照旋转的原因和解决方案
资料来自掘金网友

为什么从相机拍照获取的图片会旋转呢?
是因为从相机拍照获取的图片的EXIF(Exchangeable image file format)会默认设置一个orientation tag
目前只有jpeg格式的图片会有

解决方案有
用EXIF.js插件获取图片的orientation进行判断
简易版EXIF.js用DataViewAPI 代码来自stackoverflow

function getOrientation(file, callback) {
    var reader = new window.FileReader();
    reader.onload = function (e) {

        var view = new window.DataView(e.target.result);
        if (view.getUint16(0, false) != 0xFFD8) {
            return callback(-2);
        }
        var length = view.byteLength, offset = 2;
        while (offset < length) {
            var marker = view.getUint16(offset, false);
            offset += 2;
            if (marker == 0xFFE1) {
                if (view.getUint32(offset += 2, false) != 0x45786966) {
                    return callback(-1);
                }
                var little = view.getUint16(offset += 6, false) == 0x4949;
                offset += view.getUint32(offset + 4, little);
                var tags = view.getUint16(offset, little);
                offset += 2;
                for (var i = 0; i < tags; i++) {
                    if (view.getUint16(offset + (i * 12), little) == 0x0112) {
                        return callback(view.getUint16(offset + (i * 12) + 8, little));
                    }

                }
            } else if ((marker & 0xFF00) != 0xFF00) {
                break;
            } else {
                offset += view.getUint16(offset, false);
            }
        }
        return callback(-1);
    };
    reader.readAsArrayBuffer(file);
}

// 将图片旋转到正确的角度
function resetOrientation(srcBase64, srcOrientation, callback) {
    var img = new Image();
    img.onload = function() {
        var width = img.width,
            height = img.height,
            canvas = document.createElement('canvas'),
            ctx = canvas.getContext("2d");
        // set proper canvas dimensions before transform & export
        if ([5,6,7,8].indexOf(srcOrientation) > -1) {
            canvas.width = height;
            canvas.height = width;
        } else {
            canvas.width = width;
            canvas.height = height;
        }
        // transform context before drawing image
        // -2: not jpeg
        // -1: not defined
        switch (srcOrientation) {
            case 2: ctx.transform(-1, 0, 0, 1, width, 0); break;
            case 3: ctx.transform(-1, 0, 0, -1, width, height ); break;
            case 4: ctx.transform(1, 0, 0, -1, 0, height ); break;
            case 5: ctx.transform(0, 1, 1, 0, 0, 0); break;
            case 6: ctx.transform(0, 1, -1, 0, height , 0); break;
            case 7: ctx.transform(0, -1, -1, 0, height , width); break;
            case 8: ctx.transform(0, -1, 1, 0, 0, width); break;
            default: ctx.transform(1, 0, 0, 1, 0, 0);
        }
        // draw image
        ctx.drawImage(img, 0, 0);
        // export base64
        callback(canvas.toDataURL('image/jpeg'));
    };
    img.src = srcBase64;
};

然后用画布旋转正确后在生成正确的base64,问题是画布兼容性也很不友好啊

如果有关于手机画布的需要能不做尽量不做,pc端可以做一做,微信的相册自带的画布是手机端最好使的,微信把手机的兼容都大概搞定了,这也是为什么说再别人的平台上做网页好的地方,API众多,兼容性也很好,微信的代码查看《微信公众号》篇

原文地址:https://www.cnblogs.com/pengdt/p/12037986.html

时间: 2024-09-29 18:48:22

canvas和base64的相关文章

canvas图片base64编码后,ajax提交到后台

如题,直接上JS var imgData = canvas.toDataURL("image/png"); var data = imgData.substr(22); $.post('Gen', { 'data': data, 'remark': $('remark').val() } ,function(success) { $('#img1').src('data:image/jpeg;base64,' + success); } ); 后台C# string inputStr

Canvas 生成base64的PNG图片快照,So Amazing!!!

function canvasSupport(){     return Modernizr.canvas;}function callCanvasApps(){  var canvasOne=document.getElementById("canvasOne");  //if(!canvasSupport())      //return;  var context=canvasOne.getContext("2d");  context.fillStyle =

使用canvas给图片添加水印, canvas转换base64,,canvas,图片,base64等转换成二进制文档流的方法,并将合成的图片上传到服务器,

一,前端合成带水印的图片 一般来说,生成带水印的图片由后端生成,但不乏有时候需要前端来处理.当然,前端处理图片一般不建议,一方面js的处理图片的方法不全,二是有些老版本的浏览器对canvas的支持度不够. 下面我们就说说,利用canvas 生成带水印的图片. 1.我们要实现一下效果 2.创建一个canvas var canvas = document.createElement('canvas'); var time = new Date(); var logoCanvas =time+' '+

&lt;canvas合成海报&gt;所遇问题及解决方案总结

最近做了一个用canvas合成海报图片的移动端项目,由于一点canvas基础都没有,所以去网上搜了一位前辈的demo,但是开发过程中遇到了很多问题,现将所遇问题及解决方法总结如下: 1.移动端canvas项目适配全屏问题 问题描述:由于canvas的width和height只能设置px值,不支持rem单位,所以想在移动设备屏幕分辨率繁杂的情况下达到canvas铺满全屏的效果很困难. 解决方法:通过js获取到手机屏幕的clientWidth值,赋给canvas,以此来达到适配全屏的效果: var

ios系统 竖屏拍照 canvas处理后 图片旋转(利用exif.js解决ios手机上传竖拍照片旋转90度问题)

转:https://www.cnblogs.com/lovelgx/articles/8656615.html ---恢复内容开始--- 问题:html5+canvas进行移动端手机照片上传时,发现ios手机上传竖拍照片会逆时针旋转90度,横拍照片无此问题:Android手机没这个问题. 解决方法:利用exif.js解决ios手机上传竖拍照片旋转90度问题 因此解决这个问题的思路是:获取到照片拍摄的方向角,对非横拍的ios照片进行角度旋转修正. 利用exif.js读取照片的拍摄信息,详见 htt

html2canvas根据DOM元素样式实现网页截图

html2canvas根据DOM元素样式实现网页截图 html2canvas是一个相当不错的JavaScript类库,它使用了html5和css3的一些新功能特性,实现了在客户端对网页进行截图的功能.html2canvas通过获取页面的DOM和元素的样式信息,并将其渲染成canvas图片,从而实现给页面截图的功能. 它不需要来自服务器任何渲染,整张图片都是在客户端浏览器创建.当浏览器不支持Canvas时,将采用Flashcanvas或ExplorerCanvas技术代替实现.以下浏览器能够很好的

node.js(express)中使用Jcrop进行图片裁切上传

需求说明 简单来说就是要实现用户上传头像,并且要保存用户裁切后的部分作为用户头像. 第一步,选择图片: 第二步,在弹窗页面中展现并进行裁切: 第三步,点击"保存",上传服务器. 实现过程 说来有点坎坷,相当于做了2遍,走了弯路. 第1遍是用户一选择图片,就进行了上传,然后返回一个地址,所以在弹层上展现的图片已经是服务器上的图片了,然后进行裁切,再保存. 第2遍找到的一个方法,是在第1遍做到裁切处理时候想到的,即弹层展现的是用户机器上选择的图片,不用先上传,但是用image/base64

js剪切web网页成图片

<html>    <head>        <meta name="layout" content="main">        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />          <script type="text/javascript" s

vuejs开发组件分享之H5图片上传、压缩及拍照旋转的问题处理

一.前言 三年.net开发转前端已经四个月了,前端主要用webpack+vue,由于后端转过来的,前端不够系统,希望分享下开发心得与园友一起学习. 图片的上传之前都是用的插件(ajaxupload),或者传统上传图片的方式,各有利弊:插件的问题是依赖jq并且会使系统比较臃肿,还有传统的web开发模式 前后端偶尔在一起及对用户体验要求低,现在公司采用webpack+vue+restfullApi开发模式 前后端完全分离,遵从高内聚,低偶尔的原则,开发人员各司其职,一则提升开发效率(从长期来看,短期