/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (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.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.pdfbox.pdmodel.font;
import java.io.IOException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Properties;
import org.apache.pdfbox.util.ResourceLoader;
/**
* This class is used as font manager.
* @author <a href="mailto:andreas@lehmi.de">Andreas Lehmkühler</a>
* @version $Revision: 1.0 $
*/
public class FontManager
{
// HashMap with all known fonts
private static HashMap envFonts = new HashMap();
// the standard font
private static String standardFont = null;
private static Properties fontMapping = new Properties();
static {
try
{
ResourceLoader.loadProperties(
"org/apache/pdfbox/resources/FontMapping.properties",
fontMapping );
}
catch( IOException io )
{
io.printStackTrace();
throw new RuntimeException( "Error loading font mapping" );
}
loadFonts();
loadFontMapping();
loadBasefontMapping();
setStandardFont();
}
private FontManager()
{
}
/**
* Get the standard font from the environment, usually Arial or Times New Roman.
*
* @return The standard font
*
*/
public static java.awt.Font getStandardFont()
{
if (standardFont != null)
{
return getAwtFont(standardFont);
}
return null;
}
/**
* Get the font for the given fontname.
*
* @param font The name of the font.
*
* @return The font we are looking for or a similar font or null if nothing is found.
*
*/
public static java.awt.Font getAwtFont(String font)
{
String fontname = normalizeFontname(font);
if (envFonts.containsKey(fontname))
{
return (java.awt.Font)envFonts.get(fontname);
}
return null;
}
/**
* Load all available fonts from the environment.
*/
private static void loadFonts()
{
java.awt.Font[] allFonts = java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();
int numberOfFonts = allFonts.length;
for (int i=0;i<numberOfFonts;i++)
{
java.awt.Font font = allFonts[i];
String family = normalizeFontname(font.getFamily());
String psname = normalizeFontname(font.getPSName());
if (isBoldItalic(font))
{
envFonts.put(family+"bolditalic", font);
}
else if (isBold(font))
{
envFonts.put(family+"bold", font);
}
else if (isItalic(font))
{
envFonts.put(family+"italic", font);
}
else
{
envFonts.put(family, font);
}
if (!family.equals(psname))
{
envFonts.put(normalizeFontname(font.getPSName()),font);
}
}
}
private static void setStandardFont()
{
// One of the following fonts will be the standard-font
if (envFonts.containsKey("arial"))
{
standardFont = "arial";
}
else if (envFonts.containsKey("timesnewroman"))
{
standardFont = "timesnewroman";
}
}
/**
* Normalize the fontname.
*
* @param fontname The name of the font.
*
* @return The normalized name of the font.
*
*/
private static String normalizeFontname(String fontname)
{
// Terminate all whitespaces, commas and hyphens
String normalizedFontname = fontname.toLowerCase().replaceAll(" ","").replaceAll(",","").replaceAll("-","");
// Terminate trailing characters up to the "+".
// As far as I know, these characters are used in names of embedded fonts
// If the embedded font can't be read, we'll try to find it here
if (normalizedFontname.indexOf("+") > -1)
{
normalizedFontname = normalizedFontname.substring(normalizedFontname.indexOf("+")+1);
}
// normalize all kinds of fonttypes. There are several possible version which have to be normalized
// e.g. Arial,Bold Arial-BoldMT Helevtica-oblique ...
boolean isBold = normalizedFontname.indexOf("bold") > -1;
boolean isItalic = normalizedFontname.indexOf("italic") > -1 || normalizedFontname.indexOf("oblique") > -1;
normalizedFontname = normalizedFontname.toLowerCase().replaceAll("bold" , "")
.replaceAll("italic" , "").replaceAll("oblique" , "");
if (isBold)
{
normalizedFontname += "bold";
}
if (isItalic)
{
normalizedFontname += "italic";
}
return normalizedFontname;
}
/**
* Add a font-mapping.
*
* @param font The name of the font.
*
* @param mappedName The name of the mapped font.
*
*/
private static boolean addFontMapping(String font, String mappedName)
{
String fontname = normalizeFontname(font);
// is there already a font mapping ?
if (envFonts.containsKey(fontname))
{
return false;
}
String mappedFontname = normalizeFontname(mappedName);
// is the mapped font available ?
if (!envFonts.containsKey(mappedFontname))
{
return false;
}
envFonts.put(fontname, envFonts.get(mappedFontname));
return true;
}
/**
* Load the mapping for the well knwon font-substitutions.
*
*/
private static void loadFontMapping()
{
boolean addedMapping = true;
// There could be some recursive mappings in the fontmapping, so that we have to
// read the list until no more additional mapping is added to it
while (addedMapping)
{
int counter = 0;
Enumeration keys = fontMapping.keys();
while (keys.hasMoreElements())
{
String key = (String)keys.nextElement();
if (addFontMapping(key,(String)fontMapping.get(key)))
{
counter++;
}
}
if (counter == 0)
{
addedMapping = false;
}
}
}
/**
* Mapping for the basefonts.
*/
private static void loadBasefontMapping()
{
addFontMapping("Times-Roman","TimesNewRoman");
addFontMapping("Times-Bold","TimesNewRoman,Bold");
addFontMapping("Times-Italic","TimesNewRoman,Italic");
addFontMapping("Times-BoldItalic","TimesNewRoman,Bold,Italic");
addFontMapping("Helvetica-Oblique","Helvetica,Italic");
addFontMapping("Helvetica-BoldOblique","Helvetica,Bold,Italic");
addFontMapping("Courier-Oblique","Courier,Italic");
addFontMapping("Courier-BoldOblique","Courier,Bold,Italic");
}
/**
* Try to determine if the font has both a BOLD and an ITALIC-type.
*
* @param name The font.
*
* @return font has BOLD and ITALIC-type or not
*/
private static boolean isBoldItalic(java.awt.Font font)
{
return isBold(font) && isItalic(font);
}
/**
* Try to determine if the font has a BOLD-type.
*
* @param name The font.
*
* @return font has BOLD-type or not
*/
private static boolean isBold(java.awt.Font font)
{
String name = font.getName().toLowerCase();
if (name.indexOf("bold") > -1)
{
return true;
}
String psname = font.getPSName().toLowerCase();
if (psname.indexOf("bold") > -1)
{
return true;
}
return false;
}
/**
* Try to determine if the font has an ITALIC-type.
*
* @param name The font.
*
* @return font has ITALIC-type or not
*/
private static boolean isItalic(java.awt.Font font)
{
String name = font.getName().toLowerCase();
// oblique is the same as italic
if (name.indexOf("italic") > -1 || name.indexOf("oblique") > -1)
{
return true;
}
String psname = font.getPSName().toLowerCase();
if (psname.indexOf("italic") > -1 || psname.indexOf("oblique") > -1)
{
return true;
}
return false;
}
}