[好玩的CMD]CMD批处理绘制彩色的像素画

不多废话,先上几张效果图:

[好玩的CMD]CMD批处理绘制彩色的像素画_第1张图片
[好玩的CMD]CMD批处理绘制彩色的像素画_第2张图片
[好玩的CMD]CMD批处理绘制彩色的像素画_第3张图片
[好玩的CMD]CMD批处理绘制彩色的像素画_第4张图片[好玩的CMD]CMD批处理绘制彩色的像素画_第5张图片[好玩的CMD]CMD批处理绘制彩色的像素画_第6张图片[好玩的CMD]CMD批处理绘制彩色的像素画_第7张图片


其实也是闲着无聊,偶然间看到网上一篇博客,介绍了window10的cmd可以使用 ANSI转义显示彩色字或背景(点我查看学习资料),感觉突然来了点灵感,cmd的黑白控制台尽然也可以显示这么多颜色!那我是不是可以拿它来画画了!哈哈,所以就有了下面的尝试.直接上java工具代码:

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 图片转化为cmd批处理文件
 *
 * @author 子牙
 * @date 2019年11月32日 下午13:55:40
 */
public class Pic2CMD {

    /**
     * 读取图片并生成输出cmd图像
     *
     * @param path      图片输入路径
     * @param pix       图片需要按多少像素扫描(意思就是你的图按多少像素截取一个小方块)
     * @param makeBat   需要在图片路径下输出一个同名批处理文件么
     * @param showColor true在控制台打印图像,false在控制台打印颜色中文(主要是调试)
     */
    private void createAsciiPic(String path, int pix, boolean makeBat, boolean showColor) {
        StringBuilder stringBuilder = new StringBuilder("@echo off\n");
        try {
            File imf = new File(path);
            final BufferedImage image = ImageIO.read(new File(path));
            int lines = image.getHeight() / pix;
            int cols = image.getWidth() / pix;
//            stringBuilder.append("title ").append(imf.getName().split("\\.")[0]).append("\n");
            stringBuilder.append("mode con cols=").append(cols * 2 + 2).append(" lines=").append(lines + 2).append("\n");
            for (int y = 0; y < image.getHeight(); y += pix) {
                stringBuilder.append("echo ");
                for (int x = 0; x < image.getWidth(); x += pix) {
                    final int pixel = image.getRGB(x, y);
                    //转化RGB值
                    final int r = (pixel & 0xff0000) >> 16, g = (pixel & 0xff00) >> 8, b = pixel & 0xff;
                    //输出该像素点的颜色
                    stringBuilder.append(getYS(r, g, b, showColor));
                    System.out.print(getYS(r, g, b, showColor));
                }
                System.out.print("\u001B[0m");
                System.out.println();
                stringBuilder.append("\n");
            }
            stringBuilder.append("pause");
            //需要输出文件的话执行
            if (makeBat) {
                File outFile = new File(path.split("\\.")[0] + "-" + pix + ".cmd");
                FileOutputStream fop = new FileOutputStream(outFile);
                fop.write(stringBuilder.toString().getBytes());
                fop.flush();
                fop.close();
                //打开这个批处理文件,用来预览
//                Runtime.getRuntime().exec("cmd /k start " + outFile.getAbsolutePath());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 控制台颜色
     */
    class MColor {
        /**
         * 颜色名
         */
        String name;
        /**
         * 对应RGB数组
         */
        int[] RGB;
        /**
         * 颜色转义代码
         */
        String colorCode;

        MColor(String name, int[] RGB, String colorCode) {
            this.name = name;
            this.RGB = RGB;
            this.colorCode = colorCode;
        }
    }

    /**
     * 根据RGB值判断应该对应的控制台颜色
     *
     * @param r
     * @param g
     * @param b
     * @param showColor
     * @return
     */
    private String getYS(int r, int g, int b, boolean showColor) {
        String w = "  ";//批处理中打印的字符,建议是2个空格
        //将所有cmd可输出的颜色输入,颜色是用的微信截图工具查看的RGB值,可能有误差
        MColor 黑 = new MColor("黑", new int[]{12, 12, 12}, "\u001B[40m" + w);
        MColor 红 = new MColor("红", new int[]{197, 15, 31}, "\u001B[41m" + w);
        MColor 绿 = new MColor("绿", new int[]{19, 161, 14}, "\u001B[42m" + w);
        MColor 黄 = new MColor("黄", new int[]{193, 156, 0}, "\u001B[43m" + w);
        MColor 蓝 = new MColor("蓝", new int[]{0, 55, 218}, "\u001B[44m" + w);
        MColor 紫 = new MColor("紫", new int[]{136, 23, 152}, "\u001B[45m" + w);
        MColor 灰紫 = new MColor("灰紫", new int[]{58, 150, 221}, "\u001B[46m" + w);
        MColor 淡灰 = new MColor("淡灰", new int[]{204, 204, 204}, "\u001B[47m" + w);
        MColor 灰 = new MColor("灰", new int[]{118, 118, 118}, "\u001B[100m" + w);
        MColor 淡红 = new MColor("淡红", new int[]{231, 72, 86}, "\u001B[101m" + w);
        MColor 淡绿 = new MColor("淡绿", new int[]{22, 198, 12}, "\u001B[102m" + w);
        MColor 淡黄 = new MColor("淡黄", new int[]{249, 241, 165}, "\u001B[103m" + w);
        MColor 淡蓝 = new MColor("淡蓝", new int[]{59, 120, 255}, "\u001B[104m" + w);
        MColor 酒红 = new MColor("酒红", new int[]{180, 0, 158}, "\u001B[105m" + w);
        MColor 天蓝 = new MColor("天蓝", new int[]{97, 214, 214}, "\u001B[106m" + w);
        MColor 白 = new MColor("白", new int[]{242, 242, 242}, "\u001B[107m" + w);
        final List colorList = Arrays.asList(黑, 红, 绿, 黄, 蓝, 紫, 灰紫, 淡灰, 灰, 淡红, 淡绿, 淡黄, 淡蓝, 酒红, 天蓝, 白);
        double minDiff = Double.MAX_VALUE;
        //最接近的颜色
        MColor minColor = 白;
        //计算该RGB值与哪个控制台颜色最接近
        for (MColor mColor : colorList) {
            int dR = Math.abs(mColor.RGB[0] - r);
            int dG = Math.abs(mColor.RGB[1] - g);
            int dB = Math.abs(mColor.RGB[2] - b);
            //计算3个值的方差,方差越小,则表示越接近该颜色
            double diff = Math.sqrt(Math.pow(dR, 2) + Math.pow(dG, 2) + Math.pow(dB, 2));
            //找出最小的方差颜色
            if (diff < minDiff) {
                //新的颜色比最小的还小,则将最小替换为新的
                minDiff = diff;
                minColor = mColor;
            }
        }
        return showColor ? minColor.colorCode : minColor.name;
    }

    private List showDirectoryFiles(File file) {
        File[] files = file.listFiles();
        List fileList = new ArrayList<>();
        for (File a : files) {
//            System.out.println(a.getAbsolutePath());
            if (a.isDirectory()) {
                showDirectoryFiles(a);
            }
            fileList.add(a);
        }
        return fileList;
    }

    public static void main(final String[] args) {
        Pic2CMD pic = new Pic2CMD();
        //读取一个文件夹下所有图片格式文件
        File file = new File("C:/Users/Administrator/Desktop/demo");
        for (File file1 : pic.showDirectoryFiles(file)) {
            if (file1.getName().contains("jpg") || file1.getName().contains("png")) {
                //批量生成
                pic.createAsciiPic(file1.getAbsolutePath(), 10, true, true);
            }
        }
    }
}

注释写的还算可读,稍微解释一下原理,首先CMD部分的原理很简单,就是一些特殊的ANSI转义字符可以显示彩色的背景,因此可以在控制台打印出彩色的空格,这个是基础,可以参看上面的链接自己尝试.

然后就是需要告诉控制台我要在哪些地方输出什么颜色的字符,输出多少,说白了就是要解决画画的问题.这一步我采用java实现,我们使用BufferedImage读取一张图片,然后按照我们设定的扫描像素,一格一格的识别图片中的RGB色值,并且我们将图片的RGB色值与控制台可以输出的颜色做一个对比,找到最接近的那个颜色,打印出来就可以了.

因为控制台支持的颜色比较少,只有16种,因此我们是没办法完美的输出图片中的颜色的,所以这边我采用简单的一种类似方差的概念去判断图片中的颜色和哪个控制台颜色最接近,这可能是关键代码了吧(请忽略颜色的中文命名,为了好记).

使用过程中需要注意的点就是:

  1. 生成的.cmd文件貌似只能用在win10及以上的版本,win7好像不支持这些转义字符(不过貌似win7也可以输出彩色字).
  2. 需要转化的像素图尽量颜色和控制台的颜色要相近,不然效果不是很好.附上控制台的颜色支持图:

[好玩的CMD]CMD批处理绘制彩色的像素画_第8张图片

@echo off

echo                     40
echo                     41
echo                     42
echo                     43
echo                     44
echo                     45
echo                     46
echo                     47
echo                     100
echo                     101
echo                     102
echo                     103
echo                     104
echo                     105
echo                     106
echo                     107
pause
  1. 转化图片时,因为每一个图片的最小像素单位可能不一样,所以传入的像素参数需要你自己修改到合适.

最后附上几张像素图和对应已经转化好的代码,大家有兴趣的可以自己再桌面上运行看看_.

@echo off
mode con cols=30 lines=16
title Pokemon
echo                               
echo                               
echo                               
echo                               
echo                               
echo                               
echo                               
echo                               
echo                               
echo                               
echo                               
echo                               
echo                               
echo                               
echo                               
pause

[好玩的CMD]CMD批处理绘制彩色的像素画_第9张图片
上面的代码会画出一个精灵球

@echo off
title Super Man
mode con cols=54 lines=30
echo                                                       
echo                                                       
echo                                                       
echo                                                       
echo                                                       
echo                                                       
echo                                                       
echo                                                       
echo                                                       
echo                                                       
echo                                                       
echo                                                       
echo                                                       
echo                                                       
echo                                                       
echo                                                       
echo                                                       
echo                                                       
echo                                                       
echo                                                       
echo                                                       
echo                                                       
echo                                                       
echo                                                       
echo                                                       
echo                                                       
echo                                                       
echo                                                       
echo                                                       
echo                                                       
pause

[好玩的CMD]CMD批处理绘制彩色的像素画_第10张图片[好玩的CMD]CMD批处理绘制彩色的像素画_第11张图片

上面是画出一个超人,和原图对比,几乎一摸一样吧

好了,大家还有其他什么好看好玩的图也可以尝试自己把它转为cmd格式的,画出来看看

你可能感兴趣的:(cmd,java,好玩的CMD)