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字节/像素
|
}
|
|
|
}
|