zoukankan      html  css  js  c++  java
  • JAI 多图片合成TIF格式

      因为项目需要,所以要做这么个工具类,发现了一些问题,接下来一一说明。

      需要引入jai-codec-1.1.3.jar跟jai_code-1.1.3.jar。

      1.判断图片格式:

      JPEG (jpg),文件头:FFD8FF ,结尾:FFD9

      PNG (png),文件头:89504E47 

      GIF (gif),文件头:47494638 

      TIFF (tif),文件头:49492A00
      Windows Bitmap (bmp),文件头:424D

      -- 可以通过UltraEdit进行查看图片的十六进制内容

        /**
         * 判断图片格式
         * @param fis
         * @return
         */
        private static String getPicType(FileInputStream fis) {
            //读取文件的前几个字节来判断图片格式
            byte[] b = new byte[4];
            try {
                fis.read(b, 0, b.length);
                String 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("424D")) {
                    return "bmp";
                }else{
                    return "unkown";
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if(fis != null){
                    try {
                        fis.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            return null;
        }
    
        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();
        }

      2.多张图片合成TIF,因为合成之后可能文件会很大,所以采用了压缩模式(TIFFEncodeParam.COMPRESSION_JPEG_TTN2),但是压缩模式需要将图片都转为JPG格式

        /**
         *
         * @param imageFileList 图片路径列表 (图片为E:/xx/xx.jpg格式)
         * @param toPath tif文件所放路径
         * @param distFileName tif文件名
         * @param convertPath 转换图片存放路径
         * @param isCompress 是否压缩(压缩的时候是先将不是jpg的格式转为jpg,因为JAI可以设置JPEG的压缩模式。
         *                            但是png转jpg会有点失真,所以建议用非压缩的方式!!!)
         */
        public static String manyImgToTif(List<String> imageFileList,String toPath, String distFileName, String convertPath, boolean isCompress) {
            String tifFile = null;
            if(imageFileList != null && imageFileList.size()>0){
                List<File> fileArr = new ArrayList<File>();
                String fileName;
                String imageFile;
                String fileType = "";
                File tmpFile ;
                FileInputStream tmpIns = null;
                boolean isNeedTransfer = false;
                for (int i = 0; i < imageFileList.size(); i++){
                    imageFile = imageFileList.get(i);
                    String[] tempFile = imageFile.split("/");
                    fileName = tempFile[tempFile.length-1];
                    tmpFile = new File(imageFile);
    
                    // 处理文件
                    try {
                        // 以防是png格式的图片直接改后缀的情况
                        tmpIns = new FileInputStream(tmpFile);
                        fileType = getPicType(tmpIns);
    
                        if(isCompress){
                            File convertFile = new File(convertPath);
                            if (!convertFile.exists()) {
                                convertFile.mkdirs();
                            }
    
                            if ("bmp".equals(fileType)
                                    || "jpg".equals(fileType)){
                                // 有时图片有损坏,但是能展示,就是用这个架包的时候会报错,
                                // 比较严格,所以需要捕获异常做一下转换
                                isNeedTransfer = false;
                                try{
                                    // 需要重新获取流,因为上面判断格式已经读过流了.
                                    tmpIns = new FileInputStream(tmpFile);
                                    JPEGImageDecoder decoder = JPEGCodec.createJPEGDecoder(tmpIns);
                                    decoder.decodeAsBufferedImage();
                                } catch (TruncatedFileException e){
                                    e.printStackTrace();
                                    logger.info("图片有损坏,需要做转换,image:"+imageFile);
                                    isNeedTransfer = true;
                                }
    
                                if(isNeedTransfer){
                                    fileArr.add(pngtoJpg(imageFile,convertPath,fileName));
                                } else {
                                    fileArr.add(new File(imageFile));
                                }
    
                            } else if("gif".equals(fileType)){
                                fileArr.add(giftoJpg(imageFile,convertPath,fileName));
                            }else if("png".equals(fileType)){
                                fileArr.add(pngtoJpg(imageFile,convertPath,fileName));
                            }
                        } else {
                            if ("bmp".equals(fileType)
                                    || "jpg".equals(fileType)
                                    || "gif".equals(fileType)
                                    || "png".equals(fileType)){
                                fileArr.add(new File(imageFile));
                            }
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    } finally {
                        if(tmpIns != null){
                            try {
                                tmpIns.close();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                    }
    
                }
    
                if (fileArr.size() > 0) {
                    try {
                        ArrayList pages = new ArrayList(fileArr.size() - 1);
                        FileSeekableStream[] stream = new FileSeekableStream[fileArr.size()];
                        for (int i = 0; i < fileArr.size(); i++) {
                            stream[i] = new FileSeekableStream(fileArr.get(i).getCanonicalPath());
                        }
                        ParameterBlock pb = (new ParameterBlock());
                        PlanarImage firstPage = JAI.create("stream", stream[0]);
                        for (int i = 1; i < fileArr.size(); i++) {
                            PlanarImage page = JAI.create("stream", stream[i]);
                            pages.add(page);
                        }
                        TIFFEncodeParam param = new TIFFEncodeParam();
                        if(isCompress){
                            param.setCompression(TIFFEncodeParam.COMPRESSION_JPEG_TTN2);
                        }
    
                        TIFFField[] extras = new TIFFField[4];
                        extras[0] = new TIFFField(262, TIFFField.TIFF_SHORT, 1, (Object) new short[] { 6 });
                        extras[1] = new TIFFField(282, 5, 1, (Object) new long[][]{{(long) 200, 1}, {0, 0}});
                        extras[2] = new TIFFField(283, 5, 1, (Object) new long[][]{{(long) 200, 1}, {0, 0}});
                        extras[3] = new TIFFField(258, TIFFField.TIFF_SHORT, 1, (Object) new char[] { 8 });
                        param.setExtraFields(extras);
                        param.setExtraImages(pages.iterator());
    
                        File f = new File(toPath);
                        if (!f.exists()) {
                            f.mkdirs();
                        }
    
                        tifFile = toPath + "\"+ distFileName+".tif";
                        OutputStream os = new FileOutputStream(tifFile);
                        ImageEncoder enc = ImageCodec.createImageEncoder("tiff", os, param);
    
                        enc.encode(firstPage);
                        //关掉流
                        os.flush();
                        os.close();
                        for (int i = 0; i < fileArr.size(); i++) {
                            stream[i].close();
                        }
    
                        logger.info("====manyImgToTif done====");
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            return tifFile;
        }

      3.遇到的问题:

    java.lang.ArrayIndexOutOfBoundsException: 3
        at com.sun.media.jai.codec.JPEGEncodeParam.getHorizontalSubsampling(JPEGEncodeParam.java:104)

      这个是因为图片不都是JPG格式,但却采用了TIFFEncodeParam.COMPRESSION_JPEG_TTN2压缩模式导致的出错,转为JPG格式就好了。

     java.lang.RuntimeException: - Unable to render RenderedOp for this operation.
        at javax.media.jai.RenderedOp.createInstance(RenderedOp.java:827)
    Caused by: com.sun.image.codec.jpeg.ImageFormatException: Not a JPEG file: starts with 0xff 0xd9

      这个是因为图片有损坏,例如JPG格式,文件头是FFD8FF ,但可能结尾不是FFD9,所以导致处理的时候会有问题,所以需要重读取流再转换一下就正常了。

      附录-两个转换方法(png->jpg,bmp->jpg)

         public static File pngtoJpg(String fromImg, String path , String fileName) {
                File outFile = new File(path+ File.separator+fileName+"_convert.jpg");
                try {
                    FileOutputStream out = new FileOutputStream(outFile);
                    File img = new File(fromImg);
                    BufferedImage image = ImageIO.read(img);
    
                    BufferedImage newBufferedImage = new BufferedImage(image.getWidth(),
                            image.getHeight(), BufferedImage.TYPE_INT_RGB);
                    //TYPE_INT_RGB:创建一个RBG图像,24位深度,成功将32位图转化成24位
                    newBufferedImage.createGraphics().drawImage(image, 0, 0, Color.WHITE, null);
                    ImageIO.write(newBufferedImage,"jpg",outFile);
    
                    out.flush();
                    out.close();
    
                }catch (IOException e){
                    e.printStackTrace();
                }
                return outFile;
            }
    
        public static File giftoJpg(String fromImg, String path, String fileName) {
            File outFile = new File(path+ File.separator+fileName+"_convert.jpg");
            try {
                File infile = new File(fromImg);
                BufferedImage src = null;
                src = ImageIO.read(infile);
                int wideth = src.getWidth(null);
                int height = src.getHeight(null);
    
                BufferedImage tag = new BufferedImage(wideth , height , BufferedImage.TYPE_INT_RGB);
                tag.getGraphics().drawImage(src, 0, 0, wideth , height , null);
                FileOutputStream out = new FileOutputStream(outFile);
                JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
                encoder.encode(tag);
                out.flush();
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
    
            return outFile;
        }
  • 相关阅读:
    matplotlib-形状
    matplotlib-区域填充
    C++文件操作
    画数学公式
    文字
    画注释
    Doubango简介-sip
    boost的asio接收单路大数据量udp包的方法
    Boost.Asio基本原理(CSDN也有Markdown了,好开森)
    boot asio 非阻塞同步编程---非阻塞的accept和receive。
  • 原文地址:https://www.cnblogs.com/zgz21/p/12017002.html
Copyright © 2011-2022 走看看