/* * 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. */ /* $Id$ */ package org.apache.fop.tools.fontlist; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.OutputStream; import java.io.PrintStream; import java.net.URI; import java.net.URL; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.SortedMap; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.sax.SAXResult; import javax.xml.transform.sax.SAXTransformerFactory; import javax.xml.transform.sax.TransformerHandler; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; import org.xml.sax.ContentHandler; import org.xml.sax.SAXException; import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.IOUtils; import org.apache.fop.Version; import org.apache.fop.apps.FOPException; import org.apache.fop.apps.Fop; import org.apache.fop.apps.FopFactory; import org.apache.fop.apps.MimeConstants; import org.apache.fop.fonts.FontEventListener; import org.apache.fop.fonts.FontTriplet; import org.apache.fop.util.GenerationHelperContentHandler; /** * Command-line application to list available fonts and to optionally produce sample pages * with those fonts. */ public final class FontListMain { private static final int GENERATE_CONSOLE = 0; private static final int GENERATE_XML = 1; private static final int GENERATE_FO = 2; private static final int GENERATE_RENDERED = 3; private FopFactory fopFactory; private boolean verbose; private File configFile; private File outputFile; private String configMime = MimeConstants.MIME_PDF; private String outputMime; private int mode = GENERATE_CONSOLE; private String singleFamilyFilter; private FontListMain() throws SAXException, IOException { } private void prepare() throws SAXException, IOException { if (this.configFile != null) { fopFactory = FopFactory.newInstance(configFile); } else { fopFactory = FopFactory.newInstance(new File(".").toURI()); } } private ContentHandler getFOPContentHandler(OutputStream out) throws FOPException { Fop fop = fopFactory.newFop(this.outputMime, out); return fop.getDefaultHandler(); } private void generateXML(SortedMap fontFamilies, File outFile, String singleFamily) throws TransformerConfigurationException, SAXException, IOException { SAXTransformerFactory tFactory = (SAXTransformerFactory)SAXTransformerFactory.newInstance(); TransformerHandler handler; if (this.mode == GENERATE_XML) { handler = tFactory.newTransformerHandler(); } else { URL url = getClass().getResource("fonts2fo.xsl"); if (url == null) { throw new FileNotFoundException("Did not find resource: fonts2fo.xsl"); } handler = tFactory.newTransformerHandler(new StreamSource(url.toExternalForm())); } if (singleFamily != null) { Transformer transformer = handler.getTransformer(); transformer.setParameter("single-family", singleFamily); } OutputStream out = new java.io.FileOutputStream(outFile); out = new java.io.BufferedOutputStream(out); if (this.mode == GENERATE_RENDERED) { handler.setResult(new SAXResult(getFOPContentHandler(out))); } else { handler.setResult(new StreamResult(out)); } try { GenerationHelperContentHandler helper = new GenerationHelperContentHandler( handler, null, null); FontListSerializer serializer = new FontListSerializer(); serializer.generateSAX(fontFamilies, singleFamily, helper); } finally { IOUtils.closeQuietly(out); } } private void generate() throws Exception { prepare(); FontEventListener listener = new FontEventListener() { public void fontLoadingErrorAtAutoDetection(Object source, String fontURL, Exception e) { System.err.println("Could not load " + fontURL + " (" + e.getLocalizedMessage() + ")"); } public void fontSubstituted(Object source, FontTriplet requested, FontTriplet effective) { //ignore } public void glyphNotAvailable(Object source, char ch, String fontName) { //ignore } public void fontDirectoryNotFound(Object source, String msg) { //ignore } public void svgTextStrokedAsShapes(Object source, String fontFamily) { // ignore } }; FontListGenerator listGenerator = new FontListGenerator(); SortedMap fontFamilies = listGenerator.listFonts(fopFactory, configMime, listener); if (this.mode == GENERATE_CONSOLE) { writeToConsole(fontFamilies); } else { writeOutput(fontFamilies); } } private void writeToConsole(SortedMap fontFamilies) throws TransformerConfigurationException, SAXException, IOException { Iterator iter = fontFamilies.entrySet().iterator(); StringBuffer sb = new StringBuffer(); while (iter.hasNext()) { Map.Entry entry = (Map.Entry)iter.next(); String firstFamilyName = (String)entry.getKey(); sb.append(firstFamilyName); sb.append(':'); sb.append('\n'); List list = (List)entry.getValue(); for (Object aList : list) { FontSpec f = (FontSpec) aList; sb.append(" "); sb.append(f.getKey()); sb.append(' '); sb.append(f.getFamilyNames()); if (verbose) { URI uri = f.getFontMetrics().getFontURI(); if (uri != null) { sb.append(' '); sb.append('('); sb.append(uri.toString()); sb.append(')'); } } sb.append('\n'); for (Object o : f.getTriplets()) { FontTriplet triplet = (FontTriplet) o; sb.append(" "); sb.append(triplet.toString()); sb.append('\n'); } } } System.out.print(sb.toString()); System.out.flush(); } private void writeOutput(SortedMap fontFamilies) throws TransformerConfigurationException, SAXException, IOException { if (this.outputFile.isDirectory()) { System.out.println("Creating one file for each family..."); for (Object o : fontFamilies.entrySet()) { Map.Entry entry = (Map.Entry) o; String familyName = (String) entry.getKey(); System.out.println("Creating output file for " + familyName + "..."); String filename; switch (this.mode) { case GENERATE_RENDERED: filename = familyName + ".pdf"; break; case GENERATE_FO: filename = familyName + ".fo"; break; case GENERATE_XML: filename = familyName + ".xml"; break; default: throw new IllegalStateException("Unsupported mode"); } File outFile = new File(this.outputFile, filename); generateXML(fontFamilies, outFile, familyName); } } else { System.out.println("Creating output file..."); generateXML(fontFamilies, this.outputFile, this.singleFamilyFilter); } System.out.println(this.outputFile + " written."); } private static void printVersion() { System.out.println("Apache FOP " + Version.getVersion() + " - http://xmlgraphics.apache.org/fop/\n"); } private static void printHelp() { printVersion(); String className = FontListMain.class.getName(); PrintStream out = System.out; out.println("USAGE"); out.println(" java [vmargs] " + className + "[-v] [-c <config-file>] [-f <mime>] [[output-dir|output-file] [font-family]]"); out.println(); out.println("PARAMETERS"); out.println(" config-file: an optional FOP configuration file"); out.println(" mime: The MIME type of the output format for which to"); out.println(" create the font list (defaults to application/pdf)"); out.println(" output-dir: Creates one sample PDF per font-family"); out.println(" output-file: writes the list as file (valid file extensions: xml, fo, pdf)"); out.println(" font-family: filters to a single font family"); out.println(); out.println("EXAMPLE"); out.println(" java [vmargs] " + className + " -c userconfig.xml all-fonts.pdf"); out.println(" --> this generates a single PDF containing a sample"); out.println(" of all configured fonts."); out.println(" java [vmargs] " + className + " -c userconfig.xml"); out.println(" --> this prints all configured fonts to the console."); out.println(); } private void parseArguments(String[] args) { if (args.length > 0) { int idx = 0; if ("--help".equals(args[idx]) || "-?".equals(args[idx]) || "-h".equals(args[idx])) { printHelp(); // @SuppressFBWarnings("DM_EXIT") System.exit(0); } if ("-v".equals(args[idx])) { verbose = true; idx += 1; } if (idx < args.length - 1 && "-c".equals(args[idx])) { String filename = args[idx + 1]; this.configFile = new File(filename); idx += 2; } if (idx < args.length - 1 && "-f".equals(args[idx])) { this.configMime = args[idx + 1]; idx += 2; } if (idx < args.length) { String name = args[idx]; this.outputFile = new File(name); if (this.outputFile.isDirectory()) { this.mode = GENERATE_RENDERED; this.outputMime = MimeConstants.MIME_PDF; } else if (FilenameUtils.getExtension(name).equalsIgnoreCase("pdf")) { this.mode = GENERATE_RENDERED; this.outputMime = MimeConstants.MIME_PDF; } else if (FilenameUtils.getExtension(name).equalsIgnoreCase("fo")) { this.mode = GENERATE_FO; } else if (FilenameUtils.getExtension(name).equalsIgnoreCase("xml")) { this.mode = GENERATE_XML; } else { throw new IllegalArgumentException( "Operating mode for the output file cannot be determined" + " or is unsupported: " + name); } idx++; } if (idx < args.length) { this.singleFamilyFilter = args[idx]; } } else { System.out.println("use --help or -? for usage information."); } } /** * The command-line interface. * @param args the command-line arguments */ public static void main(String[] args) { try { FontListMain app = new FontListMain(); app.parseArguments(args); app.generate(); } catch (Throwable t) { printHelp(); t.printStackTrace(); System.exit(-1); } } }