@Override public byte[] convertToBytes(Glyph glyph) { byte[] bytes = new byte[1]; if (fontEncoding.isFontSpecific()) { bytes[0] = (byte) glyph.getCode(); } else { if (fontEncoding.canEncode(glyph.getUnicode())) { bytes[0] = (byte) fontEncoding.convertToByte(glyph.getUnicode()); } else { return EMPTY_BYTES; } } shortTag[bytes[0] & 0xff] = 1; return bytes; }
@Override protected void checkNonSymbolicTrueTypeFont(PdfTrueTypeFont trueTypeFont) { String encoding = trueTypeFont.getFontEncoding().getBaseEncoding(); // non-symbolic true type font will always has an encoding entry in font dictionary in itext7 if (!PdfEncodings.WINANSI.equals(encoding) && !encoding.equals(PdfEncodings.MACROMAN) || trueTypeFont.getFontEncoding().hasDifferences()) { throw new PdfAConformanceException(PdfAConformanceException.ALL_NON_SYMBOLIC_TRUE_TYPE_FONT_SHALL_SPECIFY_MAC_ROMAN_OR_WIN_ANSI_ENCODING_AS_THE_ENCODING_ENTRY, trueTypeFont); } }
public static FontEncoding createFontEncoding(String baseEncoding) { FontEncoding encoding = new FontEncoding(); encoding.baseEncoding = normalizeEncoding(baseEncoding); if (encoding.baseEncoding.startsWith("#")) { encoding.fillCustomEncoding(); } else { encoding.fillNamedEncoding(); } return encoding; }
@Override public boolean containsGlyph(int unicode) { if (fontEncoding.isFontSpecific()) { return fontProgram.getGlyphByCode(unicode) != null; } else { return fontEncoding.canEncode(unicode) && getFontProgram().getGlyph(fontEncoding.getUnicodeDifference(unicode)) != null; } }
@Override public boolean containsGlyph(int unicode) { return (fontEncoding.canEncode(unicode) || unicode < 33) && getFontProgram().getGlyph(fontEncoding.getUnicodeDifference(unicode)) != null; }
if (fontEncoding.canDecode(k)) { shortTag[k] = 1; } else if (!fontEncoding.hasDifferences() && fontProgram.getGlyphByCode(k) != null) { shortTag[k] = 1; } else { if (fontEncoding.hasDifferences()) { if (!FontEncoding.NOTDEF.equals(fontEncoding.getDifference(k))) { firstChar = k; break; if (!FontEncoding.NOTDEF.equals(fontEncoding.getDifference(k))) { lastChar = k; break; diff.add(new PdfName(fontEncoding.getDifference(k))); } else { gap = true; } else if (!fontEncoding.isFontSpecific()) { getPdfObject().put(PdfName.Encoding, PdfEncodings.CP1252.equals(fontEncoding.getBaseEncoding()) ? PdfName.WinAnsiEncoding : PdfName.MacRomanEncoding); if (isForceWidthsOutput() || !isBuiltInFont() || fontEncoding.hasDifferences()) { getPdfObject().put(PdfName.FirstChar, new PdfNumber(firstChar)); getPdfObject().put(PdfName.LastChar, new PdfNumber(lastChar));
@Override public int appendAnyGlyph(String text, int from, List<Glyph> glyphs) { Glyph glyph; if (fontEncoding.isFontSpecific()) { glyph = fontProgram.getGlyphByCode(text.charAt(from)); } else { glyph = getGlyph((int) text.charAt(from)); } if (glyph != null) { glyphs.add(glyph); } return 1; }
static TrueTypeFont createFontProgram(PdfDictionary fontDictionary, FontEncoding fontEncoding, CMapToUnicode toUnicode) { DocTrueTypeFont fontProgram = new DocTrueTypeFont(fontDictionary); fillFontDescriptor(fontProgram, fontDictionary.getAsDictionary(PdfName.FontDescriptor)); PdfNumber firstCharNumber = fontDictionary.getAsNumber(PdfName.FirstChar); int firstChar = firstCharNumber != null ? Math.max(firstCharNumber.intValue(), 0) : 0; int[] widths = FontUtil.convertSimpleWidthsArray(fontDictionary.getAsArray(PdfName.Widths), firstChar, fontProgram.getMissingWidth()); fontProgram.avgWidth = 0; int glyphsWithWidths = 0; for (int i = 0; i < 256; i++) { Glyph glyph = new Glyph(i, widths[i], fontEncoding.getUnicode(i)); fontProgram.codeToGlyph.put(i, glyph); //FontEncoding.codeToUnicode table has higher priority if (glyph.hasValidUnicode() && fontEncoding.convertToByte(glyph.getUnicode()) == i) { fontProgram.unicodeToGlyph.put(glyph.getUnicode(), glyph); } else if (toUnicode != null) { glyph.setChars(toUnicode.lookup(i)); } if (widths[i] > 0) { glyphsWithWidths++; fontProgram.avgWidth += widths[i]; } } if (glyphsWithWidths != 0) { fontProgram.avgWidth /= glyphsWithWidths; } return fontProgram; }
/** * {@inheritDoc} */ @Override public GlyphLine decodeIntoGlyphLine(PdfString content) { byte[] contentBytes = content.getValueBytes(); List<Glyph> glyphs = new ArrayList<>(contentBytes.length); for (byte b : contentBytes) { int code = b & 0xff; Glyph glyph = null; if (toUnicode != null && toUnicode.lookup(code) != null && (glyph = fontProgram.getGlyphByCode(code)) != null) { if (!Arrays.equals(toUnicode.lookup(code), glyph.getChars())) { // Copy the glyph because the original one may be reused (e.g. standard Helvetica font program) glyph = new Glyph(glyph); glyph.setChars(toUnicode.lookup(code)); } } else { int uni = fontEncoding.getUnicode(code); if (uni > -1) { glyph = getGlyph(uni); } else if (fontEncoding.getBaseEncoding() == null) { glyph = fontProgram.getGlyphByCode(code); } } if (glyph != null) { glyphs.add(glyph); } } return new GlyphLine(glyphs); }
@Override public void flush() { if (isFlushed()) return; ensureUnderlyingObjectHasIndirectReference(); if (((Type3Font) getFontProgram()).getNumberOfGlyphs() < 1) { throw new PdfException("No glyphs defined for type3 font."); } PdfDictionary charProcs = new PdfDictionary(); for (int i = 0; i < 256; i++) { if (fontEncoding.canDecode(i)) { Type3Glyph glyph = getType3Glyph(fontEncoding.getUnicode(i)); if (glyph != null) { charProcs.put(new PdfName(fontEncoding.getDifference(i)), glyph.getContentStream()); glyph.getContentStream().flush(); } } } getPdfObject().put(PdfName.CharProcs, charProcs); getPdfObject().put(PdfName.FontMatrix, new PdfArray(getFontMatrix())); getPdfObject().put(PdfName.FontBBox, new PdfArray(fontProgram.getFontMetrics().getBbox())); String fontName = fontProgram.getFontNames().getFontName(); super.flushFontData(fontName, PdfName.Type3); //BaseFont is not listed as key in Type 3 font specification. getPdfObject().remove(PdfName.BaseFont); super.flush(); }
if (unicode != -1 && fontEncoding.canEncode(unicode)) { int code = fontEncoding.convertToByte(unicode); ((Type3Font) getFontProgram()).addGlyph(code, unicode, widths[code], null, new Type3Glyph(charProcsDic.getAsStream(glyphName), getDocument()));
@Override protected void checkSymbolicTrueTypeFont(PdfTrueTypeFont trueTypeFont) { if (trueTypeFont.getFontEncoding().hasDifferences()) { throw new PdfAConformanceException(PdfAConformanceException.ALL_SYMBOLIC_TRUE_TYPE_FONTS_SHALL_NOT_SPECIFY_ENCODING); } // if symbolic font encoding doesn't have differences, itext7 won't write encoding for such font }
@Override protected void checkNonSymbolicTrueTypeFont(PdfTrueTypeFont trueTypeFont) { String encoding = trueTypeFont.getFontEncoding().getBaseEncoding(); // non-symbolic true type font will always has an encoding entry in font dictionary in itext7 if (!PdfEncodings.WINANSI.equals(encoding) && !encoding.equals(PdfEncodings.MACROMAN)) { throw new PdfAConformanceException(PdfAConformanceException.ALL_NON_SYMBOLIC_TRUE_TYPE_FONT_SHALL_SPECIFY_MAC_ROMAN_ENCODING_OR_WIN_ANSI_ENCODING, trueTypeFont); } // if font has differences array, itext7 ensures that all names in it are listed in AdobeGlyphList }
/** * Converts a {@code String} to a {@code byte} array according to the encoding. * String could contain a unicode symbols or font specific codes. * * @param text the {@code String} to be converted. * @return an array of {@code byte} representing the conversion according to the encoding */ public byte[] convertToBytes(String text) { if (text == null || text.length() == 0) { return emptyBytes; } int ptr = 0; byte[] bytes = new byte[text.length()]; for (int i = 0; i < text.length(); i++) { if (unicodeToCode.containsKey(text.charAt(i))) { bytes[ptr++] = (byte) convertToByte(text.charAt(i)); } } return ArrayUtil.shortenArray(bytes, ptr); }
public static FontEncoding createEmptyFontEncoding() { FontEncoding encoding = new FontEncoding(); encoding.baseEncoding = null; encoding.fontSpecific = false; encoding.differences = new String[256]; for (int ch = 0; ch < 256; ch++) { encoding.unicodeDifferences.put(ch, ch); } return encoding; }
@Override public byte[] convertToBytes(String text) { byte[] bytes = fontEncoding.convertToBytes(text); for (byte b : bytes) { shortTag[b & 0xff] = 1; } return bytes; }
/** * Gets first empty code, that could use with {@see addSymbol()} * * @return code from 1 to 255 or -1 if all slots are busy. */ private int getFirstEmptyCode() { final int startFrom = 1; for (int i = startFrom; i < 256; i++) { if (!fontEncoding.canDecode(i)) { return i; } } return -1; }
/** * Creates a Type 3 font. * * @param colorized defines whether the glyph color is specified in the glyph descriptions in the font. */ PdfType3Font(PdfDocument document, boolean colorized) { super(); makeIndirect(document); subset = true; embedded = true; fontProgram = new Type3Font(colorized); fontEncoding = FontEncoding.createEmptyFontEncoding(); }
glyph = new Type3Glyph(getDocument(), wx, llx, lly, urx, ury, ((Type3Font) getFontProgram()).isColorized()); ((Type3Font) getFontProgram()).addGlyph(code, c, wx, new int[]{llx, lly, urx, ury}, glyph); fontEncoding.addSymbol((byte) code, c);
@Override public boolean containsGlyph(int unicode) { if (fontEncoding.canEncode(unicode)) { if (fontEncoding.isFontSpecific()) { return getFontProgram().getGlyphByCode(unicode) != null; } else { return getFontProgram().getGlyph(fontEncoding.getUnicodeDifference(unicode)) != null; } } else { return false; } }