问题描述:
我通过html5的canvas绘制了一个图像,然后用toDataURL("image/jpeg")将生成的数据提交到服务器端。因为提交过来其实是data URI地址,而且该地址分为两部分,中间用逗号分割,其中第一部分为“data:”+导出图像的MIME类型+“;base64”,第二部分为一个经过base64编码的字符串。我想通过Base64解码后将数据保存成图片,但是我的方法保存的图片无法查看,打开时显示“已经损坏”,求解答。
我的主要代码:
public class Base64 {
/**
* 对字符串进行Base64解码
* @param s 要解码的字符串
* @return 返回解码后的字符串
*/
public static String decode(String s){
String decoded_str=null;
BASE64Decoder decoder=new BASE64Decoder();
try {
byte[] bytes=decoder.decodeBuffer(s);
decoded_str=new String(bytes);
} catch (IOException e) {
e.printStackTrace();
}
return decoded_str;
}
}
/**
* 得到经过Base64解码的图像二进制数据
*/
public String getImgData(){
/*
* 利用canvas元素的toDataURL("image/jpeg")方法生成的图像地址格式为:
* 第一部分:data:image/jpeg;base64
* 中间一个逗号
* 第二部分:一个经过base64编码的字符串,通过Base64解码后即可得到该图像原始二进制数据
*/
String[] data=fileUrl.split(",");//这里fileUrl就是前台toDataURL()方法传过来的数据
return Base64.decode(data[1]);
}
/**
* 保存Base64解码后的二进制数据到文件
* @param base64Str 经Base64解码后的图片原始二进制数据
* @param path 文件路径
*/
public void saveImage(String base64Str,String path){
File file=new File(path);
FileOutputStream outputStream=null;
try {
outputStream=new FileOutputStream(file);
outputStream.write(base64Str.getBytes());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally{
closeSteam(outputStream);
}
}
/**
* 关闭文件输出流
* @param outputStream
*/
public void closeSteam(FileOutputStream outputStream){
if(outputStream!=null){
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
最后调用saveImage(getImgData(), imgPath);保存到图片文件。
解答(by 德问用户YODA):
首先你得搞明白为什么需要Base64这个东西,Base64的主要应用场景就是把二进制(Binary)的内容通过一个映射转换到可以用ASCII字符表达的字符串,然后便于使用HTTP协议在客户端和服务器端传输数据。所以,关键的一部你做的有些问题
byte[] bytes=decoder.decodeBuffer(s);
这里解码出来的byte[]已经是你的图片内容了,这些byte不可能再成功的构造成字符串了,否则为何还需要用Base64啊。所以,你需要保存的是解码出来的byte[],而不是Base64的字符串。
另外,Base64的编解码器,你用的那个BASE64Decoder是sun.misc提供的,为了确保最大化的兼容,比如运行在非Sun JVM的环境时,建议使用apache的common-codec。
解决:
修改Base64工具类的decode方法,并对其他调用方法进行相应修改。
修改后程序如下:
public class Base64 {
/**
* 对字符串进行Base64解码
* @param s 要解码的字符串
* @return 返回解码后的字符串
*/
public static byte[] decode(String s){
String decoded_str=null;
BASE64Decoder decoder=new BASE64Decoder();
byte[] bytes=null;
try {
bytes=decoder.decodeBuffer(s);
} catch (IOException e) {
e.printStackTrace();
}
return bytes;
}
}
/**
* 得到经过Base64解码的图像二进制数据
*/
public byte[] getImgData(){
/*
* 利用canvas元素的toDataURL("image/jpeg")方法生成的图像地址格式为:
* 第一部分:data:image/jpeg;base64
* 中间一个逗号
* 第二部分:一个经过base64编码的字符串,通过Base64解码后即可得到该图像原始二进制数据
*/
String[] data=fileUrl.split(",");//这里fileUrl就是前台toDataURL()方法传过来的数据
return Base64.decode(data[1]);
}
/**
* 保存Base64解码后的二进制数据到文件
* @param base64Str 经Base64解码后的图片原始二进制数据
* @param path 文件路径
*/
public void saveImage(byte[] imageBytes,String path){
File file=new File(path);
FileOutputStream outputStream=null;
try {
outputStream=new FileOutputStream(file);
outputStream.write(imageBytes);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally{
closeSteam(outputStream);
}
}
/**
* 关闭文件输出流
* @param outputStream
*/
public void closeSteam(FileOutputStream outputStream){
if(outputStream!=null){
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}