Java 开发 - Java 实现图片压缩、Java 实现图片缩放
·
Java 实现图片压缩
1、具体实现
- UnknownImageTypeException.java
public class UnknownImageTypeException extends Exception {
public UnknownImageTypeException(String message) {
super(message);
}
}
- ImageCompressor.java
public class ImageCompressor {
public static final int IMAGE_TYPE_UNKNOWN = 0;
public static final int IMAGE_TYPE_PNG = 1;
public static final int IMAGE_TYPE_JPG = 2;
public static int getImageType(byte[] bytes) {
if (bytes == null) {
return IMAGE_TYPE_UNKNOWN;
}
if (bytes.length >= 8
&& bytes[0] == (byte) 0x89
&& bytes[1] == (byte) 0x50
&& bytes[2] == (byte) 0x4E
&& bytes[3] == (byte) 0x47
&& bytes[4] == (byte) 0x0D
&& bytes[5] == (byte) 0x0A
&& bytes[6] == (byte) 0x1A
&& bytes[7] == (byte) 0x0A) {
return IMAGE_TYPE_PNG;
}
if (bytes.length >= 3
&& bytes[0] == (byte) 0xFF
&& bytes[1] == (byte) 0xD8
&& bytes[2] == (byte) 0xFF) {
return IMAGE_TYPE_JPG;
}
return IMAGE_TYPE_UNKNOWN;
}
public static byte[] compress(byte[] bytes, float quality) throws UnknownImageTypeException {
int imageType = getImageType(bytes);
if (imageType == IMAGE_TYPE_JPG) {
return compressJpg(bytes, quality);
} else if (imageType == IMAGE_TYPE_PNG) {
return compressPng(bytes, quality);
} else {
throw new UnknownImageTypeException("未知的图片格式");
}
}
public static byte[] compressJpg(byte[] bytes, float quality) {
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
try {
BufferedImage bufferedImage = ImageIO.read(byteArrayInputStream);
// ImageIO read 方法返回 null 的情况
// 1、图片格式不支持
// 2、图片损坏
if (bufferedImage == null) {
return null;
}
// 开始压缩图片
ImageWriter imageWriter = ImageIO.getImageWritersByFormatName("jpg").next();
// 设置输出流
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ImageOutputStream imageOutputStream = ImageIO.createImageOutputStream(byteArrayOutputStream);
imageWriter.setOutput(imageOutputStream);
// 设置压缩参数
JPEGImageWriteParam param = (JPEGImageWriteParam) imageWriter.getDefaultWriteParam();
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionQuality(quality);
imageWriter.write(null, new IIOImage(bufferedImage, null, null), param);
// 释放资源
imageWriter.dispose();
return byteArrayOutputStream.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public static byte[] compressPng(byte[] bytes, float quality) {
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
try {
BufferedImage bufferedImage = ImageIO.read(byteArrayInputStream);
// ImageIO read 方法返回 null 的情况
// 1、图片格式不支持
// 2、图片损坏
if (bufferedImage == null) {
return null;
}
// 开始压缩图片
ImageWriter imageWriter = ImageIO.getImageWritersByFormatName("png").next();
// 设置输出流
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ImageOutputStream imageOutputStream = ImageIO.createImageOutputStream(byteArrayOutputStream);
imageWriter.setOutput(imageOutputStream);
// 设置压缩参数
ImageWriteParam param = imageWriter.getDefaultWriteParam();
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionType("Deflate");
int compressionLevel = Math.min(9, Math.max(0, (int) (quality * 9)));
param.setCompressionQuality(compressionLevel / 9.0f);
imageWriter.write(null, new IIOImage(bufferedImage, null, null), param);
// 释放资源
imageWriter.dispose();
return byteArrayOutputStream.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
2、测试
FileInputStream fileInputStream = null;
byte[] bytes = null;
try {
fileInputStream = new FileInputStream("file/compressimagetest/testPng.png");
bytes = fileInputStream.readAllBytes();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fileInputStream != null) {
try {
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
if (bytes == null) {
System.out.println("图片读取失败");
return;
}
System.out.println("图片压缩前,大小:" + bytes.length);
int imageType = ImageCompressor.getImageType(bytes);
if (imageType == ImageCompressor.IMAGE_TYPE_UNKNOWN) {
System.out.println("图片格式未知");
return;
}
byte[] result = null;
try {
result = ImageCompressor.compress(bytes, 0.1f);
} catch (UnknownImageTypeException e) {
System.out.println("图片压缩失败,原因:" + e.getMessage());
return;
}
System.out.println("图片压缩后,大小:" + result.length);
String newFileName = "file/compressimagetest/testPngCompress.";
if (imageType == ImageCompressor.IMAGE_TYPE_PNG) {
newFileName += "png";
} else if (imageType == ImageCompressor.IMAGE_TYPE_JPG) {
newFileName += "jpg";
}
FileOutputStream fileOutputStream = null;
try {
fileOutputStream = new FileOutputStream(newFileName);
fileOutputStream.write(result);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fileOutputStream != null) {
try {
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
- 测试压缩 PNG 格式图片,从
file/compressimagetest/testPng.png读取图片,压缩后保存到file/compressimagetest/testPngCompress.png,输出结果
图片压缩前,大小:138713
图片压缩后,大小:134312
- 测试压缩 JPG 格式图片,从
file/compressimagetest/testJpg.jpg读取图片,压缩后保存到file/compressimagetest/testJpgCompress.jpg,输出结果
图片压缩前,大小:21984
图片压缩后,大小:2381
3、小结
-
JPEG 与 JPG 在技术上是完全相同的格式,只是文件扩展名不同
-
PNG 采用无损压缩,JPG 采用有损压缩,PNG 的压缩效果不如 JPG 明显
-
有时候,图片后缀是 jpg,但是通过魔数判断,实际图片格式可能是 PNG(反之亦然)
-
大部分现代图片查看器、浏览器、图片处理软件都实现了格式自检测,所以修改图片后缀后,图片仍然能正常使用
-
缩减尺寸通常是比调整压缩参数更有效的压缩手段
Java 实现图片缩放
1、具体实现
- UnknownImageTypeException.java
public class UnknownImageTypeException extends Exception {
public UnknownImageTypeException(String message) {
super(message);
}
}
- ImageScaler.java
public class ImageScaler {
public static final int IMAGE_TYPE_UNKNOWN = 0;
public static final int IMAGE_TYPE_PNG = 1;
public static final int IMAGE_TYPE_JPG = 2;
public static int getImageType(byte[] bytes) {
if (bytes == null) {
return IMAGE_TYPE_UNKNOWN;
}
if (bytes.length >= 8
&& bytes[0] == (byte) 0x89
&& bytes[1] == (byte) 0x50
&& bytes[2] == (byte) 0x4E
&& bytes[3] == (byte) 0x47
&& bytes[4] == (byte) 0x0D
&& bytes[5] == (byte) 0x0A
&& bytes[6] == (byte) 0x1A
&& bytes[7] == (byte) 0x0A) {
return IMAGE_TYPE_PNG;
}
if (bytes.length >= 3
&& bytes[0] == (byte) 0xFF
&& bytes[1] == (byte) 0xD8
&& bytes[2] == (byte) 0xFF) {
return IMAGE_TYPE_JPG;
}
return IMAGE_TYPE_UNKNOWN;
}
public static byte[] scale(byte[] bytes, double scale) throws UnknownImageTypeException {
int imageType = getImageType(bytes);
if (imageType == IMAGE_TYPE_JPG) {
return scaleJpg(bytes, scale);
} else if (imageType == IMAGE_TYPE_PNG) {
return scalePng(bytes, scale);
} else {
throw new UnknownImageTypeException("未知的图片格式");
}
}
public static byte[] scaleJpg(byte[] bytes, double scale) {
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
try {
BufferedImage srcImage = ImageIO.read(byteArrayInputStream);
if (srcImage == null) {
return null;
}
int newWidth = (int) (srcImage.getWidth() * scale);
int newHeight = (int) (srcImage.getHeight() * scale);
BufferedImage destImage = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = destImage.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
g2d.drawImage(srcImage, 0, 0, newWidth, newHeight, null);
g2d.dispose();
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
boolean success = ImageIO.write(destImage, "jpg", byteArrayOutputStream);
if (!success) {
return null;
}
return byteArrayOutputStream.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public static byte[] scalePng(byte[] bytes, double scale) {
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
try {
BufferedImage srcImage = ImageIO.read(byteArrayInputStream);
if (srcImage == null) {
return null;
}
AffineTransform transform = new AffineTransform();
transform.scale(scale, scale);
AffineTransformOp op = new AffineTransformOp(transform, AffineTransformOp.TYPE_BILINEAR);
BufferedImage destImage = op.filter(srcImage, null);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ImageIO.write(destImage, "png", byteArrayOutputStream);
return byteArrayOutputStream.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
2、测试
FileInputStream fileInputStream = null;
byte[] bytes = null;
try {
fileInputStream = new FileInputStream("file/compressimagetest/testPng.png");
bytes = fileInputStream.readAllBytes();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fileInputStream != null) {
try {
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
if (bytes == null) {
System.out.println("图片读取失败");
return;
}
System.out.println("图片缩放前,大小:" + bytes.length);
int imageType = ImageScaler.getImageType(bytes);
if (imageType == ImageScaler.IMAGE_TYPE_UNKNOWN) {
System.out.println("图片格式未知");
return;
}
byte[] result = null;
try {
result = ImageScaler.scale(bytes, 0.5);
} catch (UnknownImageTypeException e) {
System.out.println("图片缩放失败,原因:" + e.getMessage());
return;
}
System.out.println("图片缩放后,大小:" + result.length);
String newFileName = "file/compressimagetest/testPngScale.";
if (imageType == ImageScaler.IMAGE_TYPE_PNG) {
newFileName += "png";
} else if (imageType == ImageScaler.IMAGE_TYPE_JPG) {
newFileName += "jpg";
}
FileOutputStream fileOutputStream = null;
try {
fileOutputStream = new FileOutputStream(newFileName);
fileOutputStream.write(result);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fileOutputStream != null) {
try {
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
- 测试缩放 PNG 格式图片,从
file/compressimagetest/testPng.png读取图片,缩放后保存到file/compressimagetest/testPngScale.png,输出结果
图片缩放前,大小:138713
图片缩放后,大小:47929
- 测试缩放 JPG 格式图片,从
file/compressimagetest/testJpg.jpg读取图片,缩放后保存到file/compressimagetest/testJpgScale.jpg,输出结果
图片缩放前,大小:21984
图片缩放后,大小:2730
更多推荐


所有评论(0)