本人使用过以下几种方式(jfinal+light7):
一、页面
这里的div之前是image,由于图片显示会被拉伸,所以换成了背景图来实现;class='fileopa'这个是让input的作用域扩大至image范围;
<div class="thumbavatar border" id="my_personal_titleimg" >
<!-- <form name="uploadForm" id="uploadForm" enctype="multipart/form-data" action="/muser/imageUpload" method="post"> -->
<input id="my_personal_file_id" class="fileopa" name="my_personal_file" type="file" accept="image/*" capture="camera" />
<!-- </form> -->
</div>
二、js
1、通过jq的ajaxFileUpload上传
$.ajaxFileUpload({
url:'/muser/imageUpload',
type: "POST",
async : false,
secureuri:false,
fileElementId:'my_personal_file_id',
dataType: 'JSON',//返回数据的类型
success: function (data) {
//把图片替换
var obj = $.parseJSON($(data).text());
if(obj.resultcode=="10000"){
var url=obj.path;
$('#my_personal_titleimg').attr("src",imgPath+url); //个人中心头像
location.href="/muser/personal";
}else{
$.alert(obj.message);
}
},
error: function (data, status, e) {
$.hideIndicator();
$.alert("头像上传失败!");
}
});
2、通过jq的ajaxsubmit上传
$("#uploadForm").ajaxSubmit({
dataType: 'json',
success:function(result,status){
if(result.success){
var url=result.path;
$('#my_personal_titleimg').attr("src",imgPath+url); //个人中心头像
//location.href="/muser/personal";
$.hideIndicator();
}else{
$.alert(result.message);
}
},
error: function(result,status,e){
$.hideIndicator();
$.alert("头像上传失败!");
}
});
以上的两种方式在本地测试时没问题的,但发现放在微信公众号上图片大小被限制上传。后面找资料发现了将文件base64再上传的方案。
3、通过js中的FileReader读取本地文件
var img = document.getElementById("my_personal_file_id");
var imgFile = new FileReader();
imgFile.readAsDataURL(img.files[0]);
imgFile.onload = function (e) {
var imgData = e.target.result; //base64数据
//$('#my_personal_titleimg').attr("src",imgData); //个人中心头像
var submitData={base64_string:imgData};
console.log(submitData);
$.ajax({
type: "POST",
url: "/muser/imageUpload",
data: submitData,
dataType:"json",
success: function(data){
//var obj = $.parseJSON($(data).text());
if(data.resultcode=="10000"){
var url=data.path;
$('#my_personal_titleimg').attr("src",imgPath+url); //个人中心头像
location.href="/muser/personal";
}else{
$.alert(data.message);
}
},
error:function(XMLHttpRequest, textStatus, errorThrown){ //上传失败
$.alert("头像上传失败!");
}
});
但这个方法有浏览器的兼容性问题,尤其是放在微信公众号里。
4、通过localResizeIMG插件来实现
$('#my_personal_file_id').localResizeIMG({
width: 400,
quality: 1,
success: function (result) {
var submitData={
base64_string:result.base64 //rst.base64 clearBase64
};
$.ajax({
type: "POST",
url: "/muser/imageUpload",
data: submitData,
dataType:"json",
success: function(data){
//var obj = $.parseJSON($(data).text());
if(data.resultcode=="10000"){
var url=data.path;
$('#my_personal_titleimg').attr("src",imgPath+url); //个人中心头像
location.href="/muser/personal";
}else{
$.alert(data.message);
}
},
complete :function(XMLHttpRequest, textStatus){
},
error:function(XMLHttpRequest, textStatus, errorThrown){ //上传失败
// alert(XMLHttpRequest.status);
// alert(XMLHttpRequest.readyState);
// alert(textStatus);
}
});
}
});
第三种和第四种都是上传base64再通过后台解码来实现图片文件上传的,目前最后一种在微信公众号里没什么问题。
三、后台
前两种就是传流保存再做其它压缩等操作即可,后两种就是需要将base64解码保存再做其它压缩等操作(当然还有业务逻辑)。这里面遇到过几个莫名其妙的问题和大家分享下:
1、在有base64串生成图片文件的时候发现图片生成有问题,后来发现服务器端接收的字符串会把“+”替换成空格,加号(+)是BASE64编码的一部分。处理办法是:把空格替换成“+”,然后解码。
2、iphone手机会把拍照的图片旋转,这个需要exif来处理。有一点metadata-extractor-2.9.1.jar这个jar包低版本的不行,好像要2.8以上。还有就是无法获取base64中的图片方向信息(这个问题还没解决)。
贴下我后台代码吧:
1、controller
public void imageUpload()
{
JSONObject result = new JSONObject();// 返回json
if (isLogin())
{
try
{
String sourcePath = ImageUtil.getPath(".jpg");
String targetPath = ImageUtil.getPath(".jpg");// 获取要存放的目标图片路径
String staticPath = String.valueOf(PropertiesPlugin.getParamMapValue(DictKeys.statics_res_path)).replace("\\","/");
String targetPathTemp = targetPath.replace(staticPath, "");// 获取返回给页面图片的路径
// 获得一个图片文件流,我这里是从flex中传过来的
String imgdata = getPara("base64_string").split(",")[1];
imgdata = imgdata.replace(" ", "+");
ImageUtil.generateImage(imgdata,sourcePath);
ImageUtil.resizeFix(sourcePath, targetPath, 400, 400);// 压缩图片并保存至目标图片路径
User user = getCUser();
UserInfo userInfo = new UserInfo();
userInfo.set("ids", user.getStr("userinfoids"));
userInfo.set("titleimg", targetPathTemp);
UserService.service.updateUserInfo(userInfo, user.getStr("ids"), getRequest());// 更新头像
ImageUtil.delete(sourcePath); // 删除原始图片
result.put("path", targetPathTemp);
returnResult(result, AppResult.common_success, "上传成功");
}
catch (Exception e)
{
returnResult(result, AppResult.common_fail, "上传失败,请重新上传");
renderJson(result);
}
}
else
{
returnResult(result, AppResult.common_fail, "未登录,请先登录");
}
renderJson(result);
}
2、ImageUtil
public static void generateImage(String imgStr, String imgFilePath) throws IOException, ImageProcessingException
{
BASE64Decoder decoder = new BASE64Decoder();
OutputStream out = null;
byte[] bytesTemp = null;
try
{
byte[] bytes = decoder.decodeBuffer(imgStr);// Base64解码
for (int i = 0; i < bytes.length; ++i)
{
if (bytes[i] < 0)
{
bytes[i] += 256;// 调整异常数据
}
}
InputStream is = new ByteArrayInputStream(bytes);
Metadata metadata = ImageMetadataReader.readMetadata(is);
Directory exif = metadata.getFirstDirectoryOfType(ExifSubIFDDirectory.class);
if (exif != null)
{
String type = exif.getString(40961);// 由于方向变量找不到,就随便弄个,相当于安卓不旋转,ios旋转
if (StringUtils.isNotBlank(type))
{
switch (Integer.parseInt(type))
{
case 2://要进行180度旋转
bytesTemp = rotateImage(bytes , 180.0 , "jpg");
break;
case 1://要进行90度旋转
bytesTemp = rotateImage(bytes , 90.0 , "jpg");
break;
case 3://要进行-90度旋转
bytesTemp = rotateImage(bytes , -90.0 , "jpg");
break;
default:
bytesTemp = bytes;
}
}
else
{
bytesTemp = bytes;
}
}
else
{
bytesTemp = bytes;
}
makeDirs(imgFilePath);
out = new FileOutputStream(new File(imgFilePath));
out.write(bytesTemp);
}
finally
{
if(out != null)
{
out.close();
}
}
}
public static byte[] rotateImage(byte[] bytes , double angle , String format) throws IOException
{
ByteArrayOutputStream baos = null;
try
{
InputStream input = new ByteArrayInputStream(bytes);
BufferedImage oldImage = ImageIO.read(input);
int width = oldImage.getWidth();
int height = oldImage.getHeight();
double[][] newPositions = new double[4][];
newPositions[0] = calculatePosition(0, 0, angle);
newPositions[1] = calculatePosition(width, 0, angle);
newPositions[2] = calculatePosition(0, height, angle);
newPositions[3] = calculatePosition(width, height, angle);
double minX = Math.min(Math.min(newPositions[0][0], newPositions[1][0]),Math.min(newPositions[2][0], newPositions[3][0]));
double maxX = Math.max(Math.max(newPositions[0][0], newPositions[1][0]),Math.max(newPositions[2][0], newPositions[3][0]));
double minY = Math.min(Math.min(newPositions[0][1], newPositions[1][1]),Math.min(newPositions[2][1], newPositions[3][1]));
double maxY = Math.max(Math.max(newPositions[0][1], newPositions[1][1]),Math.max(newPositions[2][1], newPositions[3][1]));
int newWidth = (int)Math.round(maxX - minX);
int newHeight = (int)Math.round(maxY - minY);
BufferedImage newImage = new BufferedImage(newWidth, newHeight , BufferedImage.TYPE_INT_BGR);
Graphics2D g = newImage.createGraphics();
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
double w = newWidth / 2.0;
double h = newHeight / 2.0;
g.rotate(Math.toRadians(angle), w, h);
int centerX = (int)Math.round((newWidth - width) / 2.0);
int centerY = (int)Math.round((newHeight - height) / 2.0);
g.drawImage(oldImage, centerX, centerY, null);
g.dispose();
baos = new ByteArrayOutputStream();
ImageIO.write(newImage, format, baos);// 利用ImageIO类的write方法,将BufferedImage以png图片的数据模式写入流。
return baos.toByteArray();
}
finally
{
if(baos != null)
{
baos.close();
}
}
}
private static double[] calculatePosition(double x, double y, double angle)
{
angle = Math.toRadians(angle);
double nx = (Math.cos(angle) * x) - (Math.sin(angle) * y);
double ny = (Math.sin(angle) * x) + (Math.cos(angle) * y);
return new double[] {nx, ny};
}
public static void resize(String sourcePath, String targetPath, int width, int height) throws IOException
{
FileOutputStream out = null;
try
{
Image img = ImageIO.read(new File(sourcePath));// Image对象
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);// 生成缩略图片
image.getGraphics().drawImage(img, 0, 0, width, height, null);// 绘制缩小后的图
out = new FileOutputStream(new File(targetPath));// 输出到文件流
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
encoder.encode(image);
}
finally
{
if(out != null)
{
out.close();
}
}
}
public static void resizeFix(String sourcePath, String targetPath, int width, int height) throws IOException
{
File file = new File(sourcePath);// 读入文件
Image img = ImageIO.read(file);// 构造Image对象
int imgWidth = img.getWidth(null);// 得到源图宽
int imgHeight = img.getHeight(null);// 得到源图长
if (imgWidth / imgHeight > width / height)
{
resizeByWidth(sourcePath, targetPath, width);
}
else
{
resizeByHeight(sourcePath, targetPath, height);
}
}
public static void resizeByWidth(String sourcePath, String targetPath, int width) throws IOException
{
File file = new File(sourcePath);// 读入文件
Image img = ImageIO.read(file);// 构造Image对象
int imgWidth = img.getWidth(null);// 得到源图宽
int imgHeight = img.getHeight(null);// 得到源图长
int height = (int) (imgHeight * width / imgWidth);
resize(sourcePath, targetPath, width, height);
}
public static void resizeByHeight(String sourcePath, String targetPath, int height) throws IOException
{
File file = new File(sourcePath);// 读入文件
Image img = ImageIO.read(file);// 构造Image对象
int imgWidth = img.getWidth(null);// 得到源图宽
int imgHeight = img.getHeight(null);// 得到源图长
int width = (int) (imgWidth * height / imgHeight);
resize(sourcePath, targetPath, width, height);
}