Base64与图片
文章目录
前言
由于平时开发中接触图片的业务,非常少,所以对于图片的处理非常少。
这段时间是因为小程序项目,例如小程序上传图片,以及验证码识别。
- 关于图片转换为Base64的问题-2020.08.16
其实有种方式,就是将验证码保存在本地,再进行业务处理:
先将图片下载到本地->业务逻辑->删除图片
这样做,非常消耗服务器的存储空间以及将会增加许多逻辑
之后,通过资料,也发现许多第三方API都支持转成Base64类型的图片
才发现,原来处理图片可以这么处理——将图片转换为Base4
而且,也看到了一篇博客,即是小程序多图片上传的实现,如下:
其中的解决方案,即是将图片一一转换为Base64,再进行业务处理。
- 题外话:关于验证码的,最后的解决方案并不是使用以上的方法
由于第三方API支持在线图片,所以将图片链接直接传给第三方API,获取返回结果即可。
时间线
- 完成初稿-2020.08.16
- 完成图片与Base64模块-2020.08.16
参考链接
Base64
Base64
什么是Base64
Base64是网络最常见的用于传输8Bit字节码的编码方式之一,
Base64就是一种基于64个可打印字符来表示二进制数据的方法。
特点
Base64编码具有不可读性
Java的Base64API-编码与解码演进史
其实Java的Base64的演进史有几个版本,总的来说,一个版本比一个版本强吧
早期版本
//引用//不需要引入第三方库
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
//编码
BASE64Encoder base64Encoder = new BASE64Encoder();
String testStr = "我是一个程序猿";
byte[] testByte = testStr.getBytes("UTF-8");
String encodedText = base64Encoder.encode(testByte);
System.out.println(encodedText);
//解码
BASE64Decoder base64Decoder = new BASE64Decoder();
base64Decoder.decodeBuffer(encodedText);
String result = new String(base64Decoder.decodeBuffer(encodedText),"UTF-8");
System.out.println(result);
Apache Commons Codec做法
//maven
<!-- https://mvnrepository.com/artifact/commons-codec/commons-codec -->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.14</version>
</dependency>
//引用
import org.apache.commons.codec.binary.Base64;
//编码与解码
Base64 base64 = new Base64();
String testStr = "我是一个程序猿";
//编码
byte[] bytes = testStr.getBytes("UTF-8");
String encodeTest = base64.encodeAsString(bytes);
System.out.println(encodeTest);
//解码
String result = new String(base64.decode(encodeTest),"UTF-8");
System.out.println(result);
Java8
//编码
Base64.Encoder encoder = Base64.getEncoder();
String testStr = "我是一个程序猿";
byte[] bytes = testStr.getBytes("UTF-8");
String encoderStr = encoder.encodeToString(bytes);
System.out.println(encoderStr);
//解码
Base64.Decoder decoder = Base64.getDecoder();
String result = new String(decoder.decode(encoderStr),"UTF-8");
System.out.println(result);
总结
演进史的3个版本,当然每个版本都是时代的产物,也因此,Java8的Base64可以说比前两个版本的完善一点
其实编码解码和之前的JSON是一样的,转换和恢复操作,也可以说是可逆的。
有两个关键词,即Encoder和Decoder
Java8的Base64编码解码的3种方式:Basic、Mine、Url
//由于Encoder与Decoder是相互的,所以这里只描述Encoder
//3种编码方式Basic、Mine、Url
//BasicEncoder
/**
* Returns a {@link Encoder} that encodes using the
* <a href="#basic">Basic</a> type base64 encoding scheme.
*
* @return A Base64 encoder.
*/
public static Encoder getEncoder() {
return Encoder.RFC4648;
}
//MineEncoder
/**
* Returns a {@link Encoder} that encodes using the
* <a href="#mime">MIME</a> type base64 encoding scheme.
*
* @return A Base64 encoder.
*/
public static Encoder getMimeEncoder() {
return Encoder.RFC2045;
}
//UrlEncodr
/**
* Returns a {@link Encoder} that encodes using the
* <a href="#url">URL and Filename safe</a> type base64
* encoding scheme.
*
* @return A Base64 encoder.
*/
public static Encoder getUrlEncoder() {
return Encoder.RFC4648_URLSAFE;
}
//区别
//BasicEncoder直接一行输出
//MimeEncoder可以换行输出
//而UrlEncoder也是直接一行输出,只不过是:
//将 / 替换成 _
//将 + 替换成 -
Base64与MD5的相同点与不同点
- 相同点
Base64和MD5都可以对信息进行简单的加密
- 不同点
加密方面
首先,如上面所讲,Base64是可逆的,通过编码进行加密,再通过解码进行解密
当然安全性非常低,因为当第三方知道使用这种方法加密,而加密者没有做相关处理,那么直接解码即可。
而MD5是不可逆的,一般用于信息校验,如下场景:
用户通过注册表单提交内容,发送请求后,服务者收到请求并将表单的内容进行持久化,一般会将敏感信息进行MD5加密,例如密码等等。
当用户下次进行登录时,服务者将登录表单内容的密码进行MD5加密后,再与数据库中的经过MD5加密后的密码进行比较,所以关键词在于校验
这样有什么好处呢,首先可以保护用户的敏感数据,如果不进行加密,一旦数据库由于某些原因而泄漏,其后果将非常严重。
如果一般某个应用忘记密码时,更多是让你进行修改密码,而不是将密码返回给你。
- 文件方面
文件都可以转成Base64和MD5,例如下面的模块 图片与Base64 其中图片也是文件的一个分支
但是为什么其它类型的文件转成Base64的应用比较窄呢,是因为文件转成Base64时,获得的字符串的存储大小是原来的文件的1/3。如果一个文件转成Base64,空间大小不降反增,其应用性必然是非常低的。
相比之下,文件转成MD5就非常有用了—可以判断文件是否存在等等。
如果有一个存储空间,用户上传文件,且希望该存储空间不会出现大量的相同文件。
那么每一次上传时,可以计算文件的MD5值,并与存储空间所有的文件的MD5进行比较即可。
这里的相同文件指的是内容相同,而不只只是文件名称文件类型相同。
当然还有其它功能,这里引用一个文件转MD值工具的说明:
MD5计算将整个文件或者字符串,通过其不可逆的字符串变换计算,产生文件或字符串的MD5散列值。任意两个文件、字符串不会有相同的散列值(即“很大可能”是不一样的,理论上要创造出两个散列值相同的字符串是很困难的)。
因此MD5常用于校验字符串或者文件,以防止文件、字符串被“篡改”。因为如果文件、字符串的MD5散列值不一样,说明文件内容也是不一样的,即经过修改的,如果发现下载的文件和给的MD5值不一样,需要慎重使用。
MD5文件校验用途非常多,例如:游戏补丁包的校验,病毒文件确认,APP提审校验等;如果要确认某一个文件的完整性和正确性,都会使用MD5进行校验。工具链接:metools-文件md5在线计算
图片与Base64
什么是图片Base64
图片的Base64编码就是将一张图片数据编码成一串字符串。
为什么使用Base64编码
一般而言,在Web上,图片往往是使用链接的方式,这就需要消耗一个Http请求了
如果将图片转换为Base64编码,并将其运用,那么就可以节省一个Http请求
这也是图片Base64编码的优点之一。
应用场景
Java的图片转换为Base64的编码解码
编码即是将图片转换为Base64
而解码是将Base64字符串转换为图片
图片来源
首先,进行编码之前,有一个前提非常关键,就是图片的来源
一般而言,图片的来源无非2个:本地路径的图片和网络链接上的图片,如下表示:
//本地图片
//Window
String localUrl = "D:\images\myimg.jpg";
//Linux
String linuxUrl = "/var/image/myimg.jpg";
//网络链接上的图片
String baiduLogoUrl = "https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png";
编码
- 本地
//图片来源:本地
String imgAdress = "D:\\images\\rotPhoto\\baidu.png";
//准备工作
BASE64Encoder encoder = new BASE64Encoder();
InputStream inputStream = null;
byte[] dataByte = null;
//两个步骤:
try {
//读取图片转换为字节流
inputStream = new FileInputStream(imgAdress);
// 读取图片字节数组
dataByte = new byte[inputStream.available()];
inputStream.read(dataByte);
inputStream.close();
//编码
String result = encoder.encode(dataByte);
System.out.println(result);
} catch (IOException ioException) {
ioException.printStackTrace();
}
-
网络连接
之所以这么繁琐,是因为使用HttpClient作为网络连接工具
大部分代码都是服务于HttpClient
String imgurl = "";
CloseableHttpClient closeableHttpClient = HttpClientBuilder.create().build();
HttpGet httpGet = new HttpGet(imgurl);
CloseableHttpResponse closeableHttpResponse = null;
String result = null;
try {
closeableHttpResponse = closeableHttpClient.execute(httpGet);
HttpEntity entity = closeableHttpResponse.getEntity();
if(entity!=null) {
InputStream inputStream = entity.getContent();
try {
ByteArrayOutputStream data = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int length;
while ((length = inputStream.read(buffer)) != -1) {
data.write(buffer, 0, length);
}
byte[] b = Base64.getMimeEncoder().encode(data.toByteArray());
result = new String(b, "utf-8");
} catch (Exception e) {
// TODO: handle exception
System.out.println("imgutil处理模块出现问题");
}
}
} catch (Exception e) {
// TODO: handle exception
System.out.println("imgutil处理模块出现问题");
} finally {
try {
if(closeableHttpResponse!=null)
//System.out.println("CloseableHttpResponse即将关闭");
closeableHttpResponse.close();
if(closeableHttpClient!=null)
//System.out.println("closeableHttpClient即将关闭");
closeableHttpClient.close();
} catch (Exception e2) {
// TODO: handle exception
System.out.println("HttpClient关闭异常");
}
}
return result;
}
显示
- Html代码中显示
<!DOCTYPE html>
<html>
<head>
<title>Display Image</title>
</head>
<body>
<img style='display:block; width:100px;height:100px;' id='base64image' src='data:image/${图片类型};base64,${Base64编码}'>
</body>
</html>
解码
//result->Base64字符串
BASE64Decoder decoder = new BASE64Decoder();
OutputStream out = null;
try {
String saveAdress = "D:\\images\\rotPhoto\\new.png";
out = new FileOutputStream(saveAdress);
// Base64解码
byte[] b = decoder.decodeBuffer(result);
for (int i = 0; i < b.length; ++i) {
if (b[i] < 0) {// 调整异常数据
b[i] += 256;
}
}
out.write(b);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
out.flush();
out.close();
}
}
优缺点
优点:方便,节省一个Http请求
缺点:
当然,并不是所有图片都转成Base64进行使用,而是针对于尺寸较小的图片,
之所以这么说,是因为将图片转换为Base64可以减少一个Http,
但也有弊端:
前端:使用Basee64表示图片,将会导致样式内容过于庞大臃肿,而且响应将会变慢
(前端资源在加载,样式空白)
后端:图片转换为Base64时,空间大小不降反增
总结
前面也有说了,这个模块的出现是因为一个项目经历——验证码识别
因为验证码以及一些Logo类图片非常适合图片转换为Base64。
当图片过大时,非常不建议转换为Base64