我的画画梦
我本该是一个会画画的人。
我的画里有山川、河流与大海,有麦田、向日葵和白云。
那时候,我坐在小镇东面河堰的草堆上,脚下的草地,像绿色的瀑布,从脚下高高的河堰上一直流淌到远方的河边,牛儿棕色的绒毛像火烧云,成群的羊儿像白云。
一张纸,一支画笔,一盒颜料。到了傍晚,牛羊就从这片草地上跑到了我的纸上。
这方面的天赋,让我一直在等着北京那两所著名的大学的录取通知。
直到家里有了电视机之后, 我在《新闻联播》之后的《天气预报》里面看到了北京的天气情况,才知道北京的冬天有多冷,这个念头从此打消。由此我也开始了南下搬砖的生活。但是画画这个梦想就像火种一样,风一来,他就要燃起来。
苏州是一个河流纵横交错,湖泊众多的城市,我时常沿着那些稻田边行走,一点也不害怕陷入那些泥地里面。累了我就坐下休息一会。
这时候一个小姐姐也从稻田的另一头走了过来,越来越近,我用手机给她拍了个照片。放大一看,惊为天人,说实话,在苏州我从来没见过这样的小姐姐。
待我抬头再去看时,她已经走远。我决定重拾画笔,为她画一幅画。历时两年,我终于在记事本里面敲出来了。
如果你觉得看不清,那很正常,因为我把像素缩小了5倍,因为如果按照原来的像素来放这些字符,已经超过了一篇文章的字数限制,来看看预览图
画画的准备材料
- 图像分析学,了解色彩的组成
- jdk1.8
- javafx
- 一张小姐姐的绝美照片
- 美好的周末的空闲时刻
- 一个装好了java开发环境的笔记本电脑
- 移位操作
- 按位与
- 按位或
- 计算机组成原理
- 灰度处理
计算机组成原理知识复习
- 一个无符号int类型的变量,在计算机内部占4个字节,每个字节占8个bit
&
这是一个按位与操作,它是一个双目运算符,它标示输入的两个值在都为1的情况下,输出才会为1,按位与操作的功能其实是一个过滤器,为什么这样说呢,请看下面这个表格
输入a | 输入b | 按位与的结果 |
---|---|---|
0 | 0 | 0 |
0 | 1 | 0 |
1 | 0 | 0 |
1 | 1 | 1 |
为什么我说它是一个过滤器呢,因为如果我手里有一个网兜,我想向水里捞一把,如果水里空空如也,那么我捞起的就是空,而如果水里有一条大鱼,我就能捕获一条鱼。那么我此刻手里握着的是一个1,那么只有我遇上1的时候,我才会微笑,因为它是我确认过的眼神。这里需要格外注意,只有最后那一行才是我们需要的,当然,这里你肯定还不知道为什么,别急,继续往下看。
|
这是一个按位或操作,他的功能是只要两个输入之中只要有一个1,那么就输出1,我忘记了代码里是否需要,先写在这里吧,看下面的表格
输入a | 输入b | 输出结果 |
---|---|---|
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 1 |
>>
这个操作符号不是两个大于号,它是移位操作,向哪里移位呢,看它的箭头方向指向何方,我想我们都是幼儿园顺利毕业的朋友,知道是箭头的方向是向右,如果实在不知道指向哪里,你就想想你在电脑上打字的时候,光标移动的方向是向哪里的,为什么介绍这个因为我们真的用得到,可以不用吗?抱歉,不用这个我不会玩,看下面的知识复习,先看一个int类型的二进制数的伪代码
int a = 10000001,10010100,01010101,010100101;
接下里,我要进行一些操作
//第一步:
a & 0xff
//输出:010100101
//第二步:
a >> 8 & 0xff
//输出:01010101
//第三步:
a >> 16 & 0xff
//输出:10010100
//第四步:
a >> 24 & 0xff
//输出:10000001
这些操作的目的是,从低位到高位,每次获取8个bit的值。
先记住这些,以后考试要考的。
色彩分析知识复习
我们都知道在计算机中,一个图片实际上就是有若干个小点点组成的,这个小点点我们通常叫做像素,而一个像素我们通常认为是有红黄蓝三种颜色组成,当然还有透明度,红黄蓝和透明度,我们通常认为都是由一个0-255
内的数字组成的,即一个字节的长度就可以表示出来,那么天然的就可以用一个int值来表示透明度和红黄蓝了,即argb
分别用一个字节来表示,合起来就是一个int
值,那么我们看到的2829929这个值有可能就是一个颜色咯。即最高八位表示透明度,然后次高八位表示红色,最低位表示蓝色,次低八位表示绿色,请看下面的表示
10101010,10101010,10101010,10101010
a r g b
透明度 红色 绿色 蓝色
灰度处理
如果你听说过灰度处理,跳过这一节,如果没听过,那就坐好听一下。
灰度处理是将一个颜色的红色的部分提取21%,绿色部分提取71%,蓝色部分提取7%得到的一个数值
别问我是怎么知道的,我只能告诉你这是我用颜料盒调了很多次才提炼出来的配方,你不需要知道原理,只要按照这个配方进行调制,炒菜的味道就会很香。
像素转化为字符
灰度处理过的图片,我们认为只有两种颜色了,但是只有两种颜色的画,失真率会特别高,除非你的照片原来就是黑白的,即使是黑白的照片,也是灰度处理过的,除非你是用画笔的黑色和白色画出来的。
为了让我们的字符画的细节更加丰富,对比不是那么强烈,我们需要让不同的像素转化成明暗不同的字符。我们通过程序获取的int
颜色值,通过灰色处理后,只剩下一个byte
范围的数值,即0-255,当然你可以找256个字符用来表示每一个灰度值,这样的效果理论上来说是效果最好的,但是我还没有发现细节变化线性变化这么好的256个字符。
我的策略是利用除法进行分组,得到这个灰度值应该大约用到哪一个字符,这在String getChar(int value)
这个方法中可以体现
全部代码,不需要打赏作者
就能出现
package lesson10;
import javafx.animation.FadeTransition;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.*;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Font;
import javafx.stage.Stage;
import javafx.util.Duration;
import java.text.SimpleDateFormat;
import java.util.regex.Pattern;
public class Login extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception {
//Image image = new Image("file:/Users/java0904/Pictures/three.jpeg",500,500,false,true);
Image image = new Image("file:/Users/java0904/Pictures/taile.jpg");
ImageView imageView = new ImageView(image);
PixelReader pixelReader = image.getPixelReader();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < image.getHeight(); i += 1) {
for (int j = 0; j < image.getWidth(); j += 1) {
//此处的取值是j,i,因为向txt文件中写入字符串的 时候,是需要一行一行写的,不是一列一列写入的
Color color = pixelReader.getColor(j, i);
int argb = pixelReader.getArgb(j, i);
int a = argb >>> 24;
int r = (argb >> 16) & 0xff;
int g = (argb >> 8) & 0xff;
int b = (argb) & 0xff;
//int value = (int) ((color.getRed() * 30 + color.getGreen() * 59 + color.getBlue() * 11) / 100 * 255);
//Color类中的color.grayscale()方法的参数值
int value = (int) ((color.getRed() * 21 + color.getGreen() * 71 + color.getBlue() * 7) / 100 * 255);
value = (int) (r * 0.21 + g * 0.71 + b * 0.07);
sb.append(getChar(value));
}
sb.append("\r\n");
}
write(sb);
BorderPane borderPane = new BorderPane();
borderPane.setCenter(imageView);
Scene scene = new Scene(borderPane);
primaryStage.setScene(scene);
primaryStage.setWidth(800);
primaryStage.setHeight(800);
primaryStage.setTitle("javafx practise");
primaryStage.show();
}
private String getChar(int value) {
String s = "龖齱龠馬車瓦日乙卜丶";
//String s = "龖齱龠馬車瓦MNHBEYUO*!";
int length = s.length();
int index = value / (256 / length + 1);
char c = s.charAt(index);
return c + "";
}
private void write(StringBuilder sb) throws Exception {
//System.out.println(sb.toString());
File file = new File("/Users/java0904/Pictures/taile.txt");
FileOutputStream fileOutputStream = new FileOutputStream(file);
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream);
BufferedWriter bufferedWriter = new BufferedWriter(outputStreamWriter);
bufferedWriter.write(sb.toString());
bufferedWriter.close();
}
}
debug
如果你直接运行上面的代码,可以肯定的是会报错,这是因为你必须定义好自己的图片的地址,以及生成字符文件的地址