个人博客导航页(点击右侧链接即可打开个人博客):大牛带你入门技术栈
最近抖音上挺火的一个小把戏,在记事本打开,一整篇的乱码字符,然后进过调整之后,出现一张由各种字符组成的黑白照片。先看一个效果图
接下来我们就用Java来实现吧。
https://gitee.com/xshuai/ai/blob/master/AIDemo/src/main/java/com/xs/util/image/AnimatedGifEncoder.java
https://gitee.com/xshuai/ai/blob/master/AIDemo/src/main/java/com/xs/util/image/LZWEncoder.java
https://gitee.com/xshuai/ai/blob/master/AIDemo/src/main/java/com/xs/util/image/NeuQuant.java
单独的项目地址
https://gitee.com/xshuai/imagetool
本项目使用的公式为: Gray = R*0.299 + G*0.587 + B*0.114
更多RGB色转灰度可以访问:https://blog.csdn.net/xdrt81y/article/details/8289963
package com.xs.util.image;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import javax.imageio.ImageIO;
import com.xs.util.image.other.ImageHelper;
/**
* Image2ASCII
* @author 小帅丶
* 2018年8月14日
*/
public class Image2ASCII{
static String ascii = "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\\|()1{}[]?-_+~<>i!lI;:,\\\"^`'.";
static String base = "@#&$%*o!;.";//小帅丶使用这个字符
//main方法调用
public static void main(String[] args) throws Exception {
load("G:/phone.jpg", "F:/gif/woman.txt");//静态图片转字符保存为txt文件
}
/**
* 图片转字符
* @param imagePath 图片路径
* @param txtPath 文本存放路径
* @throws IOException
*/
public static void load(String imagePath, String txtPath)
throws IOException {
BufferedImage image = ImageHelper.resize(ImageIO.read(new File(imagePath)),150,150);
load(image, txtPath);
}
/**
* 图片转字符
* @param bi BufferedImage图片
* @param txtPath 文本存放路径
* @throws IOException
*/
public static void load(BufferedImage bi, String txtPath)
throws IOException {
try {
int width = bi.getWidth();
int height = bi.getHeight();
boolean flag = false;
String result = "";
for (int i = 0; i < height; i += 2) {
for (int j = 0; j < width; j++) {
int pixel = bi.getRGB(j, i); // 下面三行代码将一个数字转换为RGB数字
int red = (pixel & 0xff0000) >> 16;
int green = (pixel & 0xff00) >> 8;
int blue = (pixel & 0xff);
float gray = 0.299f * red + 0.578f * green + 0.114f * blue;
int index = Math.round(gray * (base.length() + 1) / 255);
result += index >= base.length() ? " " : String.valueOf(base.charAt(index));
}
result += "\r\n";
}
flag = writeTxtFile(result,txtPath);//保存字符到文本文件
System.out.println(flag?"图片转字符保存成功":"图片转字符保存失败");
} catch (Exception e) {
System.out.println("图片转字符异常"+e.getMessage());
}
}
/**
* 字符保存到txt文件中
* @param imageStr 字符
* @param txtPath txt文件
* @return boolean
* @throws Exception
*/
private static boolean writeTxtFile(String imageStr, String txtPath) throws Exception{
// 先读取原有文件内容,然后进行写入操作
boolean flag = false;
String filein = imageStr;
String temp = "";
FileInputStream fis = null;
InputStreamReader isr = null;
BufferedReader br = null;
FileOutputStream fos = null;
PrintWriter pw = null;
try {
// 文件路径
File file = new File(txtPath);
if (!file.exists()) {
file.createNewFile();
}
// 将文件读入输入流
fis = new FileInputStream(file);
isr = new InputStreamReader(fis);
br = new BufferedReader(isr);
StringBuffer buf = new StringBuffer();
// 保存该文件原有的内容
for (int j = 1; (temp = br.readLine()) != null; j++) {
buf = buf.append(temp);
}
buf.append(filein);
fos = new FileOutputStream(file);
pw = new PrintWriter(fos);
pw.write(buf.toString().toCharArray());
pw.flush();
flag = true;
} catch (IOException e) {
System.out.println("文件保存失败"+e.getMessage());
} finally {
if (pw != null) {
pw.close();
}
if (fos != null) {
fos.close();
}
if (br != null) {
br.close();
}
if (isr != null) {
isr.close();
}
if (fis != null) {
fis.close();
}
}
return flag;
}
}
直接保存为图片也可以。
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import javax.imageio.ImageIO;
import sun.misc.BASE64Encoder;
/**
* Image2ASCII
* @author 小帅丶
* 2018年8月14日
*/
public class Image2ASCII{
static String ascii = "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\\|()1{}[]?-_+~<>i!lI;:,\\\"^`'.";
static String base = "@#&$%*o!;.";//小帅丶使用这个字符
/** 图片类型 */
private static final int IMAGE_TYPE = BufferedImage.TYPE_INT_RGB;
/**
* 图片转字符再保存为图片 只返回图片的base64
* @param bi 原图
* @param outPutPath
* @return String
*/
public static String txtToImageByBase64(BufferedImage bi) {
System.out.println("进来的时间"+System.currentTimeMillis());
int width = bi.getWidth();
int height = bi.getHeight();
int minx = bi.getMinX();
int miny = bi.getMinY();
int speed = 7;
BufferedImage bufferedImage = new BufferedImage(width,height,IMAGE_TYPE);
// 获取图像上下文
Graphics g = createGraphics(bufferedImage, width, height, speed);
// 图片中文本行高
final int Y_LINEHEIGHT = speed;
int lineNum = 1;
for (int i = miny; i < height; i += speed) {
for (int j = minx; j < width; j += speed) {
int pixel = bi.getRGB(j, i); // 下面三行代码将一个数字转换为RGB数字
int red = (pixel & 0xff0000) >> 16;
int green = (pixel & 0xff00) >> 8;
int blue = (pixel & 0xff);
float gray = 0.299f * red + 0.578f * green + 0.114f * blue;
int index = Math.round(gray * (base.length() + 1) / 255);
String c = index >= base.length() ? " " : String.valueOf(base.charAt(index));
g.drawString(String.valueOf(c), j, i);
}
lineNum++;
}
g.dispose();
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
ImageIO.write(bufferedImage,"jpg",out);
BASE64Encoder base64Encoder = new BASE64Encoder();
String base64 =base64Encoder.encode(out.toByteArray());
return base64;
} catch (IOException e) {
System.out.println("ImageIO.write异常" + e.getMessage());
}finally{
if(null!=out){
try {
out.close();
} catch (IOException e) {
System.out.println("out.close()异常" + e.getMessage());
}
}
}
return null;
}
/**
* 画板默认一些参数设置
* @param image 图片
* @param width 图片宽
* @param height 图片高
* @param size 字体大小
* @return
*/
private static Graphics createGraphics(BufferedImage image, int width,
int height, int size) {
Graphics g = image.createGraphics();
g.setColor(null); // 设置背景色
g.fillRect(0, 0, width, height);// 绘制背景
g.setColor(Color.BLACK); // 设置前景色
g.setFont(new Font("微软雅黑", Font.PLAIN, size)); // 设置字体
return g;
}
}
方法返回的为图片的base64数据。格式为jpg。加头信息即可在img标签的src中显示图片哦。
在线转base64为图片 需要加头信息 data:image/jpg;base64,
http://imgbase64.duoshitong.com/
package com.xs.util.image;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import javax.imageio.spi.ImageReaderSpi;
import javax.imageio.stream.FileImageInputStream;
import com.sun.image.codec.jpeg.ImageFormatException;
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;
import com.sun.imageio.plugins.gif.GIFImageReader;
import com.sun.imageio.plugins.gif.GIFImageReaderSpi;
import sun.misc.BASE64Encoder;
/**
* Image2ASCII
* @author 小帅丶
* 2018年8月14日
*/
public class Image2ASCII{
static String ascii = "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\\|()1{}[]?-_+~<>i!lI;:,\\\"^`'.";
static String base = "@#&$%*o!;.";//小帅丶使用这个字符
/** 图片类型 */
private static final int IMAGE_TYPE = BufferedImage.TYPE_INT_RGB;
/**
* gif图片转gif字符图
* @param imagePath 原图路径
* @param outPath 输出图片的文件夹路径
* @throws IOException
*/
public static void loadGif(String imagePath, String outPath)
throws IOException {
File imageFile = new File(imagePath);
FileImageInputStream in = new FileImageInputStream(imageFile);
ImageReaderSpi readerSpi = new GIFImageReaderSpi();
GIFImageReader gifImageReader = new GIFImageReader(readerSpi);
gifImageReader.setInput(in);
int num = gifImageReader.getNumImages(true);
System.out.println(num);
BufferedImage[] bufferedImages = new BufferedImage[num];
for (int i = 0; i < num; i++) {
BufferedImage bi = gifImageReader.read(i);
bufferedImages[i] = txtToImage(bi, outPath + "out" + i + ".jpeg"); //每一帧都保存为图片
}
jpgToGif(bufferedImages,outPath + imagePath.substring(imagePath.length() - 6)+ "outGif.gif", 200);
}
/**
* 图片转字符再保存为图片
* @param bi 原图
* @param outPutPath
* @return BufferedImage
*/
public static BufferedImage txtToImage(BufferedImage bi, String outPutPath) {
File imageFile = new File(outPutPath);
if (!imageFile.exists()) {
try {
imageFile.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
int width = bi.getWidth();
int height = bi.getHeight();
int minx = bi.getMinX();
int miny = bi.getMinY();
System.out.println(width + " " + height);
int speed = 7;
BufferedImage bufferedImage = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
// 获取图像上下文
Graphics g = createGraphics(bufferedImage, width, height, speed);
// 图片中文本行高
final int Y_LINEHEIGHT = speed;
int lineNum = 1;
for (int i = miny; i < height; i += speed) {
for (int j = minx; j < width; j += speed) {
int pixel = bi.getRGB(j, i); // 下面三行代码将一个数字转换为RGB数字
int red = (pixel & 0xff0000) >> 16;
int green = (pixel & 0xff00) >> 8;
int blue = (pixel & 0xff);
float gray = 0.299f * red + 0.578f * green + 0.114f * blue;
int index = Math.round(gray * (base.length() + 1) / 255);
// char c = ascii.charAt((int) (gray / 255 * ascii.length()));
// char c = toChar((int) gray);
// char c = toChar(index);
String c = index >= base.length() ? " " : String.valueOf(base.charAt(index));
g.drawString(String.valueOf(c), j, i);
}
lineNum++;
}
g.dispose();
// 保存为jpg图片
FileOutputStream fos;
try {
fos = new FileOutputStream(imageFile);
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(fos);
OutputStream out = encoder.getOutputStream();
BASE64Encoder base64Encoder = new BASE64Encoder();
encoder.encode(bufferedImage);
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (ImageFormatException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return bufferedImage;
}
/**
* 画板默认一些参数设置
* @param image 图片
* @param width 图片宽
* @param height 图片高
* @param size 字体大小
* @return
*/
private static Graphics createGraphics(BufferedImage image, int width,
int height, int size) {
Graphics g = image.createGraphics();
g.setColor(null); // 设置背景色
g.fillRect(0, 0, width, height);// 绘制背景
g.setColor(Color.BLACK); // 设置前景色
g.setFont(new Font("微软雅黑", Font.PLAIN, size)); // 设置字体
return g;
}
/**
* n张jpg转gif方法
* @param bufferedImages
* @param newPic
* @param playTime
*/
private static void jpgToGif(BufferedImage[] bufferedImages, String newPic,
int playTime) {
try {
AnimatedGifEncoder e = new AnimatedGifEncoder();
e.setRepeat(0);
e.start(newPic);
for (int i = 0; i < bufferedImages.length; i++) {
e.setDelay(playTime); // 设置播放的延迟时间
e.addFrame(bufferedImages[i]); // 添加到帧中
}
e.finish();
} catch (Exception e) {
System.out.println("jpgToGif Failed:");
}
}
}
调用代码
public static void main(String[] args) throws Exception {
loadGif("C:/Users/Administrator/Desktop/页面录屏显示.gif", "F:/gif/");//动图转为动态的字符图片
}
附Java/C/C++/机器学习/算法与数据结构/前端/安卓/Python/程序员必读/书籍书单大全:
(点击右侧 即可打开个人博客内有干货):技术干货小栈
=====>>①【Java大牛带你入门到进阶之路】<<====
=====>>②【算法数据结构+acm大牛带你入门到进阶之路】<<===
=====>>③【数据库大牛带你入门到进阶之路】<<=====
=====>>④【Web前端大牛带你入门到进阶之路】<<====
=====>>⑤【机器学习和python大牛带你入门到进阶之路】<<====
=====>>⑥【架构师大牛带你入门到进阶之路】<<=====
=====>>⑦【C++大牛带你入门到进阶之路】<<====
=====>>⑧【ios大牛带你入门到进阶之路】<<====
=====>>⑨【Web安全大牛带你入门到进阶之路】<<=====
=====>>⑩【Linux和操作系统大牛带你入门到进阶之路】<<=====天下没有不劳而获的果实,望各位年轻的朋友,想学技术的朋友,在决心扎入技术道路的路上披荆斩棘,把书弄懂了,再去敲代码,把原理弄懂了,再去实践,将会带给你的人生,你的工作,你的未来一个美梦。