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

  需要引入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;
}

最新文章

  1. C++基础知识(3)---new 和 delete
  2. label与input间距的小问题
  3. iOS之 动态热修补技术JSPatch
  4. Openwrt flash 空间不足的临时解决方法
  5. WCF TCP 错误代码 10061: 由于目标计算机积极拒绝
  6. 来自“Java中国”优秀的程序员不会觉得累成狗是一种荣耀
  7. 纯CSS完美实现垂直水平居中的6种方式
  8. wordpress 如何从后台数据库修改theme(图文教程)
  9. Linux Shell 学习笔记
  10. 【原创】poj ----- 2376 Cleaning Shifts 解题报告
  11. 使用crontab,让linux定时执行shell脚本
  12. Effective Java 第三版——1. 考虑使用静态工厂方法替代构造方法
  13. hadoop用户写入文件权限不够的问题
  14. MySQL 存储过程循环
  15. 将数据转换成树型层级的Json格式的String
  16. C#设计模式之四建造者模式(Builder Pattern)【创建型】
  17. MySQL 5.6 GTID Replication
  18. Angular service定义服务
  19. 2018 How to register and install LAUNCH ICARSCAN software ?
  20. [ASE][Daily Scrum]11.11

热门文章

  1. MySQL8.0 存储引擎(InnoDB )buffer pool的实现原理
  2. linux 操作命令大全
  3. .net core 3.1 上传大文件报错413 Payload Too Large
  4. VUE学习-自定义指令
  5. Pygame的基本应用(14周)
  6. js 页面小数相加精度问题
  7. 粉色的猫MISC(bugku)
  8. 第4关—input()函数
  9. linux 源码安装 xrdp
  10. C# 海康威视网络半球摄像头回调YV12取画面