KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > info > magnolia > cms > taglibs > util > TextToImageTag


1 /**
2  *
3  * Magnolia and its source-code is licensed under the LGPL.
4  * You may copy, adapt, and redistribute this file for commercial or non-commercial use.
5  * When copying, adapting, or redistributing this document in keeping with the guidelines above,
6  * you are required to provide proper attribution to obinary.
7  * If you reproduce or distribute the document without making any substantive modifications to its content,
8  * please use the following attribution line:
9  *
10  * Copyright 1993-2006 obinary Ltd. (http://www.obinary.com) All rights reserved.
11  *
12  */

13 package info.magnolia.cms.taglibs.util;
14
15 import info.magnolia.cms.core.Content;
16 import info.magnolia.cms.core.ItemType;
17
18 import java.awt.FontFormatException JavaDoc;
19 import java.awt.Graphics2D JavaDoc;
20 import java.awt.Image JavaDoc;
21 import java.awt.image.BufferedImage JavaDoc;
22 import java.io.File JavaDoc;
23 import java.io.FileNotFoundException JavaDoc;
24 import java.io.IOException JavaDoc;
25 import java.util.StringTokenizer JavaDoc;
26
27 import javax.imageio.ImageIO JavaDoc;
28 import javax.jcr.AccessDeniedException;
29 import javax.jcr.PathNotFoundException;
30 import javax.jcr.RepositoryException;
31 import javax.servlet.http.HttpServletRequest JavaDoc;
32 import javax.servlet.jsp.JspException JavaDoc;
33 import javax.servlet.jsp.JspWriter JavaDoc;
34 import javax.servlet.jsp.PageContext JavaDoc;
35
36 import org.apache.commons.lang.SystemUtils;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
39
40
41 /**
42  * Tag that converts text into PNG iamges, and outputs a div element containing a set of img elements. The font face,
43  * text color, text size and background color can be set via the tag attributes. <br />
44  * <br />
45  * The images are saved under the node specified by the attribute parentContentNodeName. Under this parent node, a new
46  * node is created, with the name specified by the attribute imageContentNodeName. Under this node, each image will have
47  * it own node. The names of the image node are based on the text that they contain. (Special characters such as &, /,
48  * chinese characters, etc. are replaces by codes to ensure that these names are legal.) <br />
49  * <br />
50  * If the images for the specified text do not exist in the repository under the specified parent node, then the this
51  * tag will create the images and save them. If the images for the text already exist, then they will not be recreated.
52  * <br />
53  * <br />
54  * The text to be converted into images can be split in three ways. If the attribute textSplit is null or is set to
55  * TEXT_SPLIT_NONE, then a single image will be created of the text on one line. If textSplit is set to
56  * TEXT_SPLIT_WORDS, then the text is plit into words (i.e. wherever there is a space). Finally, if textSplit is set to
57  * TEXT_SPLIT_CHARACTERS, then a seperate image is created for each letter. <br />
58  * <br />
59  * The tag outputs a div that contains one or more img's. The CSS class applied to the div is specified by the divCSS
60  * attribute. The CSS applied to the images depends on how the text was split. For text that was not split, the CSS
61  * applied is set to CSS_TEXT_IMAGE, for words it is CSS_WORD_IMAGE, and for characters it is CSS_CHARACTER_IMAGE. Any
62  * spacing that is required between images will need to be set in your css stylesheet. <br />
63  * <br />
64  * The textFontFace attribute may either be a font name of a font installed on the server, or it may be a path to a TTF
65  * file. The class to generate PNG images from TrueType font strings is originally by Philip McCarthy -
66  * http://chimpen.com (http://chimpen.com/things/archives/001139.php). I have made a couple of small changes. <br />
67  * <br />
68  * @author Patrick Janssen
69  * @author Fabrizio Giustina
70  * @version 1.0
71  */

72 public class TextToImageTag extends BaseImageTag {
73
74     /**
75      * The image that is created can first be created at a larger size, and then scaled down. This overcomes kerning
76      * problems on the Windows platform, which results in very irregular spacing between characters. If you are not
77      * using Windows, this can be set to 1.
78      */

79     private static final double SCALE_FACTOR = SystemUtils.IS_OS_WINDOWS ? 4 : 1;
80
81     /**
82      * The CSS class applied to images of individual characters.
83      */

84     private static final String JavaDoc CSS_CHARACTER_IMAGE = "character-image";
85
86     /**
87      * The CSS class appled to images of words.
88      */

89     private static final String JavaDoc CSS_WORD_IMAGE = "word-image";
90
91     /**
92      * The CSS class applied to images of whole sentances, or other text.
93      */

94     private static final String JavaDoc CSS_TEXT_IMAGE = "text-image";
95
96     /**
97      * The text will not be split
98      */

99     private static final String JavaDoc TEXT_SPLIT_NONE = "none";
100
101     /**
102      * The text will be split into words
103      */

104     private static final String JavaDoc TEXT_SPLIT_WORDS = "words";
105
106     /**
107      * The text will be split into characters
108      */

109     private static final String JavaDoc TEXT_SPLIT_CHARACTERS = "characters";
110
111     /**
112      * Logger.
113      */

114     private static Logger log = LoggerFactory.getLogger(BaseImageTag.class);
115
116     /**
117      * Attribute: Text to convert to an image
118      */

119     private String JavaDoc text;
120
121     /**
122      * Attribute: Text Font Face
123      */

124     private String JavaDoc textFontFace;
125
126     /**
127      * Attribute: Text Font Size
128      */

129     private int textFontSize;
130
131     /**
132      * Attribute: Text Font Color
133      */

134     private String JavaDoc textFontColor;
135
136     /**
137      * Attribute: Text Background Color
138      */

139     private String JavaDoc textBackColor;
140
141     /**
142      * Attribute: Method for splitting text: words, characters or none.
143      */

144     private String JavaDoc textSplit;
145
146     /**
147      * Attribute: The name of the CSS class to apply to the text box div. If this is null, the default will be
148      * 'text-box'.
149      */

150     private String JavaDoc divCSS;
151
152     /**
153      * Setter for the <code>text</code> tag attribute.
154      * @param text
155      */

156     public void setText(String JavaDoc text) {
157         this.text = text;
158     }
159
160     /**
161      * Setter for the <code>imageContentNodeName</code> tag attribute.
162      * @param imageContentNodeName
163      */

164     public void setImageContentNodeName(String JavaDoc imageContentNodeName) {
165         this.imageContentNodeName = imageContentNodeName;
166     }
167
168     /**
169      * Setter for the <code>parentContentNodeName</code> tag attribute.
170      * @param parentContentNodeName
171      */

172     public void setParentContentNodeName(String JavaDoc parentContentNodeName) {
173         this.parentContentNodeName = parentContentNodeName;
174     }
175
176     /**
177      * Setter for the <code>textFontFace</code> tag attribute.
178      * @param textFontFace
179      */

180     public void setTextFontFace(String JavaDoc textFontFace) {
181         this.textFontFace = textFontFace;
182     }
183
184     /**
185      * Setter for the <code>textFontSize</code> tag attribute.
186      * @param textFontSize
187      */

188     public void setTextFontSize(int textFontSize) {
189         this.textFontSize = textFontSize;
190     }
191
192     /**
193      * Setter for the <code>textFontColor</code> tag attribute.
194      * @param textFontColor
195      */

196     public void setTextFontColor(String JavaDoc textFontColor) {
197         this.textFontColor = textFontColor;
198     }
199
200     /**
201      * Setter for the <code>textBackColor</code> tag attribute.
202      * @param textBackColor
203      */

204     public void setTextBackColor(String JavaDoc textBackColor) {
205         this.textBackColor = textBackColor;
206     }
207
208     /**
209      * Setter for the <code>textSplit</code> tag attribute.
210      * @param textBackColor
211      */

212     public void setTextSplit(String JavaDoc textSplit) {
213         this.textSplit = textSplit;
214     }
215
216     /**
217      * Setter for the <code>divCSS</code> tag attribute.
218      * @param divCSS
219      */

220     public void setDivCSS(String JavaDoc divCSS) {
221         this.divCSS = divCSS;
222     }
223
224     /**
225      * @see info.magnolia.cms.taglibs.util.BaseImageTag#getFilename()
226      */

227     protected String JavaDoc getFilename() {
228         return "textImage";
229     }
230
231     /**
232      * Initialize settings
233      */

234     public void setUp() {
235
236         // check that all the necessary attributes are set
237
if (this.text == null) {
238             this.text = "Test Test Test";
239         }
240         if (this.textFontFace == null) {
241             this.textFontFace = SystemUtils.IS_OS_WINDOWS ? "Arial" : "Helvetica";
242         }
243         if (this.textFontSize == 0) {
244             this.textFontSize = 12;
245         }
246         if (this.textFontColor == null) {
247             this.textFontColor = "000000";
248         }
249         if (this.textBackColor == null) {
250             this.textBackColor = "ffffff";
251         }
252         if (this.textSplit == null) {
253             this.textSplit = TEXT_SPLIT_NONE;
254         }
255         else if (!((this.textSplit.equals(TEXT_SPLIT_WORDS)) || (this.textSplit.equals(TEXT_SPLIT_CHARACTERS)))) {
256             this.textSplit = TEXT_SPLIT_NONE;
257         }
258         if (this.divCSS == null) {
259             this.divCSS = "text-box";
260         }
261     }
262
263     /**
264      * Do this tag
265      */

266     public void doTag() throws JspException JavaDoc {
267
268         this.setUp();
269
270         try {
271             Content imageContentNode = getImageContentNode();
272
273             String JavaDoc[] subStrings = this.getTextSubStrings(this.text);
274             String JavaDoc[] imageURIs = this.getImageURIs(
275                 subStrings,
276                 (HttpServletRequest JavaDoc) ((PageContext JavaDoc) this.getJspContext()).getRequest(),
277                 imageContentNode);
278             this.drawTextImages(imageURIs, subStrings);
279         }
280         catch (PathNotFoundException e) {
281             log.error("PathNotFoundException occured during text-to-image conversion: " + e.getMessage(), e);
282         }
283         catch (AccessDeniedException e) {
284             log.error("AccessDeniedException occured during text-to-image conversion: " + e.getMessage(), e);
285         }
286         catch (RepositoryException e) {
287             log.error("RepositoryException occured during text-to-image conversion: " + e.getMessage(), e);
288         }
289         catch (FileNotFoundException JavaDoc e) {
290             log.error("FileNotFoundException occured during text-to-image conversion: " + e.getMessage(), e);
291         }
292         catch (IOException JavaDoc e) {
293             log.error("IOException occured during text-to-image conversion: " + e.getMessage(), e);
294         }
295         catch (FontFormatException JavaDoc e) {
296             log.error("FontFormatException occured during text-to-image conversion: " + e.getMessage(), e);
297         }
298         this.cleanUp();
299     }
300
301     /**
302      * Set objects to null
303      */

304     public void cleanUp() {
305         this.parentContentNodeName = null;
306         this.imageContentNodeName = null;
307         this.text = null;
308         this.textFontFace = null;
309         this.textFontSize = 0;
310         this.textFontColor = null;
311         this.textBackColor = null;
312         this.textSplit = null;
313         this.divCSS = null;
314     }
315
316     /**
317      * Draws a div box that contains the text images.
318      * @param imageURLs an array of urls
319      * @param subStrings an array of strings
320      * @throws IOException jspwriter exception
321      */

322     private void drawTextImages(String JavaDoc[] imageURIs, String JavaDoc[] subStrings) throws IOException JavaDoc {
323         JspWriter JavaDoc out = this.getJspContext().getOut();
324
325         if (this.divCSS != null) {
326             out.print("<div class=\"");
327             out.print(this.divCSS);
328             out.print("\">");
329         }
330
331         for (int i = 0; i < imageURIs.length; i++) {
332             out.print("<img class=\"");
333             if (this.textSplit.equals(TEXT_SPLIT_CHARACTERS)) {
334                 out.print(CSS_CHARACTER_IMAGE);
335             }
336             else if (this.textSplit.equals(TEXT_SPLIT_WORDS)) {
337                 out.print(CSS_WORD_IMAGE);
338             }
339             else {
340                 out.print(CSS_TEXT_IMAGE);
341             }
342             out.print("\" SRC=\"");
343             out.print(imageURIs[i]);
344             out.print("\" alt=\"");
345             out.print(subStrings[i]);
346             out.print("\" />");
347         }
348
349         if (this.divCSS != null) {
350             out.print("</div>");
351         }
352     }
353
354     /**
355      * Splits a string into words or characters, depending on the textSplit attribute. For words, spaces at either end
356      * are removed.
357      * @param The string to split
358      * @return An array of words
359      */

360     private String JavaDoc[] getTextSubStrings(String JavaDoc text) {
361         String JavaDoc[] subStrings = null;
362         if (this.textSplit.equals(TEXT_SPLIT_CHARACTERS)) {
363             subStrings = new String JavaDoc[text.length()];
364             for (int i = 0; i < text.length(); i++) {
365                 subStrings[i] = text.substring(i, i + 1);
366             }
367         }
368         else if (this.textSplit.equals(TEXT_SPLIT_WORDS)) {
369             StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(text, " "); // Split sentence into words
370
subStrings = new String JavaDoc[st.countTokens()];
371             for (int i = 0; st.hasMoreTokens(); i++) {
372                 subStrings[i] = st.nextToken().trim();
373             }
374         }
375         else {
376             subStrings = new String JavaDoc[]{text};
377         }
378         return subStrings;
379     }
380
381     /**
382      * Get an array of image URIs, one URI for each text string.
383      * @param The array of text strings.
384      * @return An array of URIs pointing to the images.
385      */

386     private String JavaDoc[] getImageURIs(String JavaDoc[] subStrings, HttpServletRequest JavaDoc req, Content imageContentNode)
387         throws PathNotFoundException, AccessDeniedException, RepositoryException, FileNotFoundException JavaDoc, IOException JavaDoc,
388         FontFormatException JavaDoc {
389
390         String JavaDoc[] imageURIs = new String JavaDoc[subStrings.length];
391         for (int i = 0; i < subStrings.length; i++) {
392             // Create a unique image node name
393
String JavaDoc tmpImgNodeName = subStrings[i]
394                 + this.textBackColor
395                 + this.textFontColor
396                 + this.textFontFace
397                 + this.textFontSize;
398             String JavaDoc imageNodeName = this.convertToSimpleString(tmpImgNodeName);
399             // If the image node with this name does not exist, then create it.
400
if (!imageContentNode.hasContent(imageNodeName)) {
401                 File JavaDoc image = createImage(subStrings[i]);
402
403                 // Create the node that will contain the image
404
Content imageNode = imageContentNode.createContent(imageNodeName, ItemType.CONTENTNODE);
405
406                 this.createImageNode(image, imageNode);
407             }
408             // Save the URI for this image in the array
409
String JavaDoc contextPath = req.getContextPath();
410             String JavaDoc handle = imageContentNode.getHandle();
411             String JavaDoc imageURI = contextPath
412                 + handle
413                 + "/"
414                 + imageNodeName
415                 + "/"
416                 + getFilename()
417                 + "."
418                 + PROPERTIES_EXTENSION_VALUE;
419             imageURIs[i] = imageURI;
420         }
421         return imageURIs;
422     }
423
424     /**
425      * Creates an image from a word. The file is saved in the location specified by TEMP_IMAGE_PATH.
426      * @param subString The text.
427      * @return An input stream.
428      */

429     private File JavaDoc createImage(String JavaDoc subString) throws FileNotFoundException JavaDoc, IOException JavaDoc, FontFormatException JavaDoc {
430
431         // Create file
432
File JavaDoc imageFile = File.createTempFile(getClass().getName(), "png");
433         imageFile.createNewFile();
434
435         // create the image
436
// due to kerning problems, the image is being created 4 times to big
437
// then being scaled down to the right size
438
Text2PngFactory tpf = new Text2PngFactory();
439         tpf.setFontFace(this.textFontFace);
440         tpf.setFontSize((int) (this.textFontSize * SCALE_FACTOR));
441         int[] textRGB = this.convertHexToRGB(this.textFontColor);
442         int[] backRGB = this.convertHexToRGB(this.textBackColor);
443         tpf.setTextRGB(textRGB[0], textRGB[1], textRGB[2]);
444         tpf.setBackgroundRGB(backRGB[0], backRGB[1], backRGB[2]);
445         tpf.setText(subString);
446
447         BufferedImage JavaDoc bigImgBuff = (BufferedImage JavaDoc) tpf.createImage();
448         if (SCALE_FACTOR != 1) {
449             BufferedImage JavaDoc smallImgBuff = this.scaleImage(bigImgBuff, (1.0 / SCALE_FACTOR));
450             ImageIO.write(smallImgBuff, "png", imageFile);
451             smallImgBuff = null;
452         }
453         else {
454             ImageIO.write(bigImgBuff, "png", imageFile);
455         }
456         bigImgBuff = null;
457         return imageFile;
458     }
459
460     /**
461      * Create an image file that is a scaled version of the original image
462      * @param the original BufferedImage
463      * @param the scale factor
464      * @return the new BufferedImage
465      */

466     private BufferedImage JavaDoc scaleImage(BufferedImage JavaDoc oriImgBuff, double scaleFactor) {
467
468         // get the dimesnions of the original image
469
int oriWidth = oriImgBuff.getWidth();
470         int oriHeight = oriImgBuff.getHeight();
471         // get the width and height of the new image
472
int newWidth = new Double JavaDoc(oriWidth * scaleFactor).intValue();
473         int newHeight = new Double JavaDoc(oriHeight * scaleFactor).intValue();
474         // create the thumbnail as a buffered image
475
Image JavaDoc newImg = oriImgBuff.getScaledInstance(newWidth, newHeight, Image.SCALE_AREA_AVERAGING);
476         BufferedImage JavaDoc newImgBuff = new BufferedImage JavaDoc(
477             newImg.getWidth(null),
478             newImg.getHeight(null),
479             BufferedImage.TYPE_INT_RGB);
480         Graphics2D JavaDoc g = newImgBuff.createGraphics();
481         g.drawImage(newImg, 0, 0, null);
482         g.dispose();
483         // return the newImgBuff
484
return newImgBuff;
485     }
486
487 }
488
Popular Tags