//----------------------------------------------------------------------------// // // // M u s i c F o n t // // // //----------------------------------------------------------------------------// // <editor-fold defaultstate="collapsed" desc="hdr"> // // Copyright © Hervé Bitteur and others 2000-2013. All rights reserved. // // This software is released under the GNU General Public License. // // Goto http://kenai.com/projects/audiveris to report bugs or suggestions. // //----------------------------------------------------------------------------// // </editor-fold> package omr.ui.symbol; import omr.Main; import omr.glyph.Shape; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.awt.Dimension; import java.awt.Font; import java.awt.font.TextLayout; import java.awt.geom.AffineTransform; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import java.util.HashMap; import java.util.Map; /** * Class {@code MusicFont} is meant to simplify the use of the * underlying music font when rendering picture or score views. * * <p>The strategy is to use a properly scaled instance of this class to carry * out the drawing of music symbols with the correct size. The scaling should * combine two factors:<ul> * <li>An interline value different from default {@link #DEFAULT_INTERLINE}</p> * <li>A zoom ratio different from 1</li></ul> * * <p>To get a properly scaled instance, use the convenient method * {@link #getFont(int)} which expects a staff height expressed in a count of * screen pixels (which thus combines the 2 factors listed above).</p> * * <p>There are two well-known pre-scaled instances of this class:<ul> * <li>{@link #baseMusicFont} for standard symbols (scale = 1)</li> * <li>{@link #iconMusicFont} for icon symbols (scale = 1/2)</li></ul> * * <p>The underlying font is <b>MusicalSymbols</b> * downloadable from http://simplythebest.net/fonts/fonts/musical_symbols.html * </p> * * @author Hervé Bitteur */ public class MusicFont extends OmrFont { //~ Static fields/initializers --------------------------------------------- /** Usual logger utility */ private static final Logger logger = LoggerFactory.getLogger(MusicFont.class); /** * The music font name: {@value} (no other one is used). * Possibilities: MusicalSymbols, Symbola, Bravura */ public static final String FONT_NAME = "MusicalSymbols"; /** * Offset for code range. * 0xf000 for MusicalSymbols * 0x1d100 for Symbola or Bravura */ public static final int CODE_OFFSET = 0xf000; /** Cache of font according to desired interline value */ private static final Map<Integer, MusicFont> sizeMap = new HashMap<>(); /** The music font used for default interline and no zoom */ public static final MusicFont baseMusicFont = getFont(DEFAULT_INTERLINE); /** The music font used for icons (half-size) */ public static final MusicFont iconMusicFont = getFont( DEFAULT_INTERLINE / 2); //~ Instance fields -------------------------------------------------------- /** Precise interline height with this font */ private final int fontInterline; //~ Constructors ----------------------------------------------------------- //-----------// // MusicFont // //-----------// /** * Creates a new MusicFont object. * * @param sizePts the point size of the {@code Font} * @param fontInterline the (zoomed?) interline value for this font */ MusicFont (int sizePts, int fontInterline) { super(FONT_NAME, Font.PLAIN, sizePts); this.fontInterline = fontInterline; } //~ Methods ---------------------------------------------------------------- //------------// // buildImage // //------------// /** * Build an image from the shape definition in MusicFont, using the * scaling determined by the provided interline value. * * @param shape the desired shape * @param interline the related interline value * @param decorated true if shape display must use decorations * @return the image built with proper scaling, or null */ public static BufferedImage buildImage (Shape shape, int interline, boolean decorated) { MusicFont font = getFont(interline); return font.buildImage(shape, decorated); } //------------// // buildImage // //------------// /** * Build an image from the shape definition in MusicFont, using the * intrinsic scaling of this font. * * @param shape the desired shape * @param decorated true if shape display must use decorations * @return the image built with proper scaling, or null */ public BufferedImage buildImage (Shape shape, boolean decorated) { ShapeSymbol symbol = Symbols.getSymbol(shape, decorated); if (symbol == null) { return null; } else { return symbol.buildImage(this); } } //----------------// // checkMusicFont // //----------------// /** * Check whether we have been able to load the font. * * @return true if OK */ public static boolean checkMusicFont () { if (baseMusicFont.getFamily().equals("Dialog")) { String msg = FONT_NAME + " font not found." + " Please install " + FONT_NAME + ".ttf"; logger.error(msg); if (Main.getGui() != null) { Main.getGui().displayError(msg); } return false; } return true; } //---------// // getFont // //---------// /** * Report the (cached) best font according to the desired interline * value. * * @param interline the desired (zoomed) interline in pixels * @return the font with proper size */ public static MusicFont getFont (int interline) { MusicFont font = sizeMap.get(interline); if (font == null) { font = new MusicFont(4 * interline, interline); logger.debug("Adding music font for interline {}", interline); sizeMap.put(interline, font); } return font; } //--------// // layout // //--------// /** * Build a TextLayout from a Shape, using its related String of * MusicFont characters, and potentially sized by an * AffineTransform instance. * * @param shape the shape to be drawn with MusicFont chars * @param fat potential affine transformation * @return the (sized) TextLayout ready to be drawn */ public TextLayout layout (Shape shape, AffineTransform fat) { ShapeSymbol symbol = Symbols.getSymbol(shape); if (symbol == null) { logger.debug("No MusicFont symbol for {}", shape); return null; } return layout(symbol.getString(), fat); } //--------// // layout // //--------// /** * Build a TextLayout from a Shape, using its related String of * MusicFont characters, and sized to fit the provided dimension. * * @param shape the shape to be drawn with MusicFont chars * @param dimension the dim to fit as much as possible * @return the adjusted TextLayout ready to be drawn */ public TextLayout layout (Shape shape, Dimension dimension) { ShapeSymbol symbol = Symbols.getSymbol(shape); if (symbol != null) { return layout(symbol, dimension); } else { return null; } } //--------// // layout // //--------// /** * Build a TextLayout from a symbol, using its related String of * MusicFont characters, and sized to fit the provided dimension. * * @param symbol the symbol to be drawn with MusicFont chars * @param dimension the dim to fit as much as possible * @return the adjusted TextLayout ready to be drawn */ public TextLayout layout (BasicSymbol symbol, Dimension dimension) { String str = symbol.getString(); TextLayout layout = new TextLayout(str, this, frc); // Compute proper affine transformation Rectangle2D rect = layout.getBounds(); AffineTransform fat = AffineTransform.getScaleInstance( dimension.width / rect.getWidth(), dimension.height / rect.getHeight()); return layout(str, fat); } //--------// // layout // //--------// /** * Build a TextLayout from a Shape, using its related String of * MusicFont character codes. * * @param shape the shape to be drawn with MusicFont chars * @return the TextLayout ready to be drawn */ public TextLayout layout (Shape shape) { return layout(shape, (AffineTransform) null); } //--------// // layout // //--------// /** * Build a TextLayout from a String of MusicFont character codes. * * @param codes the MusicFont codes * @return the TextLayout ready to be drawn */ public TextLayout layout (int... codes) { return layout(new String(codes, 0, codes.length)); } //------------------// // getFontInterline // //------------------// /** * Report the number of pixels of the interline that corresponds to * this font. * * @return the scaled interline for this font */ protected int getFontInterline () { return fontInterline; } }