1. 程式人生 > >用Java做被抖音帶火的“字元舞蹈”

用Java做被抖音帶火的“字元舞蹈”

這個是從抖音上學來的,一開始刷抖音,遇到不少字串跳舞的視訊,因此來實踐一下

主要分為三個部分

靜態圖片轉靜態圖片

gif轉gif

視訊轉視訊

靜態圖片轉靜態圖片

其實原理很簡單,讀取圖片的畫素,新建一張大小一樣的圖片,根據原影象素的灰度,決定是不是要顯示出來,並在新圖相應的位置新增字元,這樣就完成了

藉助前輩寫的工具,主要包含一下四個類:

AnimatedGifEncoder、GifDecoder、LZWEncoder、NeuQuant

環境:

JDK 1.8

注:Java原生程式碼實現使用jdk內部的GIFImageReader、GIFImageWriter等類,maven在編譯的時候會提示這是sun公司的私有API,在1.7、1.8版的JDK中已經刪除,所以是有風險的。在此使用ImageIO這個類來進行圖片的操作。

主要程式碼如下所示:

import java.awt.Color;

import java.awt.Font;

import java.awt.Graphics;

import java.awt.image.BufferedImage;

import java.io.File;

import java.io.FileInputStream;

import java.io.IOException;

import javax.imageio.ImageIO;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

/**

* @ClassName: ImgUtil

* @Description: TODO

* @author jiang

* @date 2018年8月14日 下午10:15:56

*

*/

public class ImgUtil {

static Logger logger = LoggerFactory.getLogger(ImgUtil.class);

public static boolean toTextImg(String inputFile, String outputFile, final String base, int threshold) {

// String blackFile = "F:/123/head_black.png";

BufferedImage src = null;

BufferedImage tag = null;

boolean res = false;

try {

src = ImageIO.read(new FileInputStream(inputFile));

int[] rgb = new int[3];

int width = src.getWidth();

int height = src.getHeight();

int minx = src.getMinX();

int miny = src.getMinY();

// 黑白化:

/*-

src = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), ull).filter(src, null);

res = ImageIO.write(src, blackFile.substring(blackFile.lastIndexOf(".") + 1), new File(blackFile));

src = ImageIO.read(new FileInputStream(blackFile));*/

tag = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR);

Graphics g = tag.getGraphics();

g.setFont(new Font("微軟雅黑", Font.PLAIN, 10));// 設定字型

g.setColor(Color.BLUE);// 設定顏色

for (int x = minx; x < width; x += 6) {

for (int y = miny; y < height; y += 6) {

int pixel = src.getRGB(x, y); // 下面三行程式碼將一個數字轉換為RGB數字

rgb[0] = (pixel & 0xff0000) >> 16;// red

rgb[1] = (pixel & 0xff00) >> 8;// green

rgb[2] = (pixel & 0xff);// blue

final float gray = 0.299f * rgb[0] + 0.578f * rgb[1] + 0.114f * rgb[2];

final int index = Math.round(gray * (base.length() + 1) / 255);

// logger.debug("{},{}",index,base.length() / threshold);

if (index <= threshold) {

g.drawString(String.valueOf(base.charAt(index % base.length())), x, y);// 文字的編寫及位置

}

/*-

if (rgb[0] + rgb[1] + rgb[2] <= 500) {

System.out.println("i=" + i + ",j=" + j + ":(" + rgb[0] + "," + rgb[1] + "," + rgb[2] + ")");

g.drawString("v", i, j);// 文字的編寫及位置

}*/

}

}

g.dispose();

// 輸出圖片

res = ImageIO.write(tag, outputFile.substring(outputFile.lastIndexOf(".") + 1),

new File(outputFile));

logger.debug("字元化結果:{}", res);

} catch (IOException e) {

logger.error("err", e);

return false;

}

return true;

}

}

程式碼的思路很簡單,src.getRGB(x, y)獲取具體畫素點的顏色值,共六位,每兩位一個顏色值,依次是red green blue,類似的使用(pixel & 0xff0000) >> 16獲取第一位的紅色等,根據灰度公式Gray = R*0.299 + G*0.587 + B*0.114計算灰度(百度顏色灰度公式,有很多來計算心理灰度的解決方案),選擇合適的灰度替換上合適的字元即可!