>

API缩放并上传图片完整示例,前端实现

- 编辑:至尊游戏网站 -

API缩放并上传图片完整示例,前端实现

前端达成 SVG 转 PNG

2015/11/16 · JavaScript · PNG, SVG

原稿出处跋山涉水的近义词 百度FEX - zhangbobell   

点评爬山涉水创造一个只管的客商分界面,并允许你决定图片的大小。上传到服务器端的多寡,并没有必要管理enctype为 multi-part/form-data 的状态,仅仅一个简便的POST表单管理程序就足以了. 好了,上边附上完整的代码示例

前言

svg 是大器晚成种矢量图形,在 web 上使用很普及,可是不菲时候是因为采用的面貌,平常必要将 svg 转为 png 格式,下载到本地等。随着浏览器对 HTML 5 的支撑度更加高,我们能够把 svg 转为 png 的办事付出浏览器来实现。

亲自过问地址跋山涉水的近义词Canvas Resize 德姆o
初藳作者爬山涉水Dr. 汤姆 Trenka
原来的文章日期爬山涉水 2011年九月6日
翻译日期爬山涉水 二零一三年十月8日

相近方法

  1. 创建 imageimage,src = xxx.svg;
  2. 始建 canvas,dragImage 将图片贴到 canvas 上;
  3. 行使 toDataUrl 函数,将 canvas 的表示为 url;
  4. new image, src = url, download = download.png;

唯独,在更改的时候有的时候不常会遇上如下的如下的多个难题跋山涉水的近义词

汤姆 Trenka 能为"小编"的博客写如日中天篇文章,对笔者来讲是三个了不起的荣幸。汤姆是Dojo框架的初期进献者之意气风发,也是自己在SitePen集团的君子之交.我见证了他最一流的天才才干,何况她连续几日第一个以前瞻性的应用方案预感了数不清困难的难题。他总是站在局外思索,改头换面但却又结实可相信地消除边缘难题。本文就是一个周全的例子。
近期自家接连被问道要成立三个客商接口API,允许顾客上传图片到服务器上(伴随其他的事情),并能在我们集团提供帮忙的雅量网址的顾客端上采用。平时来讲那都以相当的轻巧的职业——创制贰个form表单,增加多个file类型的input输入框,让客户从计算机里甄选图片,并在form标签上设置enctype="multipart/form-data"表单属性,然后上传就能够。特别简单,不是吗?事实上,这里有三个丰富轻巧的例子;点击踏入
然则如火如荼旦您想要通过有个别形式开始时期管理一下图形再上传,那该如何是好?举例说,你不得不先削减图片尺寸,或许需求图片只可以是有个别类别的格式,如 png 大概jpg,你咋做?
用canvas来解决!

主题素材 1 爬山涉水浏览器对 canvas 节制

Canvas 的 W3C 的科班上并未有聊起 canvas 的最大高/宽度和面积,不过各类厂家的浏览器出于浏览器品质的思虑,在不相同的阳台上安装了最大的高/宽度恐怕是渲染面积,超过了这一个阈值渲染的结果会是空白。测量检验了二种浏览器的 canvas 品质如下跋山涉水的近义词

  • chrome (版本 46.0.2490.80 (64-bit))
    • 最大规模爬山涉水268, 435, 456 px^2 = 16, 384 px * 16, 384 px
    • 最大宽/高:32, 767 px
  • firefox (版本 42.0)
    • 最大规模:32, 767 px * 16, 384 px
    • 最大宽/高:32, 767px
  • safari (版本 9.0.1 (11601.2.7.2))
    • 最大范围爬山涉水 268, 435, 456 px^2 = 16, 384 px * 16, 384 px
  • ie 10(版本 10.0.9200.17414)
    • 最大宽/高: 8, 192px * 8, 192px

在近似的 web 应用中,或许少之又少会超过这么些节制。可是,如若当先了那么些限定,则 会导致导出为空白或许出于内部存款和储蓄器走漏导致浏览器崩溃。

并且从另一面来讲, 导出 png 也是如日方升项很费用内部存款和储蓄器的操作,粗略估量一下,导出 16, 384 px * 16, 384 px 的 svg 会消耗 16384 * 16384 * 4 / 1024 / 1024 = 1024 M 的内部存款和储蓄器。所以,在周围这么些极限值的时候,浏览器也会 反应变慢,能或不能导出成功也跟系统的可用内部存款和储蓄器大小等等皆有涉嫌。

对此那几个主题材料,犹如下三种缓解措施:

  1. 将数据发送给后端,在后端达成 转变;
  2. 前端将 svg 切分成多少个图片导出;

首先种办法能够应用 PhantomJS、inkscape、ImageMagick 等工具,绝对来讲比较轻松,这里大家任重(英文名爬山涉水rèn zhòng)而道远探求第三种缓慢解决格局。

Canvas简介
canvas 是四个HTML5新扩大的DOM成分,允许顾客在页面上直接地绘制图形,经常是使用JavaScript.而分歧的格式标准也是莫衷一是的,比方SVG是光栅API(raster API) 而VML却是向量API(vector API).能够思考选择Adobe Illustrator(矢量图)作图与使用 Adobe Photoshop (光栅图)作图的分别。

svg 切分成八个图片导出

思路爬山涉水浏览器尽管对 canvas 有尺寸和面积的界定,然则对于 image 成分并不曾分明性的限定,也正是第一步生成的 image 其实展现是正规的,大家要做的只是在其次步 dragImage 的时候分数十二回将 image 成分切分并贴到 canvas 上然后下载下来。 同期,应留心到 image 的载入是一个异步的进度。

最首要代码

JavaScript

// 构造 svg Url,此处省略将 svg 经字符过滤后转为 url 的经过。 var svgUrl = DomUEnclaveL.createObjectU中华VL(blob); var svgWidth = document.querySelector('#kity_svg').getAttribute('width'); var svgHeight = document.querySelector('#kity_svg').getAttribute('height'); // 分片的宽度和中度,可依靠浏览器做适配 var w0 = 8192; var h0 = 8192; // 每行和每列能包容的分片数 var M = Math.ceil(svgWidth / w0); var N = Math.ceil(svgHeight / h0); var idx = 0; loadImage(svgUrl).then(function(img) { while(idx < M * N) { // 要分开的面片在 image 上的坐标和尺寸 var targetX = idx % M * w0, targetY = idx / M * h0, targetW = (idx + 1) % M ? w0 : (svgWidth - (M - 1) * w0), targetH = idx >= (N - 1) * M ? (svgHeight - (N - 1) * h0) : h0; var canvas = document.createElement('canvas'), ctx = canvas.getContext('2d'); canvas.width = targetW; canvas.height = targetH; ctx.drawImage(img, targetX, targetY, targetW, targetH, 0, 0, targetW, targetH); console.log('now it is ' + idx); // 绸缪在前面三个下载 var a = document.createElement('a'); a.download = 'naotu-' + idx + '.png'; a.href = canvas.toDataU景逸SUVL('image/png'); var click伊夫nt = new Mouse伊夫nt('click', { 'view': window, 'bubbles': true, 'cancelable': false }); a.dispatchEvent(click伊夫nt); idx++; } }, function(err) { console.log(err); }); // 加载 image function loadImage(url) { return new Promise(function(resolve, reject) { var image = new Image(); image.src = url; image.crossOrigin = 'Anonymous'; image.onload = function() { resolve(this); }; image.onerror = function(err) { reject(err); }; }); }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
// 构造 svg Url,此处省略将 svg 经字符过滤后转为 url 的过程。
var svgUrl = DomURL.createObjectURL(blob);
var svgWidth = document.querySelector('#kity_svg').getAttribute('width');
var svgHeight = document.querySelector('#kity_svg').getAttribute('height');
 
// 分片的宽度和高度,可根据浏览器做适配
var w0 = 8192;
var h0 = 8192;
 
// 每行和每列能容纳的分片数
var M = Math.ceil(svgWidth / w0);
var N = Math.ceil(svgHeight / h0);
 
var idx = 0;
loadImage(svgUrl).then(function(img) {
 
    while(idx < M * N) {
        // 要分割的面片在 image 上的坐标和尺寸
        var targetX = idx % M * w0,
            targetY = idx / M * h0,
            targetW = (idx + 1) % M ? w0 : (svgWidth - (M - 1) * w0),
            targetH = idx >= (N - 1) * M ? (svgHeight - (N - 1) * h0) : h0;
 
        var canvas = document.createElement('canvas'),
            ctx = canvas.getContext('2d');
 
            canvas.width = targetW;
            canvas.height = targetH;
 
            ctx.drawImage(img, targetX, targetY, targetW, targetH, 0, 0, targetW, targetH);
 
            console.log('now it is ' + idx);
 
            // 准备在前端下载
            var a = document.createElement('a');
            a.download = 'naotu-' + idx + '.png';
            a.href = canvas.toDataURL('image/png');
 
            var clickEvent = new MouseEvent('click', {
                'view': window,
                'bubbles': true,
                'cancelable': false
            });
 
            a.dispatchEvent(clickEvent);
 
        idx++;
    }
 
}, function(err) {
    console.log(err);
});
 
// 加载 image
function loadImage(url) {
    return new Promise(function(resolve, reject) {
        var image = new Image();
 
        image.src = url;
        image.crossOrigin = 'Anonymous';
        image.onload = function() {
            resolve(this);
        };
 
        image.onerror = function(err) {
            reject(err);
        };
    });
}

说明:

  1. 出于在前端下载有浏览器宽容性、客商体验等难点,在事实上中,也许须求将调换后的数目发送到后端,并作为二个减去包下载。
  2. 分片的尺码这里运用的是 8192 * 9192,在实际上中,为了加强包容性和心得,能够依靠浏览器和平台做适配,比如在 iOS 下的 safari 的最大范围是 4096 *4096。

在canvas(画布)上能做的事务正是读取和渲染图像,况且同意你通过JavaScript操纵图像数据。已经有过多留存的篇章来为您演示基本的图像管理——首要关心与种种分裂的图像过滤技艺( image filtering techniques)——但大家必要的然则是缩放图片并调换成特定的文件格式,而canvas完全能够做到那些事情。

主题素材 2 爬山涉水导出富含图表的 svg

在导出的时候,还恐怕会遇上另三个主题材料跋山涉水的近义词假设 svg 里面含有图表,你会开采经过以上办法导出的 png 里面,原本的图纸是不出示的。日常认为是 svg 里面包涵的图样跨域了,不过即使您把这么些图形换开支域的图片,仍旧会产出这种气象。图片 1

图片中上局部是导出前的 svg,下图是导出后的 png。svg 中的图片是本域的,在导出后不展现。

我们假设的须求,比方图像高度不超越100像素,不管原始图像有多高。基本的代码如下所示:

难点源于

大家依照作品最早步建议的步子,稳步逐个审查,会发掘在第一步的时候,svg 中的图片就不出示了。也正是,当 image 元素的 src 为二个 svg,并且 svg 里面含有图表,那么被含有的图片是不会来得的,纵然那些图片是本域的。

W3C 关于这几个题目并不曾 做表达,最终在  找到了有关那么些难点的认证。 意思是跋山涉水的近义词制止这么做是由于安全着想,svg 里面引用的保有 表面财富 满含image, stylesheet, script 等都会被堵住。

内部还举了四个例子爬山涉水即使未有这么些范围,倘若贰个论坛允许顾客上传那样的 svg 作为头像,就有非常的大或者出现那样的现象,一人红客上传 svg 作为头像,里面包蕴代码爬山涉水<image xlink:href="http://evilhacker.com/myimage.png">(假若那位骇客具备对于 evil骇客.com 的调节权),那么那位骇客就全盘能不负众望上边包车型客车业务爬山涉水

  • 设若有人查看他的资料,evil骇客.com 就能够选用到三次 ping 的乞请(进而能够得到查看者的 ip);
  • 能够成功对于差别的 ip 地址的人出示不平等的头像;
  • 能够每一日调换头像的外观(而不用经过论坛管理员的稽核)。

阅览此间,大概就理解了整整难点的全进程了,当然还可能有少数原因只怕是制止图像递归。

代码如下:

化解办法

思路爬山涉水由于安全因素,其实首先步的时候,图片已经显得不出来了。那么我们以往虚构的法门是在首先步之后遍历 svg 的布局,将持有的 image 成分的 url、地方和尺寸保存下来。在第三步之后,按梯次贴到 canvas 上。那样,最终导出的 png 图片就能够有 svg 里面包车型大巴 image。最首要代码

JavaScript

// 此处略去变通 svg url 的历程 var svgUrl = DomU猎豹CS6L.createObjectU昂CoraL(blob); var svgWidth = document.querySelector('#kity_svg').getAttribute('width'); var svgHeight = document.querySelector('#kity_svg').getAttribute('height'); var embededImages = document.querySelectorAll('#kity_svg image'); // 由 nodeList 转为 array embededImages = Array.prototype.slice.call(embededImages); // 加载底层的图 loadImage(svgUrl).then(function(img) { var canvas = document.createElement('canvas'), ctx = canvas.getContext("2d"); canvas.width = svgWidth; canvas.height = svgHeight; ctx.drawImage(img, 0, 0); // 遍历 svg 里面有着的 image 成分embededImages.reduce(function(sequence, svgImg){ return sequence.then(function() { var url = svgImg.getAttribute('xlink:href') + 'abc', dX = svgImg.getAttribute('x'), dY = svgImg.getAttribute('y'), dWidth = svgImg.getAttribute('width'), dHeight = svgImg.getAttribute('height'); return loadImage(url).then(function( sImg) { ctx.drawImage(sImg, 0, 0, sImg.width, sImg.height, dX, dY, dWidth, dHeight); }, function(err) { console.log(err); }); }, function(err) { console.log(err); }); }, Promise.resolve()).then(function() { // 打算在前端下载 var a = document.createElement("a"); a.download = 'download.png'; a.href = canvas.toDataUCRUISERL("image/png"); var clickEvent = new Mouse伊芙nt("click", { "view": window, "bubbles": true, "cancelable": false }); a.dispatch伊夫nt(clickEvent); }); }, function(err) { console.log(err); }) // 省略了 loadImage 函数 // 代码和率先个例子相通

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
// 此处略去生成 svg url 的过程
var svgUrl = DomURL.createObjectURL(blob);
var svgWidth = document.querySelector('#kity_svg').getAttribute('width');
var svgHeight = document.querySelector('#kity_svg').getAttribute('height');
 
var embededImages = document.querySelectorAll('#kity_svg image');
// 由 nodeList 转为 array
embededImages = Array.prototype.slice.call(embededImages);
// 加载底层的图
loadImage(svgUrl).then(function(img) {
 
var canvas = document.createElement('canvas'),
ctx = canvas.getContext("2d");
 
canvas.width = svgWidth;
canvas.height = svgHeight;
 
ctx.drawImage(img, 0, 0);
    // 遍历 svg 里面所有的 image 元素
    embededImages.reduce(function(sequence, svgImg){
 
        return sequence.then(function() {
            var url = svgImg.getAttribute('xlink:href') + 'abc',
                dX = svgImg.getAttribute('x'),
                dY = svgImg.getAttribute('y'),
                dWidth = svgImg.getAttribute('width'),
                dHeight = svgImg.getAttribute('height');
 
            return loadImage(url).then(function( sImg) {
                ctx.drawImage(sImg, 0, 0, sImg.width, sImg.height, dX, dY, dWidth, dHeight);
            }, function(err) {
                console.log(err);
            });
        }, function(err) {
            console.log(err);
        });
    }, Promise.resolve()).then(function() {
        // 准备在前端下载
        var a = document.createElement("a");
        a.download = 'download.png';
        a.href = canvas.toDataURL("image/png");
 
        var clickEvent = new MouseEvent("click", {
            "view": window,
            "bubbles": true,
            "cancelable": false
        });
 
        a.dispatchEvent(clickEvent);
 
        });
 
      }, function(err) {
        console.log(err);
   })
 
   // 省略了 loadImage 函数
   // 代码和第一个例子相同

说明

  1. 事例中 svg 里面的图疑似根节点下边的,由此用于表示地方的 x, y 直接取来就可以使用,在事实上中,这几个地方可能须要跟别的品质做一些运算之后得出。假使是基于 svg 库营造的,那么能够直接使用Curry面用于固定的函数,比平素从最底层运算尤其惠及和纯粹。
  2. 大家这里探究的是本域的图样的导出难点,跨域的图片由于「污染了」画布,在施行 toDataUrl 函数的时候会报错。

// 参数,最大高度
var MAX_HEIGHT = 100;
// 渲染
function render(src){
// 成立二个 Image 对象
var image = new Image();
// 绑定 load 事件管理器,加载成功后进行
image.onload = function(){
// 获取 canvas DOM 对象
var canvas = document.getElementById("myCanvas");
// 要是高度超过标准
if(image.height > MAX_HEIGHT) {
// 宽度等比例缩放 *=
image.width *= MAX_HEIGHT / image.height;
image.height = MAX_HEIGHT;
}
// 获取 canvas的 2d 遭遇目的,
// 能够知晓Context是管理员,canvas是房子
var ctx = canvas.getContext("2d");
// canvas清屏
ctx.clearRect(0, 0, canvas.width, canvas.height);
// 重置canvas宽高
canvas.width = image.width;
canvas.height = image.height;
// 将图像绘制到canvas上
ctx.drawImage(image, 0, 0, image.width, image.height);
// !!! 注意,image 没有加入到 dom之中
};
// 设置src属性,浏览器会自行加载。
// 记住必需先绑定事件,技艺安装src属性,不然会出壹只难题。
image.src = src;
};

结语

在那和大家享受了 在前端将 svg 转为 png 的办法和进度中或许会遇见的五个难题,二个是浏览器对 canvas 的尺寸节制,另一个是导出图片的主题素材。当然,那多少个难点还也可以有别的的消除办法,相同的时间鉴于文化所限,本文内容难免有漏洞,招待大家议论指正。最终多谢@techird 和 @Naxior 关于那七个难题的座谈。

1 赞 2 收藏 评论

图片 2

在地方的例证中,你可以接收canvas 的 toDataU凯雷德L() 方法赢得图像的 Base64编码的值(能够临近通晓为16进制字符串,恐怕二进制数据流).
瞩目跋山涉水的近义词 canvas 的 toDataU瑞鹰L() 获取的UXC90L以字符串开首,有贰10个空头的数据 "data:image/png;base64,",须求在顾客端依旧服务端举行过滤.
条件上生气勃勃经浏览器帮衬,UEscortL地址的长短是平昔不范围的,而1024的尺寸限定,是老一代IE所只有的。

试问,如何收获我们需求的图像呢?
好孩子,很欢畅你能这么问。你并无法因此File 输入框来直接管理,你从那么些文件输入框成分所能获取的只有是客户所筛选文件的path路径。遵照正规想象,你能够透过那个path路线音信来加载图像,不过,在浏览器里面那是不现实的。(译者注:浏览器商家必得确定保障自个儿的浏览器相对安全,才具获得市集,最少幸免媒体的大张伐罪,假设同意那样做,那恶意网址能够由此拼凑文件路线来品尝获得有个别敏感新闻).
为了贯彻这一个供给,大家得以选用HTML5的File API 来读取顾客磁盘上的公文,并用这么些file来作为图像的源(src,source).

File API简介
新的File API接口是在不违反任何安全沙盒准则下,读取和列出客户文件目录的一个路线—— 通过沙盒(sandbox)限定,恶意网址并无法将病毒写入客商磁盘,当然更不能够推行。
大家要接纳的文本读取对象叫做 FileReader,FileReader允许开采者读取文件的内容(具体浏览器的贯彻格局或许大不相通)。

假定我们已经得到了图像文件的path路线,那么重视前边的代码,使用FileReader来加载和渲染图像就变得超级轻松了跋山涉水的近义词

代码如下:

// 加载 图像文件(url路径)
function loadImage(src){
// 过滤掉 非 image 类型的文书
if(!src.type.match(/image.*/)){
if(window.console){
console.log("选取的文件类型不是图表: ", src.type);
} else {
window.confirm("只好接受图片文件");
}
return;
}
// 创造 FileReader 对象 并调用 render 函数来产生渲染.
var reader = new FileReader();
// 绑定load事件自动回调函数
reader.onload = function(e){
// 调用前面包车型大巴 render 函数
render(e.target.result);
};
// 读取文件内容
reader.readAsDataURL(src);
};

借问,怎样获取文件呢?
小白兔,要有耐烦!大家的下一步正是获取文件,当然有那多少个方式能够兑现啦。举例跋山涉水的近义词你可以用文本框让顾客输入文件路线,但很扎眼大超级多顾客都不是开辟者,对输入什么值根本就不停解.
为了顾客使用方便,大家使用 Drag and Drop API接口。

使用 Drag and Drop API
拖拽接口(Drag and Drop)特别轻易——在大部分的DOM元素上,你都足以经过绑定事件处理器来兑现. 只要客户从磁盘上拖动二个文书到dom对象上并扩充鼠标,那我们就可以读取这一个文件。代码如下跋山涉水的近义词

代码如下:

function init(){
// 获取DOM成分对象
var target = document.getElementById("drop-target");
// 阻止 dragover(拖到DOM成分上方) 事件传递
target.addEventListener("dragover", function(e){e.preventDefault();}, true);
// 拖动并推广鼠标的风浪
target.addEventListener("drop", function(e){
// 阻止暗许事件,以至事件传播
e.preventDefault();
// 调用前边的加载图像 函数,参数为dataTransfer对象的首先个文本
loadImage(e.dataTransfer.files[0]);
}, true);
var setheight = document.getElementById("setheight");
var maxheight = document.getElementById("maxheight");
setheight.addEventListener("click", function(e){
//
var value = maxheight.value;
if(/^d+$/.test(value)){
MAX_HEIGHT = parseInt(value);
}
e.preventDefault();
},true);
var btnsend = document.getElementById("btnsend");
btnsend.addEventListener("click", function(e){
//
sendImage();
},true);
};

我们还足以做一些别样的拍卖,举个例子展现预览图。但若是不想减小图片的话,那很恐怕没什么用。我们将应用Ajax通过HTTP 的post方式上传图片数据。上面包车型客车事例是利用Dojo框架来成功央求的,当然你也得以利用任何的Ajax才能来完结.
Dojo 代码如下:

代码如下:

// 译者并不懂Dojo,所以将要背后附上jQuery的落到实处
// Remember that DTK 1.7+ is AMD!
require(["dojo/request"], function(request){
// 设置恳求ULacrosseL,参数,以致回调。
request.post("image-handler.php", {
data: {
imageName: "myImage.png",
imageData: encodeURIComponent(document.getElementById("canvas").toDataURL("image/png"))
}
}).then(function(text){
console.log("The server returned: ", text);
});
});

jQuery 实现如下跋山涉水的近义词

代码如下:

// 上传图片,jQuery版
function sendImage(){
// 获取 canvas DOM 对象
var canvas = document.getElementById("myCanvas");
// 获取Base64编码后的图像数据,格式是字符串
// "data:image/png;base64,"开端,必要在顾客端如故服务器端将其去掉,前面包车型地铁片段能够直接写入文件。
var dataurl = canvas.toDataURL("image/png");
// 为安全 对U揽胜极光I进行编码
// data%3Aimage%2Fpng%3Bbase64%2C 开头
var imagedata = encodeURIComponent(dataurl);
//var url = $("#form").attr("action");
// 1. 借使form表单不好管理,可以选取有些hidden掩没域来安装央求地址
// <input type="hidden" name="action" value="receive.jsp" />
var url = $("input[name='action']").val();
// 2. 也得以一直用某些dom对象的习性来博取
// <input id="imageaction" type="hidden" action="receive.jsp">
// var url = $("#imageaction").attr("action");
// 因为是string,所以服务器须求对数据开展转码,写文件操作等。
// 个人约定,全数http参数名字全体大写
console.log(dataurl);
//console.log(imagedata);
var data = {
imagename: "myImage.png",
imagedata: imagedata
};
jQuery.ajax( {
url : url,
data : data,
type : "POST",
// 期望的归来值类型
dataType: "json",
complete : function(xhr,result) {
//console.log(xhr.responseText);
var $tip2 = $("#tip2");
if(!xhr){
$tip2.text('网络连接退步!');
return false;
}
var text = xhr.responseText;
if(!text){
$tip2.text('网络错误!');
return false;
}
var json = eval("("+text+")");
if(!json){
$tip2.text('分析错误!');
return false;
} else {
$tip2.text(json.message);
}
//console.dir(json);
//console.log(xhr.responseText);
}
});
};

OK,消除!你还索要做的,正是成立一个只管的客户分界面,并允许你决定图片的大小。上传到服务器端的数量,并无需管理enctype为 multi-part/form-data 的景况,仅仅多少个粗略的POST表单处理程序就足以了.
好了,上边附上完整的代码示例爬山涉水

代码如下:

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE html>
<html>
<head>
<title>通过Canvas及File API缩放并上传图片</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="Canvas,File,Image">
<meta http-equiv="description" content="2013年8月8日,[email protected]">
<script src=";
<script>
// 参数,最大中度
var MAX_HEIGHT = 100;
// 渲染
function render(src){
// 创制叁个 Image 对象
var image = new Image();
// 绑定 load 事件管理器,加载成功后进行
image.onload = function(){
// 获取 canvas DOM 对象
var canvas = document.getElementById("myCanvas");
// 要是中度超标
if(image.height > MAX_HEIGHT) {
// 宽度等比例缩放 *=
image.width *= MAX_HEIGHT / image.height;
image.height = MAX_HEIGHT;
}
// 获取 canvas的 2d 情状目的,
// 能够精通Context是组织者,canvas是房子
var ctx = canvas.getContext("2d");
// canvas清屏
ctx.clearRect(0, 0, canvas.width, canvas.height);
// 重置canvas宽高
canvas.width = image.width;
canvas.height = image.height;
// 将图像绘制到canvas上
ctx.drawImage(image, 0, 0, image.width, image.height);
// !!! 注意,image 未有参与到 dom之中
};
// 设置src属性,浏览器会自行加载。
// 记住必需先绑定事件,才干设置src属性,不然会出一块难题。
image.src = src;
};
// 加载 图像文件(url路线)
function loadImage(src){
// 过滤掉 非 image 类型的文件
if(!src.type.match(/image.*/)){
if(window.console){
console.log("采纳的文件类型不是图片: ", src.type);
} else {
window.confirm("只可以选用图片文件");
}
return;
}
// 创建 FileReader 对象 并调用 render 函数来成功渲染.
var reader = new FileReader();
// 绑定load事件自动回调函数
reader.onload = function(e){
// 调用前边的 render 函数
render(e.target.result);
};
// 读取文件内容
reader.readAsDataURL(src);
};
// 上传图片,jQuery版
function sendImage(){
// 获取 canvas DOM 对象
var canvas = document.getElementById("myCanvas");
// 获取Base64编码后的图像数据,格式是字符串
// "data:image/png;base64,"开头,须要在客商端恐怕服务器端将其去掉,后边的有个别能够平素写入文件。
var dataurl = canvas.toDataURL("image/png");
// 为安全 对U哈弗I举行编码
// data%3Aimage%2Fpng%3Bbase64%2C 开头
var imagedata = encodeURIComponent(dataurl);
//var url = $("#form").attr("action");
// 1. 只要form表单倒霉管理,能够接纳某些hidden隐蔽域来安装要求地址
// <input type="hidden" name="action" value="receive.jsp" />
var url = $("input[name='action']").val();
// 2. 也能够平素用有些dom对象的天性来获得
// <input id="imageaction" type="hidden" action="receive.jsp">
// var url = $("#imageaction").attr("action");
// 因为是string,所以服务器需求对数据开展转码,写文件操作等。
// 个人约定,全体http参数名字全体大写
console.log(dataurl);
//console.log(imagedata);
var data = {
imagename: "myImage.png",
imagedata: imagedata
};
jQuery.ajax( {
url : url,
data : data,
type : "POST",
// 期望的回来值类型
dataType: "json",
complete : function(xhr,result) {
//console.log(xhr.responseText);
var $tip2 = $("#tip2");
if(!xhr){
$tip2.text('网络连接战败!');
return false;
}
var text = xhr.responseText;
if(!text){
$tip2.text('互连网错误!');
return false;
}
var json = eval("("+text+")");
if(!json){
$tip2.text('剖析错误!');
return false;
} else {
$tip2.text(json.message);
}
//console.dir(json);
//console.log(xhr.responseText);
}
});
};
function init(){
// 获取DOM元素对象
var target = document.getElementById("drop-target");
// 阻止 dragover(拖到DOM成分上方) 事件传递
target.addEventListener("dragover", function(e){e.preventDefault();}, true);
// 拖动并加大鼠标的平地风波
target.addEventListener("drop", function(e){
// 阻止私下认可事件,以至事件传播
e.preventDefault();
// 调用前面包车型客车加载图像 函数,参数为dataTransfer对象的率先个公文
loadImage(e.dataTransfer.files[0]);
}, true);
var setheight = document.getElementById("setheight");
var maxheight = document.getElementById("maxheight");
setheight.addEventListener("click", function(e){
//
var value = maxheight.value;
if(/^d+$/.test(value)){
MAX_HEIGHT = parseInt(value);
}
e.preventDefault();
},true);
var btnsend = document.getElementById("btnsend");
btnsend.addEventListener("click", function(e){
//
sendImage();
},true);
};
window.addEventListener("DOMContentLoaded", function() {
//
init();
},false);
</script>
</head>
<body>
<div>
<h1>通过Canvas及File API缩放并上传图片</h1>
<p>从文件夹拖动一张相片到俗世的盒子里, canvas 和 JavaScript将会活动的张开缩放.</p>
<div>
<input type="text" id="maxheight" value="100"/>
<button id="setheight">设置图片最大中度</button>
<input type="hidden" name="action" value="receive.jsp" />
</div>
<div id="preview-row">
<div id="drop-target" style="width:400px;height:200px;min-height:100px;min-width:200px;background:#eee;cursor:pointer;">拖动图片文件到那边...</div>
<div>
<div>
<button id="btnsend"> 上 传 </button> <span id="tip2" style="padding:8px 0;color:#f00;"></span>
</div>
</div>
<div><h4>缩略图:</h4></div>
<div id="preview" style="background:#f4f4f4;width:400px;height:200px;min-height:100px;min-width:200px;">
<canvas id="myCanvas"></canvas>
</div>
</div>
</div>
</body>
</html>

服务端页面,receive.jsp

代码如下:

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@page import="sun.misc.BASE64Decoder"%>
<%@page import="java.io.*"%>
<%@page import="org.springframework.web.util.UriComponents"%>
<%@page import="java.net.URLDecoder"%>
<%!
// 本文件:/receive.jsp
// 图片贮存路线
String photoPath = "D:/blog/upload/photo/";
File photoPathFile = new File(photoPath);
// references:
private boolean saveImageToDisk(byte[] data,String imageName) throws IOException{
int len = data.length;
//
// 写入到文件
FileOutputStream outputStream = new FileOutputStream(new File(photoPathFile,imageName));
outputStream.write(data);
outputStream.flush();
outputStream.close();
//
return true;
}
private byte[] decode(String imageData) throws IOException{
BASE64Decoder decoder = new BASE64Decoder();
byte[] data = decoder.decodeBuffer(imageData);
for(int i=0;i<data.length;++i)
{
if(data[i]<0)
{
//调度特别数据
data[i]+=256;
}
}
//
return data;
}
%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<%
//若是是IE,那么须要安装为text/html,否则会弹框下载
//response.setContentType("text/html;charset=UTF-8");
response.setContentType("application/json;charset=UTF-8");
//
String imageName = request.getParameter("imagename");
String imageData = request.getParameter("imagedata");
int success = 0;
String message = "";
if(null == imageData || imageData.length() < 100){
// 数据太短,分明不客观
message = "上传退步,数据太短或空头支票";
} else {
// 去除开端不创立的数量
imageData = imageData.substring(30);
imageData = URLDecoder.decode(imageData,"UTF-8");
//System.out.println(imageData);
byte[] data = decode(imageData);
int len = data.length;
int len2 = imageData.length();
if(null == imageName || imageName.length() < 1){
imageName = System.currentTimeMillis()+".png";
}
saveImageToDisk(data,imageName);
//
success = 1;
message = "上传成功,参数长度:"+len2+"字符,解析文件大小:"+len+"字节";
}
// 后台打印
System.out.println("message="+message);
%>
{
"message": "<%=message %>",
"success": <%=success %>
}

本文由门户名站发布,转载请注明来源:API缩放并上传图片完整示例,前端实现