diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 035a21dea8..db50e4f01d 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -3,6 +3,7 @@ name: OpenPDF maven build on: + workflow_dispatch: push: branches: [ '*' ] pull_request: diff --git a/openpdf/src/main/java/com/lowagie/text/pdf/BaseFont.java b/openpdf/src/main/java/com/lowagie/text/pdf/BaseFont.java index 671e4cdaaf..b6b8e59eae 100644 --- a/openpdf/src/main/java/com/lowagie/text/pdf/BaseFont.java +++ b/openpdf/src/main/java/com/lowagie/text/pdf/BaseFont.java @@ -724,6 +724,7 @@ public static BaseFont createFont(String name, String encoding, if (cached) { fontFound = fontCache.get(key); if (fontFound != null) { + LayoutProcessor.loadFont(fontFound, name); return fontFound; } } diff --git a/openpdf/src/main/java/com/lowagie/text/pdf/FontDetails.java b/openpdf/src/main/java/com/lowagie/text/pdf/FontDetails.java index 54beb26f99..567210e793 100755 --- a/openpdf/src/main/java/com/lowagie/text/pdf/FontDetails.java +++ b/openpdf/src/main/java/com/lowagie/text/pdf/FontDetails.java @@ -54,6 +54,7 @@ import com.lowagie.text.Utilities; import java.awt.font.GlyphVector; import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; @@ -155,6 +156,18 @@ void putFillerCmap(Integer key, int[] value) { fillerCmap.put(key, value); } + void addMissingCmapEntries(String text, GlyphVector glyphVector, BaseFont baseFont) { + + if (baseFont instanceof TrueTypeFontUnicode trueTypeFont && getFillerCmap() != null) { + int[][] localCmap = trueTypeFont.getSentenceMissingCmap(text, glyphVector); + + for (int[] ints : localCmap) { + putFillerCmap(ints[0], new int[]{ints[0], ints[1]}); + } + } + } + + /** * Gets the indirect reference to this font. * @@ -291,6 +304,32 @@ private byte[] getCJKEncodingBytes(int[] glyph, int size) { return result; } + /** + * Convert a glyph code to bytes + * + * @param glyphCode + * @return byte array with one or two bytes as UTF-16BE representation of the glyph code + * @see convertToBytes(GlyphVector glyphVector,...) + */ + byte[] convertToBytes(final int glyphCode) { + if (fontType != BaseFont.FONT_TYPE_TTUNI) { + throw new UnsupportedOperationException("Only supported for True Type Unicode fonts"); + } + if (glyphCode == 0xFFFE || glyphCode == 0xFFFF) { + // considered non-glyphs by AWT + return new byte[]{}; + } + if (!longTag.containsKey(glyphCode)) { + int glyphWidth = ttu.getGlyphWidth(glyphCode); + Integer charCode = ttu.getCharacterCode(glyphCode); + int[] metrics = charCode != null ? new int[]{glyphCode, glyphWidth, charCode} : new int[]{ + glyphCode, glyphWidth}; + longTag.put(glyphCode, metrics); + } + String s = new String(Character.toChars(glyphCode)); + return s.getBytes(StandardCharsets.UTF_16BE); + } + byte[] convertToBytes(GlyphVector glyphVector, int beginIndex, int endIndex) { if (fontType != BaseFont.FONT_TYPE_TTUNI || symbolic) { throw new UnsupportedOperationException("Only supported for True Type Unicode fonts"); @@ -305,7 +344,7 @@ byte[] convertToBytes(GlyphVector glyphVector, int beginIndex, int endIndex) { continue; } - glyphs[glyphCount++] = (char) code; // FIXME supplementary plane? + glyphCount += Character.toChars(code, glyphs, glyphCount); Integer codeKey = code; if (!longTag.containsKey(codeKey)) { @@ -318,11 +357,7 @@ byte[] convertToBytes(GlyphVector glyphVector, int beginIndex, int endIndex) { } String s = new String(glyphs, 0, glyphCount); - try { - return s.getBytes(CJKFont.CJK_ENCODING); - } catch (UnsupportedEncodingException e) { - throw new ExceptionConverter(e); - } + return s.getBytes(StandardCharsets.UTF_16BE); } diff --git a/openpdf/src/main/java/com/lowagie/text/pdf/LayoutProcessor.java b/openpdf/src/main/java/com/lowagie/text/pdf/LayoutProcessor.java index 58e81d9943..8c66f7c69b 100644 --- a/openpdf/src/main/java/com/lowagie/text/pdf/LayoutProcessor.java +++ b/openpdf/src/main/java/com/lowagie/text/pdf/LayoutProcessor.java @@ -1,7 +1,7 @@ /* * LayoutProcessor.java * - * Copyright 2020-2022 Volker Kunert. + * Copyright 2020-2024 Volker Kunert. * * The contents of this file are subject to the Mozilla Public License Version 1.1 * (the "License"); you may not use this file except in compliance with the License. @@ -65,6 +65,13 @@ */ public class LayoutProcessor { + public enum Version { + ONE, + TWO + } + + private static Version version = Version.TWO; + private static final int DEFAULT_FLAGS = -1; private static final Map awtFontMap = new ConcurrentHashMap<>(); @@ -74,6 +81,8 @@ public class LayoutProcessor { private static boolean enabled = false; private static int flags = DEFAULT_FLAGS; + private static boolean writeActualText; + private LayoutProcessor() { throw new UnsupportedOperationException("static class"); } @@ -132,6 +141,17 @@ public static boolean isEnabled() { return enabled; } + /** + * Set version + * + * @param version to set + * @deprecated To be used *only*, if version two produces incorrect PDF - please file an issue if this occurs + */ + @Deprecated + public static void setVersion(Version version) { + LayoutProcessor.version = version; + } + /** * Set kerning * @@ -208,8 +228,8 @@ private static void setRunDirection(com.lowagie.text.Font font, Boolean runDirec * * @param font The font for which kerning is to be turned on * @param textAttributes Map of text attributes to be set - * @see Oracle: The Java™ Tutorials, - * Using Text Attributes to Style Text + * @see + * Oracle: The Java™ Tutorials, Using Text Attributes to Style Text */ private static void setTextAttributes(com.lowagie.text.Font font, Map textAttributes) { BaseFont baseFont = font.getBaseFont(); @@ -220,10 +240,26 @@ private static void setTextAttributes(com.lowagie.text.Font font, Map= deltaY) { + if (!ga.isEmpty()) { + cb.showText(ga); + ga.clear(); + } + cb.setTextRise(-py); + } + if (Math.abs(dx) >= deltaX) { + ga.add(-dx * factorX); + } + ga.add(glyphVector.getGlyphCode(i)); + if (Math.abs(py) >= deltaY) { + cb.showText(ga); + ga.clear(); + cb.setTextRise(0.0f); + } + lastX = (float) p.getX(); + } + Point2D p = glyphVector.getGlyphPosition(glyphVector.getNumGlyphs()); + float ax = (glyphVector.getNumGlyphs() == 0) ? 0.0f : glyphVector.getGlyphMetrics(glyphVector.getNumGlyphs() - 1).getAdvanceX(); + float dx = (float) p.getX() - lastX - ax; + if (Math.abs(dx) >= deltaX) { + ga.add(-dx * factorX); + } + cb.showText(ga); + ga.clear(); } public static void disable() { @@ -407,5 +519,7 @@ public static void disable() { flags = DEFAULT_FLAGS; awtFontMap.clear(); globalTextAttributes.clear(); + writeActualText = false; + setVersion(Version.TWO); } } diff --git a/openpdf/src/main/java/com/lowagie/text/pdf/PdfContentByte.java b/openpdf/src/main/java/com/lowagie/text/pdf/PdfContentByte.java index 40b1fae2c7..fc11e8acbc 100644 --- a/openpdf/src/main/java/com/lowagie/text/pdf/PdfContentByte.java +++ b/openpdf/src/main/java/com/lowagie/text/pdf/PdfContentByte.java @@ -261,17 +261,17 @@ public static PdfTextArray getKernArray(String text, BaseFont font) { */ static byte[] escapeString(byte[] b) { ByteBuffer content = new ByteBuffer(); - escapeString(b, content); + escapeAndAppendString(b, content); return content.toByteArray(); } /** - * Escapes a byte array according to the PDF conventions. + * Escapes a byte array according to the PDF conventions and append it to content * * @param b the byte array to escape - * @param content the content + * @param content the content to append the escaped string */ - static void escapeString(byte[] b, ByteBuffer content) { + static void escapeAndAppendString(byte[] b, ByteBuffer content) { content.append_i('('); for (byte c : b) { switch (c) { @@ -1688,7 +1688,7 @@ private void showText2(String text) { MessageLocalization.getComposedMessage("font.and.size.must.be.set.before.writing.any.text")); } byte[] b = state.fontDetails.convertToBytes(text, getPdfDocument().getTextRenderingOptions()); - escapeString(b, content); + escapeAndAppendString(b, content); } /** @@ -1747,7 +1747,7 @@ public void showText(GlyphVector glyphVector, int beginIndex, int endIndex) { MessageLocalization.getComposedMessage("font.and.size.must.be.set.before.writing.any.text")); } byte[] b = state.fontDetails.convertToBytes(glyphVector, beginIndex, endIndex); - escapeString(b, content); + escapeAndAppendString(b, content); content.append("Tj").append_i(separator); } @@ -2161,8 +2161,8 @@ public PdfPatternPainter createPattern(float width, float height, Color color) { * Creates a new template. *

* Creates a new template that is nothing more than a form XObject. This template can be included in this - * PdfContentByte or in another template. Templates are only written to the output when the document - * is closed permitting things like showing text in the first page that is only defined in the last page. + * PdfContentByte or in another template. Templates are only written to the output when the document is + * closed permitting things like showing text in the first page that is only defined in the last page. * * @param width the bounding box width * @param height the bounding box height @@ -2750,6 +2750,36 @@ protected void checkWriter() { } } + /** + * Show an array of glyphs. + * + * @param glyphs array of glyphs + */ + public void showText(PdfGlyphArray glyphs) { + if (state.fontDetails == null) { + throw new NullPointerException( + MessageLocalization.getComposedMessage("font.and.size.must.be.set.before.writing.any.text")); + } + content.append("["); + List arrayList = glyphs.getList(); + boolean lastWasDisplacement = false; + for (Object obj : arrayList) { + if (obj instanceof Integer) { // glyph code + byte[] b = state.fontDetails.convertToBytes((Integer) obj); + escapeAndAppendString(b, content); // appends escapedString to content + lastWasDisplacement = false; + } else { // displacement + if (lastWasDisplacement) { + content.append(' '); + } else { + lastWasDisplacement = true; + } + content.append((Float) obj); + } + } + content.append("]TJ").append_i(separator); + } + /** * Show an array of text. * diff --git a/openpdf/src/main/java/com/lowagie/text/pdf/PdfGlyphArray.java b/openpdf/src/main/java/com/lowagie/text/pdf/PdfGlyphArray.java new file mode 100644 index 0000000000..fc491c76f0 --- /dev/null +++ b/openpdf/src/main/java/com/lowagie/text/pdf/PdfGlyphArray.java @@ -0,0 +1,70 @@ +/* + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * https://github.com/LibrePDF/OpenPDF + * + */ + +package com.lowagie.text.pdf; + +import java.util.LinkedList; +import java.util.List; + +/** + * Defines an array with displacements and glyph codes. + */ +public class PdfGlyphArray { + private final List list = new LinkedList<>(); + + public void add(float displacement) { + list.add(displacement); + } + + public void add(int glyphCode) { + list.add(glyphCode); + } + + List getList() { + return list; + } + + public void clear() { + list.clear(); + } + + public boolean isEmpty() { + return list.isEmpty(); + } +} diff --git a/openpdf/src/main/java/com/lowagie/text/pdf/TrueTypeFontUnicode.java b/openpdf/src/main/java/com/lowagie/text/pdf/TrueTypeFontUnicode.java index 926fb236fa..344e2ed8f0 100755 --- a/openpdf/src/main/java/com/lowagie/text/pdf/TrueTypeFontUnicode.java +++ b/openpdf/src/main/java/com/lowagie/text/pdf/TrueTypeFontUnicode.java @@ -179,6 +179,7 @@ protected Integer getCharacterCode(int code) { return inverseCmap == null ? null : inverseCmap.get(code); } + /** * Gets the width of a char in normalized 1000 units. * @@ -234,17 +235,18 @@ public int getWidth(String text) { return total; } - int[][] getSentenceMissingCmap(char[] chars, GlyphVector glyph) { - char[] unicodeChar = Arrays.copyOf(chars, chars.length); - int[] glyphChar = glyph.getGlyphCodes(0, glyph.getNumGlyphs(), new int[glyph.getNumGlyphs()]); + int[][] getSentenceMissingCmap(String text, GlyphVector glyphVector) { + char[] chars = text.toCharArray(); + int[] glyphCodes = glyphVector.getGlyphCodes(0, glyphVector.getNumGlyphs(), + new int[glyphVector.getNumGlyphs()]); List missingCmapList = new ArrayList<>(); - for (int i = 0; i < glyphChar.length; i++) { - int charIndex = glyph.getGlyphCharIndex(i); - int glyphCode = glyphChar[i]; + for (int i = 0; i < glyphCodes.length; i++) { + int charIndex = glyphVector.getGlyphCharIndex(i); + int glyphCode = glyphCodes[i]; Integer cmapCharactherCode = getCharacterCode(glyphCode); if (cmapCharactherCode == null) { - missingCmapList.add(new int[]{glyphCode, unicodeChar[charIndex]}); + missingCmapList.add(new int[]{glyphCode, chars[charIndex]}); } } diff --git a/openpdf/src/test/java/com/lowagie/text/pdf/TTFCacheTest.java b/openpdf/src/test/java/com/lowagie/text/pdf/TTFCacheTest.java index feff755ce1..224465956a 100644 --- a/openpdf/src/test/java/com/lowagie/text/pdf/TTFCacheTest.java +++ b/openpdf/src/test/java/com/lowagie/text/pdf/TTFCacheTest.java @@ -12,8 +12,8 @@ class TTFCacheTest { @Test - void whenGetTTFFileWithNullTtuShouldThrowNpe() { - assertThatNullPointerException().isThrownBy(() -> TTFCache.getTTFFile("test", null)); + void whenGetTTFFileWithNotExistingFileAndNullTtuShouldThrowNpe() { + assertThatNullPointerException().isThrownBy(() -> TTFCache.getTTFFile("test-TFFile-With-Null-Ttu", null)); } @Test @@ -24,7 +24,7 @@ void whenGetTTFFileWithNullFileNameShouldThrowNpe() throws IOException { } @Test - void whenGetTTFFileShouldThrowNpe() throws IOException { + void whenTTFCacheGetShouldEqualToTTFFileGet() throws IOException { // given TrueTypeFontUnicode font = (TrueTypeFontUnicode) BaseFont .createFont("fonts/Viaoda_Libre/ViaodaLibre-Regular.ttf", BaseFont.IDENTITY_H, false); diff --git a/openpdf/src/test/java/com/lowagie/text/pdf/TextExtractTest.java b/openpdf/src/test/java/com/lowagie/text/pdf/TextExtractTest.java index 3bb13f4ba2..224c157604 100644 --- a/openpdf/src/test/java/com/lowagie/text/pdf/TextExtractTest.java +++ b/openpdf/src/test/java/com/lowagie/text/pdf/TextExtractTest.java @@ -59,6 +59,8 @@ void textCreateAndExtractTest2() throws IOException { // FileOutputStream test = new FileOutputStream("/tmp/output2.pdf"); // pdfOutput.writeTo(test); - Assertions.assertEquals("ก ข น ํ้ า ต า ญูญูิ่ ก้กิ้", pdfTextExtractor.getTextFromPage(1)); + // Ignore spaces in comparison + Assertions.assertEquals("ก ข น ํ้ า ต า ญูญูิ่ ก้กิ้".replaceAll(" ", ""), + pdfTextExtractor.getTextFromPage(1).replaceAll(" ", "")); } } diff --git a/pdf-toolbox/src/test/java/com/lowagie/examples/fonts/GlyphLayoutDocumentBidi.java b/pdf-toolbox/src/test/java/com/lowagie/examples/fonts/GlyphLayoutDocumentBidi.java index e4fdfdbf28..a12bf1638b 100644 --- a/pdf-toolbox/src/test/java/com/lowagie/examples/fonts/GlyphLayoutDocumentBidi.java +++ b/pdf-toolbox/src/test/java/com/lowagie/examples/fonts/GlyphLayoutDocumentBidi.java @@ -1,7 +1,5 @@ /* - * GlyphLayoutDocumentDinSpec91379 - * * This code is part of the 'OpenPDF Tutorial'. * You can find the complete tutorial at the following address: * https://github.com/LibrePDF/OpenPDF/wiki/Tutorial diff --git a/pdf-toolbox/src/test/java/com/lowagie/examples/fonts/GlyphLayoutDocumentBidiPerFont.java b/pdf-toolbox/src/test/java/com/lowagie/examples/fonts/GlyphLayoutDocumentBidiPerFont.java index ac6107e6d9..de3be8adc3 100644 --- a/pdf-toolbox/src/test/java/com/lowagie/examples/fonts/GlyphLayoutDocumentBidiPerFont.java +++ b/pdf-toolbox/src/test/java/com/lowagie/examples/fonts/GlyphLayoutDocumentBidiPerFont.java @@ -1,7 +1,5 @@ /* - * GlyphLayoutDocumentDinSpec91379 - * * This code is part of the 'OpenPDF Tutorial'. * You can find the complete tutorial at the following address: * https://github.com/LibrePDF/OpenPDF/wiki/Tutorial diff --git a/pdf-toolbox/src/test/java/com/lowagie/examples/fonts/GlyphLayoutDocumentDin91379.java b/pdf-toolbox/src/test/java/com/lowagie/examples/fonts/GlyphLayoutDocumentDin91379.java index ee9b76c29c..4dd0661a61 100644 --- a/pdf-toolbox/src/test/java/com/lowagie/examples/fonts/GlyphLayoutDocumentDin91379.java +++ b/pdf-toolbox/src/test/java/com/lowagie/examples/fonts/GlyphLayoutDocumentDin91379.java @@ -1,6 +1,4 @@ /* - * GlyphLayoutDocumentDin91379 - * * This code is part of the 'OpenPDF Tutorial'. * You can find the complete tutorial at the following address: * https://github.com/LibrePDF/OpenPDF/wiki/Tutorial @@ -29,14 +27,13 @@ public class GlyphLayoutDocumentDin91379 { public static String TEXT_INTRO = "Test of formatting for letters and sequences defined in:\n" - + "DIN 91379:2022-08: Characters and defined character sequences in Unicode for the electronic\n " - + "processing of names and data exchange in Europe, with CD-ROM\n" - + "See https://www.beuth.de/de/norm/din-91379/353496133\n" - + " https://github.com/String-Latin/DIN-91379-Characters-and-Sequences" + + "DIN 91379:2022-08: Characters and defined character sequences in Unicode for the\n" + + "electronic processing of names and data exchange in Europe, with CD-ROM.\n" + + "See https://github.com/String-Latin/DIN-91379-Characters-and-Sequences\n" + "and https://en.wikipedia.org/wiki/DIN_91379\n\n" + "Fonts used: Noto Sans Regular, Noto Sans Math Regular, Noto Serif Regular\n" - + " see https://fonts.google.com/noto/specimen/Noto+Sans" - + " and https://github.com/googlefonts/noto-fonts/tree/main/hinted/ttf\n" + + "See https://fonts.google.com/noto/specimen/Noto+Sans\n" + + "and https://github.com/googlefonts/noto-fonts/tree/main/hinted/ttf\n" + "Using LayoutProcessor for glyph layout with Java built-in routines.\n\n"; public static String LATIN_CHARS_DIN_91379 = @@ -79,7 +76,7 @@ public class GlyphLayoutDocumentDin91379 { + "bnlnot; Non-Letters N4 (normative)\n" + "-omitted-\n" + "dc; Combining diacritics (normative)\n" - + "̀-omitted-\n" + + "-omitted-\n" + "gl; Greek Letters (extended)\n" + "Ά Έ Ή Ί Ό Ύ Ώ ΐ Α Β Γ Δ Ε Ζ Η Θ Ι Κ Λ Μ Ν Ξ Ο Π Ρ Σ \n" + "Τ Υ Φ Χ Ψ Ω Ϊ Ϋ ά έ ή ί ΰ α β γ δ ε ζ η θ ι κ λ μ ν \n" @@ -100,13 +97,6 @@ public class GlyphLayoutDocumentDin91379 { "Additional non-letters (not included in DIN 91379)\n" + "– — •�\n\n"; - public static String TEST_KERNING = - "Kerning\n" - + "AVATAR Vector TeX\n\n"; - - public static String TEST_LIGATURES = - "Ligatures\n" - + "ff ffi ffl fi fl\n\n"; /** * Register and get font @@ -128,7 +118,7 @@ private static Font loadFont(String path, String alias, float fontSize) { * @param args -- not used */ public static void main(String[] args) throws Exception { - test("GlyphLayoutDocumentDin91379.pdf", true); + test("GlyphLayoutDocumentDin91379.pdf"); } @@ -136,9 +126,8 @@ public static void main(String[] args) throws Exception { * Run the test: Print the characters of DIN 91379 in a pdf document * * @param fileName Name of output file - * @param testChunks if true some chunks are added to test positioning */ - public static void test(String fileName, boolean testChunks) throws IOException { + public static void test(String fileName) throws IOException { // Enable the LayoutProcessor with kerning and ligatures LayoutProcessor.enableKernLiga(); @@ -153,8 +142,6 @@ public static void test(String fileName, boolean testChunks) throws IOException String sansFontName = sansFont.getBaseFont().getPostscriptFontName(); Font mathFont = loadFont(fontDir + "noto/NotoSansMath-Regular.ttf", "math", fontSize); String mathFontName = mathFont.getBaseFont().getPostscriptFontName(); - Font serifFont = loadFont(fontDir + "noto/NotoSerif-Regular.ttf", "serif", fontSize); - String serifFontName = serifFont.getBaseFont().getPostscriptFontName(); try (Document document = new Document()) { PdfWriter writer = PdfWriter.getInstance(document, Files.newOutputStream(Paths.get(fileName))); @@ -166,28 +153,7 @@ public static void test(String fileName, boolean testChunks) throws IOException document.add(new Chunk(sansFontName + "\n" + LATIN_CHARS_DIN_91379, sansFont)); document.add(new Chunk(mathFontName + "\n" + LATIN_CHARS_DIN_91379_MATH, mathFont)); document.add(new Chunk(sansFontName + "\n" + LATIN_CHARS_ADDITIONAL, sansFont)); - document.add(new Chunk(sansFontName + "\n" + TEST_KERNING, sansFont)); - document.add(new Chunk(serifFontName + "\n" + TEST_LIGATURES, serifFont)); - - if (testChunks) { - addChunks(document, sansFont); - } } LayoutProcessor.disable(); } - - /* - * Add several chunks to test positioning - */ - private static void addChunks(Document document, Font font) { - document.add(new Chunk("\n")); - document.add(new Chunk("Test of several Chunks on one line: A", font)); - document.add(new Chunk("A̋C̀C̄C̆C̈", font)); - document.add(new Chunk("C̈C̕C̣C̦C̨̆", font)); - document.add(new Chunk(".\n", font)); - document.add(new Chunk("Another line: S", font)); - document.add(new Chunk("Ṣ̄ṣ̄Ṭ̄ṭ̄Ạ̈ạ̈Ọ̈ọ̈Ụ̄Ụ̈ụ̄ụ̈", font)); - document.add(new Chunk("j́S̛̄s̛̄K̛", font)); - document.add(new Chunk(".\n", font)); - } } diff --git a/pdf-toolbox/src/test/java/com/lowagie/examples/fonts/GlyphLayoutDocumentKernLiga.java b/pdf-toolbox/src/test/java/com/lowagie/examples/fonts/GlyphLayoutDocumentKernLiga.java index f2de839ba4..66e2b02f5b 100644 --- a/pdf-toolbox/src/test/java/com/lowagie/examples/fonts/GlyphLayoutDocumentKernLiga.java +++ b/pdf-toolbox/src/test/java/com/lowagie/examples/fonts/GlyphLayoutDocumentKernLiga.java @@ -1,7 +1,5 @@ /* - * GlyphLayoutDocumentDinSpec91379 - * * This code is part of the 'OpenPDF Tutorial'. * You can find the complete tutorial at the following address: * https://github.com/LibrePDF/OpenPDF/wiki/Tutorial diff --git a/pdf-toolbox/src/test/java/com/lowagie/examples/fonts/GlyphLayoutDocumentKernLigaPerFont.java b/pdf-toolbox/src/test/java/com/lowagie/examples/fonts/GlyphLayoutDocumentKernLigaPerFont.java index fccaaa8d5a..1540fe0f78 100644 --- a/pdf-toolbox/src/test/java/com/lowagie/examples/fonts/GlyphLayoutDocumentKernLigaPerFont.java +++ b/pdf-toolbox/src/test/java/com/lowagie/examples/fonts/GlyphLayoutDocumentKernLigaPerFont.java @@ -1,7 +1,5 @@ /* - * GlyphLayoutDocumentDinSpec91379 - * * This code is part of the 'OpenPDF Tutorial'. * You can find the complete tutorial at the following address: * https://github.com/LibrePDF/OpenPDF/wiki/Tutorial diff --git a/pdf-toolbox/src/test/java/com/lowagie/examples/fonts/GlyphLayoutDocumentWithImage.java b/pdf-toolbox/src/test/java/com/lowagie/examples/fonts/GlyphLayoutDocumentWithImage.java new file mode 100644 index 0000000000..070b78b5b8 --- /dev/null +++ b/pdf-toolbox/src/test/java/com/lowagie/examples/fonts/GlyphLayoutDocumentWithImage.java @@ -0,0 +1,98 @@ +/* + * This code is part of the 'OpenPDF Tutorial'. + * You can find the complete tutorial at the following address: + * https://github.com/LibrePDF/OpenPDF/wiki/Tutorial + * + * This code is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + */ +package com.lowagie.examples.fonts; + +import com.lowagie.text.Chunk; +import com.lowagie.text.Document; +import com.lowagie.text.Font; +import com.lowagie.text.FontFactory; +import com.lowagie.text.Image; +import com.lowagie.text.pdf.BaseFont; +import com.lowagie.text.pdf.LayoutProcessor; +import com.lowagie.text.pdf.PdfWriter; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; + +/** + * Prints characters and sequences of DIN 91379 with correct glyph layout and kerning + */ +public class GlyphLayoutDocumentWithImage { + + + /** + * Register and get font + * + * @param path of font file + * @param alias name + * @param fontSize size of font + * @return the loaded font + */ + private static Font loadFont(String path, String alias, float fontSize) { + FontFactory.register(path, alias); + return FontFactory.getFont(alias, BaseFont.IDENTITY_H, fontSize); + } + + + /** + * Main method + * + * @param args -- not used + */ + public static void main(String[] args) throws Exception { + test("GlyphLayoutDocumentWithImage.pdf"); + } + + + /** + * Run the test: Print the characters of DIN 91379 in a pdf document + * + * @param fileName Name of output file + */ + public static void test(String fileName) throws IOException { + + // Enable the LayoutProcessor with kerning and ligatures + LayoutProcessor.enableKernLiga(); + + float fontSize = 16.0f; + + // The OpenType fonts loaded with FontFactory.register() are + // available for glyph layout. + // Only these fonts can be used. + String fontDir = "com/lowagie/examples/fonts/"; + Font font = loadFont(fontDir + "noto/NotoSans-Regular.ttf", "sans", fontSize); + + try (Document document = new Document()) { + PdfWriter writer = PdfWriter.getInstance(document, Files.newOutputStream(Paths.get(fileName))); + writer.setInitialLeading(20.0f); + document.open(); + + document.add(new Chunk("Te", font)); + document.add(new Chunk("xt\nwith NewLine\n", font)); + + document.add(new Chunk("Test of several Chunks on one line: A", font)); + Image image = Image.getInstance("pdf-toolbox/src/test/resources/com/lowagie/examples/fonts/images/mushroom.png"); + image.scaleToFit(80f, 50f); + document.add(new Chunk(image, 0.0f, 0.0f)); + document.add(new Chunk("A̋", font)); + document.add(new Chunk("C̀\nC̄C̆C̈", font)); + + document.add(new Chunk("ab\nc", font)); + document.add(new Chunk("C̈C̕C̣C̦C̨̆", font)); + document.add(new Chunk(".\n", font)); + + document.add(new Chunk("Ṣ̄ṣ̄Ṭ̄ṭ̄Ạ̈ạ̈Ọ̈ọ̈Ụ̄Ụ̈ụ̄ụ̈", font)); + document.add(new Chunk("xyz", font)); + document.add(new Chunk("j́S̛̄s̛̄K̛", font)); + document.add(new Chunk(".\n", font)); + } + LayoutProcessor.disable(); + } +} diff --git a/pdf-toolbox/src/test/java/com/lowagie/examples/fonts/GlyphLayoutFormDin91379.java b/pdf-toolbox/src/test/java/com/lowagie/examples/fonts/GlyphLayoutFormDin91379.java index 70a0cded58..82164caa63 100644 --- a/pdf-toolbox/src/test/java/com/lowagie/examples/fonts/GlyphLayoutFormDin91379.java +++ b/pdf-toolbox/src/test/java/com/lowagie/examples/fonts/GlyphLayoutFormDin91379.java @@ -1,6 +1,4 @@ /* - * GlyphLayoutFormDin91379 - * * This code is part of the 'OpenPDF Tutorial'. * You can find the complete tutorial at the following address: * https://github.com/LibrePDF/OpenPDF/wiki/Tutorial @@ -30,14 +28,13 @@ public class GlyphLayoutFormDin91379 { public static String TEXT_INTRO = "Test of formatting for letters and sequences defined in:\n" - + "DIN 91379:2022-08: Characters and defined character sequences in Unicode for the electronic\n " - + "processing of names and data exchange in Europe, with CD-ROM\n" - + "See https://www.beuth.de/de/norm/din-91379/353496133\n" - + " https://github.com/String-Latin/DIN-91379-Characters-and-Sequences" + + "DIN 91379:2022-08: Characters and defined character sequences in Unicode for the\n" + + "electronic processing of names and data exchange in Europe, with CD-ROM.\n" + + "See https://github.com/String-Latin/DIN-91379-Characters-and-Sequences\n" + "and https://en.wikipedia.org/wiki/DIN_91379\n\n" - + "Fonts used: Noto Sans Regular, Noto Sans Math Regular\n" - + " see https://fonts.google.com/noto/specimen/Noto+Sans" - + " and https://github.com/googlefonts/noto-fonts/tree/main/hinted/ttf\n" + + "Fonts used: Noto Sans Regular, Noto Sans Math Regular, Noto Serif Regular\n" + + "See https://fonts.google.com/noto/specimen/Noto+Sans\n" + + "and https://github.com/googlefonts/noto-fonts/tree/main/hinted/ttf\n" + "Using LayoutProcessor for glyph layout with Java built-in routines.\n\n"; public static String LATIN_CHARS_DIN_91379 = @@ -78,7 +75,7 @@ public class GlyphLayoutFormDin91379 { + "bnlopt; Non-Letters N3 (normative)\n" + "¤ ¦ ¸ ¼ ½ ¾ \n" + "bnlnot; Non-Letters N4 (normative) -omitted-\n" - + "dc; Combining diacritics (normative) ̀-omitted-\n" + + "dc; Combining diacritics (normative) -omitted-\n" + "gl; Greek Letters (extended)\n" + "Ά Έ Ή Ί Ό Ύ Ώ ΐ Α Β Γ Δ Ε Ζ Η Θ Ι Κ Λ Μ Ν Ξ Ο Π Ρ Σ " + "Τ Υ Φ Χ Ψ Ω Ϊ Ϋ ά έ ή ί ΰ α β γ δ ε ζ η θ ι κ λ μ ν " @@ -97,19 +94,18 @@ public class GlyphLayoutFormDin91379 { * @param args -- not used */ public static void main(String[] args) throws Exception { - test("GlyphLayoutFormDin91379.pdf", "com/lowagie/examples/fonts/form/PdfFormLayoutProcessor.pdf", - TEXT_INTRO + LATIN_CHARS_DIN_91379); + test("GlyphLayoutFormDin91379.pdf"); } /** * Run the test: Print the characters of DIN 91379 in a pdf form * * @param fileName Name of output file - * @param formPath Name of input pdf form - * @param text Text to show * @throws Exception in case of error */ - public static void test(String fileName, String formPath, String text) throws Exception { + public static void test(String fileName) throws Exception { + String formPath = "com/lowagie/examples/fonts/form/PdfFormLayoutProcessor.pdf"; + String text = TEXT_INTRO + LATIN_CHARS_DIN_91379; // Enable the LayoutProcessor with kerning and ligatures LayoutProcessor.enableKernLiga(); diff --git a/pdf-toolbox/src/test/java/com/lowagie/examples/fonts/RunGlyphLayoutExamples.java b/pdf-toolbox/src/test/java/com/lowagie/examples/fonts/RunGlyphLayoutExamples.java new file mode 100644 index 0000000000..325354ef6a --- /dev/null +++ b/pdf-toolbox/src/test/java/com/lowagie/examples/fonts/RunGlyphLayoutExamples.java @@ -0,0 +1,47 @@ +/* + * This code is part of the 'OpenPDF Tutorial'. + * You can find the complete tutorial at the following address: + * https://github.com/LibrePDF/OpenPDF/wiki/Tutorial + * + * This code is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + */ +package com.lowagie.examples.fonts; + +import com.lowagie.text.pdf.LayoutProcessor; +import com.lowagie.text.pdf.LayoutProcessor.Version; + +/** + * Calls glyph layout examples with current and deprecated version + */ +public class RunGlyphLayoutExamples { + + /** + * Main method + * + * @param args -- not used + */ + public static void main(String[] args) throws Exception { + //Version[] versions = new Version[]{Version.ONE, Version.TWO}; // Version.ONE is deprecated! + Version[] versions = new Version[]{Version.TWO}; + + for (Version version : versions) { + LayoutProcessor.setVersion(version); + GlyphLayoutDocumentBidi.test(String.format("GlyphLayoutDocumentBidi-%s.pdf", version)); + LayoutProcessor.setVersion(version); + GlyphLayoutDocumentBidiPerFont.test(String.format("GlyphLayoutDocumentBidiPerFont-%s.pdf", version)); + LayoutProcessor.setVersion(version); + GlyphLayoutDocumentDin91379.test(String.format("GlyphLayoutDocumentDin91379-%s.pdf", version)); + LayoutProcessor.setVersion(version); + GlyphLayoutDocumentKernLiga.test(String.format(" GlyphLayoutDocumentKernLiga-%s.pdf", version)); + LayoutProcessor.setVersion(version); + GlyphLayoutDocumentKernLigaPerFont.test( + String.format("GlyphLayoutDocumentKernLigaPerFont-%s.pdf", version)); + LayoutProcessor.setVersion(version); + GlyphLayoutDocumentWithImage.test(String.format("GlyphLayoutDocumentWithImage-%s.pdf", version)); + LayoutProcessor.setVersion(version); + GlyphLayoutFormDin91379.test(String.format("GlyphLayoutFormDin91379-%s.pdf", version)); + } + } +} diff --git a/pdf-toolbox/src/test/resources/com/lowagie/examples/fonts/images/mushroom.png b/pdf-toolbox/src/test/resources/com/lowagie/examples/fonts/images/mushroom.png new file mode 100644 index 0000000000..5f165ee81f Binary files /dev/null and b/pdf-toolbox/src/test/resources/com/lowagie/examples/fonts/images/mushroom.png differ