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

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

微信截图20191121133327.png
微信截图20191121133414.png
微信截图20191121133037.png
微信截图20191121133015.png微信截图20191121132953.png微信截图20191121132944.png微信截图20191121133641.png


其实也是闲着无聊,偶然间看到网上一篇博客,介绍了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<MColor> 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<File> showDirectoryFiles(File file) {
        File[] files = file.listFiles();
        List<File> 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. 需要转化的像素图尽量颜色和控制台的颜色要相近,不然效果不是很好.附上控制台的颜色支持图:

微信截图20191121140716.png

@echo off

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

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

@echo off
mode con cols=30 lines=16
title Pokemon
echo [107m  [107m  [107m  [40m  [40m  [40m  [40m  [40m  [40m  [40m  [40m  [40m  [107m  [107m  [107m  
echo [107m  [107m  [40m  [41m  [41m  [41m  [41m  [41m  [41m  [41m  [41m  [41m  [40m  [107m  [107m  
echo [107m  [40m  [41m  [41m  [41m  [41m  [41m  [41m  [41m  [41m  [41m  [41m  [41m  [40m  [107m  
echo [40m  [41m  [41m  [41m  [41m  [41m  [41m  [41m  [41m  [41m  [41m  [41m  [41m  [41m  [40m  
echo [40m  [41m  [41m  [41m  [41m  [41m  [41m  [41m  [41m  [41m  [41m  [41m  [41m  [41m  [40m  
echo [40m  [41m  [41m  [41m  [41m  [41m  [41m  [41m  [41m  [41m  [41m  [41m  [41m  [41m  [40m  
echo [40m  [41m  [41m  [41m  [41m  [41m  [40m  [40m  [40m  [41m  [41m  [41m  [41m  [41m  [40m  
echo [40m  [40m  [40m  [40m  [40m  [40m  [40m  [107m  [40m  [40m  [40m  [40m  [40m  [40m  [40m  
echo [40m  [107m  [107m  [107m  [107m  [107m  [40m  [40m  [40m  [107m  [107m  [107m  [107m  [107m  [40m  
echo [40m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [40m  
echo [40m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [40m  
echo [40m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [40m  
echo [107m  [40m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [40m  [107m  
echo [107m  [107m  [40m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [40m  [107m  [107m  
echo [107m  [107m  [107m  [40m  [40m  [40m  [40m  [40m  [40m  [40m  [40m  [40m  [107m  [107m  [107m  
pause

微信截图20191121141228.png
上面的代码会画出一个精灵球

@echo off
title Super Man
mode con cols=54 lines=30
echo [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  
echo [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  
echo [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  
echo [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [40m  [40m  [40m  [40m  [40m  [40m  [40m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  
echo [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [40m  [40m  [40m  [40m  [40m  [40m  [40m  [40m  [40m  [40m  [40m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  
echo [107m  [107m  [107m  [107m  [107m  [107m  [107m  [40m  [40m  [40m  [40m  [40m  [40m  [40m  [40m  [40m  [40m  [40m  [40m  [40m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  
echo [107m  [107m  [107m  [107m  [107m  [107m  [40m  [40m  [40m  [40m  [40m  [40m  [40m  [40m  [40m  [40m  [40m  [40m  [40m  [40m  [40m  [107m  [107m  [107m  [107m  [107m  [107m  
echo [107m  [107m  [107m  [107m  [107m  [107m  [40m  [40m  [40m  [40m  [40m  [40m  [40m  [103m  [103m  [40m  [40m  [40m  [40m  [40m  [40m  [107m  [107m  [107m  [107m  [107m  [107m  
echo [107m  [107m  [107m  [107m  [107m  [107m  [40m  [40m  [40m  [103m  [40m  [103m  [103m  [103m  [103m  [103m  [103m  [40m  [40m  [40m  [40m  [107m  [107m  [107m  [107m  [107m  [107m  
echo [107m  [107m  [107m  [107m  [107m  [107m  [40m  [40m  [103m  [103m  [40m  [40m  [103m  [103m  [103m  [103m  [103m  [103m  [40m  [40m  [40m  [107m  [107m  [107m  [107m  [107m  [107m  
echo [107m  [107m  [107m  [107m  [107m  [107m  [40m  [103m  [103m  [103m  [103m  [40m  [103m  [103m  [103m  [103m  [103m  [103m  [103m  [103m  [40m  [107m  [107m  [107m  [107m  [107m  [107m  
echo [107m  [107m  [107m  [107m  [107m  [107m  [40m  [103m  [103m  [103m  [103m  [103m  [103m  [103m  [103m  [103m  [103m  [103m  [103m  [103m  [40m  [107m  [107m  [107m  [107m  [107m  [107m  
echo [107m  [107m  [107m  [107m  [107m  [107m  [40m  [103m  [103m  [103m  [40m  [107m  [103m  [103m  [103m  [40m  [107m  [103m  [103m  [103m  [40m  [107m  [107m  [107m  [107m  [107m  [107m  
echo [107m  [107m  [107m  [107m  [107m  [107m  [107m  [40m  [103m  [103m  [40m  [40m  [103m  [103m  [103m  [40m  [40m  [103m  [103m  [40m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  
echo [107m  [107m  [107m  [107m  [107m  [107m  [107m  [40m  [103m  [103m  [103m  [103m  [103m  [103m  [103m  [103m  [103m  [103m  [103m  [40m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  
echo [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [40m  [103m  [103m  [103m  [103m  [103m  [103m  [103m  [103m  [103m  [40m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  
echo [107m  [107m  [107m  [107m  [107m  [107m  [107m  [40m  [41m  [40m  [40m  [103m  [103m  [103m  [103m  [103m  [40m  [40m  [41m  [40m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  
echo [107m  [107m  [107m  [107m  [107m  [107m  [40m  [41m  [40m  [44m  [44m  [40m  [40m  [40m  [40m  [40m  [44m  [44m  [40m  [41m  [40m  [107m  [107m  [107m  [107m  [107m  [107m  
echo [107m  [107m  [107m  [107m  [107m  [40m  [41m  [40m  [44m  [44m  [44m  [41m  [41m  [41m  [41m  [41m  [44m  [44m  [44m  [40m  [41m  [40m  [107m  [107m  [107m  [107m  [107m  
echo [107m  [107m  [107m  [107m  [40m  [41m  [40m  [44m  [44m  [40m  [44m  [41m  [43m  [43m  [43m  [41m  [44m  [40m  [44m  [44m  [40m  [41m  [40m  [107m  [107m  [107m  [107m  
echo [107m  [107m  [107m  [40m  [41m  [40m  [103m  [103m  [44m  [40m  [44m  [44m  [41m  [41m  [41m  [44m  [44m  [40m  [44m  [103m  [103m  [40m  [41m  [40m  [107m  [107m  [107m  
echo [107m  [107m  [40m  [41m  [41m  [40m  [103m  [103m  [40m  [40m  [44m  [44m  [44m  [41m  [44m  [44m  [44m  [40m  [40m  [103m  [103m  [40m  [41m  [41m  [40m  [107m  [107m  
echo [107m  [107m  [40m  [41m  [41m  [41m  [40m  [40m  [41m  [40m  [44m  [44m  [44m  [44m  [44m  [44m  [44m  [40m  [41m  [40m  [40m  [41m  [41m  [41m  [40m  [107m  [107m  
echo [107m  [107m  [40m  [41m  [41m  [41m  [41m  [41m  [41m  [40m  [43m  [41m  [43m  [43m  [43m  [41m  [43m  [40m  [41m  [41m  [41m  [41m  [41m  [41m  [40m  [107m  [107m  
echo [107m  [107m  [107m  [40m  [41m  [41m  [41m  [41m  [40m  [44m  [44m  [44m  [44m  [44m  [44m  [44m  [44m  [44m  [40m  [41m  [41m  [41m  [41m  [40m  [107m  [107m  [107m  
echo [107m  [107m  [107m  [40m  [41m  [41m  [41m  [41m  [40m  [41m  [44m  [44m  [40m  [40m  [40m  [44m  [44m  [41m  [40m  [41m  [41m  [41m  [41m  [40m  [107m  [107m  [107m  
echo [107m  [107m  [107m  [40m  [40m  [41m  [41m  [40m  [40m  [41m  [41m  [40m  [41m  [41m  [41m  [40m  [41m  [41m  [40m  [40m  [41m  [41m  [40m  [40m  [107m  [107m  [107m  
echo [107m  [107m  [107m  [107m  [107m  [40m  [40m  [40m  [41m  [41m  [41m  [40m  [40m  [40m  [40m  [40m  [41m  [41m  [41m  [40m  [40m  [40m  [107m  [107m  [107m  [107m  [107m  
echo [107m  [107m  [107m  [107m  [107m  [107m  [107m  [40m  [40m  [40m  [40m  [40m  [107m  [107m  [107m  [40m  [40m  [40m  [40m  [40m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  
echo [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  [107m  
pause

微信截图20191121141321.png6.png

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

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

SSD1106是一种常用的OLED显示屏驱动芯片,它支持使用SPI或I2C进行通信。下面是一个使用C语言编写的SSD1106 OLED显示屏画点的函数示例: ```c #include <stdio.h> #include <wiringPi.h> #include <wiringPiSPI.h> #define SSD1106_SPI_CHANNEL 0 #define SSD1106_SPI_SPEED 8000000 void ssd1106_draw_pixel(int x, int y, int color) { // 计算字节偏移量和位偏移量 int byte_offset = (y / 8) * 128 + x; int bit_offset = y % 8; // 设置SPI通信速度 wiringPiSPISetup(SSD1106_SPI_CHANNEL, SSD1106_SPI_SPEED); // 选择绘制区域 wiringPiSPIDataRW(SSD1106_SPI_CHANNEL, "\x21\x00\x7F", 3); // 设置绘制位置 unsigned char set_x_cmd[] = {0x00, (unsigned char)(0x10 + (x >> 4)), (unsigned char)(0x00 + (x & 0x0F))}; wiringPiSPIDataRW(SSD1106_SPI_CHANNEL, set_x_cmd, sizeof(set_x_cmd)); unsigned char set_y_cmd[] = {0x00, (unsigned char)(0xB0 + (y >> 3)), (unsigned char)(bit_offset & 0x07)}; wiringPiSPIDataRW(SSD1106_SPI_CHANNEL, set_y_cmd, sizeof(set_y_cmd)); // 绘制像素点 unsigned char draw_cmd[2]; draw_cmd[0] = 0x40; draw_cmd[1] = color ? 0xFF : 0x00; wiringPiSPIDataRW(SSD1106_SPI_CHANNEL, draw_cmd, sizeof(draw_cmd)); } ``` 这个函数使用了wiringPi库进行SPI通信,你需要在编译前安装并配置wiringPi库。这个函数可以通过指定像素点的坐标和颜色来在SSD1106 OLED显示屏上绘制点。其中,x和y表示像素点的坐标,color为1表示白色,color为0表示黑色。 请注意,具体的驱动细节可能因不同的硬件平台和库的使用方式而有所差异,请根据你的实际情况进行适当的调整。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值