gpt4 book ai didi

java - ClassCastException使用iText将TIF转换为PDF

转载 作者:行者123 更新时间:2023-12-02 12:28:15 27 4
gpt4 key购买 nike

我在Windows 7上使用带有Java 7(1.7.0_71)64位的iText版本5.5.6(也已测试5.3.4)

这是示例代码

@Test
public void testConvert() throws Exception {
try{
//Read the Tiff File
RandomAccessFileOrArray myTiffFile=new RandomAccessFileOrArray("C:\\local\\docs\\test.01.tif");
//Find number of images in Tiff file
int numberOfPages= TiffImage.getNumberOfPages(myTiffFile);
System.out.println("Number of Images in Tiff File: " + numberOfPages);
Document TifftoPDF=new Document();
PdfWriter.getInstance(TifftoPDF, new FileOutputStream("C:\\local\\docs\\test.01.pdf"));
TifftoPDF.open();
//Run a for loop to extract images from Tiff file
//into a Image object and add to PDF recursively
for(int i=1;i<=numberOfPages;i++){
//*******
//******* this next line is generating the error
//*******
Image tempImage=TiffImage.getTiffImage(myTiffFile, i);
TifftoPDF.add(tempImage);
}
TifftoPDF.close();
System.out.println("Tiff to PDF Conversion in Java Completed" );
}
catch (Exception i1){
i1.printStackTrace();
}
}


产生以下错误

java.lang.ClassCastException
at com.itextpdf.text.pdf.codec.TIFFField.getAsInt(TIFFField.java:315)
at com.itextpdf.text.pdf.codec.TiffImage.getTiffImage(TiffImage.java:163)
at com.itextpdf.text.pdf.codec.TiffImage.getTiffImage(TiffImage.java:315)
at com.itextpdf.text.pdf.codec.TiffImage.getTiffImage(TiffImage.java:303)
at com.pdf.ImageConverterImplIT.testConvert(ImageConverterImplIT.java:116)

最佳答案

我将深入探讨文件的十六进制手术,iText异常的原因以及最终导致此错误的原因。然后,我将继续说明这一现象的发生原因。

您的文件结构合理,因此主IFD位于文件末尾。这是文件头:

49 49 2A 00 96 6C 00 00 
intel magic offset-----


其中说:“我是Intel(小尾数)字节顺序的TIFF,我的主要IFD从偏移量0x6c9c开始。

如果您跳到该地点,您会看到以下内容:

0F 00 <- this is the total number of tags, each tag is 12 bytes

# | ID |Type | Count | Value |
01. 00 01 04 00 01 00 00 00 A2 06 00 00 width = 6a2
02. 01 01 04 00 01 00 00 00 4A 04 00 00 height = 44a
03. 02 01 03 00 01 00 00 00 01 00 00 00 bits per sample = 1
04. 03 01 03 00 01 00 00 00 04 00 00 00 Compression = CCITT G4
05. 06 01 03 00 01 00 00 00 00 00 00 00 Photometric = min is white
06. 0A 01 04 00 01 00 00 00 01 00 00 00 Fill order = msb to lsb
07. 11 01 04 00 01 00 00 00 08 00 00 00 Offset of strips = 8
08. 15 01 03 00 01 00 00 00 01 00 00 00 Samples per pixel = 4
09. 16 01 04 00 01 00 00 00 4A 04 00 00 Rows per strip = 448
0a. 17 01 04 00 01 00 00 00 5B 6C 00 00 Strip byte counts = 6c5b
0b. 1A 01 05 00 01 00 00 00 63 6C 00 00 Offset to x resolution = 6c63
0c. 1B 01 05 00 01 00 00 00 6B 6C 00 00 Offset to y resolution = 6c6b
0d. 1C 01 03 00 01 00 00 00 01 00 00 00 Planar Config = Contiguous
0e. 28 01 03 00 01 00 00 00 02 00 00 00 Resolution unit = inches
0f. 31 01 02 00 23 00 00 00 73 6C 00 00 Software string offset = 6c73
Location of next IFD, 0 means no more
00 00 00 00


现在,查看调用堆栈并将其追溯到源,我看到正在进行调用以获取填充顺序。 1位文件的填充顺序描述了字节中的高位还是低位在显示的最左边。

TIFFField fillOrderField =  dir.getField(TIFFConstants.TIFFTAG_FILLORDER);
if (fillOrderField != null)
fillOrder = fillOrderField.getAsInt(0);


我们知道这会被调用,因为您的IFD中有一个填充顺序标记,该标记是一个4字节的整数,值1。

不幸的是,对 TIFFFIELD.getAsInt(0)的调用导致失败。

如果您查看该代码:

public int getAsInt(int index) {
switch (type) {
case TIFF_BYTE: case TIFF_UNDEFINED:
return ((byte[])data)[index] & 0xff;
case TIFF_SBYTE:
return ((byte[])data)[index];
case TIFF_SHORT:
return ((char[])data)[index] & 0xffff;
case TIFF_SSHORT:
return ((short[])data)[index];
case TIFF_SLONG:
return ((int[])data)[index];
default:
throw new ClassCastException();
}
}


您可以看到,如果类型不匹配,它会引发ClassCastException,在这种情况下,它将是因为这些情况下的那些类型常量分别为1、7、6、3、8和9,并且标记的类型为4。

那么为什么代码错误呢?

TIFF标记的问题是,即使规格非常清楚,FillOrder标记(10a)应该是无符号的short(类型3),文件中的标记也是4字节的无符号int(类型4),但是那里的switch语句并不能解决这个问题(TIFF_LONG则不适用)。

为什么没有这种情况?查看周围的代码,该库将4字节无符号整数视为Java类型'long',并尝试将4字节无符号int视为4字节有符号int可能导致符号位溢出(即使没有合法值)因为此标记会触发该操作),因此由于该转换可能会导致错误,因此将其始终视为一个。

最终,导致此错误的原因有两点:


Java仅具有一种无符号整数类型(对于您在家中的那些人来说,为 char),并且该库选择使用 long表示无符号4字节int。
这个特定的档案不符合规格,并且在这个标签中使用 unsigned int


更具体地说,在所选的Java类型和此TIFF文件之间存在阻抗不匹配。该域代码正试图成为类型强。调用代码正在尝试接受各种各样的类型。它错过了这种情况。

我看了看自己的标记代码,看看是否会受到这个特殊问题的困扰。答案是否定的,因为如果我要这样做,我的getIntValue()版本会让您溢出到符号位中。

因此,真正的解决方法是将代码更改为:

TIFFField fillOrderField =  dir.getField(TIFFConstants.TIFFTAG_FILLORDER);
if (fillOrderField != null)
fillOrder = (int)fillOrderField.getAsLong(0);


或对文件执行十六进制手术,并将填充顺序标签的数据类型更改为 unsigned short。最终,这是一个糟糕的解决方案,因为使用的代码仍然容易受到不良TIFF文件的影响。



免费熨平板

在过去的10年中,我了解到使用TIFF文件的一件事是,不乏损坏的TIFF文件,也​​没有缺乏工程师,他们要么没有阅读规范,要么没有正确实施规范,无法制作新的损坏文件(有时我是那个工程师)。其中一些是研究生,他们需要立即输出TIFF,并编写一个快速且肮脏的编码器,当IrfanView可以打开其输出时,他们认为正确(这是自IrfanView以来的无效测试,并且我的TIFF编解码器也打开了)各种各样的基本中断的TIFF)。

TIFF specification似乎是直截了当的。我说这是因为格式本身感觉应该相对容易生成。标签是合乎逻辑的,IFD是标签的简单集合,指针标签可能很棘手,但易于管理。发生的结果是,编写的代码缺乏抽象级别,这将阻止错误类别的泄漏,否则这些错误类别可能会漏掉。

该特定文件不是由研究生编写的。至少我不这么认为。

在这种情况下,此问题可能是由 fCoder引起的。我们知道这一点是因为他们将其放入软件字符串 Created by fCoder Graphics Processor中。我之所以称呼他们是因为他们使用软件字符串来标识自己。该错误(类型错误,可能是由于其源中的复制粘贴错误所致),虽然是次要错误,但会引起问题,也许他们会解决。在我的世界中,排名第一的优先删除所有错误是“生成错误的文件”。如果我这样做了,我肯定会想知道的,这样我就可以修复我的代码。同时,iText还应该更新其代码,以便能够接受此类文件。

得到教训:


规范是对“我的文件正确”问题的答案。
编写体面的TIFF编码器或解码器很困难。在编写自己的库之前,请考虑一个商业库(尽管在此示例中,我们发现的错误不是在一个商业库中而是在两个商业库中)。
生成文件时,请输入软件字符串,以便在出现问题时与您联系。


在这里结束这一课。

关于java - ClassCastException使用iText将TIF转换为PDF,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30171261/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com