@ -0,0 +1,429 @@
package com.fuyuanshen.common.core.utils ;
import javax.imageio.ImageIO ;
import java.awt.* ;
import java.awt.image.BufferedImage ;
import java.io.ByteArrayOutputStream ;
import java.io.File ;
import java.io.IOException ;
import java.io.InputStream ;
import java.util.ArrayList ;
public class ImageWithTextGenerate {
/**
* 生成160*80画布, 嵌入背景图片并居中显示文字( 支持自动换行) , 输出RGB565格式数据
*
* @param text 要显示的文字
* @param fixedLength 固定输出长度(字节数)
* @return RGB565格式的图像数据
*/
public static byte [ ] generate160x80ImageWithText2 ( String text , InputStream backgroundImageInputStream , int fixedLength ) throws IOException {
// 创建160*80的图像
BufferedImage image = new BufferedImage ( 160 , 80 , BufferedImage . TYPE_INT_RGB ) ;
Graphics2D g = image . createGraphics ( ) ;
// 绘制白色背景
g . setColor ( Color . WHITE ) ;
g . fillRect ( 0 , 0 , 160 , 80 ) ;
// 如果提供了背景图片,则绘制背景
if ( backgroundImageInputStream ! = null ) {
BufferedImage backgroundImage = ImageIO . read ( backgroundImageInputStream ) ;
// 缩放并绘制背景图片以适应160*80画布
g . drawImage ( backgroundImage , 0 , 0 , 160 , 80 , null ) ;
}
// 设置文字属性
Font font = new Font ( " 宋体 " , Font . PLAIN , 12 ) ; // 可根据需要调整字体大小
g . setFont ( font ) ;
g . setColor ( new Color ( 255 , 255 , 255 , ( int ) ( 0 . 6 * 255 ) ) ) ;
// 关闭抗锯齿以获得清晰的点阵效果
g . setRenderingHint ( RenderingHints . KEY_TEXT_ANTIALIASING ,
RenderingHints . VALUE_TEXT_ANTIALIAS_OFF ) ;
g . setRenderingHint ( RenderingHints . KEY_RENDERING ,
RenderingHints . VALUE_RENDER_QUALITY ) ;
// 获取字体度量信息
FontMetrics metrics = g . getFontMetrics ( ) ;
int lineHeight = metrics . getHeight ( ) ;
// 文本换行处理
ArrayList < String > lines = wrapText ( text , metrics , 120 ) ; // 160为画布宽度
// 计算垂直居中起始位置
int totalTextHeight = lines . size ( ) * lineHeight ;
int startY = ( 80 - totalTextHeight ) / 2 + metrics . getAscent ( ) ;
// 绘制每一行文字
for ( int i = 0 ; i < lines . size ( ) ; i + + ) {
String line = lines . get ( i ) ;
int lineWidth = metrics . stringWidth ( line ) ;
int x = ( 160 - lineWidth ) / 2 ; // 水平居中
int y = startY + i * lineHeight ;
g . drawString ( line , x , y ) ;
}
g . dispose ( ) ;
// 转换像素数据为RGB565格式( 高位在前)
ByteArrayOutputStream byteStream = new ByteArrayOutputStream ( ) ;
for ( int yCoord = 0 ; yCoord < 80 ; yCoord + + ) {
for ( int xCoord = 0 ; xCoord < 160 ; xCoord + + ) {
int rgb = image . getRGB ( xCoord , yCoord ) ;
// 提取RGB分量
int r = ( rgb > > 16 ) & 0xFF ;
int g1 = ( rgb > > 8 ) & 0xFF ;
int b = rgb & 0xFF ;
// 转换为RGB565( 5位红, 6位绿, 5位蓝)
int r5 = ( r > > 3 ) & 0x1F ;
int g6 = ( g1 > > 2 ) & 0x3F ;
int b5 = ( b > > 3 ) & 0x1F ;
// 组合为16位值
int rgb565 = ( r5 < < 11 ) | ( g6 < < 5 ) | b5 ;
// 高位在前(大端序)写入字节
byteStream . write ( ( rgb565 > > 8 ) & 0xFF ) ; // 高字节
byteStream . write ( rgb565 & 0xFF ) ; // 低字节
}
}
// 调整到固定长度
byte [ ] rawData = byteStream . toByteArray ( ) ;
byte [ ] result = new byte [ fixedLength ] ;
int copyLength = Math . min ( rawData . length , fixedLength ) ;
System . arraycopy ( rawData , 0 , result , 0 , copyLength ) ;
return result ;
}
/**
* 生成160*80画布, 嵌入背景图片并居中显示文字( 支持自动换行) , 输出RGB565格式数据
*
* @param text 要显示的文字
* @param backgroundImagePath 背景图片路径
* @param fixedLength 固定输出长度(字节数)
* @return RGB565格式的图像数据
*/
public static byte [ ] generate160x80ImageWithText ( String text , String backgroundImagePath , int fixedLength ) throws IOException {
// 创建160*80的图像
BufferedImage image = new BufferedImage ( 160 , 80 , BufferedImage . TYPE_INT_RGB ) ;
Graphics2D g = image . createGraphics ( ) ;
// 绘制白色背景
g . setColor ( Color . WHITE ) ;
g . fillRect ( 0 , 0 , 160 , 80 ) ;
// 如果提供了背景图片,则绘制背景
if ( backgroundImagePath ! = null & & ! backgroundImagePath . isEmpty ( ) ) {
File backgroundFile = new File ( backgroundImagePath ) ;
if ( backgroundFile . exists ( ) ) {
BufferedImage backgroundImage = ImageIO . read ( backgroundFile ) ;
// 缩放并绘制背景图片以适应160*80画布
g . drawImage ( backgroundImage , 0 , 0 , 160 , 80 , null ) ;
}
}
// 设置文字属性
Font font = new Font ( " 宋体 " , Font . PLAIN , 12 ) ; // 可根据需要调整字体大小
g . setFont ( font ) ;
g . setColor ( new Color ( 255 , 255 , 255 , ( int ) ( 0 . 6 * 255 ) ) ) ;
// 关闭抗锯齿以获得清晰的点阵效果
g . setRenderingHint ( RenderingHints . KEY_TEXT_ANTIALIASING ,
RenderingHints . VALUE_TEXT_ANTIALIAS_OFF ) ;
g . setRenderingHint ( RenderingHints . KEY_RENDERING ,
RenderingHints . VALUE_RENDER_QUALITY ) ;
// 获取字体度量信息
FontMetrics metrics = g . getFontMetrics ( ) ;
int lineHeight = metrics . getHeight ( ) ;
// 文本换行处理
ArrayList < String > lines = wrapText ( text , metrics , 120 ) ; // 160为画布宽度
// 计算垂直居中起始位置
int totalTextHeight = lines . size ( ) * lineHeight ;
int startY = ( 80 - totalTextHeight ) / 2 + metrics . getAscent ( ) ;
// 绘制每一行文字
for ( int i = 0 ; i < lines . size ( ) ; i + + ) {
String line = lines . get ( i ) ;
int lineWidth = metrics . stringWidth ( line ) ;
int x = ( 160 - lineWidth ) / 2 ; // 水平居中
int y = startY + i * lineHeight ;
g . drawString ( line , x , y ) ;
}
g . dispose ( ) ;
// 转换像素数据为RGB565格式( 高位在前)
ByteArrayOutputStream byteStream = new ByteArrayOutputStream ( ) ;
for ( int yCoord = 0 ; yCoord < 80 ; yCoord + + ) {
for ( int xCoord = 0 ; xCoord < 160 ; xCoord + + ) {
int rgb = image . getRGB ( xCoord , yCoord ) ;
// 提取RGB分量
int r = ( rgb > > 16 ) & 0xFF ;
int g1 = ( rgb > > 8 ) & 0xFF ;
int b = rgb & 0xFF ;
// 转换为RGB565( 5位红, 6位绿, 5位蓝)
int r5 = ( r > > 3 ) & 0x1F ;
int g6 = ( g1 > > 2 ) & 0x3F ;
int b5 = ( b > > 3 ) & 0x1F ;
// 组合为16位值
int rgb565 = ( r5 < < 11 ) | ( g6 < < 5 ) | b5 ;
// 高位在前(大端序)写入字节
byteStream . write ( ( rgb565 > > 8 ) & 0xFF ) ; // 高字节
byteStream . write ( rgb565 & 0xFF ) ; // 低字节
}
}
// 调整到固定长度
byte [ ] rawData = byteStream . toByteArray ( ) ;
byte [ ] result = new byte [ fixedLength ] ;
int copyLength = Math . min ( rawData . length , fixedLength ) ;
System . arraycopy ( rawData , 0 , result , 0 , copyLength ) ;
return result ;
}
/**
* 文本换行处理
*
* @param text 原始文本
* @param metrics 字体度量信息
* @param maxWidth 最大宽度
* @return 换行后的文本行列表
*/
private static ArrayList < String > wrapText ( String text , FontMetrics metrics , int maxWidth ) {
ArrayList < String > lines = new ArrayList < > ( ) ;
String [ ] paragraphs = text . split ( " \ n " ) ;
for ( String paragraph : paragraphs ) {
String [ ] words = paragraph . split ( " (?<= \\ S)(?= \\ s)|(?<= \\ s)(?= \\ S) " ) ;
StringBuilder line = new StringBuilder ( ) ;
for ( String word : words ) {
String testLine = line . toString ( ) + word ;
int lineWidth = metrics . stringWidth ( testLine ) ;
if ( lineWidth < = maxWidth ) {
line . append ( word ) ;
} else {
if ( line . length ( ) > 0 ) {
lines . add ( line . toString ( ) ) ;
line = new StringBuilder ( word ) ;
} else {
// 单个词就超过宽度,需要进一步拆分
lines . addAll ( wrapWord ( word , metrics , maxWidth ) ) ;
}
}
}
if ( line . length ( ) > 0 ) {
lines . add ( line . toString ( ) ) ;
}
}
// 限制最大行数以适应80像素高度
if ( lines . size ( ) > 6 ) { // 假设每行最多13像素高, 80/13约等于6
return ( ArrayList < String > ) lines . subList ( 0 , 6 ) ;
}
return lines ;
}
/**
* 对单个超长词进行拆分
*
* @param word 单词
* @param metrics 字体度量信息
* @param maxWidth 最大宽度
* @return 拆分后的词列表
*/
private static ArrayList < String > wrapWord ( String word , FontMetrics metrics , int maxWidth ) {
ArrayList < String > result = new ArrayList < > ( ) ;
StringBuilder current = new StringBuilder ( ) ;
for ( char c : word . toCharArray ( ) ) {
String testStr = current . toString ( ) + c ;
if ( metrics . stringWidth ( testStr ) < = maxWidth ) {
current . append ( c ) ;
} else {
if ( current . length ( ) > 0 ) {
result . add ( current . toString ( ) ) ;
}
current = new StringBuilder ( String . valueOf ( c ) ) ;
}
}
if ( current . length ( ) > 0 ) {
result . add ( current . toString ( ) ) ;
}
return result ;
}
/**
* 生成160*80画布, 嵌入背景图片并居中显示文字, 输出RGB565格式数据( 支持InputStream)
*
* @param text 要显示的文字
* @param backgroundImageInputStream 背景图片输入流
* @param fixedLength 固定输出长度(字节数)
* @return RGB565格式的图像数据
*/
public static byte [ ] generate160x80ImageWithText ( String text , InputStream backgroundImageInputStream , int fixedLength ) throws IOException {
// 创建160*80的图像
BufferedImage image = new BufferedImage ( 160 , 80 , BufferedImage . TYPE_INT_RGB ) ;
Graphics2D g = image . createGraphics ( ) ;
// 绘制白色背景
g . setColor ( Color . WHITE ) ;
g . fillRect ( 0 , 0 , 160 , 80 ) ;
// 如果提供了背景图片,则绘制背景
if ( backgroundImageInputStream ! = null ) {
BufferedImage backgroundImage = ImageIO . read ( backgroundImageInputStream ) ;
// 缩放并绘制背景图片以适应160*80画布
g . drawImage ( backgroundImage , 0 , 0 , 160 , 80 , null ) ;
}
// 设置文字属性
Font font = new Font ( " 宋体 " , Font . PLAIN , 16 ) ; // 可根据需要调整字体大小
g . setFont ( font ) ;
g . setColor ( Color . BLACK ) ;
// 关闭抗锯齿以获得清晰的点阵效果
g . setRenderingHint ( RenderingHints . KEY_TEXT_ANTIALIASING ,
RenderingHints . VALUE_TEXT_ANTIALIAS_OFF ) ;
g . setRenderingHint ( RenderingHints . KEY_RENDERING ,
RenderingHints . VALUE_RENDER_QUALITY ) ;
// 获取字体度量信息
FontMetrics metrics = g . getFontMetrics ( ) ;
// 计算文字的宽度和高度
int textWidth = metrics . stringWidth ( text ) ;
int textHeight = metrics . getHeight ( ) ;
// 计算居中位置
int x = ( 160 - textWidth ) / 2 ; // 水平居中
int y = ( 80 - textHeight ) / 2 + metrics . getAscent ( ) ; // 垂直居中
// 绘制文字
g . drawString ( text , x , y ) ;
g . dispose ( ) ;
// 转换像素数据为RGB565格式( 高位在前)
ByteArrayOutputStream byteStream = new ByteArrayOutputStream ( ) ;
for ( int yCoord = 0 ; yCoord < 80 ; yCoord + + ) {
for ( int xCoord = 0 ; xCoord < 160 ; xCoord + + ) {
int rgb = image . getRGB ( xCoord , yCoord ) ;
// 提取RGB分量
int r = ( rgb > > 16 ) & 0xFF ;
int g1 = ( rgb > > 8 ) & 0xFF ;
int b = rgb & 0xFF ;
// 转换为RGB565( 5位红, 6位绿, 5位蓝)
int r5 = ( r > > 3 ) & 0x1F ;
int g6 = ( g1 > > 2 ) & 0x3F ;
int b5 = ( b > > 3 ) & 0x1F ;
// 组合为16位值
int rgb565 = ( r5 < < 11 ) | ( g6 < < 5 ) | b5 ;
// 高位在前(大端序)写入字节
byteStream . write ( ( rgb565 > > 8 ) & 0xFF ) ; // 高字节
byteStream . write ( rgb565 & 0xFF ) ; // 低字节
}
}
// 调整到固定长度
byte [ ] rawData = byteStream . toByteArray ( ) ;
byte [ ] result = new byte [ fixedLength ] ;
int copyLength = Math . min ( rawData . length , fixedLength ) ;
System . arraycopy ( rawData , 0 , result , 0 , copyLength ) ;
return result ;
}
/**
* 将RGB565格式的字节数组转换为BufferedImage
*
* @param data RGB565格式的数据
* @param height 图像高度
* @param width 图像宽度
* @return 转换后的BufferedImage
*/
public static BufferedImage convertByteArrayToImage ( byte [ ] data , int height , int width ) {
if ( data = = null | | data . length = = 0 ) {
return new BufferedImage ( 1 , 1 , BufferedImage . TYPE_INT_RGB ) ;
}
// 创建图像
BufferedImage image = new BufferedImage ( width , height , BufferedImage . TYPE_INT_RGB ) ;
// 处理RGB565数据
int dataIndex = 0 ;
for ( int y = 0 ; y < height ; y + + ) {
for ( int x = 0 ; x < width ; x + + ) {
// 每个像素占2个字节
if ( dataIndex + 1 > = data . length ) {
return image ;
}
// 读取两个字节组成RGB565值
int highByte = data [ dataIndex + + ] & 0xFF ;
int lowByte = data [ dataIndex + + ] & 0xFF ;
int rgb565 = ( highByte < < 8 ) | lowByte ;
// 将RGB565转换为RGB888
int r = ( ( rgb565 > > 11 ) & 0x1F ) < < 3 ;
int g = ( ( rgb565 > > 5 ) & 0x3F ) < < 2 ;
int b = ( rgb565 & 0x1F ) < < 3 ;
int rgb = ( r < < 16 ) | ( g < < 8 ) | b ;
image . setRGB ( x , y , rgb ) ;
}
}
return image ;
}
public static void main ( String [ ] args ) throws IOException {
// ... 原有代码 ...
// 测试生成160*80画布, 嵌入背景图片并居中显示文字
// String text = "现在危险,停止救援紧急撤离至安全区域";
String text = " 现在危险,停止救援,紧急撤离至安全区域! " ;
String backgroundImagePath = " D: \\ background.png " ; // 替换为实际背景图片路径
byte [ ] imageData = generate160x80ImageWithText ( text , backgroundImagePath , 25600 ) ;
System . out . println ( " 生成的160*80 RGB565图像数据: " ) ;
System . out . println ( " 数据长度: " + imageData . length + " 字节 " ) ;
// 生成预览图片
// 生成预览图片
BufferedImage image160x80 = convertByteArrayToImage ( imageData , 80 , 160 ) ;
ImageIO . write ( image160x80 , " PNG " , new File ( " D: \\ bitmap_160x80_preview.png " ) ) ;
// System.out.println("成功生成160*80预览图片: D:\\bitmap_160x80_preview.png");
// 转换为十进制数组
// int[] decimalArray = convertHexToDecimal(imageData);
// System.out.println("生成的十进制数据( 前50个) :");
// System.out.println(Arrays.toString(Arrays.copyOf(decimalArray, Math.min(50, decimalArray.length))));
//
// // 将数据分割成512字节的块
// List<byte[]> chunks = splitByteArrayIntoChunks(imageData, 512);
// printChunkInfo(chunks);
//
// // 示例:获取特定块的数据
// byte[] specificChunk = getChunk(imageData, 0, 512); // 获取第1块( 索引0)
// System.out.println("第1块数据大小: " + specificChunk.length + " 字节");
}
}