001/*******************************************************************************
002 * This software is provided as a supplement to the authors' textbooks on digital
003 * image processing published by Springer-Verlag in various languages and editions.
004 * Permission to use and distribute this software is granted under the BSD 2-Clause
005 * "Simplified" License (see http://opensource.org/licenses/BSD-2-Clause).
006 * Copyright (c) 2006-2023 Wilhelm Burger, Mark J. Burge. All rights reserved.
007 * Visit https://imagingbook.com for additional details.
008 ******************************************************************************/
009package imagingbook.pdf;
010
011import com.lowagie.text.DocumentException;
012import com.lowagie.text.pdf.BaseFont;
013import com.lowagie.text.pdf.DefaultFontMapper;
014import com.lowagie.text.pdf.FontMapper;
015
016import java.awt.Font;
017import java.io.IOException;
018import java.util.Arrays;
019import java.util.HashSet;
020
021/**
022 * An implementation of {@link FontMapper} that substitutes unknown fonts with embedded core fonts (Type1).
023 *
024 * @author WB
025 */
026public class CoreFontMapper extends DefaultFontMapper {
027        
028        public static boolean VERBOSE = false;
029        private static String classname = CoreFontMapper.class.getSimpleName();
030
031        static String[] namesMonospaced = {"DIALOG", "DIALOGINPUT", "MONOSPACED", "COURIER", "COURIER NEW"};
032        static String[] namesSerif = {"SERIF", "TIMES", "TIMESROMAN", "TIMES NEW ROMAN"};
033
034        private final HashSet<String> keysMonospaced;
035        private final HashSet<String> keysSerif;
036
037        public CoreFontMapper() {
038                keysMonospaced = new HashSet<>(Arrays.asList(namesMonospaced));
039                keysSerif      = new HashSet<>(Arrays.asList(namesSerif));
040        }
041        
042        // --------------------------------------------------
043
044        /**
045         * Adds the logical name of a font to be treated as monospaced. All such fonts will be replaced by {@code Courier}
046         * in the PDF.
047         *
048         * @param key the logical font name
049         * @return true if insertion was successful
050         */
051        public boolean addKeyMonospaced(String key) {
052                return keysMonospaced.add(key.toUpperCase());
053        }
054
055        /**
056         * Adds the logical name of a font to be treated as a serif font. All such fonts will be replaced by {@code Times}
057         * in the PDF.
058         *
059         * @param key the logical font name
060         * @return true if insertion was successful
061         */
062        public boolean addKeySerif(String key) {
063                return keysSerif.add(key.toUpperCase());
064        }
065
066        // --------------------------------------------------
067        
068        public BaseFont awtToPdf(Font font) {           
069                BaseFontParameters p = getBaseFontParameters(font.getFontName());
070                if (p != null) {                // font is known/registered
071                        BaseFont bf = null;
072                        try {
073                                bf = BaseFont.createFont(p.fontName, p.encoding, p.embedded, p.cached, p.ttfAfm, p.pfb);
074                        } catch (DocumentException | IOException e) {
075                                System.out.println("***** BaseFont.createFont() failed! ***");
076                        }
077                        if (VERBOSE) System.out.println(classname + ": mapped to known font " + bf.getPostscriptFontName());
078                        return bf;
079                }
080                
081                // font is not known/registered
082                String logicalName = font.getName();
083                int pos =  logicalName.indexOf('.'); // extract up to first '.'
084                if (pos >= 0) {
085                        logicalName = logicalName.substring(0, pos);    //TODO: bug in DefaultFontMapper !
086                }
087
088                boolean isIt = font.isItalic();
089                boolean isBf = font.isBold();
090
091                Type1CoreFont sf = null;
092
093                String key = logicalName.toUpperCase();
094                if (keysMonospaced.contains(key)) {
095                        if (isIt)
096                                sf = (isBf) ? Type1CoreFont.CourierBoldOblique : Type1CoreFont.CourierOblique;
097                        else
098                                sf = (isBf) ? Type1CoreFont.CourierBold : Type1CoreFont.Courier;
099                }
100                else if (keysSerif.contains(key)) {
101                        if (isIt)
102                                sf = (isBf) ? Type1CoreFont.TimesBoldItalic : Type1CoreFont.TimesItalic;
103                        else
104                                sf = (isBf) ? Type1CoreFont.TimesBold : Type1CoreFont.TimesRoman;
105                }
106                else {
107                        if (isIt)
108                                sf = (isBf) ? Type1CoreFont.HelveticaBoldOblique : Type1CoreFont.HelveticaOblique;
109                        else
110                                sf = (isBf) ? Type1CoreFont.HelveticaBold : Type1CoreFont.Helvetica;
111                }
112
113                if (VERBOSE) System.out.println(classname + ": mapped to Type1 font " + logicalName + " --> " + sf.toString());
114
115                return (sf != null) ? sf.getBaseFont() : null;
116        }
117
118        @Override
119        public Font pdfToAwt(BaseFont font, int size) {
120                return null;
121        }
122
123
124
125        // ------------------------------------------------------------------------------------
126
127        // public static void main(String[] args) {
128        //      FontMapper dfm = new CoreFontMapper();
129        //
130        //      //              java.awt.Font awtFont1 = new java.awt.Font(java.awt.Font.SANS_SERIF, java.awt.Font.PLAIN, 18);
131        //      java.awt.Font awtFont1 = new java.awt.Font(java.awt.Font.DIALOG, java.awt.Font.ITALIC, 18);
132        //      BaseFont bf1 = dfm.awtToPdf(awtFont1);
133        //      System.out.println("bf1 = " + bf1.getPostscriptFontName());
134        //      System.out.println("bf1.isEmbedded = " + bf1.isEmbedded());
135        //
136        // }
137}