001/**
002 * Copyright (c) 2011, The University of Southampton and the individual contributors.
003 * All rights reserved.
004 *
005 * Redistribution and use in source and binary forms, with or without modification,
006 * are permitted provided that the following conditions are met:
007 *
008 *   *  Redistributions of source code must retain the above copyright notice,
009 *      this list of conditions and the following disclaimer.
010 *
011 *   *  Redistributions in binary form must reproduce the above copyright notice,
012 *      this list of conditions and the following disclaimer in the documentation
013 *      and/or other materials provided with the distribution.
014 *
015 *   *  Neither the name of the University of Southampton nor the names of its
016 *      contributors may be used to endorse or promote products derived from this
017 *      software without specific prior written permission.
018 *
019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
020 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
022 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
023 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
026 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
028 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029 */
030package org.openimaj.image.typography;
031
032import java.text.AttributedCharacterIterator.Attribute;
033import java.text.AttributedString;
034import java.util.Map;
035
036import org.openimaj.image.renderer.ImageRenderer;
037import org.openimaj.image.typography.hershey.HersheyFont;
038
039/**
040 * Base class for the representation of font styles.
041 * 
042 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk)
043 *
044 * @param <T> the pixel type
045 */
046public class FontStyle<T> {
047        /**
048         * Attributes for styling {@link AttributedString}s.
049         * 
050         * @author Jonathon Hare (jsh2@ecs.soton.ac.uk)
051         */
052        public static class FontStyleAttribute extends Attribute {
053                private static final long serialVersionUID = 1L;
054
055                /**
056                 * Default constructor
057                 * @param name the name of the attribute
058                 */
059                public FontStyleAttribute(final String name) {
060                        super(name);
061                }
062        }
063
064        /**
065         * Horizontal alignment options
066         * 
067         * @author Jonathon Hare (jsh2@ecs.soton.ac.uk)
068         *
069         */
070        public static enum HorizontalAlignment {
071                /**
072                 * Centered text from the starting point
073                 */
074                HORIZONTAL_CENTER,
075                /**
076                 * Left-aligned text from the starting point
077                 */
078                HORIZONTAL_LEFT,
079                /**
080                 * Right-aligned text from the starting point
081                 */
082                HORIZONTAL_RIGHT,
083        }
084
085        /**
086         * Vertical alignment options
087         * 
088         * @author Jonathon Hare (jsh2@ecs.soton.ac.uk)
089         *
090         */
091        public static enum VerticalAlignment {
092                /**
093                 * 
094                 */
095                VERTICAL_TOP,
096                /**
097                 * 
098                 */
099                VERTICAL_HALF,
100                /**
101                 * 
102                 */
103                VERTICAL_CAP,
104                /**
105                 * Bottom of characters aligned
106                 */
107                VERTICAL_BOTTOM,
108        }
109
110        /**
111         * Attribute for the font. Value should be a {@link Font}.
112         */
113        public static final Attribute FONT = new FontStyleAttribute("font");
114
115        /**
116         * Attribute for italic text. Value should be Boolean.
117         */
118        public static final Attribute ITALIC = new FontStyleAttribute("italic");
119
120        /**
121         * Attribute for rotating the text. Value should be a Number in radians.
122         */
123        public static final Attribute ANGLE = new FontStyleAttribute("angle");
124
125        /**
126         * Attribute for stroke colour. Value should be of type <T>.
127         */
128        public static final Attribute COLOUR = new FontStyleAttribute("colour");
129
130        /**
131         * Attribute for horizontal alignment. Must be an instance of {@link HorizontalAlignment}
132         */
133        public static final Attribute HORIZONTAL_ALIGNMENT = new FontStyleAttribute("horizontalAlignment");
134
135        /**
136         * Attribute for vertical alignment. Must be an instance of {@link VerticalAlignment}
137         */
138        public static final Attribute VERTICAL_ALIGNMENT = new FontStyleAttribute("verticalAlignment");
139
140        /**
141         * Attribute for font size. Must be a Number in pixels.
142         */
143        public static final Attribute FONT_SIZE = new FontStyleAttribute("fontSize");
144
145        private static final Font<?> DEFAULT_FONT = HersheyFont.ROMAN_SIMPLEX;
146
147        /**
148         * The font
149         */
150        protected Font<?> font;
151
152        /**
153         * should the associated text be rendered in italic?
154         */
155        protected boolean italic;
156
157        /**
158         * Angle in radians for drawing the associated text
159         */
160        protected float angle;
161
162        /**
163         * Stroke colour for drawing the associated text
164         */
165        protected T colour;
166
167        /**
168         * horizontal alignment of the text
169         */
170        protected HorizontalAlignment horizontalAlignment = HorizontalAlignment.HORIZONTAL_LEFT;
171
172        /**
173         * vertical alignment of the text
174         */
175        protected VerticalAlignment verticalAlignment = VerticalAlignment.VERTICAL_BOTTOM;
176
177        /**
178         * Font size in pixels
179         */
180        protected int fontSize = 24;
181
182        protected FontStyle(final Font<?> font, final ImageRenderer<T, ?> renderer) {
183                this.colour = renderer.defaultForegroundColour();
184                this.font = font;
185        }
186        
187        /**
188         * @param font
189         * @param col
190         */
191        public FontStyle(final Font<?> font, final T col) {
192                this.colour= col;
193                this.font = font;
194        }
195
196        /**
197         * Parse the attributes map and set this FontStyle accordingly.
198         * Subclasses should override this method to add extra attributes.
199         * 
200         * @param attrs the attribute map
201         */
202        @SuppressWarnings("unchecked")
203        public void parseAttributes(final Map<? extends Attribute,Object> attrs) {
204                if (attrs.containsKey(FontStyle.FONT)) this.font = (Font<?>) attrs.get(FontStyle.FONT);
205                if (attrs.containsKey(FontStyle.ITALIC)) this.italic = (Boolean) attrs.get(FontStyle.ITALIC);
206                if (attrs.containsKey(FontStyle.ANGLE)) this.angle = ((Number) attrs.get(FontStyle.ANGLE)).floatValue();
207                if (attrs.containsKey(FontStyle.COLOUR)) this.colour = (T) attrs.get(FontStyle.COLOUR);
208                if (attrs.containsKey(FontStyle.HORIZONTAL_ALIGNMENT)) this.horizontalAlignment = (HorizontalAlignment) attrs.get(FontStyle.HORIZONTAL_ALIGNMENT);
209                if (attrs.containsKey(FontStyle.VERTICAL_ALIGNMENT)) this.verticalAlignment = (VerticalAlignment) attrs.get(FontStyle.VERTICAL_ALIGNMENT);
210                if (attrs.containsKey(FontStyle.FONT_SIZE)) this.fontSize = ((Number) attrs.get(FontStyle.FONT_SIZE)).intValue();
211        }
212
213        /**
214         * Get the renderer suitable for rendering text with this style
215         * into the given image.
216         * @param renderer the image renderer
217         * @return the renderer
218         */
219        public FontRenderer<T, FontStyle<T>> getRenderer(final ImageRenderer<T, ?> renderer) {
220                return this.font.getRenderer(renderer);
221        }
222
223        /**
224         * Construct a new FontStyle from the given attribute map, suitable for
225         * rendering into the given image.
226         * @param <T> the pixel type.
227         * @param attrs the attribute map
228         * @param renderer the image renderer
229         * @return the FontStyle
230         */
231        public static <T> FontStyle<T> parseAttributes(final Map<? extends Attribute,Object> attrs, final ImageRenderer<T,?> renderer) {
232                Font<?> fnt = (Font<?>) attrs.get(FontStyle.FONT);
233
234                if (fnt == null)
235                        fnt = FontStyle.DEFAULT_FONT;
236
237                final FontStyle<T> sty = fnt.createStyle(renderer);
238                sty.parseAttributes(attrs);
239                return sty;
240        }
241
242        /**
243         * @return the font
244         */
245        public Font<?> getFont() {
246                return this.font;
247        }
248
249        /**
250         * @param font the font to set
251         */
252        public void setFont(final Font<?> font) {
253                this.font = font;
254        }
255
256        /**
257         * @return the italic
258         */
259        public boolean isItalic() {
260                return this.italic;
261        }
262
263        /**
264         * @param italic the italic to set
265         */
266        public void setItalic(final boolean italic) {
267                this.italic = italic;
268        }
269
270        /**
271         * @return the angle
272         */
273        public float getAngle() {
274                return this.angle;
275        }
276
277        /**
278         * @param angle the angle to set
279         */
280        public void setAngle(final float angle) {
281                this.angle = angle;
282        }
283
284        /**
285         * @return the colour
286         */
287        public T getColour() {
288                return this.colour;
289        }
290
291        /**
292         * @param colour the colour to set
293         */
294        public void setColour(final T colour) {
295                this.colour = colour;
296        }
297
298        /**
299         * @return the horizontalAlignment
300         */
301        public HorizontalAlignment getHorizontalAlignment() {
302                return this.horizontalAlignment;
303        }
304
305        /**
306         * @param horizontalAlignment the horizontalAlignment to set
307         */
308        public void setHorizontalAlignment(final HorizontalAlignment horizontalAlignment) {
309                this.horizontalAlignment = horizontalAlignment;
310        }
311
312        /**
313         * @return the verticalAlignment
314         */
315        public VerticalAlignment getVerticalAlignment() {
316                return this.verticalAlignment;
317        }
318
319        /**
320         * @param verticalAlignment the verticalAlignment to set
321         */
322        public void setVerticalAlignment(final VerticalAlignment verticalAlignment) {
323                this.verticalAlignment = verticalAlignment;
324        }
325
326        /**
327         * @return the fontSize
328         */
329        public int getFontSize() {
330                return this.fontSize;
331        }
332
333        /**
334         * @param fontSize the fontSize to set
335         */
336        public void setFontSize(final int fontSize) {
337                this.fontSize = fontSize;
338        }
339}