Java 使用有损jpeg压缩多页tiff图像

Java 使用有损jpeg压缩多页tiff图像,java,image,compression,tiff,Java,Image,Compression,Tiff,我需要压缩一个tif文件,其中包含多页的几个16位灰度图像。我在这里尝试过使用ImageIO:最初,tif文件中的每个图像都来自另一个tiff文件。当我想使用压缩器时,我有以下选项: CCITT RLE、CCITT.4、CCITT.6:他们给了我一个错误:javax.imageio.IIOException:I/O错误写入TIFF文件! LZW。我不能用它。我的图像是16位的,LZW增加了16位图像的大小 JPEG。不可能用于16位图像。 兹利布。即使我指定setCompressionQuali

我需要压缩一个tif文件,其中包含多页的几个16位灰度图像。我在这里尝试过使用ImageIO:最初,tif文件中的每个图像都来自另一个tiff文件。当我想使用压缩器时,我有以下选项:

CCITT RLE、CCITT.4、CCITT.6:他们给了我一个错误:javax.imageio.IIOException:I/O错误写入TIFF文件! LZW。我不能用它。我的图像是16位的,LZW增加了16位图像的大小 JPEG。不可能用于16位图像。 兹利布。即使我指定setCompressionQuality0.0f,它也只会减少10%; 背包。不压缩。 瘪下来比如ZLIB。 EXIF JPEG。它给了我一个错误:javax.imageio.IIOException:不支持旧的JPEG压缩!
有人知道其他的选择吗?我看到了一个apache imaging库,但tif压缩只支持上述或更少的选项。有人知道JPEG2000压缩机吗?任何其他类型的替代方案?

PNG无损压缩16位图像。图书馆和公共设施随处可见。JPEG2000具有有损16位模式,但您必须找到一些支持该模式的软件。可能


然而,我不得不问:当你有可接受的图像质量时,你的标准是什么?如果它是可视的,那么不管怎么说,最终都可能是正常的JPEG格式,每像素的有效位不到8位。

将图像的16位减少到8位。假设你有一个字节[]变量平面16,在那里你有你的图像的所有像素。 注意:My byte[]plane16从16位图像获取数据,但字节为8bit=1byte。因此,该数组行中的2个元素为2byte=16位。这就是为什么我在操作之前将其转换为短[]。如果从短[]开始,则ommit ByteBuffer.wrapplane16.orderByteOrder.LITTLE_ENDIAN.asShortBuffer.getshorts

byte[] plane16; //Fill it with your image!!!

//Do stuff with imageIO. Set writer and compresion method
ImageIO.scanForPlugins();
TIFFImageWriterSpi tiffspi = new TIFFImageWriterSpi();
javax.imageio.ImageWriter writerIO = tiffspi.createWriterInstance();
ImageWriteParam param = writerIO.getDefaultWriteParam();
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionType("ZLib");
param.setCompressionQuality(0.5f);
File fOutputFile = new File(route+".tif");
ImageOutputStream ios = ImageIO.createImageOutputStream(fOutputFile);
writerIO.setOutput(ios);

//Reducing 16bit to 8bit
short[] shorts = new short[plane16.length/2];
ByteBuffer.wrap(plane16).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(shorts);

int max = 0;
int min = 999999;
for (int v = 0; v<shorts.length;v++){
    if (max<shorts[v]) max = shorts[v];
    if (min>shorts[v]) min = shorts[v];
}

double range = 255./(max-min);
byte[] plane8 = new byte[shorts.length];
for (int v = 0; v<plane8.length;v++){
    plane8[v] = (byte) ((shorts[v]+min)*range - 128);   
}                       
//16bit:    
/*BufferedImage convertedGrayscale = new BufferedImage(width,
                            heigth, BufferedImage.TYPE_USHORT_GRAY);    
  convertedGrayscale.getRaster().setDataElements(0, 0, width,
                            heigth, shorts);*/

//8bit:
BufferedImage convertedGrayscale = new BufferedImage(width,
                            heigth, BufferedImage.TYPE_BYTE_GRAY);  
convertedGrayscale.getRaster().setDataElements(0, 0, width,
                            heigth, plane8);

//Save image
//If you have a stack of images in tiff, do this trick. "image" is the image number you are setting inside the tiff. If you only have 1 image, remove the if and take the expression from the else.
if (image!=0){
    writerIO.writeInsert(image, new IIOImage(convertedGrayscale, null, null), param);                   
}else{
    writerIO.write(null, new IIOImage(convertedGrayscale, null, null), param);
}

//do the next only after the last image to be saved
writerIO.dispose();
ios.flush();
ios.close();

事实上,你让我想如果我能直接把16位转换成8位。如果我这样做了,我在视觉上看到的图像会很好,体重也会减少。如果有人需要将16位转换成8位的代码,请看我的答案。