我有几个文件包含一个特定的标题,后跟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
我应该在合并标题和图像数据之前解压缩图像数据吗?
答案 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)。对于XResolution
和YResolution
,只需写入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);
}