@

背景

用Java实现字符拼成一个图片,先看一下效果:

  • 左边是原图,右边是用字符拼成的效果,即写好代码,读入一张图片,然后用指定的字符把这个图片的轮廓拼出来



    放大之后是这个样子
  • 用love拼成了哆啦A梦的轮廓

源码

public class AscPic {
public static void main(String[] args) throws IOException {
String path = "d:/qqq.png";//导入的图片
String base = "love";//将会用这个字符串里的字符填充图片
BufferedImage image = ImageIO.read(new File(path));//读入图片,并用图片缓冲区对象来接收 //双层for循环,遍历图片
for (int y = 0; y < image.getHeight(); y++) {//先竖向遍历,再横向遍历,即一行一行的找,后面也会一行一行的打印
for (int x = 0; x < image.getWidth(); x++) {
int color = image.getRGB(x, y);//图片缓冲区自带的方法,可以得到当前点的颜色值,返回值是int类型
int r=(color>>16)&0xff;
int g=(color>>8)&0xff;
int b=color&0xff;
float gray = 0.299f * r + 0.578f * g + 0.114f * b;//灰度值计算公式,固定比例,无需理解
int index = Math.round(gray * (base.length()) / 255);
if(index>=base.length()) {
System.out.print(" ");//白色的地方打空格,相当于白色背景,这样图片轮廓比较明显
}else {
System.out.print(base.charAt(index));//有颜色的地方打字符
}
}
System.out.println();//一行打完,换行
}
}
}

代码思路

整体思路为导入想好处理的图片,遍历,得到每个像素点的颜色,然后将其转换成灰度值(也就是把彩色转换成黑白),根据得到的灰度值计算字符串索引,达到效果就是不同颜色可以对应不同的下标,以此来匹配字符串中的字符,最后按照原有的坐标点把这些字符打印出来即可

  1. 定义好想要填充的字符串
  2. 导入想要处理的图片,需要用到BufferedImage(图片缓冲区)这个对象
  3. 遍历整张图片,这里需要注意,外层循环遍历y轴,内层遍历x轴,因为打印的时候需要一行一行打印,打完一行要换行
  4. 根据getRGB(x,y)方法,传入当前的坐标点,得到当前点的颜色
  5. 从得到的颜色中单独拆分出r,g,b的值
  6. 根据得到的rgb计算对应的灰度值
  7. 根据灰度值计算索引
  8. 打印

难点讲解

如何得到rgb

int color = image.getRGB(x, y);//图片缓冲区自带的方法,可以得到当前点的颜色值,返回值是int类型
int r=(color>>16)&0xff;
int g=(color>>8)&0xff;
int b=color&0xff;

首先明确一点,所谓的rgb就是三原色,red,green,blue,无论是ps还是程序,都会通过给rgb赋值来拼成一个新的颜色。通过etRGB(x,y)得到的颜色是一个int类型,我们用color来表示。这个值包含四部分内容,分别为a,r,g,b,即透明度,red,green,blue。每一部分恰好占一个字节。所以我们要做的就是从这个int中去单独得到从左数第二,第三,第四字节的数值。

怎么做呢?先来回顾两个位运算的基本知识:

  1. "&",与,都是0则结果为0,都是1结果为1,一个1一个0结果为0.从数学上理解,&操作符其实是在取交集。

    7&5=?

    首先换算成二进制,7的二进制是0111,5的二进制是0101

    0111&0101=0101,还是5。

    通过上面的计算有没有发现一个规律,如果我想要让一个数和另一个数&完结果还是这个数本身怎么办?比如我想让0101,0111,0011和一个数&完结果还是他们本身,那么这个数应该是多少。
  2. ">>",右移.

    8>>2,表示8向右平移两位,结果为2.

    8的二进制1000,右移两位,0010.

现在想想,怎么样通过上面两个符号从一个int中得到某一个字节的数值,比如得到第二字节的值,也就是r的值。



假装你们想了20分钟。

我们用二进制来看,假设我们得到的color换算成二进制是:

01111100 01011010 10001101 00111110

我们要得到从左数第二个字节的值,怎么办?

首先,把这个数向右平移两个字节,也就是16位,那么就是color>>16,结果为

00000000 00000000 01111100 01011010

此时,再和11111111与一下,是不是就得到这个数本身了。

00000000 00000000 01111100 01011010

&

00000000 00000000 00000000 11111111

=

00000000 00000000 00000000 01011010

现在得到的就是r的值。写法:(color>>16)& 0xff.

0x表示16进制,16进制的ff表示的就是二进制的8个1。

以此类推,得到g就是(color>>8)& 0xff,得到b就是color & 0xff。

注:这里注意,方法不唯一,也可以先与后右移。这种方法是用位运算符来做的,当然也能转换成二进制数组然后拆分。那么为什么要用位运算符来做呢,第一是方便,第二就是很有逼格啊老铁。

如何让不同颜色匹配不同字符

int index = Math.round(gray * (base.length()) / 255);

gray是我们求出的灰度值,它的最大值也是255。不同颜色得到的gray不一样,同理,gray/255得到的就是不同颜色对应的一个比例,用这个比例乘以字符串长度就完成了不同颜色或者说不同颜色段匹配了不同的字符下标。因此得到gray * (base.length()) / 255,然后通过Math.round()方法四舍五入取整。

这里需要注意一下, 这样打印出来的字符图片色调会比较深,为了让颜色区分更明显,我们可以让一些接近于白色的浅色都打印成空格,那么我们就写成

int index = Math.round(gray * (base.length()+1) / 255);

把字符串长度加一,然后再做乘除操作,这样会让一部分颜色对应的索引大于字符串长度。

我们打印的时候是这样判断的,如果index大于等于字符串长度就打印空格,如果不是才打印字符。

为什么我的图片只能打一半

eclipse的控制台输出的行数有限,超过规定行数就覆盖了。这时可以把y++,改成y+=2,相当于每隔两个点取一下颜色并打印,也就是把原图纵向上缩小了一半。为了保持原图的比例,同理也可以把x做相应调整。

OutOfMemoryError错误

内存溢出,图片太大了,换个小一点的图片

为什么用汉字来打印图案会扭曲

字母或字符占得大小比汉字要小,汉字所占的空间很大,如果按照原有的点来打印汉字,因为汉字的宽度几乎比字母大一倍,所以会被挤出去,造成了扭曲。解决方法:改变y和x的自增数,也就是把x++改成+2,+3这样的,横向上每隔两个点打印一下,给汉字预留出空间

装逼时刻

找你女神的照片来打印,字符可以用“love”或者“我爱你”



放大



互联网+时代,表白当然也要用技术手段表白,程序员不是不解风情,我们的浪漫,与众不同。

Java字符拼成图片(image-ASCII)的更多相关文章

  1. python实战===老司机奇技淫巧系列之字符转换成图片

    先放两张效果图:

  2. Java PDF转换成图片并输出给前台展示

    首先需要导入所需工具类 <dependency> <groupId>org.apache.pdfbox</groupId> <artifactId>fo ...

  3. 将图片转为ASCII字符画

    原文:将图片转为ASCII字符画 Copyright 2012 Conmajia 源代码下载:点击这里 什么是字符画?就是用ASCII字符来近似组成图像,就像这样: ╭╮ ╭╮ ││ ││ ╭┴┴—— ...

  4. 【Java】字符拼接成字符串的注意点

    这两天敲代码的时候,偶然间发现一个好玩的事情,分享一下,记录一下. 该段代码主要是:先产生的几个整数,把整数转换成对应的字符,最后的字符拼接成字符串,在把字符拼接成字符串的时候,个人因为偷懒使用+号进 ...

  5. AsciiPic Java视频转成字符画

    AsciiPic Java视频转成字符画 github下载 https://github.com/dejavudwh/AsciiPic 运行截图 //没有做GUI 比较简陋 节省时间 main里的文件 ...

  6. Oracle一列的多行数据拼成一行显示字符

    Oracle一列的多行数据拼成一行显示字符   oracle 提供了两个函数WMSYS.WM_CONCAT 和 ListAgg函数.    www.2cto.com   先介绍:WMSYS.WM_CO ...

  7. java中如何把图片转换成二进制流的代码

    在学习期间,把开发过程经常用到的一些代码段做个备份,下边代码内容是关于java中如何把图片转换成二进制流的代码,应该能对各朋友也有用处. public byte[] SetImageToByteArr ...

  8. ditaa - 把ascii图形转成图片

    ditaa ditaa是一个把ascii图形转成图片的工具. 在查看zguide时看到这个文档是用gitdown生成的.zguide文档格式排版非常不错,以后要抽时间好好学习一下. 每章写一个txt文 ...

  9. 将java project打包成jar包,web project 打包成war包的几种演示 此博文包含图片

    转: http://blog.csdn.net/christine_ruan/article/details/7491559 http://developer.51cto.com/art/200907 ...

随机推荐

  1. 暑期训练狂刷系列——Hdu 3506 Largest Rectangle in a Histogram (单调栈)

    题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=1506 题目大意: 给出一个数列An,问以Ai为最小值的区间内有多少个元素? 解题思路: 手动模拟一个 ...

  2. python vs java的rsa加密

    首先:java的加密解密模块需要更加精细的算法细节指定 java的加密方式 javax.crypto.Cipher,定义的获取方式 tatic Cipher getInstance(String tr ...

  3. C# 控制台语音计算器

    记得上高中时,给人当会计,帮忙结算月度工资:用的就是带语音功能的计算器! 当时用起来倍儿爽,于是速度加倍,效率加速:结果让老板赔了不少钱! 就是因为这个,才对语音计算器有了深刻印象!可能是这货坑了我! ...

  4. [BZOJ1088][SCOI2005]扫雷Mine DP

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1088 记录下每一个格子对应左边格子放的雷的情况,然后dp转移就好了. #include&l ...

  5. html添加css——样式选择器

    如何给html添加样式.两种方法: 一.新建立一个css样式表,与原html同目录,然后通过link标签链接.如:<link type="text/css" rel=&quo ...

  6. javascript动态创建div循环列表

    动态循环加载列表,实现vue中v-for的效果 效果图: 代码: var noApplicationRecord = document.getElementById('noApplicationRec ...

  7. 一个完整的http请求分析

    Request URL:http://localhost:8080/test.jhtmlRequest Method:POSTStatus Code:200 OKRemote Address:[::1 ...

  8. web调用手机相册,并实现动态增加图片功能

    注:经测试h5调用相册效果有兼容性问题,安卓仅能调用拍照功能(部分安卓可能会调不起来,所以建议用app原生调用),ios可调起拍照和相册功能. <html xmlns="http:// ...

  9. vue2.0 自定义指令详解

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  10. node.js入门之三

    Node.js REPL(交互式解释器) Node.js REPL(Read Eval Print Loop:交互式解释器) 表示一个电脑的环境,类似 Window 系统的终端或 Unix/Linux ...