View Javadoc

1   package org.freehep.graphicsio.ps;
2   
3   import java.awt.font.TextAttribute;
4   import java.util.Map;
5   
6   import org.freehep.graphics2d.GenericTagHandler;
7   import org.freehep.util.ScientificFormat;
8   import org.freehep.util.Value;
9   
10  /**
11   * Class to create a "cfont" tag in PS. Use {@link PSStringStyler#getStyledString(java.util.Map, String)}
12   * to operate.
13   *
14   * @author Charles Loomis
15   * @author Steffen Greiffenberg
16   * @version $Id: PSStringStyler.java 8584 2006-08-10 23:06:37Z duns $
17   */
18  public class PSStringStyler {
19  
20      /**
21       * The value 5 / 6 was found by try and error, e.g.
22       * a font size of 300 has a valid cfont size of 250.
23       * Not clear why.
24       */
25      private static final float FONTSIZE_CORRECTION = 5.0f / 6.0f;
26  
27      // Constant strings for the styles.
28      // private final String UNSTYLED_FLAG = "\\340\\000";
29  
30      private static final String BOLD_CHAR = "\\340\\001";
31  
32      private static final String ITALIC_CHAR = "\\340\\002";
33  
34      private static final String BOLD_ITALIC_CHAR = "\\340\\003";
35  
36      // Constant strings for the ornaments (underlining, etc.)
37      // superscript is done by transformation
38      // private final String SUPERSUBSCRIPT_FLAG = "\\360\\000";
39  
40      private static final String STRIKEOUT_FLAG = "\\360\\001";
41  
42      private static final String UNDERLINE_FLAG = "\\360\\002";
43  
44      private static final String DASHED_UNDERLINE_FLAG = "\\360\\003";
45  
46      private static final String DOTTED_UNDERLINE_FLAG = "\\360\\004";
47  
48      private static final String GRAY_UNDERLINE_FLAG = "\\360\\005";
49  
50      private static final String THICK_UNDERLINE_FLAG = "\\360\\006";
51  
52      private static final String OVERLINE_FLAG = "\\360\\007";
53  
54      // Constant strings giving the begin-group and end-group markers.
55      private static final String BEGIN_GROUP = "\\360\\376";
56  
57      private static final String END_GROUP = "\\360\\377";
58  
59      /**
60       * Must override the parse method because the PostScript string must be
61       * initialized and terminated.
62       */
63      public static String getStyledString(Map /*<TextAttribute,?>*/ attributes, String string) {
64          StringBuffer result = new StringBuffer();
65  
66          Float size = (Float) attributes.get(TextAttribute.SIZE);
67  
68          // FIXME: The lines are taken from PSTagHandler, but
69          // they produced a to large text output.
70          result.append(new ScientificFormat(6, 9, false).format(size.floatValue() * FONTSIZE_CORRECTION));
71          result.append(" ");
72  
73          // cfont tag
74          result.append("cfont");
75  
76          // replace font name
77          String fontName = ((String)attributes.get(TextAttribute.FAMILY)).toLowerCase();
78          if (fontName.indexOf("helvetica") != -1) {
79              result.append("H");
80          } else if (fontName.indexOf("dialog") != -1) {
81              result.append("H");
82          } else if (fontName.indexOf("dialoginput") != -1) {
83              result.append("H");
84          } else if (fontName.indexOf("sansserif") != -1) {
85              result.append("H");
86          } else if (fontName.indexOf("times") != -1) {
87              result.append("T");
88          } else if (fontName.indexOf("serif") != -1) {
89              result.append("T");
90          } else if (fontName.indexOf("courier") != -1) {
91              result.append("C");
92          } else if (fontName.indexOf("monospaced") != -1) {
93              result.append("C");
94          } else if (fontName.indexOf("typewriter") != -1) {
95              result.append("C");
96          } else {
97              result.append("H");
98          }
99  
100         // weight
101         Object weight = attributes.get(TextAttribute.WEIGHT);
102         if (TextAttribute.WEIGHT_BOLD.equals(weight)) {
103             result.append("B");
104         }
105 
106         // posture
107         Object posture = attributes.get(TextAttribute.POSTURE);
108         if (TextAttribute.POSTURE_OBLIQUE.equals(posture)) {
109             result.append("I");
110         }
111 
112         // open the brackets for text string
113         result.append("\n(");
114 
115         // count BEGIN_GROUP for writing END_GROUP
116         Value openGroups = new Value();
117         openGroups.set(0);
118 
119         result.append(getOpenTag(attributes, openGroups));
120         result.append(getUnicodes(string));
121         result.append(getCloseTag(openGroups));
122 
123         result.append(")");
124 
125         return result.toString();
126     }
127 
128     /**
129      * Converts str into unicodes
130      *
131      * @return list of unicodes for str
132      */
133     public static String getUnicodes(String str) {
134 
135         // Copy string to temporary string buffer.
136         StringBuffer codedString = new StringBuffer();
137 
138         for (int i = 0; i < str.length(); i++) {
139             int chr = (int) str.charAt(i);
140             int cvalue = (chr & 0x000000ff);
141             int fvalue = (chr & 0x0000ff00) >>> 8;
142             String cbyte = Integer.toOctalString(cvalue);
143             String fbyte = Integer.toOctalString(fvalue);
144 
145             // Put in the font byte first.
146             codedString.append('\\');
147             for (int j = 0; j < (3 - fbyte.length()); j++) {
148                 codedString.append('0');
149             }
150             codedString.append(fbyte);
151 
152             // Now the character itself. Write as octal codes
153             // non-printable characters, the backslash, parentheses,
154             // and the percent.
155             if (cvalue < 32 || cvalue > 126 || cvalue == '\\' || cvalue == '%'
156                     || cvalue == '(' || cvalue == ')') {
157                 codedString.append('\\');
158                 for (int j = 0; j < (3 - cbyte.length()); j++) {
159                     codedString.append('0');
160                 }
161                 codedString.append(cbyte);
162             } else {
163                 codedString.append((char) cvalue);
164             }
165         }
166 
167         return codedString.toString();
168     }
169 
170     /**
171      * @param str string to convert
172      * @return str with replaced (, ), \, %
173      */
174     public static String getEscaped(String str) {
175 
176         // Then protect against unbalanced parentheses in the string.
177         // Copy string to temporary string buffer.
178         StringBuffer result = new StringBuffer();
179 
180         result.append("(");
181 
182         // Loop over all characters in the string and escape the
183         // parentheses.
184         for (int i = 0; i < str.length(); i++) {
185             char c = str.charAt(i);
186             if (c == '(' || c == ')' || c == '\\' || c == '%') {
187                 result.append('\\');
188                 result.append(c);
189             } else if (c == 0) {
190                 result.append('?');
191             } else {
192                 result.append(c);
193             }
194         }
195 
196         result.append(")");
197 
198         return result.toString();
199     }
200 
201     /**
202      * handles various instances of {@link TextAttribute}
203      *
204      * @param attributes font to translate in PS tags
205      */
206     private static String getOpenTag(Map/* Map<TextAttribute,?>*/ attributes, Value open) {
207 
208         int openGroups = open.getInt();
209 
210         StringBuffer result = new StringBuffer();
211 
212         // weight
213         Object weight = attributes.get(TextAttribute.WEIGHT);
214 
215         // italic
216         Object posture = attributes.get(TextAttribute.POSTURE);
217 
218         // bold and italic?
219         if (weight != null && !TextAttribute.WEIGHT_REGULAR.equals(weight)) {
220             if (TextAttribute.POSTURE_OBLIQUE.equals(posture)) {
221                 result.append(BOLD_ITALIC_CHAR);
222             } else {
223                 result.append(BOLD_CHAR);
224             }
225             openGroups ++;
226             result.append(BEGIN_GROUP);
227 
228         } else
229 
230         // simple italic?
231         if (TextAttribute.POSTURE_OBLIQUE.equals(posture)) {
232             result.append(ITALIC_CHAR);
233             openGroups ++;
234             result.append(BEGIN_GROUP);
235         }
236 
237         // superScript is done by font.getTransform()
238         // Object superScript = attributes.get(TextAttribute.SUPERSCRIPT);
239 
240         // underline
241         Object underline = attributes.get(TextAttribute.UNDERLINE);
242         if (TextAttribute.UNDERLINE_LOW_DASHED.equals(underline)) {
243             result.append(DASHED_UNDERLINE_FLAG);
244             openGroups ++;
245             result.append(BEGIN_GROUP);
246         } else if (TextAttribute.UNDERLINE_ON.equals(underline)) {
247             result.append(UNDERLINE_FLAG);
248             openGroups ++;
249             result.append(BEGIN_GROUP);
250         } else if (TextAttribute.UNDERLINE_LOW_DOTTED.equals(underline)) {
251             result.append(DOTTED_UNDERLINE_FLAG);
252             openGroups ++;
253             result.append(BEGIN_GROUP);
254         } else if (TextAttribute.UNDERLINE_LOW_TWO_PIXEL.equals(underline)) {
255             result.append(THICK_UNDERLINE_FLAG);
256             openGroups ++;
257             result.append(BEGIN_GROUP);
258         } else if (TextAttribute.UNDERLINE_LOW_GRAY.equals(underline)) {
259             result.append(GRAY_UNDERLINE_FLAG);
260             openGroups ++;
261             result.append(BEGIN_GROUP);
262         } else if (TextAttribute.UNDERLINE_LOW_DASHED.equals(underline)) {
263             result.append(DASHED_UNDERLINE_FLAG);
264             openGroups ++;
265             result.append(BEGIN_GROUP);
266         } else if (GenericTagHandler.UNDERLINE_OVERLINE.equals(underline)) {
267             result.append(OVERLINE_FLAG);
268             result.append(BEGIN_GROUP);
269         }
270 
271         // strike through
272         Object strike = attributes.get(TextAttribute.STRIKETHROUGH);
273         if (TextAttribute.STRIKETHROUGH_ON.equals(strike)) {
274             result.append(STRIKEOUT_FLAG);
275             openGroups ++;
276             result.append(BEGIN_GROUP);
277         }
278 
279         // set the counter
280         open.set(openGroups);
281 
282         return result.toString();
283     }
284 
285     /**
286      * @return string for closing all BEGIN_GROUP's
287      */
288     private static String getCloseTag(Value open) {
289         StringBuffer result = new StringBuffer();
290 
291         for (int i = 0; i < open.getInt(); i++) {
292             result.append(END_GROUP);
293         }
294 
295         // not needed but to leave the counter in correct state
296         open.set(0);
297 
298         return result.toString();
299     }
300 }