通过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();
    }

}
ImageUtil-origin

以前使用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();
    }

}
ImageUtil

和初始的工具类相比没什么太多的变动。。。

最后是3个包的下载地址 https://gitee.com/shizuru/ImageUtil/tree/master

原文地址:https://www.cnblogs.com/s1165482267/p/8717407.html