图片用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编码

posted on 2022-09-17 15:00  肥兔子爱豆畜子  阅读(1721)  评论(0编辑  收藏  举报

导航