Base64与图片

Base64与图片

前言

由于平时开发中接触图片的业务,非常少,所以对于图片的处理非常少。

这段时间是因为小程序项目,例如小程序上传图片,以及验证码识别。

  • 关于图片转换为Base64的问题-2020.08.16

其实有种方式,就是将验证码保存在本地,再进行业务处理:

先将图片下载到本地->业务逻辑->删除图片

这样做,非常消耗服务器的存储空间以及将会增加许多逻辑

之后,通过资料,也发现许多第三方API都支持转成Base64类型的图片

才发现,原来处理图片可以这么处理——将图片转换为Base4

而且,也看到了一篇博客,即是小程序多图片上传的实现,如下:

小程序多图片上传

其中的解决方案,即是将图片一一转换为Base64,再进行业务处理。

  • 题外话:关于验证码的,最后的解决方案并不是使用以上的方法

由于第三方API支持在线图片,所以将图片链接直接传给第三方API,获取返回结果即可。

时间线

  • 完成初稿-2020.08.16
  • 完成图片与Base64模块-2020.08.16

参考链接

Base64

Java8的Base64编码与解码

玩转图片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是一样的,转换和恢复操作,也可以说是可逆的。

有两个关键词,即EncoderDecoder

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都可以对信息进行简单的加密

  • 不同点
  1. 加密方面

    首先,如上面所讲,Base64是可逆的,通过编码进行加密,再通过解码进行解密

当然安全性非常低,因为当第三方知道使用这种方法加密,而加密者没有做相关处理,那么直接解码即可。

而MD5是不可逆的,一般用于信息校验,如下场景:

用户通过注册表单提交内容,发送请求后,服务者收到请求并将表单的内容进行持久化,一般会将敏感信息进行MD5加密,例如密码等等。

当用户下次进行登录时,服务者将登录表单内容的密码进行MD5加密后,再与数据库中的经过MD5加密后的密码进行比较,所以关键词在于校验

在这里插入图片描述

这样有什么好处呢,首先可以保护用户的敏感数据,如果不进行加密,一旦数据库由于某些原因而泄漏,其后果将非常严重。

如果一般某个应用忘记密码时,更多是让你进行修改密码,而不是将密码返回给你。

  1. 文件方面

文件都可以转成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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值