在android开发中上传图片(头像)到服务器,压缩图片,直接用对应的API,获取原图的长宽,然后取得压缩比例,compress到指定的质量,输出保存就行了,下文介绍。今天因为web活动页广告中需要上传图片,如果太大直接上传,用户体验和服务器压力,简直不能直视。so,一起学习下前端压缩图片的方式吧。
1,实现原理
compress jpeg or png files using angularjs on client side - using HTML5 Canvas & File API (based off of a J-I-C project on github).
本案例可以在github上面找到,我fork了:
https://github.com/duqian291902259/ng-image-compress。
选择一张图片,用FileReader读取,然后计算图片的宽和高,确定缩放比例,在canvas上面drawImage,最后用toDataURL获得压缩后的图片。
2,web HTML页面
<div>
<input id="inputImage" type="file" accept="image/*" image="image1" resize-max-height="1000" resize-max-width="1000" resize-quality="0.7" resize-type="image/jpg" />
<img ng-src="{{image1.compressed.dataURL}}" /> <!-- just do a console.log of {{image1}} to see what other options are in the file object -->
</div>
<!--<script src="http://apps.bdimg.com/libs/angular.js/1.2.16/angular.min.js"></script>-->
<script src="scripts/angular.min.js"></script>
<script src="scripts/app.js"></script>
<script src="scripts/ng-image-compress.js"></script>
3,angular.min.js
angularJs,你懂得,很火的前端框架,适合移动端web页面,可以去官网下载,也可以这下载,不是最新,凑合着用吧:
http://apps.bdimg.com/libs/angular.js/1.2.16/angular.min.js
4,app.js
可以拿到app变量,方便在在其他文件中定义controller directive。
'use strict';
var app = angular.module('angNewsApp', []);
5,ng-image-compress.js
页面中没有canvas,就创建canvas控件,并将其隐藏。
'use strict';
app.directive('image', ['$q',
function($q) {
var URL = window.URL || window.webkitURL;
var getResizeArea = function() {
var resizeAreaId = 'fileupload-resize-area';
var resizeArea = document.getElementById(resizeAreaId);
if (!resizeArea) {
resizeArea = document.createElement('canvas');
resizeArea.id = resizeAreaId;
resizeArea.style.visibility = 'hidden';
document.body.appendChild(resizeArea);
}
return resizeArea;
};
/**
* 接收JPG OR PNG图片,返回压缩图片对象
* @param {Image} sourceImgObj 原图
* @param {Integer} quality 输出图片的质量,最高100
* @return {Image} result_image_obj 压缩后的图片
*/
var jicCompress = function(sourceImgObj, options) {
var outputFormat = options.resizeType;
var quality = options.resizeQuality * 100 || 70;
var mimeType = 'image/jpeg';
if (outputFormat !== undefined && outputFormat === 'png') {
mimeType = 'image/png';
}
var maxHeight = options.resizeMaxHeight || 300;
var maxWidth = options.resizeMaxWidth || 250;
var height = sourceImgObj.height;
var width = sourceImgObj.width;
// 计算宽高,限制压缩后的最大尺寸
if (width > height) {
if (width > maxWidth) {
height = Math.round(height *= maxWidth / width);
width = maxWidth;
}
}
else {
if (height > maxHeight) {
width = Math.round(width *= maxHeight / height);
height = maxHeight;
}
}
//画布绘制图片
var cvs = document.createElement('canvas');
cvs.width = width; //sourceImgObj.naturalWidth;
cvs.height = height; //sourceImgObj.naturalHeight;
var ctx = cvs.getContext('2d').drawImage(sourceImgObj, 0, 0, width, height);
var newImageData = cvs.toDataURL(mimeType, quality / 100);
var resultImageObj = new Image();
resultImageObj.src = newImageData;
return resultImageObj.src;
};
var resizeImage = function(origImage, options) {
var maxHeight = options.resizeMaxHeight || 300;
var maxWidth = options.resizeMaxWidth || 250;
var quality = options.resizeQuality || 0.7;
var type = options.resizeType || 'image/jpg';
var canvas = getResizeArea();
var height = origImage.height;
var width = origImage.width;
if (width > height) {
if (width > maxWidth) {
height = Math.round(height *= maxWidth / width);
width = maxWidth;
}
}
else {
if (height > maxHeight) {
width = Math.round(width *= maxHeight / height);
height = maxHeight;
}
}
//画布的宽高与指定的相同
canvas.width = width;
canvas.height = height;
//canvas上绘制图片
var ctx = canvas.getContext('2d');
ctx.drawImage(origImage, 0, 0, width, height);
// 获取指定格式和质量的图片数据
return canvas.toDataURL(type, quality);
};
var createImage = function(url, callback) {
var image = new Image();
image.onload = function() {
callback(image);
};
image.src = url;
};
var fileToDataURL = function(file) {
var deferred = $q.defer();
var reader = new FileReader();
reader.onload = function(e) {
deferred.resolve(e.target.result);
};
reader.readAsDataURL(file);
return deferred.promise;
};
return {
restrict: 'A',
scope: {
image: '=',
resizeMaxHeight: '@?',
resizeMaxWidth: '@?',
resizeQuality: '@?',
resizeType: '@?'
},
link: function postLink(scope, element, attrs) {
var doResizing = function(imageResult, callback) {
createImage(imageResult.url, function(image) {
//var dataURL = resizeImage(image, scope);
var dataURLcompressed = jicCompress(image, scope);
// imageResult.resized = {
// dataURL: dataURL,
// type: dataURL.match(/:(.+\/.+);/)[1]
// };
imageResult.compressed = {
dataURL: dataURLcompressed,
type: dataURLcompressed.match(/:(.+\/.+);/)[1]
};
callback(imageResult);
});
};
var applyScope = function(imageResult) {
scope.$apply(function() {
console.log(imageResult);
if (attrs.multiple) {
scope.image.push(imageResult);
}
else {
scope.image = imageResult;
}
});
};
element.bind('change', function(evt) {
//选中文件后,如果有多个文件,则遍历取出
if (attrs.multiple)
{scope.image = [];}
var files = evt.target.files;
for (var i = 0; i < files.length; i++) {
//create a result object for each file in files
var imageResult = {
file: files[i],
url: URL.createObjectURL(files[i])
};
fileToDataURL(files[i]).then(function(dataURL) {
console.log(dataURL)
imageResult.dataURL = dataURL;
});
if (scope.resizeMaxHeight || scope.resizeMaxWidth) { //resize image
doResizing(imageResult, function(imageResult) {
applyScope(imageResult);
});
}
else { //no resizing
applyScope(imageResult);
}
}
});
}
};
}
]);
6,总结
之前做了一年多的web前端。现在的前端技术,越来越6666了。js是不能写压缩图片的功能的,只能用HTML5的canvas,有一定的兼容性。足见HTML5的强大,此文,我只是分享的搬运工,拿去研究吧。
Dusan,291902259,OpenDeveloper。