3.7. Bilder in Dokumenten

Überblick

Bilder in einem PDF-Dokument sind selten optisches Beiwerk geringer Bedeutung. Sie enthalten Informationen, die in manchen Fällen vertragsrelevanten Charakter haben können. Typische Fehler im Zusammenhang mit Bildern sind:

  • Befindet sich ein Bild auf der erwarteten Seite?

  • Fehlt ein Bild, weil es im Erstellungsprozess nicht gefunden werden konnte?

  • Enthält ein Brief wirklich das neue Unternehmens-Logo, und nicht das alte?

  • Entspricht ein Text in Bildern dem erwarteten Text, beispielsweise einer Anschrift?

  • Ist der Inhalt eines Barcodes oder QR-Codes der erwartete?

Alle Fehler können mit passenden Testmethoden erkannt werden:

// Testing images in PDF:
.hasImage().matching(..)
.hasImage().matchingOneOf(..)

.hasImage().withBarcode()           3.5: „Barcode“ 
.hasImage().withBarcodeInRegion()   3.5: „Barcode“ 
.hasImage().withText().xxx(..)      3.29: „Texte - in Bildern (OCR)“ 
.hasImage().withTextInRegion()      3.29: „Texte - in Bildern (OCR)“ 
.hasImage().withQRCode()            3.23: „QR-Code“ 
.hasImage().withQRCodeInRegion()    3.23: „QR-Code“ 
.hasImage().withHeightInPixel()
.hasImage().withWidthInPixel()

.hasNoImage()

.hasNumberOfDifferentImages(..)
.hasNumberOfVisibleImages(..)

Anzahl unterschiedlicher Bilder im Dokument

Eine wichtige Bemerkung vorweg: Die Anzahl der sichtbaren Bilder entspricht überlicherweise nicht der Anzahl der im PDF-Dokument selbst gespeicherten Bilder. Ein Logo, das auf 10 Seiten sichtbar ist, wird intern nur einmal gespeichert. Deshalb gibt es zwei Testmethoden. Die Methode hasNumberOfDifferentImages(..) überprüft die Anzahl der internen Bilder während die Methode hasNumberOfVisibleImages(..) die Anzahl der sichtbaren Bilder überprüft.

Das erste Beispiel zeigt die Validierung der Anzahl der intern gespeicherten Bilder:

@Test
public void hasNumberOfDifferentImages() throws Exception {
  String filename = "documentUnderTest.pdf";
  
  AssertThat.document(filename)
            .hasNumberOfDifferentImages(2) 
  ;
}

Wie kommt man in diesem Beispiel auf die 2? Wie können Sie für ein bestimmtes PDF wissen, welche Bilder tatsächlich intern gespeichert sind? Zur Beantwortung dieser Fragen extrahieren Sie alle Bilder Ihres PDF-Dokumentes mit dem von PDFUnit mitgelieferten Hilfsprogramm ExtractImages. Eine Beschreibung dieses Programms steht in Kapitel 9.3: „Bilder aus PDF extrahieren“.

Anzahl sichtbarer Bilder im Dokument

Das nächste Beispiel validiert die Anzahl der sichtbaren Bilder:

@Test
public void hasNumberOfVisibleImages() throws Exception {
  String filename = "documentUnderTest.pdf";
  
  AssertThat.document(filename)
            .hasNumberOfVisibleImages(8) 
  ;
}

Das Beispieldokument hat 8 Bilder auf 6 Seiten, davon 2 Bilder auf Seite 3, kein Bild auf Seite 4 und 3 Bilder auf Seite 6.

Der Test auf die sichtbaren Bilder kann auf spezifizierte Seiten beschränkt werden. So werden im nächsten Beispiel nur die Bilder auf Seite 6 in einem bestimmten Bereich überprüft:

@Test
public void numberOfVisibleImages() throws Exception {
  String filename = "documentUnderTest.pdf";
  
  int leftX  = 14; // in millimeter
  int upperY = 91;
  int width  = 96;
  int height = 43;
  PageRegion pageRegion = new PageRegion(leftX, upperY, width, height);
  PagesToUse page6 = PagesToUse.getPage(6);

  AssertThat.document(filename)
            .restrictedTo(page6)
            .restrictedTo(pageRegion)
            .hasNumberOfVisibleImages(1)
  ;
}

Bilder, die mehrfach auf einer Seite zu sehen sind, werden auch mehrfach gezählt.

Die verschiedenen Möglichkeiten, Tests auf bestimmte Seiten zu beschränken, werden in Kapitel 13.2: „Seitenauswahl“ ausführlich beschrieben.

Bestimmte Bilder vergleichen

Nach dem Zählen der Bilder folgt die Prüfung auf das Aussehen der Bilder. Im nachfolgenden Beispiel sucht PDFUnit innerhalb des PDF-Dokumentes ein Bild, das exakt so aussieht, wie das der angegebenen Datei:

@Test  
public void hasImage() throws Exception {
  String filename = "documentUnderTest.pdf";
  String imageFile = "images/apache-software-foundation-logo.png";
  
  AssertThat.document(filename)
            .restrictedTo(ANY_PAGE)
            .hasImage()
            .matching(imageFile)
  ; 
}

Das Ergebnis eines Vergleiches zweier Bilddateien hängt von den Dateiformaten ab. PDFUnit kann alle Dateiformate verarbeiten, die von Java in ein java.awt.image.BufferedImage umgewandelt werden können: JPEG, PNG, GIF, BMP und WBMP. Die Bilder werden von PDFUnit Byte-weise verglichen. Deshalb werden die BMP- und PNG-Versionen eines Bildes nicht als gleich erkannt.

Das Bild kann in unterschiedlichen Formaten an die Testmethode gegeben werden:

// Types for images:

.hasImage().matching(BufferedImage image);
.hasImage().matching(String imageFileName);
.hasImage().matching(File imageFile);
.hasImage().matching(InputStream imageStream);
.hasImage().matching(URL imageURL);

Beim Erzeugen von PDF kann es zu einer Formatumwandlung zwischen den Bildvorlagen als Datei und den intern gespeicherten Bildern kommen. Dadurch wird es unmöglich, die internen Bilder mit den Vorlagen zu vergleichen. Sollte es dieses Problem geben, extrahieren Sie die Bilder aus dem PDF-Dokument und verwenden für die nachfolgenden Tests ein extrahiertes Bild. Zuvor sollten sie es auf seine Korrektheit überprüft haben.

Die in einem PDF enthaltenen Bilder können auch gegen die Bilder in einem Referenz-Dokument verglichen werden. Eine genaue Beschreibung dazu enthält das Kapitel 4.4: „Bilder vergleichen“.

Eine Menge von Bildern als Vergleichsvorlage

Es kann die Situation geben, dass ein PDF-Dokument eines von drei möglichen Unterschriften enthält. Für diese Situation gibt es die Testmethode matchingOneOf(..):

@Test
public void containsOneOfManyImages() throws Exception {
  BufferedImage signatureAlex = ImageHelper.getAsImage("images/signature-alex.png");
  BufferedImage signatureBob  = ImageHelper.getAsImage("images/signature-bob.png");
  BufferedImage[] allPossibleImages = {signatureAlex, signatureBob};

  String documentSignedByAlex = "letter-signed-by-alex.pdf";
  AssertThat.document(documentSignedByAlex)
            .restrictedTo(LAST_PAGE)
            .matchingOneOf(allPossibleImages)
  ;
  
  String documentSignedByBob = "letter-signed-by-bob.pdf";
  AssertThat.document(documentSignedByBob)
            .restrictedTo(LAST_PAGE)
            .matchingOneOf(allPossibleImages)
  ;
}

Der Test kann sich nicht nur auf eine Seite beziehen, wie hier die letzte Seite, sondern auch auf mehrere, wie der folgende Abschnitt zeigt.

Bilder auf unterschiedlichen Seiten

Die Suche nach Bildern kann grundsätzlich auf einzelne, mehrere individuelle oder mehrere zusammenhängende Seiten eingeschränkt werden. Es stehen dafür die Möglichkeiten zur Verfügung, die in Kapitel 13.2: „Seitenauswahl“ beschrieben.

Hier ein Beispiel:

@Test 
public void containsImage_OnAllPagesAfter5() throws Exception {
  String filename = "documentUnderTest.pdf";
  String imageFileName = "images/apache-ant-logo.jpg";
  File imageFile = new File(imageFileName);
  
  AssertThat.document(filename)
            .restrictedTo(EVERY_PAGE.after(5))
            .hasImage()
            .matching(imageFile)
  ; 
}

Die Abwesenheit von Bilder prüfen

Manche Seiten oder Seitenausschnitte sollen keine Bilder enthalten. Solche Fälle sollte natürlich auch getestet werden können. Das nächste Beispiel überprüft, dass der zentrale Seitenbereich - ohne Header und Footer - der letzten Seite leer ist.

@Test
public void lastPageBodyShouldBeEmpty() throws Exception {
  String pdfUnderTest = "documentUnderTest.pdf";
  PageRegion textBody = createBodyRegion();
  
  AssertThat.document(pdfUnderTest)
            .restrictedTo(LAST_PAGE)
            .restrictedTo(textBody)
            .hasNoImage()
            .hasNoText()
  ;
}