通过ImageReader进行图像裁剪时出现NoSuchElementException异常
首先放上最初的Image工具类
package util; import java.awt.Rectangle; import java.awt.image.BufferedImage; import java.io.File; import java.io.FileInputStream; import java.util.Iterator; import javax.imageio.ImageIO; import javax.imageio.ImageReadParam; import javax.imageio.ImageReader; import javax.imageio.stream.ImageInputStream; public class ImageUtil { private ImageUtil() { } /** * 裁剪图像 * * @param x,y 起始点 * @param width,height 宽高 * @param srcpath 被裁减图像路径 * @param subpath 裁剪后保存路径 * @param type 图像类型 * @throws Exception */ public static void cut(int x, int y, int width, int height, String srcpath, String subpath, String type) throws Exception { FileInputStream is = null; ImageInputStream iis = null; try { // 读取图片文件 is = new FileInputStream(srcpath); Iterator<ImageReader> it = ImageIO.getImageReadersByFormatName(type); ImageReader reader = it.next(); // 获取图片流 iis = ImageIO.createImageInputStream(is); reader.setInput(iis, true); ImageReadParam param = reader.getDefaultReadParam(); Rectangle rect = new Rectangle(x, y, width, height); // 提供一个 BufferedImage,将其用作解码像素数据的目标。 param.setSourceRegion(rect); BufferedImage bi = reader.read(0, param); ImageIO.write(bi, type, new File(subpath)); } finally { if (is != null) is.close(); if (iis != null) iis.close(); } } /** * 获取图像真实类型 * * @param path 图像路径 * @return 图像类型 * @throws Exception */ public static String getTypeByStream(String path) throws Exception { FileInputStream is = new FileInputStream(path); String type = ""; byte[] b = new byte[4]; try { is.read(b, 0, b.length); } catch (Exception e) { e.printStackTrace(); } finally { if (null != is) { is.close(); } } type = bytesToHexString(b).toUpperCase(); if (type.contains("FFD8FF")) { return "jpg"; } else if (type.contains("89504E47")) { return "png"; } else if (type.contains("47494638")) { return "gif"; } else if (type.contains("49492A00")) { return "tif"; } else if (type.contains("424D")) { return "bmp"; } return type; } /** * byte数组转换成16进制字符串 * * @param src * @return */ private static String bytesToHexString(byte[] src) { StringBuilder stringBuilder = new StringBuilder(); if (src == null || src.length <= 0) { return null; } for (int i = 0; i < src.length; i++) { int v = src[i] & 0xFF; String hv = Integer.toHexString(v); if (hv.length() < 2) { stringBuilder.append(0); } stringBuilder.append(hv); } return stringBuilder.toString(); } }
以前使用ImageReader对jpg图像进行裁剪没有任何异常,这几天接到新的需求,要能对tif图像进行裁剪。原以为只需将传入的type值改为tif即可,但报出了NoSuchElementException异常
java.util.NoSuchElementException at javax.imageio.spi.FilterIterator.next(ServiceRegistry.java:825) at javax.imageio.ImageIO$ImageReaderIterator.next(ImageIO.java:528) at javax.imageio.ImageIO$ImageReaderIterator.next(ImageIO.java:513)
网上查了半天,各种说法都有,最终找到了问题所在:
在jdk下的src中可以看到jdk自带支持的imageio类型——bmp、gif、jpeg(jpg)、png等,就 是 没 有 tif !!!
所以就有了解决的方向——导入tif的imageio,需要的jar包有3个jai_codec、jai_core、jai_imageio
导入3个jar包后,对工具类进行测试,发现不报异常了,图像也正确切割了
原本到此应该就已经结束了,但是。。。
放到web项目中又报出了NoSuchElementException的异常
于是又是一顿搜索和实验,终于找到了正解——要在迭代器中注册tif的imageio类
IIORegistry registry = IIORegistry.getDefaultInstance(); registry.registerServiceProvider(new com.sun.media.imageioimpl.plugins.tiff.TIFFImageWriterSpi()); registry.registerServiceProvider(new com.sun.media.imageioimpl.plugins.tiff.TIFFImageReaderSpi());
加上这段代码后,在web中终于不会报异常了
所以最后的图片工具类就变成了这样
import java.awt.Rectangle; import java.awt.image.BufferedImage; import java.io.File; import java.io.FileInputStream; import java.util.Iterator; import javax.imageio.ImageIO; import javax.imageio.ImageReadParam; import javax.imageio.ImageReader; import javax.imageio.spi.IIORegistry; import javax.imageio.stream.ImageInputStream; public class ImageUtil { private ImageUtil() { } static { IIORegistry registry = IIORegistry.getDefaultInstance(); registry.registerServiceProvider(new com.sun.media.imageioimpl.plugins.tiff.TIFFImageWriterSpi()); registry.registerServiceProvider(new com.sun.media.imageioimpl.plugins.tiff.TIFFImageReaderSpi()); } /** * 裁剪图像 * * @param x,y 起始点 * @param width,height 宽高 * @param srcpath 被裁减图像路径 * @param subpath 裁剪后保存路径 * @param type 图像类型 * @throws Exception */ public static void cut(int x, int y, int width, int height, String srcpath, String subpath, String type) throws Exception { FileInputStream is = null; ImageInputStream iis = null; try { // 读取图片文件 is = new FileInputStream(srcpath); Iterator<ImageReader> it = ImageIO.getImageReadersByFormatName(type); ImageReader reader = it.next(); // 获取图片流 iis = ImageIO.createImageInputStream(is); reader.setInput(iis, true); ImageReadParam param = reader.getDefaultReadParam(); Rectangle rect = new Rectangle(x, y, width, height); // 提供一个 BufferedImage,将其用作解码像素数据的目标。 param.setSourceRegion(rect); BufferedImage bi = reader.read(0, param); ImageIO.write(bi, type, new File(subpath)); } finally { if (is != null) is.close(); if (iis != null) iis.close(); } } /** * 获取图像真实类型 * * @param path 图像路径 * @return 图像类型 * @throws Exception */ public static String getTypeByStream(String path) throws Exception { FileInputStream is = new FileInputStream(path); String type = ""; byte[] b = new byte[4]; try { is.read(b, 0, b.length); } catch (Exception e) { e.printStackTrace(); } finally { if (null != is) { is.close(); } } type = bytesToHexString(b).toUpperCase(); if (type.contains("FFD8FF")) { return "jpg"; } else if (type.contains("89504E47")) { return "png"; } else if (type.contains("47494638")) { return "gif"; } else if (type.contains("49492A00")) { return "tif"; } else if (type.contains("424D")) { return "bmp"; } return type; } /** * byte数组转换成16进制字符串 * * @param src * @return */ private static String bytesToHexString(byte[] src) { StringBuilder stringBuilder = new StringBuilder(); if (src == null || src.length <= 0) { return null; } for (int i = 0; i < src.length; i++) { int v = src[i] & 0xFF; String hv = Integer.toHexString(v); if (hv.length() < 2) { stringBuilder.append(0); } stringBuilder.append(hv); } return stringBuilder.toString(); } }
和初始的工具类相比没什么太多的变动。。。
最后是3个包的下载地址 https://gitee.com/shizuru/ImageUtil/tree/master