Skip to content

Commit acdfde5

Browse files
glenn.volckaertguustysebie
authored andcommitted
Update CCITT EOL handling to cope with fill.
DEVSIX-5565
1 parent 1f84b91 commit acdfde5

File tree

5 files changed

+70
-104
lines changed

5 files changed

+70
-104
lines changed

io/src/main/java/com/itextpdf/io/codec/TIFFFaxDecoder.java

Lines changed: 14 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -852,7 +852,7 @@ public void decode2D(byte[] buffer, byte[] compData, int startX, int height, lon
852852
fillBits = (int) ((tiffT4Options & 0x04) >> 2);
853853

854854
// The data must start with an EOL code
855-
if (readEOL(true) != 1) {
855+
if (readEOL() != 1) {
856856
throw new IOException(IOException.FirstScanlineMustBe1dEncoded);
857857
}
858858

@@ -868,7 +868,7 @@ public void decode2D(byte[] buffer, byte[] compData, int startX, int height, lon
868868

869869
// Every line must begin with an EOL followed by a bit which
870870
// indicates whether the following scanline is 1D or 2D encoded.
871-
if (readEOL(false) == 0) {
871+
if (readEOL() == 0) {
872872
// 2D encoded scanline follows
873873

874874
// Initialize previous scanlines changing elements, and
@@ -1386,61 +1386,16 @@ private int decodeBlackCodeWord() {
13861386
return runLength;
13871387
}
13881388

1389-
private int readEOL(boolean isFirstEOL) {
1390-
if (fillBits == 0) {
1391-
int next12Bits = nextNBits(12);
1392-
if (isFirstEOL && next12Bits == 0) {
1393-
1394-
// Might have the case of EOL padding being used even
1395-
// though it was not flagged in the T4Options field.
1396-
// This was observed to be the case in TIFFs produced
1397-
// by a well known vendor who shall remain nameless.
1398-
1399-
if (nextNBits(4) == 1) {
1400-
1401-
// EOL must be padded: reset the fillBits flag.
1402-
1403-
fillBits = 1;
1404-
return 1;
1405-
}
1406-
}
1407-
if (next12Bits != 1) {
1408-
throw new IOException(IOException.ScanlineMustBeginWithEolCodeWord);
1409-
}
1410-
} else if (fillBits == 1) {
1411-
1412-
// First EOL code word xxxx 0000 0000 0001 will occur
1413-
// As many fill bits will be present as required to make
1414-
// the EOL code of 12 bits end on a byte boundary.
1415-
1416-
int bitsLeft = 8 - bitPointer;
1417-
1418-
if (nextNBits(bitsLeft) != 0) {
1419-
throw new IOException(IOException.AllFillBitsPrecedingEolCodeMustBe0);
1420-
}
1421-
1422-
// If the number of bitsLeft is less than 8, then to have a 12
1423-
// bit EOL sequence, two more bytes are certainly going to be
1424-
// required. The first of them has to be all zeros, so ensure
1425-
// that.
1426-
if (bitsLeft < 4) {
1427-
if (nextNBits(8) != 0) {
1428-
throw new IOException(IOException.AllFillBitsPrecedingEolCodeMustBe0);
1429-
}
1430-
}
1431-
1432-
// There might be a random number of fill bytes with 0s, so
1433-
// loop till the EOL of 0000 0001 is found, as long as all
1434-
// the bytes preceding it are 0's.
1435-
int n;
1436-
while ((n = nextNBits(8)) != 1) {
1437-
// If not all zeros
1438-
if (n != 0) {
1439-
throw new IOException(IOException.AllFillBitsPrecedingEolCodeMustBe0);
1440-
}
1441-
}
1389+
private int readEOL() {
1390+
// scan to first none 0 bit and return 12 bits
1391+
while (nextLesserThan8Bits(1) == 0) {
1392+
// nothing to do here
1393+
}
1394+
updatePointer(12);
1395+
int next12Bits = nextNBits(12);
1396+
if (next12Bits != 1) {
1397+
throw new IOException(IOException.AllFillBitsPrecedingEolCodeMustBe0);
14421398
}
1443-
14441399
// If one dimensional encoding mode, then always return 1
14451400
if (oneD == 0) {
14461401
return 1;
@@ -1606,14 +1561,9 @@ private int nextLesserThan8Bits(int bitsToGet) {
16061561

16071562
// Move pointer backwards by given amount of bits
16081563
private void updatePointer(int bitsToMoveBack) {
1609-
int i = bitPointer - bitsToMoveBack;
1610-
1611-
if (i < 0) {
1612-
bytePointer--;
1613-
bitPointer = 8 + i;
1614-
} else {
1615-
bitPointer = i;
1616-
}
1564+
int totalBits = bytePointer * 8 + bitPointer - bitsToMoveBack;
1565+
bitPointer = totalBits % 8;
1566+
bytePointer = totalBits / 8;
16171567
}
16181568

16191569
// Move to the next byte boundary

io/src/test/java/com/itextpdf/io/image/TiffTest.java

Lines changed: 15 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -131,24 +131,18 @@ public void getStringDataFromTiff() throws IOException {
131131
}
132132

133133
@Test
134-
// TODO: DEVSIX-5565 (update test when support for T4 compression tiff image will be realized)
135-
public void group3CompressionCreateTiffImageTest() {
136-
Exception e = Assert.assertThrows(com.itextpdf.io.exceptions.IOException.class,
137-
() -> ImageDataFactory.createTiff(UrlUtil.toURL(SOURCE_FOLDER + "group3CompressionImage.tif"),
138-
false, 1, false));
139-
140-
Assert.assertEquals(MessageFormatUtil.format(
141-
com.itextpdf.io.exceptions.IOException.CannotReadTiffImage), e.getMessage());
134+
public void group3CompressionCreateTiffImageTest() throws MalformedURLException {
135+
String sourceFile = SOURCE_FOLDER + "group3CompressionImage.tif";
136+
createTiff(sourceFile, 1, 1024D, 768D);
142137
}
143138

144139
@Test
145-
// TODO: DEVSIX-5565 (update test when support for T4 compression tiff image will be realized)
146-
public void group3CompressionCreateImageDataTest() {
147-
Exception e = Assert.assertThrows(com.itextpdf.io.exceptions.IOException.class,
148-
() -> ImageDataFactory.create(UrlUtil.toURL(SOURCE_FOLDER + "group3CompressionImage.tif")));
149-
150-
Assert.assertEquals(MessageFormatUtil.format(
151-
com.itextpdf.io.exceptions.IOException.CannotReadTiffImage), e.getMessage());
140+
public void group3CompressionCreateImageDataTest() throws MalformedURLException {
141+
String sourceFile = SOURCE_FOLDER + "group3CompressionImage.tif";
142+
ImageData img = ImageDataFactory.create(UrlUtil.toURL(SOURCE_FOLDER + "group3CompressionImage.tif"));
143+
Assert.assertEquals(1024, img.getWidth(), 0);
144+
Assert.assertEquals(768, img.getHeight(), 0);
145+
Assert.assertEquals(1, img.getBpc());
152146
}
153147

154148
@Test
@@ -194,7 +188,7 @@ public void adobeDeflateCompression8BitRgbTest() throws IOException {
194188
}
195189

196190
@Test
197-
// TODO: DEVSIX-5565 (update test when support for adobeDeflate compression tiff image will be realized)
191+
// TODO: DEVSIX-5791 (update test when support for adobeDeflate compression tiff image will be realized)
198192
public void adobeDeflateComp16BitMinIsBlackCreateTiffTest() {
199193
Exception e = Assert.assertThrows(com.itextpdf.io.exceptions.IOException.class,
200194
() -> ImageDataFactory.createTiff(UrlUtil.toURL(
@@ -206,7 +200,7 @@ public void adobeDeflateComp16BitMinIsBlackCreateTiffTest() {
206200
}
207201

208202
@Test
209-
// TODO: DEVSIX-5565 (update test when support for adobeDeflate compression tiff image will be realized)
203+
// TODO: DEVSIX-5791 (update test when support for adobeDeflate compression tiff image will be realized)
210204
public void adobeDeflateComp16BitMinIsBlackCreateImageTest() {
211205
Exception e = Assert.assertThrows(com.itextpdf.io.exceptions.IOException.class,
212206
() -> ImageDataFactory.create(UrlUtil.toURL(
@@ -217,7 +211,7 @@ public void adobeDeflateComp16BitMinIsBlackCreateImageTest() {
217211
}
218212

219213
@Test
220-
// TODO: DEVSIX-5565 (update test when support for adobeDeflate compression tiff image will be realized)
214+
// TODO: DEVSIX-5791 (update test when support for adobeDeflate compression tiff image will be realized)
221215
public void adobeDeflateComp16BitMinIsWhiteCreateTiffTest() {
222216
Exception e = Assert.assertThrows(com.itextpdf.io.exceptions.IOException.class,
223217
() -> ImageDataFactory.createTiff(UrlUtil.toURL(
@@ -229,7 +223,7 @@ public void adobeDeflateComp16BitMinIsWhiteCreateTiffTest() {
229223
}
230224

231225
@Test
232-
// TODO: DEVSIX-5565 (update test when support for adobeDeflate compression tiff image will be realized)
226+
// TODO: DEVSIX-5791 (update test when support for adobeDeflate compression tiff image will be realized)
233227
public void adobeDeflateComp16BitMinIsWhiteCreateImageTest() {
234228
Exception e = Assert.assertThrows(com.itextpdf.io.exceptions.IOException.class,
235229
() -> ImageDataFactory.create(UrlUtil.toURL(
@@ -240,7 +234,7 @@ public void adobeDeflateComp16BitMinIsWhiteCreateImageTest() {
240234
}
241235

242236
@Test
243-
// TODO: DEVSIX-5565 (update test when support for adobeDeflate compression tiff image will be realized)
237+
// TODO: DEVSIX-5791 (update test when support for adobeDeflate compression tiff image will be realized)
244238
public void adobeDeflateCompression16BitRgbCreateTiffTest() {
245239
Exception e = Assert.assertThrows(com.itextpdf.io.exceptions.IOException.class,
246240
() -> ImageDataFactory.createTiff(UrlUtil.toURL(
@@ -252,7 +246,7 @@ public void adobeDeflateCompression16BitRgbCreateTiffTest() {
252246
}
253247

254248
@Test
255-
// TODO: DEVSIX-5565 (update test when support for adobeDeflate compression tiff image will be realized)
249+
// TODO: DEVSIX-5791 (update test when support for adobeDeflate compression tiff image will be realized)
256250
public void adobeDeflateCompression16BitRgbCreateImageTest() {
257251
Exception e = Assert.assertThrows(com.itextpdf.io.exceptions.IOException.class,
258252
() -> ImageDataFactory.create(UrlUtil.toURL(

kernel/src/test/java/com/itextpdf/kernel/pdf/xobject/PdfImageXObjectTest.java

Lines changed: 41 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ This file is part of the iText (R) project.
4242
*/
4343
package com.itextpdf.kernel.pdf.xobject;
4444

45-
import com.itextpdf.commons.utils.MessageFormatUtil;
4645
import com.itextpdf.io.image.ImageDataFactory;
4746
import com.itextpdf.io.util.UrlUtil;
4847
import com.itextpdf.kernel.geom.Rectangle;
@@ -164,15 +163,11 @@ public void sRgbImageTest() throws IOException {
164163
}
165164

166165
@Test
167-
// TODO: DEVSIX-5565 (update test when support for adobeDeflate compression tiff image will be realized)
168-
public void group3CompressionTiffImageTest() {
166+
public void group3CompressionTiffImageTest() throws IOException {
169167
String image = SOURCE_FOLDER + "group3CompressionImage.tif";
170-
171-
Exception e = Assert.assertThrows(com.itextpdf.io.exceptions.IOException.class,
172-
() -> ImageDataFactory.create(UrlUtil.toURL(image)));
173-
174-
Assert.assertEquals(MessageFormatUtil.format(
175-
com.itextpdf.io.exceptions.IOException.CannotReadTiffImage), e.getMessage());
168+
convertAndCompare(DESTINATION_FOLDER + "group3CompressionTiffImage.pdf",
169+
SOURCE_FOLDER + "cmp_group3CompressionTiffImage.pdf",
170+
new PdfImageXObject(ImageDataFactory.create(UrlUtil.toURL(image))));
176171
}
177172

178173
@Test
@@ -196,22 +191,22 @@ public void group3CompTiffImgRecoverErrorAndDirectTest() throws IOException, Int
196191
}
197192

198193
@Test
199-
// TODO: DEVSIX-5565 (update test when support for adobeDeflate compression tiff image will be realized)
200-
public void group3CompTiffImgNoRecoverErrorAndNotDirectTest() {
194+
public void group3CompTiffImgNoRecoverErrorAndNotDirectTest() throws IOException {
201195
String image = SOURCE_FOLDER + "group3CompressionImage.tif";
202196

203-
Exception e = Assert.assertThrows(com.itextpdf.io.exceptions.IOException.class,
204-
() -> ImageDataFactory.createTiff(UrlUtil.toURL(image),
205-
false, 1, false));
206-
207-
Assert.assertEquals(MessageFormatUtil.format(
208-
com.itextpdf.io.exceptions.IOException.CannotReadTiffImage), e.getMessage());
197+
convertAndCompare(DESTINATION_FOLDER + "group3CompTiffImgNoRecoverErrorAndNotDirect.pdf",
198+
SOURCE_FOLDER + "cmp_group3CompTiffImgNoRecoverErrorAndNotDirect.pdf",
199+
new PdfImageXObject(ImageDataFactory.createTiff(UrlUtil.toURL(image),
200+
false, 1, false)));
209201
}
210202

211203
private void convertAndCompare(String outFilename, String cmpFilename, String imageFilename)
212204
throws IOException {
205+
206+
System.out.println("Out pdf: " + UrlUtil.getNormalizedFileUriString(outFilename));
207+
System.out.println("Cmp pdf: " + UrlUtil.getNormalizedFileUriString(cmpFilename)+ "\n");
208+
213209
PdfDocument pdfDoc = new PdfDocument(new PdfWriter(outFilename));
214-
PdfDocument cmpDoc = new PdfDocument(new PdfReader(cmpFilename));
215210

216211
PdfImageXObject imageXObject = new PdfImageXObject(ImageDataFactory.create(imageFilename));
217212

@@ -222,14 +217,41 @@ private void convertAndCompare(String outFilename, String cmpFilename, String im
222217
PdfDocument outDoc = new PdfDocument(new PdfReader(outFilename));
223218

224219
PdfStream outStream = outDoc.getFirstPage().getResources().getResource(PdfName.XObject).getAsStream(new PdfName("Im1"));
220+
221+
PdfDocument cmpDoc = new PdfDocument(new PdfReader(cmpFilename));
225222
PdfStream cmpStream = cmpDoc.getFirstPage().getResources().getResource(PdfName.XObject).getAsStream(new PdfName("Im1"));
226223

227224

228225
Assert.assertNull(new CompareTool().compareStreamsStructure(outStream, cmpStream));
229226

230-
231227
cmpDoc.close();
232228
outDoc.close();
229+
}
230+
231+
private void convertAndCompare(String outFilename, String cmpFilename,PdfImageXObject imageXObject )
232+
throws IOException {
233+
234+
System.out.println("Out pdf: " + UrlUtil.getNormalizedFileUriString(outFilename));
235+
System.out.println("Cmp pdf: " + UrlUtil.getNormalizedFileUriString(cmpFilename)+ "\n");
236+
237+
PdfDocument pdfDoc = new PdfDocument(new PdfWriter(outFilename));
238+
233239

240+
PdfCanvas canvas = new PdfCanvas(pdfDoc.addNewPage());
241+
canvas.addXObjectFittedIntoRectangle(imageXObject, new Rectangle(10, 20, 575 , 802));
242+
pdfDoc.close();
243+
244+
PdfDocument outDoc = new PdfDocument(new PdfReader(outFilename));
245+
246+
PdfStream outStream = outDoc.getFirstPage().getResources().getResource(PdfName.XObject).getAsStream(new PdfName("Im1"));
247+
248+
PdfDocument cmpDoc = new PdfDocument(new PdfReader(cmpFilename));
249+
PdfStream cmpStream = cmpDoc.getFirstPage().getResources().getResource(PdfName.XObject).getAsStream(new PdfName("Im1"));
250+
251+
252+
Assert.assertNull(new CompareTool().compareStreamsStructure(outStream, cmpStream));
253+
254+
cmpDoc.close();
255+
outDoc.close();
234256
}
235257
}

0 commit comments

Comments
 (0)