吉安感知网项目-后端
xiebin
2026-01-06 d207a86cdf1ab52ef8cb7cd83bad8fceab8038cf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
package org.sxkj.common.utils;
 
import it.geosolutions.imageio.plugins.tiff.TIFFImageWriteParam;
import org.apache.commons.imaging.ImageFormats;
import org.apache.commons.imaging.ImageReadException;
import org.apache.commons.imaging.ImageWriteException;
import org.apache.commons.imaging.Imaging;
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.plugins.jpeg.JPEGImageWriteParam;
import javax.imageio.stream.ImageOutputStream;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
 
/**
 * tif 图片压缩工具类
 * @author zhongrj
 * @date 2025-05-20
 */
public class TifCompressorUtils {
 
    /**
     * tif 图片压缩
     * @param inputFile
     * @param targetSizeKB
     * @param targetName 目标名称 "_samll.tif"
     * @return
     * @throws IOException
     */
    public static File compressTif(File inputFile, int targetSizeKB,String targetName) throws IOException {
        // 读取原始图像并保留原始类型
        BufferedImage originalImage = null;
        try (InputStream is = new BufferedInputStream(new FileInputStream(inputFile))) {
            originalImage = Imaging.getBufferedImage(is);
        } catch (ImageReadException e) {
            e.printStackTrace();
        }
 
        // 创建与原始图像类型相同的新图像
        BufferedImage image = new BufferedImage(
            originalImage.getWidth(),
            originalImage.getHeight(),
            originalImage.getType() == 0 ? BufferedImage.TYPE_INT_RGB : originalImage.getType()
        );
 
        // 绘制原始图像到新图像,填充白色背景
        Graphics2D g = image.createGraphics();
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, image.getWidth(), image.getHeight());
        g.drawImage(originalImage, 0, 0, null);
        g.dispose();
 
        // 计算压缩参数
        long targetSizeBytes = targetSizeKB * 1024L;
        long originalSizeBytes = inputFile.length();
        double compressionRatio = (double) targetSizeBytes / originalSizeBytes;
 
        File outputFile = new File(inputFile.getParent(), inputFile.getName().replace(".tif", targetName));
        int attempts = 0;
        int maxAttempts = 5;
        float quality = 0.8f;
 
        do {
            // 调整尺寸
            int targetWidth = (int) (image.getWidth() * Math.sqrt(compressionRatio));
            int targetHeight = (int) (image.getHeight() * Math.sqrt(compressionRatio));
 
            // 创建压缩图像并确保白色背景
            BufferedImage compressedImage = new BufferedImage(
                targetWidth,
                targetHeight,
                image.getType() == 0 ? BufferedImage.TYPE_INT_RGB : image.getType()
            );
 
            Graphics2D g2 = compressedImage.createGraphics();
            g2.setColor(Color.WHITE);
            g2.fillRect(0, 0, targetWidth, targetHeight);
            g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
                RenderingHints.VALUE_INTERPOLATION_BILINEAR);
            g2.drawImage(image, 0, 0, targetWidth, targetHeight, null);
            g2.dispose();
 
            // 保存为TIF
            saveAsTiff(compressedImage, outputFile, quality);
 
            // 检查文件大小
            long compressedSize = outputFile.length();
            if (compressedSize <= targetSizeBytes || attempts >= maxAttempts) {
                break;
            }
 
            quality *= 0.7f;
            compressionRatio *= 0.8f;
            attempts++;
 
        } while (true);
 
        return outputFile;
    }
 
 
    /**
     * 将图像保存为TIF格式
     */
    private static void saveAsTiff(BufferedImage image, File outputFile, float quality) throws IOException {
        ImageWriter writer = ImageIO.getImageWritersByFormatName("TIFF").next();
        try (ImageOutputStream ios = ImageIO.createImageOutputStream(outputFile)) {
            writer.setOutput(ios);
            TIFFImageWriteParam param = new TIFFImageWriteParam(null);
            param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
            param.setCompressionType("LZW");
            writer.write(null, new IIOImage(image, null, null), param);
        }
    }
 
    /**
     * 两阶段转换:先压缩TIF,再转JPEG
     * @param inputFile     原始TIF文件
     * @param targetSizeKB  目标大小(KB)
     * @param tifSuffix     TIF输出后缀(如 "_compressed.tif")
     * @param jpegSuffix    JPEG输出后缀(如 "_final.jpg")
     * @return 最终的JPEG文件
     * @throws IOException
     */
    public static File convertTifToJpeg(File inputFile, int targetSizeKB,
                                        String tifSuffix, String jpegSuffix) throws IOException {
        // 第一阶段:压缩TIF
        File compressedTif = compressTif(inputFile, targetSizeKB, tifSuffix);
 
        // 第二阶段:TIF转JPEG
        return convertTifToJpeg(compressedTif, jpegSuffix);
    }
 
    /**
     * 将TIF转换为JPEG(新增方法)
     * @param tifFile     输入的TIF文件
     * @param jpegSuffix  JPEG文件后缀(如 "_converted.jpg")
     * @return 生成的JPEG文件
     */
    public static File convertTifToJpeg(File tifFile, String jpegSuffix) throws IOException {
        // 读取TIF图像
        BufferedImage tifImage;
        try (InputStream is = new BufferedInputStream(new FileInputStream(tifFile))) {
            tifImage = Imaging.getBufferedImage(is);
        } catch (ImageReadException e) {
            throw new IOException("Failed to read TIFF image", e);
        }
 
        // 创建输出文件路径
        File jpegFile = new File(tifFile.getParent(),
            tifFile.getName().replace(".tif", jpegSuffix));
 
        // 配置JPEG编码参数
        float jpegQuality = 0.95f; // 默认质量(0.7-0.9之间最佳)
        saveAsJpeg(tifImage, jpegFile, jpegQuality);
 
        return jpegFile;
    }
 
    /**
     * 优化后的JPEG保存方法
     */
    private static void saveAsJpeg(BufferedImage image, File outputFile, float quality) throws IOException {
        // 确保图像是RGB格式(JPEG不支持透明通道)
        BufferedImage rgbImage = ensureRgbFormat(image);
 
        // 获取JPEG编码器
        Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName("jpeg");
        if (!writers.hasNext()) {
            throw new IllegalStateException("No JPEG encoder available");
        }
 
        ImageWriter writer = writers.next();
        try (ImageOutputStream ios = ImageIO.createImageOutputStream(outputFile)) {
            writer.setOutput(ios);
 
            // 配置压缩参数
            JPEGImageWriteParam jpegParams = new JPEGImageWriteParam(null);
            jpegParams.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
            jpegParams.setCompressionQuality(quality);
 
            // 高级设置(优化压缩)
            jpegParams.setOptimizeHuffmanTables(true);  // 启用Huffman优化
            jpegParams.setProgressiveMode(ImageWriteParam.MODE_DISABLED); // 非渐进式
 
            // 执行编码
            writer.write(null, new IIOImage(rgbImage, null, null), jpegParams);
        } finally {
            writer.dispose();
        }
    }
 
    /**
     * 确保图像为RGB格式(处理可能的透明度问题)
     */
    private static BufferedImage ensureRgbFormat(BufferedImage image) {
        if (image.getType() == BufferedImage.TYPE_INT_RGB) {
            return image;
        }
 
        // 转换格式并填充白色背景
        BufferedImage rgbImage = new BufferedImage(
            image.getWidth(),
            image.getHeight(),
            BufferedImage.TYPE_INT_RGB);
 
        Graphics2D g = rgbImage.createGraphics();
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, rgbImage.getWidth(), rgbImage.getHeight());
        g.drawImage(image, 0, 0, null);
        g.dispose();
 
        return rgbImage;
    }
 
    /**
     * 将图像保存为TIF格式
     */
    private static void saveAsTiffByImaging(BufferedImage image, File outputFile, float quality) throws IOException {
        // 设置TIF压缩参数
        Map<String, Object> params = new HashMap<>();
        params.put("compression", "LZW"); // 或 "Deflate", "PackBits"
        params.put("quality", quality);
 
        // 保留原始元数据(如果存在)
        try (OutputStream os = new BufferedOutputStream(new FileOutputStream(outputFile))) {
            Imaging.writeImage(image, os, ImageFormats.TIFF);
        } catch (ImageWriteException e) {
            e.printStackTrace();
        }
    }
 
    /**
     * 获取图像的内存大小估算值
     */
    private static long getImageSize(BufferedImage image) {
        return (long) image.getWidth() * image.getHeight() * 3; // 假设RGB 3字节/像素
    }
 
 
}