1
0

发送设备信息代码实现

This commit is contained in:
2025-08-04 15:35:59 +08:00
parent 6413888a1c
commit 57f074995e
10 changed files with 621 additions and 22 deletions

View File

@ -242,7 +242,7 @@ public class Bitmap80x12Generator {
return byteListToArray(byteList);
}
private static byte[] byteListToArray(List<Byte> byteList) {
public static byte[] byteListToArray(List<Byte> byteList) {
byte[] result = new byte[byteList.size()];
for (int i = 0; i < byteList.size(); i++) {
result[i] = byteList.get(i);

View File

@ -33,7 +33,7 @@ public class ImageToCArrayConverter {
public static void main(String[] args) throws IOException {
byte[] largeData = convertImageToCArray("E:\\workspace\\6170_强光_160_80_2.jpg", 160, 80,25600);
byte[] largeData = convertImageToCArray("E:\\workspace\\demo.png", 160, 80,25600);
System.out.println("长度:"+largeData.length);
System.out.println("原始数据大小: " + largeData.length + " 字节");

View File

@ -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;
// 转换为RGB5655位红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;
// 转换为RGB5655位红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;
// 转换为RGB5655位红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 + " 字节");
}
}