Atitit图像截取裁剪与java img api 艾提拉总结
目录
与其用ImageIO类来进行所有的解码操作,不如用ImageIO类去得到一个ImageReader对象, 再用这个对象去进行读操作:
[if !supportLists]00001. [endif]
Iterator readers = ImageIO.getImageReadersByFormatName(“gif”);
[if !supportLists]00002. [endif]
[if !supportLists]00003. [endif]
ImageReader reader = (ImageReader)readers.next();
[if !supportLists]00004. [endif]
ImageReader对象也可以基于文件内容、文件后缀或MIME类型获得。这个用于查找和初始 化ImageReader对象的机制用到了javax.imageio.spi.ImageReaderSpi类,它可以在不用初 始化插件的情况下获得插件的信息。”service provider interfaces” (SPIs)将会在下一 章详细讨论。一旦获得了一个ImageReader对象,必须给它是指一个输入源。大部分 ImageReader对象可以从ImageInputStream类输入源读取数据,ImageInputStream是Image I/O API定义的专用输入源。获得一个ImageInputStream 是简单的。给定一个File或InputStream,一个 ImageInputStream对象可以通过调用如下函数产生:
[if !supportLists]00001. [endif]
Object source; // File or InputStream
[if !supportLists]00002. [endif]
[if !supportLists]00003. [endif]
ImageInputStream iis = ImageIO.createImageInputStream(source);
[if !supportLists]00004. [endif]
一旦有了输入源,可以把它与一个ImageReader对象关联起来:
reader.setInput(iis, true);
如果输入源文件包含多张图片,而程序不保证按顺序读取时,第二个参数应该设置为false。对于那些只允许存储一张图片的文件格式,永远传递true是合理的。 当ImageReader对象有了输入源后,我们就可以获取图片信息而不用把整张图片数据都读入 内存。例如,调用reader.getImageWidth(0)可以让我们获得文件中第一张图片的宽度。一 个好的插件会试图解码文件的必要部分,去获得图片的宽度,而不用读取任何一个像素。为读取图片,可以调用reader.read(imageIndex), imageIndex是文件(当包含多张图片时) 中图片的索引。这与上一节调用ImageIO.read()产生的结果相同。
BufferedImage bi = reader.read(imageIndex, param);
如果需要更多的控制,可以向read()方法传递一个ImageReadParam类型的参数。一个 ImageReadParam对象可以让程序更好的利用内存。它不仅允许指定一个感兴趣的区域,还 可以指定一个抽样因子,用于向下采样。例如,为了只解码图片的左上角的1/4,程序可以先获取一个合适的ImageReadParam对象:
另一个例子,为了读取每三个像素中的一个,产生一个原图片1/9大小的图片,可以用 ImageReadParam指定抽样因子:
[if !supportLists]00001. [endif]
param = reader.getDefaultImageParam();
[if !supportLists]00002. [endif]
[if !supportLists]00003. [endif]
param.setSourceSubsampling(3, 3, 0, 0);
[if !supportLists]00004. [endif]
[if !supportLists]00005. [endif]
BufferedImage bi3 = reader.read(0, param);
[if !supportLists]00006. [endif]
ImageReader 中所有与图片打交道的方法都有一个imageIndex 参数,这个参数用于读取多 图片文件中的一张。ImageReader.getNumImages()返回多图片文件中的图片个数。这个方法有一个boolean参数, allowSearch。有的图片格式,典型的GIF,没有提供任何获取文件中的图片个数方法,除 非读取整个进行解析。这样代价很高,因此设置allowSearch为false可以让方法直接返回 -1,而不是实际的图片个数。如果此参数是true,则该方法总会返回文件中实际的图片个 数。即使在不知道文件中图片个数的情况下,仍可以调用read(imageIndex); 如果索引值过大, 该方法会抛出IndexOutOfBoundsException异常。因此,程序可以递增索引去获取图片, 直到异常。
有的图片格式允许一个(或多个)小的预览图,与主图片一起存储在文件中。这些“缩略图”对于快速识别图片很有用,不用解码整个图片。程序可以调用如下代码,探测一张图片有多少张缩略图:reader.getNumThumbnails(imageIndex);如果存在缩略图,可以调用如下代码获取:
[if !supportLists]00001. [endif]
int thumbailIndex = 0;
[if !supportLists]00002. [endif]
[if !supportLists]00003. [endif]
BufferedImage bi;
[if !supportLists]00004. [endif]
[if !supportLists]00005. [endif]
bi = reader.readThumbnail(imageIndex, thumbnailIndex);
[if !supportLists]00006. [endif]
[if !supportLists]00007. [endif]
[if !supportLists]00008. [endif]
就像我们可以用ImageIO 的一个方法获取某种图片格式的ImageReader对象一样,我们也可 以获取ImageWriter对象:
[if !supportLists]00001. [endif]
Iterator writers = ImageIO.getImageWritersByFormatName(“png”);
[if !supportLists]00002. [endif]
[if !supportLists]00003. [endif]
ImageWriter writer = (ImageWriter)writers.next();
[if !supportLists]00004. [endif]
一旦获取了一个ImageWriter对象,必须给它设置一个输出源ImageOutputStream。
[if !supportLists]00001. [endif]
File f = new File(“c:imagesmyimage.png”);
[if !supportLists]00002. [endif]
[if !supportLists]00003. [endif]
ImageOutputStream ios = ImageIO.createImageOutputStream(f);
[if !supportLists]00004. [endif]
[if !supportLists]00005. [endif]
writer.setOutput(ios);
[if !supportLists]00006. [endif]
最后,可以把图片写入到输出源:
[if !supportLists]00001. [endif]
BufferedImage bi;
[if !supportLists]00002. [endif]
[if !supportLists]00003. [endif]
writer.write(bi)
[if !supportLists]00004. [endif]
IIOImage类用于存储图片,缩略图或元信息的引用。下一节将讨论Metadata,目前,我们 简单地给Metadata相关参数传递null。 ImageWriter 类有一个方法write(),用于从IIOImage创建一个新文件,还有一个方法 writeInsert(),用于向一个已存在文件添加一个IIOImage对象。通过调用这两者,可以创 建一个多图片文件:
[if !supportLists]00001. [endif]
BufferedImage first_bi, second_bi;
[if !supportLists]00002. [endif]
[if !supportLists]00003. [endif]
IIOImage first_IIOImage = new IIOImage(first_bi, null, null);
[if !supportLists]00004. [endif]
[if !supportLists]00005. [endif]
IIOImage second_IIOImage = new IIOImage(second_bi, null, null);
[if !supportLists]00006. [endif]
[if !supportLists]00007. [endif]
writer.write(null, first_IIOImage, null);
[if !supportLists]00008. [endif]
[if !supportLists]00009. [endif]
if (writer.canInsertImage(1)) {
[if !supportLists]00010. [endif]
[if !supportLists]00011. [endif]
writer.writeInsert(1, second_IIOImage, null);
[if !supportLists]00012. [endif]
[if !supportLists]00013. [endif]
} else {
[if !supportLists]00014. [endif]
[if !supportLists]00015. [endif]
System.err.println(“Writer can’t append a second image!”);
[if !supportLists]00016. [endif]
[if !supportLists]00017. [endif]
}
[if !supportLists]00018. [endif]
所有与像素无关的信息,都属于在Metadata。javax.imageio.metadata 包含了用于访问 Metadata的类和接口。Image I/O API 将stream metadata 和image metadata区别对待。stream metadata与一个 文件中存储了多张图片有关,image metadata只与单个图片有关。如果一个文件只包含一张 图片,那么就只存在image metadata。可以通过调用ImageReader.getStreamMetadata 和 getImageMetadata(int imageIndex)来 获取metadata。这些方法会返回一个实现了IIOMetadata接口的对象,该对象会被向上转化 为ImageReader类型,
略
[if !supportLists]4. [endif]Code
D:\workspace\wechatTelbookOcrVcf
public class imgUtil {
public static void main(String[] args) throws FileNotFoundException, IOException {
String srcimg = "D:\\bawei\\Screenshot_2019-05-09-18-57-58-500_com.tencent.mm.png";
//385 287,93 27
Rectangle rect = new Rectangle(282, 258, 430, 36);
//rect = new Rectangle(100, 100, 100, 36);
String dest = "D:\\0img\\Screenshot_2019-05-09-18-57-58-500_com.tencent.mm.cut.png";
BufferedImage bi =imgUtil.cutImg( srcimg, rect,"png");
ImageIO.write(bi, "png", new FileOutputStream(dest));
System.out.println("--");
}
public static BufferedImage cutImg(String srcimg, Rectangle rect, String imgFmt)
throws FileNotFoundException, IOException {
return cutImg(ImageIO.read(new FileInputStream(srcimg)), rect, imgFmt);
}
static org.apache.log4j.Logger logger = Logger.getLogger(imgUtil.class);
public static BufferedImage cutImg(BufferedImage img, Rectangle rect, String suffix) throws IOException {
logger.info(img.getWidth()+":"+img.getHeight());
//for debug ,show witdh height.. IllegalArgumentException: Empty region!
// 根据图片类型获取该种类型的ImageReader
/**
* reader.setInput(iis, true); 如果输入源文件包含多张图片,而程序不保证按顺序读取时,第二个参数应该设置为
* false。对于那些只允许存储一张图片的文件格式,永远传递true是合理的。
* 当ImageReader对象有了输入源后,我们就可以获取图片信息而不用把整张图片数据都读入
* 内存。例如,调用reader.getImageWidth(0)可以让我们获得文件中第一张图片的宽度。一
* 个好的插件会试图解码文件的必要部分,去获得图片的宽度,而不用读取任何一个像素。
*/
ImageReader ImageReader1 = ImageIO.getImageReadersBySuffix(suffix).next();
ImageReader1.setInput(
ImageIO.createImageInputStream(new ByteArrayInputStream(bufferedImageToByteArray(img, suffix))), true);
ImageReadParam imageReadParam = new Supplier() {
@Override
public ImageReadParam get() {
ImageReadParam ImageReadParam1 = ImageReader1.getDefaultReadParam();
ImageReadParam1.setSourceRegion(rect);
return ImageReadParam1;
}
}.get();
//为读取图片,可以调用reader.read(imageIndex), imageIndex是文件(当包含多张图片时) 中图片的索引
BufferedImage bi = ImageReader1.read(0, imageReadParam);
return bi;
// return cutImg(rect, ImageReader1, ImageReadParam1);
}
private static byte[] bufferedImageToByteArray(BufferedImage img, String suffix) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
boolean flag = ImageIO.write(img, suffix, out);
byte[] b = out.toByteArray();
return b;
}
private static BufferedImage rectx(String srcimg, Rectangle rect) throws Exception {
// 图片输入流
ImageInputStream iis = ImageIO.createImageInputStream(srcimg);
// 图片读取器
Iterator it = ImageIO.getImageReaders(iis);
if (it.hasNext()) {
ImageReader r = it.next();
// 设置输入流
r.setInput(iis, true);
System.out.println("格式=" + r.getFormatName());
System.out.println("宽=" + r.getWidth(0));
System.out.println("高=" + r.getHeight(0));
// 读取参数
ImageReadParam param = r.getDefaultReadParam();
// 创建要截取的矩形范围
// Rectangle rect = new Rectangle(100, 100, 400, 200);
// 设置截取范围参数
param.setSourceRegion(rect);
// 读取截图数据
BufferedImage bi = r.read(0, param);
// 保存图片
// ImageIO.write(bi, "jpg", t);
return bi;
}
return null;
}
}
(2条消息)Java使用imageio 读写图像 - Code-Create-World - CSDN博客.html
>