如何从TIFF图像数据创建TIFF文件

时间:2014-08-07 09:51:55

标签: java image tiff

我有几个文件包含一个特定的标题,后跟TIFF图像数据。 如何将这些TIFF图像数据写入TIFF文件? 谢谢你的帮助。

编辑:这是我测试的内容:

InputStream is = new FileInputStream(filePath);
is.skip(252);
BufferedImage bufferedImage = ImageIO.read(is);
File fileOut = new File(fileOutPath);
ImageIO.write(bufferedImage,"TIFF", fileOut);

我跳过文件的特定标题(252Bytes)以获取Tiff图像数据字节。 但是bufferedImage为null所以我得到了一个java.lang.IllegalArgumentException:im == null!异常。

在简历中,我有一个没有TIFF标题的TIFF文件。 TIFF标题已被特定标题替换,但图像字节与TIFF文件中的完全相同。

编辑: 感谢haraldK,我终于可以创建一个TIFF标题。但我无法打开图像,可能是因为压缩:“M2 =修改后的读码II(MRII),即传真组4”。

这是我创建的标题:

SubFileType (1 Long): Zero
ImageWidth (1 Long): 210
ImageLength (1 Long): 297
BitsPerSample (3 Short): 8, 8, 8
Compression (1 Short): Group 4 Fax (aka CCITT FAX4)
Photometric (1 Short): RGB
StripOffsets (1 Long): 306
SamplesPerPixel (1 Short): 3
RowsPerStrip (1 Short): 297
StripByteCounts (1 Long): 187110
ResolutionUnit (1 Short): None
XResolution (72 Rational): 
YResolution (1 Rational): Unexpected numeric
DateTime (20 ASCII): 2014:07:12 10:51:51 
Software (28 ASCII): Put your software name here 
ImageDescription (30 ASCII): Put an image description here 

我应该在合并标题和图像数据之前解压缩图像数据吗?

2 个答案:

答案 0 :(得分:0)

您可以尝试javax.imageio.ImageIO读/写操作,如下所示:

ImageIO.write(img, "TIFF", new File('fileName'));

或者您可以使用Java Advanced Imaging API

答案 1 :(得分:0)

免责声明:这不是一个完全有效的例子(我需要一些示例文件来验证),而是概述了这个想法。

首先,打开一个文件流,然后跳过专有标题(你的代码假定你总是可以跳过你喜欢的字节数,但情况并非如此):

InputStream is = new FileInputStream(filePath);

int toSkip = 252;
int skipped = 0;

while (toSkip > 0 && (skipped = is.skip(toSkip)) >= 0) {
    toSkip -= skipped;
}

然后,根据TIFF specification重新创建有效的最小TIFF标头。这实际上并不太难:

ByteArrayOutputStream bytes = new ByteArrayOutputStream();
DataOutputStream dataOut = new DataOutputStream(bytes);

dataOut.write('M');
dataOut.write('M');     // "Motorola" (network) byte order
dataOut.writeShort(42); // TIFF magic identifier (42)

dataOut.writeUnsignedInt(8); // Offset to 1st IFD

// ... write IFD, containing minimal info as per the spec

由于您的输入数据似乎是双层或黑/白传真格式(参考注释),请参阅规范中的第3节:双层图像(第17页)以获取必填字段和允许值。有关普通RGB图像,请参阅第6节:RGB全彩色图像(第24页)。

请注意,规范中的SHORT是Java中的(无符号)short,但LONG是(无符号)int。另请注意,必须按增加的标记顺序写入字段。 RATIONAL可以写成两个LONG(即两个无符号int s)。对于XResolutionYResolution,只需写入72/1,因为这是默认的72 DPI。对于在IFD之前写入的字节,StripOffsets将是IFD + 8的长度。如果您没有条带,请将RowsPerStrip设置为ImageLength,将StripByteCounts设置为等于整个(压缩)图像数据的长度。

完成对标题的编码后,合并标题和图像数据,然后读取它:

ByteArrayInputStream header = new ByteArrayInputStream(bytes.toByteArray());
InputStream stream = new SequenceInputStream(header, is); // Merge header and image data

现在,您可以阅读图片:

BufferedImage image = ImageIO.read(stream); // Read image

// TODO: Test that image is non-null before attempting to write

但是,如果您只将TIFF写回文件,则可以将数据从stream复制到新文件,并尝试在外部工具中打开它。与在Java中解码图像,然后将其编码回TIFF(并且不需要JAI或ImageIO的其他TIFF插件)相比,这种方法将更快,所需内存更少:

OutputStream os = new FileOutputStream(new File(...));

byte[] buffer = new byte[1024];
int read;

while ((read = stream.read(buffer) >= 0) {
   os.write(0, read, buffer);
}