PDInlineImageTest.java
/*
* Copyright 2014 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.pdfbox.pdmodel.graphics.image;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.awt.Color;
import java.awt.Paint;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import org.apache.pdfbox.Loader;
import org.apache.pdfbox.cos.COSArray;
import org.apache.pdfbox.cos.COSDictionary;
import org.apache.pdfbox.cos.COSInteger;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.PDPageContentStream.AppendMode;
import org.apache.pdfbox.pdmodel.graphics.color.PDDeviceGray;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
/**
* Unit tests for PDInlineImage
*
* @author Tilman Hausherr
*/
class PDInlineImageTest
{
private static final File TESTRESULTSDIR = new File("target/test-output/graphics");
@BeforeAll
static void setUp()
{
TESTRESULTSDIR.mkdirs();
}
/**
* Tests PDInlineImage#PDInlineImage(COSDictionary parameters, byte[] data,
* Map<String, PDColorSpace> colorSpaces)
*/
@Test
void testInlineImage() throws IOException
{
COSDictionary dict = new COSDictionary();
dict.setBoolean(COSName.IM, true);
int width = 31;
int height = 27;
dict.setInt(COSName.W, width);
dict.setInt(COSName.H, height);
dict.setInt(COSName.BPC, 1);
int rowbytes = width / 8;
if (rowbytes * 8 < width)
{
// PDF spec:
// If the number of data bits per row is not a multiple of 8,
// the end of the row is padded with extra bits to fill out the last byte.
++rowbytes;
}
// draw a grid
int datalen = rowbytes * height;
byte[] data = new byte[datalen];
for (int i = 0; i < datalen; ++i)
{
data[i] = (i / 4 % 2 == 0) ? (byte) Integer.parseInt("10101010", 2) : 0;
}
PDInlineImage inlineImage1 = new PDInlineImage(dict, data, null);
assertTrue(inlineImage1.isStencil());
assertEquals(width, inlineImage1.getWidth());
assertEquals(height, inlineImage1.getHeight());
assertEquals(1, inlineImage1.getBitsPerComponent());
COSDictionary dict2 = new COSDictionary();
dict2.addAll(dict);
// use decode array to revert in image2
COSArray decodeArray = new COSArray();
decodeArray.add(COSInteger.ONE);
decodeArray.add(COSInteger.ZERO);
dict2.setItem(COSName.DECODE, decodeArray);
PDInlineImage inlineImage2 = new PDInlineImage(dict2, data, null);
Paint paint = new Color(0, 0, 0);
BufferedImage stencilImage = inlineImage1.getStencilImage(paint);
assertEquals(width, stencilImage.getWidth());
assertEquals(height, stencilImage.getHeight());
BufferedImage stencilImage2 = inlineImage2.getStencilImage(paint);
assertEquals(width, stencilImage2.getWidth());
assertEquals(height, stencilImage2.getHeight());
BufferedImage image1 = inlineImage1.getImage();
assertEquals(width, image1.getWidth());
assertEquals(height, image1.getHeight());
BufferedImage image2 = inlineImage2.getImage();
assertEquals(width, image2.getWidth());
assertEquals(height, image2.getHeight());
// write and read
boolean writeOk = ImageIO.write(image1, "png", new File(TESTRESULTSDIR + "/inline-grid1.png"));
assertTrue(writeOk);
BufferedImage bim1 = ImageIO.read(new File(TESTRESULTSDIR + "/inline-grid1.png"));
assertNotNull(bim1);
assertEquals(width, bim1.getWidth());
assertEquals(height, bim1.getHeight());
writeOk = ImageIO.write(image2, "png", new File(TESTRESULTSDIR + "/inline-grid2.png"));
assertTrue(writeOk);
BufferedImage bim2 = ImageIO.read(new File(TESTRESULTSDIR + "/inline-grid2.png"));
assertNotNull(bim2);
assertEquals(width, bim2.getWidth());
assertEquals(height, bim2.getHeight());
// compare: pixels with even coordinates are white (FF), all others are black (0)
for (int x = 0; x < width; ++x)
{
for (int y = 0; y < height; ++y)
{
if (x % 2 == 0 && y % 2 == 0)
{
assertEquals(0xFFFFFF, bim1.getRGB(x, y) & 0xFFFFFF);
}
else
{
assertEquals(0, bim1.getRGB(x, y) & 0xFFFFFF);
}
}
}
// compare: pixels with odd coordinates are white (FF), all others are black (0)
for (int x = 0; x < width; ++x)
{
for (int y = 0; y < height; ++y)
{
if (x % 2 == 0 && y % 2 == 0)
{
assertEquals(0, bim2.getRGB(x, y) & 0xFFFFFF);
}
else
{
assertEquals(0xFFFFFF, bim2.getRGB(x, y) & 0xFFFFFF);
}
}
}
File pdfFile = new File(TESTRESULTSDIR, "inline.pdf");
try (PDDocument document = new PDDocument())
{
PDPage page = new PDPage();
document.addPage(page);
try (PDPageContentStream contentStream = new PDPageContentStream(document, page, AppendMode.APPEND, false))
{
contentStream.drawImage(inlineImage1, 150, 400);
contentStream.drawImage(inlineImage1, 150, 500, inlineImage1.getWidth() * 2, inlineImage1.getHeight() * 2);
contentStream.drawImage(inlineImage1, 150, 600, inlineImage1.getWidth() * 4, inlineImage1.getHeight() * 4);
contentStream.drawImage(inlineImage2, 350, 400);
contentStream.drawImage(inlineImage2, 350, 500, inlineImage2.getWidth() * 2, inlineImage2.getHeight() * 2);
contentStream.drawImage(inlineImage2, 350, 600, inlineImage2.getWidth() * 4, inlineImage2.getHeight() * 4);
}
document.save(pdfFile);
}
try (PDDocument document = Loader.loadPDF(pdfFile))
{
new PDFRenderer(document).renderImage(0);
}
}
// 3 Tests for PDFBOX-5360 with very small images (the last one based on a comment
// by Oliver Schmidtmer at the end of PDFBOX-5340). All images are fully black bars.
@Test
void testShortCCITT1() throws IOException
{
byte[] ba = { 8, 0x10, 0x20, 0x40, (byte) 0x81, 2, 4, 8, 0x10, 0, 0x40, 4, 0, 0x40, 4, 0, 0x40, 4 };
doInlineCcittImage(23, 10, ba);
}
@Test
void testShortCCITT2() throws IOException
{
byte[] ba = { 8, 0x10, 0x20, 0x40, (byte) 0x81, 2, 0, 8, 0, (byte) 0x80, 8, 8, (byte) 0x80, 8, 0, (byte) 0x80};
doInlineCcittImage(23, 7, ba);
}
@Test
void testShortCCITT3() throws IOException
{
byte[] ba = { 103, 44, 103, 44, 103, 44, 103, 44, 0, 16, 1, 0, 16, 1, 0, 16, 1, 10};
doInlineCcittImage(683, 4, ba);
}
private void doInlineCcittImage(int width, int height, byte[] ba) throws IOException
{
COSDictionary dict = new COSDictionary();
dict.setInt(COSName.W, width);
dict.setInt(COSName.H, height);
dict.setInt(COSName.BPC, 1);
COSArray array = new COSArray();
array.add(COSInteger.ONE);
array.add(COSInteger.ZERO);
dict.setItem(COSName.D, array);
dict.setBoolean(COSName.IM, true);
dict.setItem(COSName.F, COSName.CCITTFAX_DECODE_ABBREVIATION);
COSDictionary dict2 = new COSDictionary();
dict2.setInt(COSName.COLUMNS, dict.getInt(COSName.W));
dict.setItem(COSName.DP, dict2);
PDInlineImage inlineImage = new PDInlineImage(dict, ba, null);
Assertions.assertEquals(true, inlineImage.isStencil());
Assertions.assertEquals(false, inlineImage.isEmpty());
Assertions.assertEquals(false, inlineImage.getInterpolate());
Assertions.assertEquals(dict, inlineImage.getCOSObject());
Assertions.assertEquals(PDDeviceGray.INSTANCE, inlineImage.getColorSpace());
Assertions.assertEquals(1, inlineImage.getBitsPerComponent());
Assertions.assertEquals("tiff", inlineImage.getSuffix());
BufferedImage bim = inlineImage.getImage();
Assertions.assertEquals(width, bim.getWidth());
Assertions.assertEquals(height, bim.getHeight());
Assertions.assertEquals(inlineImage.getWidth(), bim.getWidth());
Assertions.assertEquals(inlineImage.getHeight(), bim.getHeight());
Assertions.assertEquals(BufferedImage.TYPE_BYTE_GRAY, bim.getType());
DataBufferByte dbb = (DataBufferByte) bim.getRaster().getDataBuffer();
Assertions.assertEquals(bim.getWidth() * bim.getHeight(), dbb.getSize());
byte[] data = dbb.getData();
for (int i = 0; i < data.length; ++i)
{
Assertions.assertEquals(0, data[i]);
}
}
}