All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.itextpdf.layout.font.FontSet Maven / Gradle / Ivy

There is a newer version: 9.0.0
Show newest version
/*
    This file is part of the iText (R) project.
    Copyright (c) 1998-2024 Apryse Group NV
    Authors: Apryse Software.

    This program is offered under a commercial and under the AGPL license.
    For commercial licensing, contact us at https://itextpdf.com/sales.  For AGPL licensing, see below.

    AGPL licensing:
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program 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 Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see .
 */
package com.itextpdf.layout.font;

import com.itextpdf.io.logs.IoLogMessageConstant;
import com.itextpdf.io.font.FontProgram;
import com.itextpdf.commons.utils.FileUtil;
import com.itextpdf.kernel.font.Type3Font;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;

/**
 * Reusable font set for FontProgram related data.
 * Add and search fonts.
 * 

* A FontSet instance could be shared for multiple threads. * However FontSet filling is not thread safe operation. * * @see FontProvider */ public final class FontSet { // FontSet MUST be final to avoid overriding #add(FontInfo) method or remove functionality. private static final AtomicLong lastId = new AtomicLong(); // Due to new logic HashSet can be used instead of List. // But FontInfo with or without alias will be the same FontInfo. private final Set fonts = new LinkedHashSet<>(); private final Map fontPrograms = new HashMap<>(); private final long id; /** * Creates a new instance of {@link FontSet}. */ public FontSet() { this.id = lastId.incrementAndGet(); } /** * Add all the fonts in a directory and possibly its subdirectories. * * @param dir path to directory. * @param scanSubdirectories recursively scan subdirectories if {@code true}. * @return number of added fonts. */ public int addDirectory(String dir, boolean scanSubdirectories) { int count = 0; String[] files = FileUtil.listFilesInDirectory(dir, scanSubdirectories); if (files == null) return 0; for (String file : files) { try { String suffix = file.length() < 4 ? null : file.substring(file.length() - 4).toLowerCase(); if (".afm".equals(suffix) || ".pfm".equals(suffix)) { // Add only Type 1 fonts with matching .pfb files. String pfb = file.substring(0, file.length() - 4) + ".pfb"; if (FileUtil.fileExists(pfb) && addFont(file)) { count++; } } else if ((".ttf".equals(suffix) || ".otf".equals(suffix) || ".ttc".equals(suffix)) && addFont(file)) { count++; } } catch (Exception ignored) { } } return count; } /** * Add all the fonts in a directory. * * @param dir path to directory. * @return number of added fonts. */ public int addDirectory(String dir) { return addDirectory(dir, false); } /** * Add not supported for auto creating FontPrograms. *

* Note, {@link FontInfo#getAlias()} do not taken into account in {@link FontInfo#equals}. * The same font with different alias will not be replaced. * Alias will replace original font family in font selector algorithm. * * @param fontProgram {@link FontProgram} * @param encoding FontEncoding for creating {@link com.itextpdf.kernel.font.PdfFont} * @param alias font alias. * @param unicodeRange sets the specific range of characters to be used from the font * @return true, if font was successfully added, otherwise false. */ public boolean addFont(FontProgram fontProgram, String encoding, String alias, Range unicodeRange) { if (fontProgram == null) { return false; } if (fontProgram instanceof Type3Font) { Logger logger = LoggerFactory.getLogger(FontSet.class); logger.error(IoLogMessageConstant.TYPE3_FONT_CANNOT_BE_ADDED); return false; } FontInfo fi = FontInfo.create(fontProgram, encoding, alias, unicodeRange); if (addFont(fi)) { fontPrograms.put(fi, fontProgram); return true; } else { return false; } } /** * Add not supported for auto creating FontPrograms. *

* Note, {@link FontInfo#getAlias()} do not taken into account in {@link FontInfo#equals}. * The same font with different alias will not be replaced. * Alias will replace original font family in font selector algorithm. * * @param fontProgram {@link FontProgram} * @param encoding FontEncoding for creating {@link com.itextpdf.kernel.font.PdfFont} * @param alias font alias. * @return true, if font was successfully added, otherwise false. */ public boolean addFont(FontProgram fontProgram, String encoding, String alias) { return addFont(fontProgram, encoding, alias, null); } /** * Add not supported for auto creating FontPrograms. * * @param fontProgram {@link FontProgram} * @param encoding FontEncoding for creating {@link com.itextpdf.kernel.font.PdfFont}. * @return true, if font was successfully added, otherwise false. */ public boolean addFont(FontProgram fontProgram, String encoding) { return addFont(fontProgram, encoding, null); } /** * Creates {@link FontInfo}, fetches {@link com.itextpdf.io.font.FontProgramDescriptor} * and adds just created {@link FontInfo} to {@link FontSet}. *

* Note, {@link FontInfo#getAlias()} do not taken into account in {@link FontInfo#equals}. * The same font with different alias will not be replaced. * Alias will replace original font family in font selector algorithm. * * @param fontPath path to font data. * @param encoding preferred font encoding. * @param alias font alias, will replace original font family. * @param unicodeRange sets the specific range of characters to be used from the font * @return true, if font was successfully added, otherwise false. * @see com.itextpdf.io.font.PdfEncodings */ public boolean addFont(String fontPath, String encoding, String alias, Range unicodeRange) { return addFont(FontInfo.create(fontPath, encoding, alias, unicodeRange)); } /** * Creates {@link FontInfo}, fetches {@link com.itextpdf.io.font.FontProgramDescriptor} * and adds just created {@link FontInfo} to {@link FontSet}. *

* Note, {@link FontInfo#getAlias()} do not taken into account in {@link FontInfo#equals}. * The same font with different alias will not be replaced. * Alias will replace original font family in font selector algorithm. * * @param fontPath path to font data. * @param encoding preferred font encoding. * @param alias font alias. * @return true, if font was successfully added, otherwise false. * @see com.itextpdf.io.font.PdfEncodings */ public boolean addFont(String fontPath, String encoding, String alias) { return addFont(fontPath, encoding, alias, null); } /** * Creates {@link FontInfo}, fetches {@link com.itextpdf.io.font.FontProgramDescriptor} * and adds just created {@link FontInfo} to {@link FontSet}. * * @param fontPath path to font data. * @param encoding preferred font encoding. * @return true, if font was successfully added, otherwise false. * @see com.itextpdf.io.font.PdfEncodings */ public boolean addFont(String fontPath, String encoding) { return addFont(FontInfo.create(fontPath, encoding, null, null)); } /** * Creates {@link FontInfo}, fetches {@link com.itextpdf.io.font.FontProgramDescriptor} * and adds just created {@link FontInfo} to {@link FontSet}. *

* Note, {@link FontInfo#getAlias()} do not taken into account in {@link FontInfo#equals}. * The same font with different alias will not be replaced. * Alias will replace original font family in font selector algorithm. * * @param fontData font data. * @param encoding preferred font encoding. * @param alias font alias. * @param unicodeRange sets the specific range of characters to be used from the font * @return true, if font was successfully added, otherwise false. * @see com.itextpdf.io.font.PdfEncodings */ public boolean addFont(byte[] fontData, String encoding, String alias, Range unicodeRange) { return addFont(FontInfo.create(fontData, encoding, alias, unicodeRange)); } /** * Creates {@link FontInfo}, fetches {@link com.itextpdf.io.font.FontProgramDescriptor} * and adds just created {@link FontInfo} to {@link FontSet}. *

* Note, {@link FontInfo#getAlias()} do not taken into account in {@link FontInfo#equals}. * The same font with different alias will not be replaced. * Alias will replace original font family in font selector algorithm. * * @param fontData font data. * @param encoding preferred font encoding. * @param alias font alias. * @return true, if font was successfully added, otherwise false. * @see com.itextpdf.io.font.PdfEncodings */ public boolean addFont(byte[] fontData, String encoding, String alias) { return addFont(fontData, encoding, alias, null); } /** * Creates {@link FontInfo}, fetches {@link com.itextpdf.io.font.FontProgramDescriptor} * and adds just created {@link FontInfo} to {@link FontSet}. * * @param fontData font data. * @param encoding preferred font encoding. * @return true, if font was successfully added, otherwise false. * @see com.itextpdf.io.font.PdfEncodings */ public boolean addFont(byte[] fontData, String encoding) { return addFont(FontInfo.create(fontData, encoding, null, null)); } /** * Creates {@link FontInfo}, fetches {@link com.itextpdf.io.font.FontProgramDescriptor} * and adds just created {@link FontInfo} to {@link FontSet}. * {@link FontProvider#getDefaultEncoding(FontProgram)} will be used to determine encoding. * * @param fontPath path to font data. * @return true, if font was successfully added, otherwise false. */ public boolean addFont(String fontPath) { return addFont(fontPath, null, null); } /** * Creates {@link FontInfo}, fetches {@link com.itextpdf.io.font.FontProgramDescriptor} * and adds just created {@link FontInfo} to {@link FontSet}. * {@link FontProvider#getDefaultEncoding(FontProgram)} will be used to determine encoding. * * @param fontData font data. * @return true, if font was successfully added, otherwise false. */ public boolean addFont(byte[] fontData) { return addFont(fontData, null, null); } /** * Adds {@link FontInfo} with alias. Could be used to fill temporary font set. *

* Note, {@link FontInfo#getAlias()} do not taken into account in {@link FontInfo#equals}. * The same font with different alias will not be replaced. * Alias will replace original font family in font selector algorithm. * * @param fontInfo font info. * @param alias font alias. * @param unicodeRange sets the specific range of characters to be used from the font * @return true, if font was successfully added, otherwise false. */ public boolean addFont(FontInfo fontInfo, String alias, Range unicodeRange) { return addFont(FontInfo.create(fontInfo, alias, unicodeRange)); } /** * Adds {@link FontInfo} with alias. Could be used to fill temporary font set. *

* Note, {@link FontInfo#getAlias()} do not taken into account in {@link FontInfo#equals}. * The same font with different alias will not be replaced. * Alias will replace original font family in font selector algorithm. * * @param fontInfo font info. * @param alias font alias. * @return true, if font was successfully added, otherwise false. */ public boolean addFont(FontInfo fontInfo, String alias) { return addFont(fontInfo, alias, null); } /** * Adds {@link FontInfo}. Could be used to fill temporary font set. *

* Note, {@link FontInfo#getAlias()} do not taken into account in {@link FontInfo#equals}. * The same font with different alias will not be replaced. * * @param fontInfo font info. * @return true, if font was successfully added, otherwise false. */ public final boolean addFont(FontInfo fontInfo) { // This method MUST be final, to avoid inconsistency with FontSelectorCache. // (Yes, FontSet is final. Double check.) if (fontInfo != null && !fonts.contains(fontInfo)) { // NOTE! We SHALL NOT replace font, because it will influence on FontSelectorCache. // FontSelectorCache reset cache ONLY if number of fonts has been changed, // while replacing will modify list of fonts without size change. fonts.add(fontInfo); return true; } return false; } /** * Search in existed fonts for PostScript name or full font name. *

* Note, this method has O(n) complexity. * * @param fontName PostScript or full name. * @return true, if {@link FontSet} contains font with given name. */ public boolean contains(String fontName) { if (fontName == null || fontName.length() == 0) { return false; } fontName = fontName.toLowerCase(); for (FontInfo fi : getFonts()) { if (fontName.equals(fi.getDescriptor().getFullNameLowerCase()) || fontName.equals(fi.getDescriptor().getFontNameLowerCase())) { return true; } } return false; } /** * Search in existed fonts for PostScript name or full font name. *

* Note, this method has O(n) complexity. * * @param fontName PostScript or full name. * @return Collection of {@link FontInfo} from set of fonts with given PostScript or full name. */ public Collection get(String fontName) { if (fontName == null || fontName.length() == 0) { return Collections.emptyList(); } fontName = fontName.toLowerCase(); List list = new ArrayList<>(); for (FontInfo fi : getFonts()) { if (fontName.equals(fi.getDescriptor().getFullNameLowerCase()) || fontName.equals(fi.getDescriptor().getFontNameLowerCase())) { list.add(fi); } } return list; } /** * Gets available fonts. *

* Note, the collection is unmodifiable. * * @return set of all available fonts */ public Collection getFonts() { return getFonts(null); } /** * Gets union of available and temporary fonts. *

* Note, the collection is unmodifiable. * * @param additionalFonts set of temporary fonts * @return set of all available and temporary fonts */ public Collection getFonts(FontSet additionalFonts) { return new FontSetCollection(fonts, additionalFonts != null ? additionalFonts.fonts : null); } /** * Returns {@code true} if this set contains no elements. * * @return {@code true} if this set contains no elements */ public boolean isEmpty() { return size() == 0; } /** * Returns the number of elements in this set. * * @return the number of elements in this set */ public int size() { return fonts.size(); } //region Internal members long getId() { return id; } FontProgram getFontProgram(FontInfo fontInfo) { return fontPrograms.get(fontInfo); } //endregion }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy