惊呆了,一张图片里居然可以存放百万字小说怎么做到的

这,是一张图片,哦不,这其实是一个百万字的小说!

target.bmp

你可能会想到,是不是字很小?

不,我们放大看,只能看到一块块的像素

录屏_选择区域_20210725130245.gif

其实,这一块块的颜色就是一个字符,没有想到吧。

颜色是怎么代表字符的  相关资料

我们知道颜色值就是rgb,通过3个255内的数字可以组合成任意的颜色,我们只需要把汉字转换成特定的颜色值就可以了,那么汉字是如何转成整数的呢?

没错,就是unicode码,比如"掘金"的unicode码是"\u6398\u91d1",接下来我们把一个unicode码分成2部分,第一部分是绿色值,第二部分是蓝色值,比如'掘'字分成63和98,那么我们就可以规定他的rgb颜色值是rgb(255,63,98),是的,我们可以选择不要红色,给红色设置一个固定值,如果是255的话,那么整体就会偏红。

有了颜色值,我们就可以创建一个画布,设置每个像素的值。

那么,这个画布要设置多大才合适?这是一个问题,假如现在有20个字符,画布是n*n的,n到底取多少?

答案最少是5,才能容纳20个像素,具体公式就是取字符数的0.5次幂,得数再向上取整。

rgb转整数    相关资料

那还有一个问题,我们要把rgb转成int类型才行,例如,我们要把rgb(255,63,98)转换成整数,或者在反向推算时,从整数中取出蓝、绿值,该如何计算?

  private static int getIntFromColor(int r, int g, int b) {
      r = (r << 16) & 0x00FF0000;
      g = (g << 8) & 0x0000FF00;
      b = b & 0x000000FF;
      return 0xFF000000 | r | g | b;
  }
复制代码
//获取绿色
(rgb >> 8) & 0xff)

//获取蓝色
(rgb >> 0) & 0xff)
复制代码

生成图片小说     相关资料

下面就是把小说编码到图片中,其中还有两个位运算,((value & 0xff00) >> 8)(value & 0xff),分别用来获取字符对应unicode码的g、b颜色部分。

从左到右、从上到下,依次设置rgb颜色,最后就会形成开头的图片。


private static void encrypt(){
    try {
        String str = readFileByLines("/home/HouXinLin/test/src.txt");
        int width = (int) Math.ceil(Math.pow(str.length(), 0.5));
        int x = 0, y = 0;
        BufferedImage renderedImage = new BufferedImage(width, width, BufferedImage.TYPE_INT_RGB);
        for (char c : str.toCharArray()) {
            int value = c;
            int intFromColor = getIntFromColor(255, ((value & 0xff00) >> 8), (value & 0xff));
            renderedImage.setRGB(x, y, intFromColor);
            if (y == width - 1) {
                y = 0;
                x += 1;
            } else {
                y += 1;
            }
        }
        ImageIO.write(renderedImage, "BMP", new FileOutputStream("/home/HouXinLin/test/target.bmp"));
    } catch (IOException e) {
        e.printStackTrace();
    }
}
复制代码

解码

解码的时候,分别获取像素的颜色值,从中取出绿色和蓝色值,最后拼接成一个四位的16进制值,转换成char类型即可。

private static void decode() {
    try {
        BufferedImage bufferedImage = ImageIO.read(new File("/home/HouXinLin/test/target.bmp"));
        int width = bufferedImage.getWidth();
        int height = bufferedImage.getHeight();
        StringBuffer stringBuffer = new StringBuffer();
        for (int i = 0; i < width; i++) {
            for (int j = 0; j < height; j++) {
                int rgb = bufferedImage.getRGB(i, j);
                String hex = Integer.toHexString((rgb >> 8) & 0xff) + "" + zero(Integer.toHexString(((rgb >> 0) & 0xff)));
                char c = (char) Integer.valueOf(hex, 16).intValue();
                stringBuffer.append(c);
            }
        }
        Files.write(Paths.get("/home/HouXinLin/test/重生2.txt"), stringBuffer.toString().getBytes(StandardCharsets.UTF_8));
    } catch (IOException e) {
        e.printStackTrace();
    }
}
private static String zero(String str) {
    if (str.length() == 1) {
        return "0" + str;
    }
    return str;
}

需要相关资料的可以通过扫一扫

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值