这,是一张图片,哦不,这其实是一个百万字的小说!
你可能会想到,是不是字很小?
不,我们放大看,只能看到一块块的像素
其实,这一块块的颜色就是一个字符,没有想到吧。
颜色是怎么代表字符的 相关资料
我们知道颜色值就是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;
}
需要相关资料的可以通过扫一扫