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>
045 *            the pixel type
046 */
047public class FontStyle<T> {
048        /**
049         * Attributes for styling {@link AttributedString}s.
050         *
051         * @author Jonathon Hare (jsh2@ecs.soton.ac.uk)
052         */
053        public static class FontStyleAttribute extends Attribute {
054                private static final long serialVersionUID = 1L;
055
056                /**
057                 * Default constructor
058                 * 
059                 * @param name
060                 *            the name of the attribute
061                 */
062                public FontStyleAttribute(final String name) {
063                        super(name);
064                }
065        }
066
067        /**
068         * Horizontal alignment options
069         *
070         * @author Jonathon Hare (jsh2@ecs.soton.ac.uk)
071         *
072         */
073        public static enum HorizontalAlignment {
074                /**
075                 * Centered text from the starting point
076                 */
077                HORIZONTAL_CENTER,
078                /**
079                 * Left-aligned text from the starting point
080                 */
081                HORIZONTAL_LEFT,
082                /**
083                 * Right-aligned text from the starting point
084                 */
085                HORIZONTAL_RIGHT,
086        }
087
088        /**
089         * Vertical alignment options
090         *
091         * @author Jonathon Hare (jsh2@ecs.soton.ac.uk)
092         *
093         */
094        public static enum VerticalAlignment {
095                /**
096                 *
097                 */
098                VERTICAL_TOP,
099                /**
100                 *
101                 */
102                VERTICAL_HALF,
103                /**
104                 *
105                 */
106                VERTICAL_CAP,
107                /**
108                 * Bottom of characters aligned
109                 */
110                VERTICAL_BOTTOM,
111        }
112
113        /**
114         * Attribute for the font. Value should be a {@link Font}.
115         */
116        public static final Attribute FONT = new FontStyleAttribute("font");
117
118        /**
119         * Attribute for italic text. Value should be Boolean.
120         */
121        public static final Attribute ITALIC = new FontStyleAttribute("italic");
122
123        /**
124         * Attribute for rotating the text. Value should be a Number in radians.
125         */
126        public static final Attribute ANGLE = new FontStyleAttribute("angle");
127
128        /**
129         * Attribute for stroke colour.
130         */
131        public static final Attribute COLOUR = new FontStyleAttribute("colour");
132
133        /**
134         * Attribute for horizontal alignment. Must be an instance of
135         * {@link HorizontalAlignment}
136         */
137        public static final Attribute HORIZONTAL_ALIGNMENT = new FontStyleAttribute("horizontalAlignment");
138
139        /**
140         * Attribute for vertical alignment. Must be an instance of
141         * {@link VerticalAlignment}
142         */
143        public static final Attribute VERTICAL_ALIGNMENT = new FontStyleAttribute("verticalAlignment");
144
145        /**
146         * Attribute for font size. Must be a Number in pixels.
147         */
148        public static final Attribute FONT_SIZE = new FontStyleAttribute("fontSize");
149
150        private static final Font<?> DEFAULT_FONT = HersheyFont.ROMAN_SIMPLEX;
151
152        /**
153         * The font
154         */
155        protected Font<?> font;
156
157        /**
158         * should the associated text be rendered in italic?
159         */
160        protected boolean italic;
161
162        /**
163         * Angle in radians for drawing the associated text
164         */
165        protected float angle;
166
167        /**
168         * Stroke colour for drawing the associated text
169         */
170        protected T colour;
171
172        /**
173         * horizontal alignment of the text
174         */
175        protected HorizontalAlignment horizontalAlignment = HorizontalAlignment.HORIZONTAL_LEFT;
176
177        /**
178         * vertical alignment of the text
179         */
180        protected VerticalAlignment verticalAlignment = VerticalAlignment.VERTICAL_BOTTOM;
181
182        /**
183         * Font size in pixels
184         */
185        protected int fontSize = 24;
186
187        protected FontStyle(final Font<?> font, final ImageRenderer<T, ?> renderer) {
188                this.colour = renderer.defaultForegroundColour();
189                this.font = font;
190        }
191
192        /**
193         * @param font
194         * @param col
195         */
196        public FontStyle(final Font<?> font, final T col) {
197                this.colour = col;
198                this.font = font;
199        }
200
201        /**
202         * Parse the attributes map and set this FontStyle accordingly. Subclasses
203         * should override this method to add extra attributes.
204         *
205         * @param attrs
206         *            the attribute map
207         */
208        @SuppressWarnings("unchecked")
209        public void parseAttributes(final Map<? extends Attribute, Object> attrs) {
210                if (attrs.containsKey(FontStyle.FONT))
211                        this.font = (Font<?>) attrs.get(FontStyle.FONT);
212                if (attrs.containsKey(FontStyle.ITALIC))
213                        this.italic = (Boolean) attrs.get(FontStyle.ITALIC);
214                if (attrs.containsKey(FontStyle.ANGLE))
215                        this.angle = ((Number) attrs.get(FontStyle.ANGLE)).floatValue();
216                if (attrs.containsKey(FontStyle.COLOUR))
217                        this.colour = (T) attrs.get(FontStyle.COLOUR);
218                if (attrs.containsKey(FontStyle.HORIZONTAL_ALIGNMENT))
219                        this.horizontalAlignment = (HorizontalAlignment) attrs.get(FontStyle.HORIZONTAL_ALIGNMENT);
220                if (attrs.containsKey(FontStyle.VERTICAL_ALIGNMENT))
221                        this.verticalAlignment = (VerticalAlignment) attrs.get(FontStyle.VERTICAL_ALIGNMENT);
222                if (attrs.containsKey(FontStyle.FONT_SIZE))
223                        this.fontSize = ((Number) attrs.get(FontStyle.FONT_SIZE)).intValue();
224        }
225
226        /**
227         * Get the renderer suitable for rendering text with this style into the
228         * given image.
229         * 
230         * @param renderer
231         *            the image renderer
232         * @return the renderer
233         */
234        public FontRenderer<T, FontStyle<T>> getRenderer(final ImageRenderer<T, ?> renderer) {
235                return this.font.getRenderer(renderer);
236        }
237
238        /**
239         * Construct a new FontStyle from the given attribute map, suitable for
240         * rendering into the given image.
241         * 
242         * @param <T>
243         *            the pixel type.
244         * @param attrs
245         *            the attribute map
246         * @param renderer
247         *            the image renderer
248         * @return the FontStyle
249         */
250        public static <T> FontStyle<T> parseAttributes(final Map<? extends Attribute, Object> attrs,
251                        final ImageRenderer<T, ?> renderer)
252        {
253                Font<?> fnt = (Font<?>) attrs.get(FontStyle.FONT);
254
255                if (fnt == null)
256                        fnt = FontStyle.DEFAULT_FONT;
257
258                final FontStyle<T> sty = fnt.createStyle(renderer);
259                sty.parseAttributes(attrs);
260                return sty;
261        }
262
263        /**
264         * @return the font
265         */
266        public Font<?> getFont() {
267                return this.font;
268        }
269
270        /**
271         * @param font
272         *            the font to set
273         */
274        public void setFont(final Font<?> font) {
275                this.font = font;
276        }
277
278        /**
279         * @return the italic
280         */
281        public boolean isItalic() {
282                return this.italic;
283        }
284
285        /**
286         * @param italic
287         *            the italic to set
288         */
289        public void setItalic(final boolean italic) {
290                this.italic = italic;
291        }
292
293        /**
294         * @return the angle
295         */
296        public float getAngle() {
297                return this.angle;
298        }
299
300        /**
301         * @param angle
302         *            the angle to set
303         */
304        public void setAngle(final float angle) {
305                this.angle = angle;
306        }
307
308        /**
309         * @return the colour
310         */
311        public T getColour() {
312                return this.colour;
313        }
314
315        /**
316         * @param colour
317         *            the colour to set
318         */
319        public void setColour(final T colour) {
320                this.colour = colour;
321        }
322
323        /**
324         * @return the horizontalAlignment
325         */
326        public HorizontalAlignment getHorizontalAlignment() {
327                return this.horizontalAlignment;
328        }
329
330        /**
331         * @param horizontalAlignment
332         *            the horizontalAlignment to set
333         */
334        public void setHorizontalAlignment(final HorizontalAlignment horizontalAlignment) {
335                this.horizontalAlignment = horizontalAlignment;
336        }
337
338        /**
339         * @return the verticalAlignment
340         */
341        public VerticalAlignment getVerticalAlignment() {
342                return this.verticalAlignment;
343        }
344
345        /**
346         * @param verticalAlignment
347         *            the verticalAlignment to set
348         */
349        public void setVerticalAlignment(final VerticalAlignment verticalAlignment) {
350                this.verticalAlignment = verticalAlignment;
351        }
352
353        /**
354         * @return the fontSize
355         */
356        public int getFontSize() {
357                return this.fontSize;
358        }
359
360        /**
361         * @param fontSize
362         *            the fontSize to set
363         */
364        public void setFontSize(final int fontSize) {
365                this.fontSize = fontSize;
366        }
367}