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;
    }
JAI 多图片合成TIF格式的更多相关文章
- C# 图片的裁剪,两个图片合成一个图片
		图片的裁剪,两个图片合成一个图片(这是从网上摘的) /// <summary> /// 图片裁剪,生成新图,保存在同一目录下,名字加_new,格式1.png 新图1_ne ... 
- 【开源java游戏框架libgdx专题】-12-开发工具-图片合成
		TexturePackerGui工具: 1.工具使用: 首先看到texturepacker的界面 界面介绍: New pack:创建项目按钮,单击后输入文件名称,创建文件. Input directo ... 
- php 图片合成时文字颜色丢失
		最近在做图片合成的时候无意间发现文字颜色丢失了,仔细找了以后才发现原来是因为图片格式的原因 当图片是png图片时文字的颜色就变成了白色的,So.........去你妹的png,用jpg吧! $dest ... 
- canvas图片合成中的坑
		需求 要用代码来实现多张外部图片和文字的合并而且要上传到七牛云,再将图片链接通过客户端分享出去.图片背景需要支持用户自定义更换. 实现方案 在一个canvas上多次调用drawImage函数,分别绘制 ... 
- pyhton图片合成模块-PIL
		文章链接:https://www.cnblogs.com/lilinwei340/p/6474170.html python PIL实现图片合成 在项目中需要将两张图片合在一起.遇到两种情况,一种 ... 
- python PIL实现图片合成
		在项目中需要将两张图片合在一起.遇到两种情况,一种就是两张非透明图片的合成, 一种是涉及到透明png的合成. 相关API见 http://pillow.readthedocs.io/en/latest ... 
- CATIA 使用技巧--转换出轻巧的tif格式文件
		问题描述: 我们在与客户和供应商打交道的过程中经常需要TIF格式2D图纸文件,而默认的CATIA设置保存出来TIF文件非常大,不利于保存和传送.对于该问题,我们可以通过修改CATIA的默认设置选项,将 ... 
- jpg/png格式图片转eps格式的方法总结
		jpg/png格式图片转eps格式的方法总结 转自http://blog.sina.com.cn/s/blog_5410e7b50101lme2.html 用latex写论文的筒子应该遇到这样的问题: ... 
- Android  PNG透明图片转JPG格式背景变黑
		Android PNG透明图片转JPG格式背景变黑 在上传图片是,需要把PNG格式转换成JPG格式的,但是在遇上透明背景时,转过来就变成黑色底图了! 原因是PNG支持透明图而 JPG格式不支持透明底 ... 
- html5 图片转为base64格式异步上传
		因为有这个需求(移动端),所以就研究了一下,发现还挺不错的.这个主要是用了html5的API,不需要其他的JS插件,不过只有支持html5的浏览器才行,就现在而言应该大部份都支持的.<!DOCT ... 
随机推荐
- 蓝桥杯题目——翻硬币无需修改‘*’与’o‘的特殊解法及其所包含的思想
			前言 本文介绍蓝桥杯题目--翻硬币的一种无需对字符串进行操作的解法及该解法所包含的思想. 题目信息 桌上放着排成一排的若干硬币.我们用 * 表示正面,用 o 表示反面(是小写字母,不是零). 比如,可 ... 
- ES6的总结的一些数组、字符串方法
			1.数组的方法 unshift() 数组头部添加内容 push() 数组尾部添加内容 pop() 数组尾部删除内容 shift() 数组头部删除内容 sort() 数组排序 a-b 升序 b-a 降序 ... 
- excel添加下拉列表
			2016年数据验证,2010是数据校验 
- ABAP学习(35):常用Function
			ABAP Function ABAP Coding过程中比较好用的Function整理. 1.获取Domain信息 代码实例: "****************************** ... 
- node版本和用的包不兼容问题,头疼
			经常遇到node版本和包不兼容的问题,在茫茫大海中学习的时候发现一个nvm,可以随时切换node版本,简直不要太开心,附上流程 环境windows 首先:下载一个nvm包https://github. ... 
- protected virtual 使用
			转载摘自:https://blog.csdn.net/qq_31116753/article/details/81203416 1.使用protected访问修饰符标记的方法或字段,只能在当前类及其子 ... 
- kafka集群under replicated分析
			近期随着业务消息量增大,现网几套kafka集群频繁收到under repliacted告警,集合近期定位分析过程,主要有以下几个方面:1. 查看是否有主机挂掉,或近期是否有主机重启,通过kafdrop ... 
- vxWidgets(一):初识
			wxWidgets 和 QT 之间的选择 跨平台的C++ GUI工具库很多,可是应用广泛的也就那么几个,Qt.wxWidgets便是其中的翘楚这里把GTK+排除在外,以C实现面向对象,上手相当困难,而 ... 
- Ubuntu14.04下Git安装与使用
			Workspace : 工作区,就是你平时存放项目代码的地方 Index / Stage : 暂存区,用于临时存放你的改动,事实上它只是一个文件,保存即将提交到文件列表信息 Repository ... 
- Biba模型(MAC)
			毕巴模型用完整性级别来对完整性进行量化描述. 设i1和i2是任意两个完整性级别,如果完整性级别为i2的实体比完整性级别为i1的实体具有更高的完整性,则称完整性级别i2绝对支配完整性级别i1,记为:i ... 
