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

  需要引入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格式的更多相关文章

  1. C# 图片的裁剪,两个图片合成一个图片

    图片的裁剪,两个图片合成一个图片(这是从网上摘的) /// <summary>         /// 图片裁剪,生成新图,保存在同一目录下,名字加_new,格式1.png  新图1_ne ...

  2. 【开源java游戏框架libgdx专题】-12-开发工具-图片合成

    TexturePackerGui工具: 1.工具使用: 首先看到texturepacker的界面 界面介绍: New pack:创建项目按钮,单击后输入文件名称,创建文件. Input directo ...

  3. php 图片合成时文字颜色丢失

    最近在做图片合成的时候无意间发现文字颜色丢失了,仔细找了以后才发现原来是因为图片格式的原因 当图片是png图片时文字的颜色就变成了白色的,So.........去你妹的png,用jpg吧! $dest ...

  4. canvas图片合成中的坑

    需求 要用代码来实现多张外部图片和文字的合并而且要上传到七牛云,再将图片链接通过客户端分享出去.图片背景需要支持用户自定义更换. 实现方案 在一个canvas上多次调用drawImage函数,分别绘制 ...

  5. pyhton图片合成模块-PIL

    文章链接:https://www.cnblogs.com/lilinwei340/p/6474170.html python PIL实现图片合成   在项目中需要将两张图片合在一起.遇到两种情况,一种 ...

  6. python PIL实现图片合成

    在项目中需要将两张图片合在一起.遇到两种情况,一种就是两张非透明图片的合成, 一种是涉及到透明png的合成. 相关API见 http://pillow.readthedocs.io/en/latest ...

  7. CATIA 使用技巧--转换出轻巧的tif格式文件

    问题描述: 我们在与客户和供应商打交道的过程中经常需要TIF格式2D图纸文件,而默认的CATIA设置保存出来TIF文件非常大,不利于保存和传送.对于该问题,我们可以通过修改CATIA的默认设置选项,将 ...

  8. jpg/png格式图片转eps格式的方法总结

    jpg/png格式图片转eps格式的方法总结 转自http://blog.sina.com.cn/s/blog_5410e7b50101lme2.html 用latex写论文的筒子应该遇到这样的问题: ...

  9. Android  PNG透明图片转JPG格式背景变黑

    Android  PNG透明图片转JPG格式背景变黑 在上传图片是,需要把PNG格式转换成JPG格式的,但是在遇上透明背景时,转过来就变成黑色底图了! 原因是PNG支持透明图而 JPG格式不支持透明底 ...

  10. html5 图片转为base64格式异步上传

    因为有这个需求(移动端),所以就研究了一下,发现还挺不错的.这个主要是用了html5的API,不需要其他的JS插件,不过只有支持html5的浏览器才行,就现在而言应该大部份都支持的.<!DOCT ...

随机推荐

  1. xml简单操作

    1.创建简单的XML 1 XmlDocument XmlDoc = new XmlDocument(); 2 //XML声明 3 var xmlDeclaration = XmlDoc.CreateX ...

  2. ubuntu22.04 git升级

    git --version  //查看版本 sudo add-apt-repository ppa:git-core/ppa   //通过PPA源方式安装软件的添加PPA源到Source list中的 ...

  3. Windows Service调试方法小结

    方法1:log记录 这是一个通用的调试方法,效率比较低,但比较实用,通过查看日志,总能达到调试的目的 方法2:附加到进程 这是Windows Service程序调试的常用方法,缺点是对Windows环 ...

  4. Codeforces 919E Congruence Equation(循环节+数论)

    Link 题意 给$n, m, p, x$,求有多少个$n(1\leq n \leq x)$使得$n·a^{n}=b(\textrm{mod}\;p)$成立 思路 考虑一下左边的循环节长度,由于$n% ...

  5. Vue npm run test 错误 (node:16672) UnhandledPromiseRejectionWarning: CssSyntaxError:xxxx.Unknown word

    记一次运行代码上传的测试服务器遇到的坑,昨天上传还好好的,今天上传就报以下错误,以为是忘记下什么插件了,简单粗暴的把node_modules下载重装了,结果还是不行,看看什么情况吧~~~ npm ru ...

  6. dp-状压dp

    https://www.bilibili.com/video/BV1Z4411x7Kw?from=search&seid=13855865082722302053 状压介绍: 状态表示: 转移 ...

  7. Vue2 常见问题汇总及解决方案

    参考:https://mp.weixin.qq.com/s/6Wapb1bZLQaYv0zlip6ygg 1.安装超时(install timeout) 方案: cnpm : 国内对npm的镜像版本 ...

  8. mysql:数据库加解密查询

    解密:SELECT CONVERT (AES_DECRYPT(UNHEX( column_name), '密钥') USING utf8) AS column_name,from table_name ...

  9. docker私有镜像仓库搭建(简)

    1.装包 yum install docker-registry 2.启动服务 systemctl start docker-distribution 3.打标自己的镜像 docker tag mys ...

  10. pg9.6进程架构

    进程架构 1.1 进程父子关系 PostgreSQL 的进程架构由多个后端进程组成,其父进程是 postmaster.进程 ID 记录在 {PGDATA}/postmaster.pid 文件中.当实例 ...