// Copyright 2001 FreeHEP package org.freehep.graphicsio.ps; import java.io.IOException; import java.awt.Shape; import java.awt.Font; import java.awt.geom.PathIterator; import java.awt.geom.Rectangle2D; import java.awt.font.GlyphMetrics; import java.awt.font.FontRenderContext; import java.io.PrintStream; import org.freehep.graphicsio.font.FontEmbedder; import org.freehep.graphicsio.font.encoding.CharTable; /** * Type 3 Font Embedder class for Postscript. * @author Sami Kama * @version $Id: PSFontEmbedder.java,v 1.1 2002/07/30 19:11:28 duns Exp $ */ public class PSFontEmbedder extends FontEmbedder { protected int dictSize = 9; protected PrintStream os; private PSPathConstructor pc; public PSFontEmbedder(FontRenderContext context, PrintStream os) { super(context); this.os = os; pc = new PSPathConstructor(os, false, true); } /** * Writes Glyph definition of given glyph. */ protected void writeGlyph(String unicodeName, Shape glyph, GlyphMetrics glyphMetrics) throws IOException { double[] points = new double[6]; double[] lastMove = new double[2]; double[] lastPoint = new double[2]; double[] controlPoint = new double[4]; PathIterator pIter = glyph.getPathIterator(null); os.println("\t/"+unicodeName); os.println("\t\t{"); while (!pIter.isDone()) { switch(pIter.currentSegment(points)) { case PathIterator.SEG_MOVETO: pc.move(points[0], points[1]); lastPoint[0] =points[0]; lastPoint[1] =points[1]; break; case PathIterator.SEG_LINETO : pc.line(points[0], points[1]); lastPoint[0] = points[0]; lastPoint[1] = points[1]; break; case PathIterator.SEG_QUADTO : controlPoint[0] = points[0]+(lastPoint[0]-points[0])/3.; controlPoint[1] = points[1]+(lastPoint[1]-points[1])/3.; controlPoint[2] = points[0]+(points[2]-points[0])/3.; controlPoint[3] = points[1]+(points[3]-points[1])/3.; pc.cubic(controlPoint[0], controlPoint[1], controlPoint[2], controlPoint[3], points[2], points[3]); lastPoint[0] = points[2]; lastPoint[1] = points[3]; break; case PathIterator.SEG_CUBICTO : pc.cubic(points[0], points[1], points[2], points[3], points[4], points[5]); lastPoint[0] = points[4]; lastPoint[1] = points[5]; break; case PathIterator.SEG_CLOSE : pc.closePath(); lastPoint[0] = 0.; lastPoint[1] = 0.; break; } pIter.next(); } // System.out.println("done once"); os.println("fill"); os.println("\t\t} def"); os.println(); } /** writes metric dictionary for the font. */ protected void writeWidths(double[] widths) throws IOException { os.println("\t/Metrics "+(getNODefinedChars()+1)+" dict def"); os.println("\t\tMetrics begin"); os.println("\t\t/"+NOTDEF+" "+(int)getUndefinedWidth()+" def"); for (int i=1; i<256; i++) { if (getCharName(i) != null) { os.println("\t\t/"+getCharName(i)+" "+widths[i]+" def"); } } os.println("\tend"); } /** writes encoding array.*/ protected void writeEncoding(CharTable charTable) throws IOException{ os.println("\t/Encoding 256 array def"); os.println("\t\t\t0 1 255 {Encoding exch /.notdef put}for"); for (int i=1; i<256; i++) { String name = charTable.toName(i); if (name != null){ os.println("\t\tEncoding "+i+" /"+name+" put"); } } } /** Writes initial parts of the font dictionary. */ protected void openIncludeFont() throws IOException { Rectangle2D boundingBox = getFontBBox(); double llx = boundingBox.getX(); double lly = -boundingBox.getY()-boundingBox.getHeight(); double urx = boundingBox.getX()+boundingBox.getWidth(); double ury = -boundingBox.getY(); os.println("9 dict begin"); os.println("/FontType 3 def"); os.println("/FontMatrix ["+(1/FONT_SIZE)+" 0 0 "+(1/FONT_SIZE)+" 0 0]def"); os.println("/FontBBox ["+(int)llx+" "+(int)lly+ " "+(int)urx+" "+(int)ury+" ] def"); // os.println("\t /"+getFontName()+" "+(getNODefinedChars()+1)+" dict def"); } /** Closes font dictionary.*/ protected void closeIncludeFont() throws IOException { this.writeBuildProcs(); } /* * Writes BuildGlyph and BuildChar procedures of font. */ protected void writeBuildProcs() throws IOException { Rectangle2D boundingBox = getFontBBox(); double llx = boundingBox.getX(); double lly = -boundingBox.getY()-boundingBox.getHeight(); double urx = boundingBox.getX()+boundingBox.getWidth(); double ury = -boundingBox.getY(); os.println("\t/BuildGlyph"); os.println("\t\t{ 2 copy exch /Metrics get exch "); os.println("\t\t\t2 copy known {get}{pop pop "+getUndefinedWidth()+"} ifelse"); os.println("\t\t\t0"); os.println("\t\t\t"+(int)llx+" "+(int)lly+" "+(int)urx+" "+ (int)ury); os.println("\t\t\tsetcachedevice"); // ????? os.println("\t\t\texch /"+getFontName()+" get exch"); os.println("\t\t\texch /CharProcs get exch"); os.println("\t\t\t2 copy known not"); os.println("\t\t\t\t\t{pop /.notdef}"); os.println("\t\t\t\tif"); os.println("\t\t\tget exec"); os.println("\t\t} bind def"); os.println(); os.println("\t/BuildChar"); os.println("\t\t{ 1 index /Encoding get exch get"); os.println("\t\t 1 index /BuildGlyph get exec"); os.println("\t } bind def"); } /** * Writes necessary commands to find Glyphs dictionary from font dictionary * and puts it on the stack, opens dictionary to write glyph definitions. */ protected void openGlyphs() throws IOException { // ??????? os.println("\t/"+getFontName()+" "+(getNODefinedChars()+1)+" dict def"); os.println("\t/CharProcs "+(getNODefinedChars()+1)+" dict def"); os.println("\tCharProcs begin"); // os.print("dup /"+getFontName()+" get begin"); os.println("\t\t\t%define Glyph dictionary and start filling"); } /** Closes Glyphs dictionary.*/ protected void closeGlyphs() throws IOException { os.print("\tend"); os.println("\t\t\t\t% close glyph dict. "); } /** Closes font dictionary.*/ protected void closeEmbedFont() throws IOException { os.print("\tcurrentdict"); os.println("\t\t\t% actually put dict on the stack"); os.print("\tend"); os.println("\t\t\t% close the dictionary now"); os.println("\t/"+getFontName()+" exch definefont pop"); os.flush(); } }