图片/视频转txt

154 阅读2分钟

在线体验

前端代码 实现了三种功能

纯前端实现


<!DOCTYPE html>
<html>
<head>
  <title>图片/视频转换为ASCII</title>
  <meta name="viewport" charset="UTF-8" content="width=device-width, initial-scale=0.1">
  <style>
    #image-container {
      font-family: monospace;
      white-space: pre-line;
      text-align: justify;
      font-size: 4px;
      line-height: 6px;
      width: 8000px;
    }
    #file-input {
      display: none;
    }

    #videoFileInput {
      display: none;
    }

    .upload-btn {
      display: inline-block;
      color: white;
      padding: 10px 20px;
      font-size: 30px;
      cursor: pointer;
      border-radius: 5px;
      margin-right: 50px;
    }
    .upload-btn:hover {
      background-color: #18a0ff;
    }

    #canvas2 {
      position: fixed;
      top: 0;
      right: 0;
      z-index: 999;
      display: block;
    }

  </style>
</head>
<body>
<form id="form1">
  <label for="file-input" class="upload-btn" onclick="document.getElementById('form1').reset();"><img src="img.png"></label>
  <input type="file" id="file-input" accept="image/*" />

  <label for="videoFileInput" class="upload-btn" onclick="document.getElementById('form1').reset();"><img src="video.png"></label>
  <input type="file" id="videoFileInput" accept="video/*" />

  <div  class="upload-btn" onclick="openCamera()"><img src="camera.png"></div>

</form>
<canvas id="canvas2" width="640" height="480"></canvas>
<div id="image-container"></div>
<script>
  document.getElementById("file-input").addEventListener("change", function () {
    canvasElement2.style.display = 'none';
    const fileInput = document.getElementById("file-input");
    const file = fileInput.files[0];
    if (file) {
      const reader = new FileReader();
      reader.onload = function (event) {
        const image = new Image();
        image.onload = function () {
          const ascii = convertToASCII(image);
          displayASCII(ascii);
        };
        image.src = event.target.result;
      };
      reader.readAsDataURL(file);
    }
  });

  function convertToASCII(image) {
    const canvas = document.createElement("canvas");
    const ctx = canvas.getContext("2d");
    canvas.width = image.width;
    canvas.height = image.height;
    ctx.drawImage(image, 0, 0);
    const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
    const data = imageData.data;
    let ascii = "";
    for (let i = 0; i < data.length; i += 4) {
      const r = data[i];
      const g = data[i + 1];
      const b = data[i + 2];
      const brightness = Math.round((r + g + b) / 3);
      const character = getCharacter(brightness);
      ascii += character;
      if (i > 0 && (i / 4) % canvas.width === 0) {
        ascii += "\n";
      }
    }
    return ascii;
  }

  function getCharacter(brightness) {
   // const characters = [".", "-", "*", "+", "=", "x", "X", "#", "%", "@", "W"];
    const characters = ["W","@","%","#","X","x","=","+","*", "-", "."];
    const index = Math.round(brightness / 255 * (characters.length - 1));
    return characters[index];
  }

  function displayASCII(ascii) {
    const imageContainer = document.getElementById("image-container");
    imageContainer.textContent = ascii;
  }
  //////////////////////////////////
  const videoFileInput = document.getElementById("videoFileInput");
  const videoElement = document.createElement("video");
  videoElement.preload = "auto";
  videoElement.controls = true;

  videoFileInput.addEventListener("change", (event) => {
    canvasElement2.style.display = 'none';
    const file = event.target.files[0];
    if (file){
      videoElement.src = URL.createObjectURL(file);
      videoElement.addEventListener("canplaythrough", () => {
        canvasElement2.width = videoElement.videoWidth;
        canvasElement2.height = videoElement.videoHeight;
        canvasElement.width = videoElement.videoWidth;
        canvasElement.height = videoElement.videoHeight;
        videoElement.play();
      });
    }
  });


  const canvasElement = document.createElement("canvas");
  const context = canvasElement.getContext("2d");
  const fps = 30;
  const canvasElement2 = document.getElementById("canvas2");
  const context2 = canvasElement2.getContext("2d");
  videoElement.addEventListener("play", () => {
    const interval = setInterval(() => {
      if (videoElement.paused || videoElement.ended) {
        clearInterval(interval);
        return;
      }
      context.drawImage(videoElement, 0, 0, canvasElement.width, canvasElement.height);
      const imageData = context.getImageData(0, 0, canvasElement.width, canvasElement.height);
      // 处理每一帧的图像数据
     // console.log(imageData);
      context2.putImageData(imageData, 0, 0);
      //context.putImageData(imageData, 0, 0);
      // 将ImageData转换为DataURL格式
      const dataURL = canvasElement2.toDataURL();

    // 创建新的Image对象并将其src属性设置为DataURL格式
      const imageElement = new Image();
      imageElement.onload = function () {
        const ascii = convertToASCII(imageElement);
        displayASCII(ascii);
      };
      imageElement.src = dataURL;

    }, 1000 / fps);
  });
  //////////////////////////////////

  function openCamera(){
   // canvasElement2.style.display = 'block';
    canvasElement2.width = 600;
    canvasElement2.height = 450;
    navigator.mediaDevices.getUserMedia({ video: true })
            .then(function(stream) {
              var videoTrack = stream.getVideoTracks()[0];
              var imageCapture = new ImageCapture(videoTrack);
              function drawVideoFrame() {
                imageCapture.grabFrame().then(function(imageBitmap) {
                  context2.drawImage(imageBitmap, 0, 0, canvasElement2.width, canvasElement2.height);
                  // 将ImageData转换为DataURL格式
                  const dataURL = canvasElement2.toDataURL();

                  // 创建新的Image对象并将其src属性设置为DataURL格式
                  const imageElement = new Image();
                  imageElement.onload = function () {
                    const ascii = convertToASCII(imageElement);
                    displayASCII(ascii);
                  };
                  imageElement.src = dataURL;
                  requestAnimationFrame(drawVideoFrame);
                });
              }
              drawVideoFrame();
            })
            .catch(function(err) {
              console.log("无法访问摄像头:" + err);
            });
  }

</script>
</body>
</html>

java版本实现

package websocket.demo.controller;


import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

/**
 * @Author Zhanglele
 * @Date 2020/12/26 14:17
 */
public class GIF {
    public static void main(String[] args) throws IOException {
        String ffmpegPath = "D://soft/ffmpeg.exe";
        //视频文件地址
        String videoPath = "D://mp5/1.mp4";

        String info = info(videoPath, ffmpegPath);
        String[] split = info.split(",");
        Integer frame=Integer.parseInt(split[0]);
        String w=split[1];
        String l=split[2];
        Integer speed=50;//数值越小速度越快
        processImg(videoPath,ffmpegPath,Integer.parseInt(w),Integer.parseInt(l));
        long name = System.currentTimeMillis();
        //解析为TXT文档
        Integer row = txt(name, frame);//fream 视频共多少帧  row 每帧像素高度
        System.out.println("row"+row);
        payer(name,row,frame,speed);
    }
    //播放器
    private static void payer(Long name,Integer row,Integer frame,Integer speed) {
        JFrame ck = new JFrame("txt滚动");
        ck.setBounds(0, 0, 1920, 1080);
        JTextArea are = new JTextArea();
        ck.add(are);
        are.setBounds(0, 0, 1920, 1080);
        are.setForeground(Color.black);
        Font font = new Font("Consolas", Font.BOLD, 7);
        are.setFont(font);
        File file = new File("D://txt/"+name+".txt");
        ck.setVisible(true);
        try {
            FileReader fr = new FileReader(file);
            BufferedReader br = new BufferedReader(fr);
            StringBuffer sb = new StringBuffer();
            int b = 0;
            int a = 0;
            while (b < frame*row) {
                b++;
                a++;
                String str = br.readLine();
                sb.append(str + "\n");
                if (a % row == 0) {
                    String str1 = sb.toString();
                    sb = new StringBuffer("");
                    are.setText(str1);

                    Thread.sleep(speed);
                }
            }
            fr.close();
            br.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static boolean processImg(String veido_path, String ffmpeg_path, Integer w,Integer l) {
        File file = new File(veido_path);
        if (!file.exists()) {
            System.err.println("路径[" + veido_path + "]对应的视频文件不存在!");
            return false;
        }
        List<String> commands = new java.util.ArrayList<String>();
        commands.add(ffmpeg_path);
        commands.add("-y");
        commands.add("-i");
        commands.add(veido_path);
        commands.add("-vf");
        commands.add("scale="+w/2+":"+l/6);
        commands.add("D://mp5/%01d.png");

        try {
            ProcessBuilder builder = new ProcessBuilder();
            builder.command(commands);
            builder.start();
            Thread.sleep(3000L);
            System.out.println("视频分解完成....");
            System.out.println("开始解析为txt字符....");
            Thread.sleep(6000L);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    public static Integer txt(Long name,Integer frame) throws IOException {
        File F = new File("D://txt/"+name+".txt");
        //如果文件不存在,就动态创建文件
        if (!F.exists()) {
            F.createNewFile();
        }
        FileWriter fw = null;
        //writeDate  写入的内容
        Integer row=0;
        for (int i = 1; i < frame; i++) {
            List<List<Integer>> imageGRB = getImageGRB("D://mp5/"+i+".png");
            System.out.println("剩余"+(frame-i)+"帧");
            row = fori(F, fw, imageGRB);
        }
        return row;

    }

    private static Integer fori(File f, FileWriter fw, List<List<Integer>> imageGRB) throws IOException {
        String[] strings = {"M", "N", "H", "Q", "$", "O", "C", "?", "7", ">", "!", ":", "–", ";", "."};
        //String[] strings = {"发", "阿", "的", "分", "他", "吗", "一", "要", "怕", "去", "我", "为", "其", "是", "对"};
        List<List<String>> listStrings = new ArrayList<>();

        try {
            fw = new FileWriter(f, true);
            for (List<Integer> list : imageGRB) {
                    List<String> stringList = new ArrayList<>();
                    for (Integer integer : list) {
                        int floor = (int) Math.floor(integer / 18);
                        //设置为:True,表示写入的时候追加数据
                        //回车并换行
                        fw.write(strings[floor]);
                    }
                    fw.write("\n");

            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fw != null) {
                fw.close();
            }
        }
        return imageGRB.size();
    }

    /**
     * 获取图片RGB数组
     *
     * @param filePath
     * @return
     */

    public static List<List<Integer>> getImageGRB(String filePath) {
        File file = new File(filePath);
        List<List<Integer>> result = new ArrayList<>();
        if (!file.exists()) {
            return result;
        }
        try {
            BufferedImage bufImg = ImageIO.read(file);

            int height = bufImg.getHeight();

            int width = bufImg.getWidth();


            for (int i = 0; i < height; i++) {
                List<Integer> list = new ArrayList<>();
                for (int j = 0; j < width; j++) {
                    Color color = new Color(bufImg.getRGB(j, i));
                    int red = color.getRed();
                    int green = color.getGreen();
                    int blue = color.getBlue();
                    //System.out.println("("+red+" "+green+" "+blue+")");
                    list.add((red + green + blue) / 3);
                }
                result.add(list);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;

    }
    public static String info(String videoPath,String ffmpegPath) {
        //ffmepg工具地址
        Integer frame=0;String w="";String l="";
//        拼接cmd命令语句
        StringBuffer buffer = new StringBuffer();
        buffer.append(ffmpegPath);
        //注意要保留单词之间有空格
        buffer.append(" -i ");
        buffer.append(videoPath);
//        执行命令语句并返回执行结果
        try {
            Process process = Runtime.getRuntime().exec(buffer.toString());
            InputStream in = process.getErrorStream();
            BufferedReader br = new BufferedReader(new InputStreamReader(in));
            String line ;
            Integer time=0;
            System.out.println("视频信息");
            while((line=br.readLine())!=null) {
                // Stream #0.0(und): Video:h264, yuv420p, 960x544, 1223 kb/s, 30 fps, 30 tbr, 600 tbn, 1200 tbc
                //根据
                //根据字符匹配进行切割


                if(line.trim().startsWith("Duration:")){
                    //根据字符匹配进行切割
                    String substring = line.trim().substring(0, line.trim().indexOf(","));
                    int length = substring.split(":").length;
                    String s = substring.split(":")[length - 1];
                    System.out.println("视频时间 = " + s+"秒");
                    time =(int) Math.floor(Double.parseDouble(s));

                }
                //一般包含fps的行就包含分辨率
                if(line.contains("fps")){
                    String definition = line.split(",")[2];
                     w = definition.trim().split("x")[0];
                     l = definition.trim().split("x")[1];
                    System.out.println("分辨率 = " + w+"x"+l);
                    String[] split = line.split(",")[4].trim().split(" ");

                    System.out.println("帧数 = " + time*Integer.parseInt(split[0]));
                    frame = time*Integer.parseInt(split[0]);
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }
return frame+","+w+","+l;
    }
}