目录
- 一、ImageIO 的基础知识
- 1.1 ImageIO 的作用
- 1.2 ImageIO 的特点
- 1.3 ImageIO 的使用环境
- 1.4 ImageIO 的基本使用方法
- 二、ImageIO 的读取操作
- 2.1 ImageIO 的 read() 方法
- 2.2 以 Byte 数组形式读取图像
- 2.3 指定图像格式
- 三、ImageIO 的写入操作
- 3.1 ImageIO 的 write() 方法
- 3.2 指定图像格式
- 3.3 指定压缩质量
- 3.4 指定保存位置
- 四、ImageIO 的格式转换
- 五、ImageIO 的高级操作
- 5.1 裁剪图像
- 5.2 旋转图像
- 5.3 缩放图像
- 5.4 反转图像
- 5.5 镜像图像
- 5.6 组合操作
- 六、注意事项
一、ImageIO 的基础知识
1.1 ImageIO 的作用
ImageIO 是 Java 标准库提供的一个类,它提供了读取和写入多种常见图像格式的功能。开发者可以使用 ImageIO 类快速、便捷地读取和写入图像,而无需关心底层的细节。
1.2 ImageIO 的特点
ImageIO 支持的图像格式非常广泛,包括 JPEG、PNG、BMP、GIF 等常见格式,同时也支持 TIFF、ICO、WBMP、JPEG 2000 等更加少见的格式。这使得开发者可以方便地读取和写入多种不同格式的图像。
ImageIO 还支持灵活的、可配置的图片格式转换。例如,可以将一张 JPEG 格式的图像读取到内存中,然后将其保存为 PNG 格式的图像。此外,ImageIO 还支持高级的图像处理操作,如裁剪、旋转、缩放、反转、镜像等。
1.3 ImageIO 的使用环境
ImageIO 是 Java 标准库中的一个类,因此不需要额外的库或安装,可以直接在 Java 应用程序中使用。它支持 Java SE 6 及以上版本,并且可以运行在所有常见的操作系统上。
1.4 ImageIO 的基本使用方法
使用 ImageIO 类读取和写入图像的基本流程如下:
- 通过 ImageIO 类的静态方法 read() 或者 write() 方法获取图片输入输出流;
- 创建 ImageInputStream 或者 ImageOutputStream;
- 读/写图像。
例如,读取一张 JPEG 格式的图片,代码如下:
String imageFilePath = "image.jpg";
try {
InputStream inputStream = new FileInputStream(new File(imageFilePath));
BufferedImage bufferedImage = ImageIO.read(inputStream);
// 图像处理逻辑
} catch (IOException e) {
e.printStackTrace();
}
上述代码通过 FileInputStream 打开文件输入流,然后通过 ImageIO.read() 方法读取图像数据,最后对图像进行了处理操作。
下面我们将详细介绍 ImageIO 类的各个方面,包括读取、写入、压缩、格式转换以及高级操作等。
二、ImageIO 的读取操作
2.1 ImageIO 的 read() 方法
ImageIO 的 read() 方法是最常见的读取图像的方式,它有多个重载形式,可以用来读取 File、InputStream、URL 和 ImageInputStream 等多种类型的输入流。此外,ImageIO 还支持从 byte 数组读取或者从任意 SeekableStream 中读取文件。
例如,通过 ImageIO 的 read() 方法从本地文件读取一张图片:
String imageFilePath = "image.jpg";
try {
BufferedImage bufferedImage = ImageIO.read(new File(imageFilePath));
// 图像处理逻辑
} catch (IOException e) {
e.printStackTrace();
}
read() 方法返回了一个 BufferedImage 对象,开发者可以对这个对象进行各种操作,如裁剪、旋转、缩放等。注意:当读取的图像不是 RGB 格式时,返回的 BufferedImage 对象可能为 null。
2.2 以 Byte 数组形式读取图像
有些场景下,开发者需要将图片数据保存在内存中,然后再进行处理。ImageIO 的 read() 方法提供了一个重载形式,可以将图像数据读取到 byte 数组中,示例代码如下:
String imageFilePath = "image.jpg";
try {
File file = new File(imageFilePath);
BufferedImage bufferedImage = ImageIO.read(file);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ImageIO.write(bufferedImage, "jpg", byteArrayOutputStream);
byte[] bytes = byteArrayOutputStream.toByteArray();
// 处理字节数组中的图像
} catch (IOException e) {
e.printStackTrace();
}
在上述代码中,首先使用 ImageIO.read() 方法将图片读取到内存中,并得到了一个 BufferedImage 对象。然后,使用 ImageIO.write() 方法将 BufferedImage 对象写入到 ByteArrayOutputStream 中,最终得到了字节数组形式的图像数据。
2.3 指定图像格式
ImageIO 的 read() 方法可以自动识别常见的图像格式,但有时候需要指定特定的格式。通过 ImageIO 的 getReaderFormatNames() 方法可以查看支持的格式列表,示例代码如下:
String[] formatNames = ImageIO.getReaderFormatNames();
for (String format : formatNames) {
System.out.println(format);
}
如果要指定读取的格式,可以使用 ImageIO 的 getImageReadersByFormatName() 方法指定,例如:
File file = new File("image.xx");
Iterator<ImageReader> readers = ImageIO.getImageReadersByFormatName("xxx");
try {
ImageReader reader = readers.next();
ImageInputStream inputStream = ImageIO.createImageInputStream(file);
reader.setInput(inputStream);
BufferedImage image = reader.read(0);
// 处理读取的图像
} catch (IOException e) {
e.printStackTrace();
}
在上述代码中,getImageReadersByFormatName() 方法传入的参数是指定的图像格式名,然后通过 Iterator 获取到 ImageReader 对象,再使用 ImageIO.createImageInputStream() 方法创建 ImageInputStream 对象,并通过 setInput() 方法设置输入源。最后通过 reader.read() 方法读取图像。
三、ImageIO 的写入操作
3.1 ImageIO 的 write() 方法
ImageIO 的 write() 方法是写入图像的主要方法,它可以将 BufferedImage 对象写入到文件或者输出流中。除此之外,ImageIO 还提供了其他的方法来指定写出的格式和压缩质量等参数。
下面是一个将 BufferedImage 写入 PNG 格式的简单示例:
BufferedImage image = new BufferedImage(100, 100, BufferedImage.TYPE_INT_RGB);
try {
ImageIO.write(image, "png", new File("output.png"));
} catch (IOException e) {
e.printStackTrace();
}
在上述代码中,使用 ImageIO.write() 方法将 BufferedImage 对象写入到本地文件 output.png 中。
3.2 指定图像格式
与读取图像类似,ImageIO 的 write() 方法默认会根据扩展名或者其他信息自动识别输出的图片格式。但是有些场景下需要手动指定输出的图像格式,可通过如下方式进行设置:
BufferedImage image = new BufferedImage(100, 100, BufferedImage.TYPE_INT_RGB);
try {
File file = new File("output.xx");
ImageWriter writer = ImageIO.getImageWritersByFormatName("xxx").next();
ImageOutputStream outputStream = ImageIO.createImageOutputStream(file);
writer.setOutput(outputStream);
writer.write(image);
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
在上述代码中,getImageWritersByFormatName() 方法传入指定的图像格式名,然后通过 ImageWriter 对象设置 ImageOutputStream,最后通过 write() 方法写入图像。
3.3 指定压缩质量
在写入图像时,ImageIO 还可以控制输出的压缩质量,从而控制输出图像文件的大小。不过需要注意的是,并非所有的图像格式都支持压缩。目前只有 JPEG 和 PNG 格式支持压缩功能。
下面是一个将 BufferedImage 写入 JPG 格式并指定压缩质量的示例:
BufferedImage image = new BufferedImage(100, 100, BufferedImage.TYPE_INT_RGB);
try {
File file = new File("output.jpg");
// 获取 JPEG 格式的 ImageWriter
ImageWriter writer = ImageIO.getImageWritersByFormatName("jpeg").next();
// 设置输出流
ImageOutputStream outputStream = ImageIO.createImageOutputStream(file);
writer.setOutput(outputStream);
// 设置压缩参数
JPEGImageWriteParam param = (JPEGImageWriteParam) writer.getDefaultWriteParam();
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionQuality(0.8f);
// 写入图像
writer.write(null, new IIOImage(image, null, null), param);
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
在上述代码中,首先从 ImageIO 中获取 JPEG 格式的 ImageWriter 对象,然后设置输出流和压缩参数。其中,setCompressionQuality() 方法用于设置压缩质量,值范围为 0.0~1.0,其中 1.0 表示不压缩,0.0 表示最大压缩。
3.4 指定保存位置
如果需要将 BufferedImage 对象写入到指定的文件目录下,可以使用 ImageIO 的 write() 方法进行操作。下面是一个将 BufferedImage 写入本地文件的示例:
BufferedImage image = new BufferedImage(100, 100, BufferedImage.TYPE_INT_RGB);
try {
File file = new File("output.png");
ImageIO.write(image, "png", file);
} catch (Exception e) {
e.printStackTrace();
}
需要注意的是,write() 方法不支持压缩参数设置,如果需要控制输出文件大小,需要使用上述的 ImageWriter 方式。
四、ImageIO 的格式转换
在实际开发中,经常需要将图像从一种格式转换成另一种格式。ImageIO 提供的格式转换功能非常灵活,可以通过如下代码片段实现:
BufferedImage srcImage = ImageIO.read(new File("input.jpg"));
File outputFile = new File("output.png");
// 获取 png 格式的 ImageWriter
ImageWriter writer = ImageIO.getImageWritersByFormatName("png").next();
// 设置输出流
ImageOutputStream outputStream = ImageIO.createImageOutputStream(outputFile);
writer.setOutput(outputStream);
// 写入图像
writer.write(null, new IIOImage(srcImage, null, null), null);
outputStream.close();
在上述代码中,首先使用 ImageIO.read() 方法读取 JPEG 格式的图像,然后通过 getImageWritersByFormatName() 方法获取 PNG 格式的 ImageWriter 对象。接着创建 ImageOutputStream 对象,并写入转换后的 PNG 格式图像。
需要注意的是,有些格式转换可能会导致图像信息的丢失,例如将 24-bit 的 RGB 图像转换成 8-bit 的 GIF 图像,会导致颜色数量减少,从而造成图像质量下降。
五、ImageIO 的高级操作
除了基本的格式读取、写入和转换外,ImageIO 还提供了一些高级的图像处理操作,如裁剪、旋转、缩放、反转、镜像等。下面简单介绍一下这些操作。
5.1 裁剪图像
通过 ImageIO.read() 方法读取的 BufferedImage 对象支持裁剪功能。可以通过调用 getSubimage() 方法获取指定区域的子图像。例如:
BufferedImage srcImage = ImageIO.read(new File("input.jpg"));
BufferedImage destImage = srcImage.getSubimage(10, 10, 100, 100);
5.2 旋转图像
ImageIO 也支持对图像进行旋转操作。可以通过 AffineTransform 类来实现图像的旋转变换。
BufferedImage srcImage = ImageIO.read(new File("input.jpg"));
double radian = Math.toRadians(30); // 旋转角度为 30 度
AffineTransform transform = new AffineTransform();
transform.rotate(radian, srcImage.getWidth() / 2, srcImage.getHeight() / 2);
AffineTransformOp op = new AffineTransformOp(transform, AffineTransformOp.TYPE_BILINEAR);
BufferedImage destImage = op.filter(srcImage, null);
在上述代码中,radian 变量表示旋转的角度,AffineTransform 类用于创建旋转变换,AffineTransformOp 类用于将变换应用到图像上。
5.3 缩放图像
缩放图像同样是 ImageIO 的高级操作之一。可以通过 AffineTransform 类来实现图像的缩放变换。
BufferedImage srcImage = ImageIO.read(new File("input.jpg"));
AffineTransform transform = new AffineTransform();
double scale = 0.5; // 图像缩小一倍
transform.scale(scale, scale);
AffineTransformOp op = new AffineTransformOp(transform, AffineTransformOp.TYPE_BILINEAR);
BufferedImage destImage = op.filter(srcImage, null);
在上述代码中,通过 AffineTransform 的 scale() 方法设置缩放比例,AffineTransformOp 类用于将变换应用到图像上。
5.4 反转图像
对于需要水平或垂直翻转的图像,ImageIO 提供了如下方式实现:
```
// 读取输入图像(示例中为名为 input.png 的图像)
BufferedImage srcImage = ImageIO.read(new File("input.png"));
// 水平镜像
AffineTransform transform = new AffineTransform(-1, 0, 0, 1, srcImage.getWidth(), 0);
AffineTransformOp op = new AffineTransformOp(transform, AffineTransformOp.TYPE_BILINEAR);
BufferedImage horizontalFlipped = op.filter(srcImage, null);
// 垂直镜像
transform = new AffineTransform(1, 0, 0, -1, 0, srcImage.getHeight());
op = new AffineTransformOp(transform, AffineTransformOp.TYPE_BILINEAR);
BufferedImage verticalFlipped = op.filter(srcImage, null);
// 上下颠倒
transform = new AffineTransform(-1, 0, 0, -1, srcImage.getWidth(), srcImage.getHeight());
op = new AffineTransformOp(transform, AffineTransformOp.TYPE_BILINEAR);
BufferedImage upsideDown = op.filter(srcImage, null);
// 保存结果图像(保存为 PNG 格式的文件)
ImageIO.write(horizontalFlipped, "png", new File("horizontal.png"));
ImageIO.write(verticalFlipped, "png", new File("vertical.png"));
ImageIO.write(upsideDown, "png", new File("upside_down.png"));
5.5 镜像图像
对于需要镜像的图像,ImageIO 提供了如下方式实现:
BufferedImage srcImage = ImageIO.read(new File("input.jpg"));
// 水平镜像
AffineTransform transform = new AffineTransform(-1, 0, 0, 1, srcImage.getWidth(), 0);
// 垂直镜像
AffineTransform transform = new AffineTransform(1, 0, 0, -1, 0, srcImage.getHeight());
在上述代码中,水平镜像通过将 x 轴翻转并沿 y 轴平移一段距离实现,垂直镜像通过将 y 轴翻转并沿 x 轴平移一段距离实现。
5.6 组合操作
同时进行多个图像变换时,可以通过 AffineTransform 中的 concatenate() 方法,将多个变换组合到一起进行处理。例如:
BufferedImage srcImage = ImageIO.read(new File("input.jpg"));
AffineTransform transform1 = new AffineTransform();
AffineTransform transform2 = new AffineTransform();
double scale = 0.5;
transform1.scale(scale, scale);
transform2.translate(50, 50);
transform1.concatenate(transform2); // 将两个变换组合在一起
AffineTransformOp op = new AffineTransformOp(transform1, AffineTransformOp.TYPE_BILINEAR);
BufferedImage destImage = op.filter(srcImage, null);
在上述代码中,首先创建两个不同的 AffineTransform 对象,一个用于缩放,一个用于平移,然后将其组合在一起。注意,组合时要先进行平移变换,再进行缩放变换,否则会产生错误的结果。
六、注意事项
在使用 ImageIO 时,需要注意以下几点:
- 避免频繁的读写文件,选择合适的内存缓存方式进行操作;
- 在处理不同格式的图像时,应该注意色彩模式、透明度等方面的差异,以避免图像信息的丢失;
- 在进行高级操作时,应该考虑到图像质量的问题,避免操作过度造成图像质量的下降。