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; 033import java.text.AttributedString; 034 035import org.openimaj.image.renderer.ImageRenderer; 036import org.openimaj.image.typography.FontStyle.HorizontalAlignment; 037import org.openimaj.image.typography.FontStyle.VerticalAlignment; 038import org.openimaj.math.geometry.shape.Rectangle; 039 040/** 041 * The FontRenderer represents an object capable of rendering text with 042 * a given font and style to an image. 043 * 044 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk) 045 * 046 * @param <T> type of image pixels 047 * @param <Q> type of {@link FontStyle} 048 */ 049public abstract class FontRenderer<T, Q extends FontStyle<T>> { 050 /** 051 * Render the given text string to the image starting at (x, y) with the 052 * given style. 053 * 054 * @param renderer the renderer 055 * @param text the text 056 * @param x the x-ordinate 057 * @param y the y-ordinate 058 * @param style the style 059 */ 060 public abstract void renderText(ImageRenderer<T,?> renderer, String text, int x, int y, Q style); 061 062 /** 063 * Calculate the bounding box of the rendered text with the given style. 064 * @param string the text 065 * @param style the style 066 * @return the bounding box 067 */ 068 public abstract Rectangle getSize(String string, Q style); 069 070 /** 071 * Calculate the bounding box of the rendered text with the given style. 072 * @param string the text 073 * @param x the x to render the font 074 * @param y the y to render the font 075 * @param sty the style 076 * @return the bounding box 077 */ 078 public Rectangle getBounds(String string, int x, int y, Q sty){ 079 Rectangle rect = this.getSize(string, sty); 080 // if we have a non-standard horizontal alignment 081 if ((sty.getHorizontalAlignment() != HorizontalAlignment.HORIZONTAL_LEFT)) { 082 // find the length of the string in pixels ... 083 float len = (float) rect.getWidth(); 084 // if we are center aligned 085 if (sty.getHorizontalAlignment() == HorizontalAlignment.HORIZONTAL_CENTER) { 086 x -= len/2; 087 } else { 088 x -= len; 089 } 090 091 } 092 093 if(sty.getVerticalAlignment() != VerticalAlignment.VERTICAL_TOP){ 094 switch (sty.getVerticalAlignment()) { 095 case VERTICAL_BOTTOM: 096 y -= rect.getHeight(); 097 break; 098 case VERTICAL_HALF: 099 y -= rect.getHeight()/2f; 100 break; 101 default: 102 break; 103 } 104 } 105 106 rect.x = x; 107 rect.y = y; 108 return rect; 109 } 110 111 112 /** 113 * Render the given {@link AttributedString} to the image starting at (x,y). 114 * @param <T> the pixel type of the image 115 * @param renderer the image renderer 116 * @param text the text 117 * @param x the x-ordinate 118 * @param y the y-ordinate 119 */ 120 @SuppressWarnings({ "unchecked", "rawtypes" }) 121 public static <T> void renderText(ImageRenderer<T,?> renderer, AttributedString text, int x, int y) { 122 AttributedCharacterIterator iterator = text.getIterator(); 123 124 while (true) { 125 Character c = iterator.current(); 126 if (c == AttributedCharacterIterator.DONE) break; 127 128 FontStyle sty = FontStyle.parseAttributes(iterator.getAttributes(), renderer); 129 FontRenderer fontRenderer = sty.getRenderer(renderer); 130 131 Rectangle rect = fontRenderer.getSize(c.toString(), sty); 132 fontRenderer.renderText(renderer, c.toString(), x, y, sty); 133 x += rect.width; 134 y += rect.height; 135 136 iterator.next(); 137 } 138 } 139 140 /** 141 * Calculate the bounding box of the given {@link AttributedString}. The image 142 * will not be modified by this call, but is used to properly configure the styles 143 * for bounds estimation. 144 * 145 * @param <T> the pixel type 146 * @param text the text 147 * @param imageRenderer the target image renderer 148 * @return the bounding box 149 */ 150 @SuppressWarnings({ "rawtypes", "unchecked" }) 151 public static <T> Rectangle getBounds(AttributedString text, ImageRenderer<T,?> imageRenderer) { 152 AttributedCharacterIterator iterator = text.getIterator(); 153 int x=0, y=0; 154 155 while (true) { 156 Character c = iterator.current(); 157 if (c == AttributedCharacterIterator.DONE) break; 158 159 FontStyle sty = FontStyle.parseAttributes(iterator.getAttributes(), imageRenderer); 160 FontRenderer renderer = sty.getRenderer(imageRenderer); 161 162 Rectangle rect = renderer.getSize(c.toString(), sty); 163 x += rect.width; 164 y += rect.height; 165 166 iterator.next(); 167 } 168 169 return new Rectangle(0,0,x,y); 170 } 171}