/* * Copyright (c) 2016, Metron, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of Metron, Inc. nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL METRON, INC. BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package com.metsci.glimpse.dnc.geosym; import static com.metsci.glimpse.util.GeneralUtils.newHashMap; import static com.metsci.glimpse.util.units.Length.millimetersToInches; import static java.awt.RenderingHints.KEY_FRACTIONALMETRICS; import static java.awt.RenderingHints.KEY_TEXT_ANTIALIASING; import static java.awt.RenderingHints.VALUE_FRACTIONALMETRICS_OFF; import static java.awt.RenderingHints.VALUE_TEXT_ANTIALIAS_OFF; import static java.awt.font.TextAttribute.FONT; import static java.awt.font.TextAttribute.FOREGROUND; import static java.awt.image.BufferedImage.TYPE_INT_ARGB; import static java.lang.Math.ceil; import static java.lang.Math.round; import static javax.swing.SwingConstants.BOTTOM; import static javax.swing.SwingConstants.LEFT; import static javax.swing.SwingConstants.RIGHT; import static javax.swing.SwingConstants.TOP; import java.awt.Color; import java.awt.Graphics2D; import java.awt.font.TextLayout; import java.awt.image.BufferedImage; import java.text.AttributedCharacterIterator.Attribute; import java.text.AttributedString; import java.util.Map; import com.metsci.glimpse.dnc.util.AnchoredImage; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; public class DncGeosymLabelUtils { public static AnchoredImage newLabelImage( AttributedString text, DncGeosymLabelLocation labelLocation, double dpi ) { BufferedImage image0 = new BufferedImage( 1, 1, TYPE_INT_ARGB ); Graphics2D g0 = (Graphics2D) image0.getGraphics( ); TextLayout layout0 = new TextLayout( text.getIterator( ), g0.getFontRenderContext( ) ); int ascent = (int) ceil( layout0.getAscent( ) ); int descent = (int) ceil( layout0.getDescent( ) ); int advance = (int) ceil( layout0.getVisibleAdvance( ) ); int border = 1; int height = ascent + descent + 2*border; int width = advance + 2*border; BufferedImage image = new BufferedImage( width, height, TYPE_INT_ARGB ); Graphics2D g = (Graphics2D) image.getGraphics( ); g.setBackground( new Color( 1, 1, 1, 0 ) ); g.clearRect( 0, 0, width, height ); g.setRenderingHint( KEY_TEXT_ANTIALIASING, VALUE_TEXT_ANTIALIAS_OFF ); g.setRenderingHint( KEY_FRACTIONALMETRICS, VALUE_FRACTIONALMETRICS_OFF ); TextLayout layout = new TextLayout( text.getIterator( ), g.getFontRenderContext( ) ); layout.draw( g, border, ascent+border ); // This will give the officially correct millimeter offset when drawn with scale 1; otherwise, // the offset will shrink/grow with the scale, which is probably what we want anyway double mmToTexels = millimetersToInches * dpi; int iAnchor = (int) round( -labelLocation.xOffset_MM * mmToTexels ); switch ( labelLocation.hAlign ) { case LEFT: iAnchor += border; break; case RIGHT: iAnchor += image.getWidth( ) - 1 - border; break; default: iAnchor += image.getWidth( ) / 2; break; } int jAnchor = (int) round( -labelLocation.yOffset_MM * mmToTexels ); switch ( labelLocation.vAlign ) { case TOP: jAnchor += image.getHeight( ) - border; break; case BOTTOM: jAnchor += descent + border; break; default: jAnchor += image.getHeight( ) / 2; break; } return new AnchoredImage( image, iAnchor, jAnchor ); } public static Map<Attribute,Object> toTextAttributes( DncGeosymTextStyle textStyle, Int2ObjectMap<Color> colors ) { Color color = colors.get( textStyle.colorCode ); Map<Attribute,Object> attributes = newHashMap( ); attributes.put( FONT, textStyle.font ); attributes.put( FOREGROUND, color ); return attributes; } }