From f35897a9cf159067e1d24b5e08a6389aaf1b09bd Mon Sep 17 00:00:00 2001 From: hongawen <83944980@qq.com> Date: Mon, 16 Jun 2025 13:53:34 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=85=AC=E5=85=B1=E6=96=B9?= =?UTF-8?q?=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/njcn/common/utils/PubUtils.java | 11 +- .../common/utils/images/ImageConverter.java | 202 ++++++++++++++++++ 2 files changed, 211 insertions(+), 2 deletions(-) create mode 100644 njcn-common/src/main/java/com/njcn/common/utils/images/ImageConverter.java diff --git a/njcn-common/src/main/java/com/njcn/common/utils/PubUtils.java b/njcn-common/src/main/java/com/njcn/common/utils/PubUtils.java index 3cc15ff..e50c723 100644 --- a/njcn-common/src/main/java/com/njcn/common/utils/PubUtils.java +++ b/njcn-common/src/main/java/com/njcn/common/utils/PubUtils.java @@ -4,6 +4,7 @@ import java.math.BigDecimal; import java.math.RoundingMode; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; /** @@ -19,7 +20,10 @@ public class PubUtils { * @param i 保留的位数 * @param value double原值 */ - public static double doubleRound(int i, double value) { + public static Double doubleRound(int i, Double value) { + if (Objects.isNull(value)) { + return null; + } BigDecimal bp = new BigDecimal(value); return bp.setScale(i, RoundingMode.HALF_UP).doubleValue(); } @@ -30,7 +34,10 @@ public class PubUtils { * @param i 保留的位数 * @param value double原值 */ - public static String doubleRoundStr(int i, double value) { + public static String doubleRoundStr(int i, Double value) { + if (Objects.isNull(value)) { + return null; + } BigDecimal bp = new BigDecimal(value); return bp.setScale(i, RoundingMode.HALF_UP).toPlainString(); } diff --git a/njcn-common/src/main/java/com/njcn/common/utils/images/ImageConverter.java b/njcn-common/src/main/java/com/njcn/common/utils/images/ImageConverter.java new file mode 100644 index 0000000..013a208 --- /dev/null +++ b/njcn-common/src/main/java/com/njcn/common/utils/images/ImageConverter.java @@ -0,0 +1,202 @@ +package com.njcn.common.utils.images; + + +import java.awt.image.BufferedImage; +import java.io.*; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +/** + * @author hongawen + * @version 1.0 + * @data 2025/6/16 13:45 + * + * 图片格式转换,目前主要用于BufferedImage转bmp、bmp转BIN + */ +public class ImageConverter { + + /** + * 将BufferedImage转换为BMP格式的字节数组 + * @param image BufferedImage对象 + * @return BMP格式的字节数组 + * @throws IOException 如果转换过程中发生IO错误 + */ + public static byte[] convertToBMP(BufferedImage image) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + // 写入BMP文件头 + writeBMPHeader(baos, image.getWidth(), image.getHeight()); + + // 写入像素数据 + for (int y = image.getHeight() - 1; y >= 0; y--) { + for (int x = 0; x < image.getWidth(); x++) { + int rgb = image.getRGB(x, y); + // 写入BGR格式(BMP格式要求) + // B + baos.write(rgb & 0xFF); + // G + baos.write((rgb >> 8) & 0xFF); + // R + baos.write((rgb >> 16) & 0xFF); + } + // 行对齐(每行必须是4字节的倍数) + int padding = (4 - (image.getWidth() * 3) % 4) % 4; + for (int i = 0; i < padding; i++) { + baos.write(0); + } + } + + return baos.toByteArray(); + } + + /** + * 将BMP格式的字节数组转换为BIN格式 + * @param bmpData BMP格式的字节数组 + * @return BIN格式的字节数组 + */ + public static byte[] convertBMPToBIN(byte[] bmpData) { + // 跳过BMP文件头(54字节) + int offset = 54; + int width = ByteBuffer.wrap(bmpData, 18, 4).order(ByteOrder.LITTLE_ENDIAN).getInt(); + int height = ByteBuffer.wrap(bmpData, 22, 4).order(ByteOrder.LITTLE_ENDIAN).getInt(); + + // 计算每行的字节数(包括对齐) + int rowSize = ((width * 3 + 3) / 4) * 4; + + // 创建BIN数据数组 + byte[] binData = new byte[width * height]; + int binIndex = 0; + + // 转换像素数据 + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + int bmpIndex = offset + (height - 1 - y) * rowSize + x * 3; + // 将BGR转换为灰度值 + int b = bmpData[bmpIndex] & 0xFF; + int g = bmpData[bmpIndex + 1] & 0xFF; + int r = bmpData[bmpIndex + 2] & 0xFF; + // 使用加权平均计算灰度值 + int gray = (int) (0.299 * r + 0.587 * g + 0.114 * b); + // 二值化(阈值设为128) + binData[binIndex++] = (byte) (gray > 128 ? 1 : 0); + } + } + + return binData; + } + + /** + * 将BufferedImage直接转换为BIN格式 + * @param image BufferedImage对象 + * @return BIN格式的字节数组 + * @throws IOException 如果转换过程中发生IO错误 + */ + public static byte[] convertToBIN(BufferedImage image) throws IOException { + byte[] bmpData = convertToBMP(image); + return convertBMPToBIN(bmpData); + } + + /** + * 写入BMP文件头 + * @param out 输出流 + * @param width 图片宽度 + * @param height 图片高度 + * @throws IOException 如果写入过程中发生IO错误 + */ + private static void writeBMPHeader(OutputStream out, int width, int height) throws IOException { + // 文件头(14字节) + out.write('B'); + out.write('M'); + writeInt(out, 54 + width * height * 3); // 文件大小 + writeInt(out, 0); // 保留 + writeInt(out, 54); // 数据偏移量 + + // 信息头(40字节) + writeInt(out, 40); // 信息头大小 + writeInt(out, width); // 宽度 + writeInt(out, height); // 高度 + writeShort(out, 1); // 颜色平面数 + writeShort(out, 24); // 每像素位数 + writeInt(out, 0); // 压缩方式 + writeInt(out, width * height * 3); // 图像数据大小 + writeInt(out, 0); // 水平分辨率 + writeInt(out, 0); // 垂直分辨率 + writeInt(out, 0); // 使用的颜色数 + writeInt(out, 0); // 重要颜色数 + } + + /** + * 写入一个整数(小端序) + * @param out 输出流 + * @param value 要写入的整数 + * @throws IOException 如果写入过程中发生IO错误 + */ + private static void writeInt(OutputStream out, int value) throws IOException { + out.write(value & 0xFF); + out.write((value >> 8) & 0xFF); + out.write((value >> 16) & 0xFF); + out.write((value >> 24) & 0xFF); + } + + /** + * 写入一个短整数(小端序) + * @param out 输出流 + * @param value 要写入的短整数 + * @throws IOException 如果写入过程中发生IO错误 + */ + private static void writeShort(OutputStream out, int value) throws IOException { + out.write(value & 0xFF); + out.write((value >> 8) & 0xFF); + } + + + /** + * 将BufferedImage保存为BMP文件 + * @param image BufferedImage对象 + * @param filePath 保存路径 + * @throws IOException 如果保存过程中发生IO错误 + */ + public static void saveAsBMP(BufferedImage image, String filePath) throws IOException { + byte[] bmpData = convertToBMP(image); + try (FileOutputStream fos = new FileOutputStream(filePath)) { + fos.write(bmpData); + } + } + + /** + * 将BufferedImage保存为BIN文件 + * @param image BufferedImage对象 + * @param filePath 保存路径 + * @throws IOException 如果保存过程中发生IO错误 + */ + public static void saveAsBIN(BufferedImage image, String filePath) throws IOException { + byte[] binData = convertToBIN(image); + try (FileOutputStream fos = new FileOutputStream(filePath)) { + fos.write(binData); + } + } + + /** + * 将BMP数据保存为文件 + * @param bmpData BMP格式的字节数组 + * @param filePath 保存路径 + * @throws IOException 如果保存过程中发生IO错误 + */ + public static void saveBMPToFile(byte[] bmpData, String filePath) throws IOException { + try (FileOutputStream fos = new FileOutputStream(filePath)) { + fos.write(bmpData); + } + } + + /** + * 将BIN数据保存为文件 + * @param binData BIN格式的字节数组 + * @param filePath 保存路径 + * @throws IOException 如果保存过程中发生IO错误 + */ + public static void saveBINToFile(byte[] binData, String filePath) throws IOException { + try (FileOutputStream fos = new FileOutputStream(filePath)) { + fos.write(binData); + } + } +}