图片用BASE64编码为字符串
想法来由
链上NFT封装存储的除了权益关系之外,对作品本身的加密摘要(数据指纹)也做了存储,这可以证明“图是不是原图”,然后图片存储在云oss上,当然买者可以下载,但是oss地址并没有存放在nft结构里,应该是怕存储位置要发生改变然后区块链又没法修改会带来麻烦。能不能把图片用BASE64编码然后存在区块链上呢?
逻辑上想想应该是不行的,既然图片过大不适合区块链存储,那编码后(不考虑各种压缩算法手段)形成的base64大小应该也是不小的,存在链上一样不适合。
代码验证
将图片转为base64字符串:
import lombok.extern.slf4j.Slf4j;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
@Slf4j
public class ImageBase64 {
public static void main(String[] arg) {
String image1 = "C:\\Users\\Administrator\\Pictures\\120K.jpg";
String image2 = "C:\\Users\\Administrator\\Pictures\\2755K.jpg";
String imageFile = image1;
String imageBase64Str = "";
FileInputStream fileInputStream = null;
byte[] data = null;
try {
fileInputStream = new FileInputStream(imageFile);
data = new byte[fileInputStream.available()];
fileInputStream.read(data);
} catch (Exception e) {
throw new RuntimeException(e);
}finally {
try {
fileInputStream.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
BASE64Encoder encoder = new BASE64Encoder();
imageBase64Str = encoder.encode(data);
log.info("base64转码后图片编码长度:{}K", imageBase64Str.length()/1024);
try {
generateImageFromBase64(imageBase64Str);
log.info("图片生成完毕");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static void generateImageFromBase64(String base64Str) throws IOException {
String outputPath = "C:\\Users\\Administrator\\Pictures\\output.jpg";
BASE64Decoder base64Decoder = new BASE64Decoder();
byte[] data = base64Decoder.decodeBuffer(base64Str);
log.info("开始生成图片...");
OutputStream os = new FileOutputStream(outputPath);
os.write(data);
os.flush();
os.close();
}
}
两个内容一样码率不同的图片,一个120K,一个2.69M,用base64转码为字符串,得到大小是:
base64转码后图片编码长度:162K
base64转码后图片编码长度:3778K
编码后的字符串大小比图片还大了一些。然后根据字符串decode解码回的图片与原图倒是一致的。
图片压缩
可以使用Hutool工具包里边的ImgUtil.scale()
方法对BASE64图片进行压缩,参见:
java使用hutool工具类实现base64字符串image的压缩
何时用
前面验证后说了,往往图片编码为BASE64字符串后,比原图还大,那什么时候使用呢?
按照前端视角来看,浏览器加载图片是异步的,对一个图片链接要启动一个连接请求去下载图片,如果图片以BASE64的方式与HTML一起返回,那么可以节省一次请求:
这是一个多一个请求与编码后字节数变多
之间的平衡取舍。所以,“如果图片足够小且因为用处的特殊性无法被制作成雪碧图(CssSprites),在整个网站的复用性很高且基本不会被更新” 这样的情况下,可以考虑用BASE64将图片与HTML融为一体返回。
参见: 【前端攻略】:玩转图片Base64编码