/* * [ShroudedImage.java] * * Summary: Displays a text field as a png, useful for masking email addresses. * * Copyright: (c) 2005-2017 Roedy Green, Canadian Mind Products, http://mindprod.com * * Licence: This software may be copied and used freely for any purpose but military. * http://mindprod.com/contact/nonmil.html * * Requires: JDK 1.8+ * * Created with: JetBrains IntelliJ IDEA IDE http://www.jetbrains.com/idea/ * * Version History: * 1.7 2009-04-04 get rid of artifacts on screen. Suggest lower case filename. */ package com.mindprod.masker; import javax.imageio.ImageIO; import javax.swing.JFileChooser; import javax.swing.JPanel; import java.awt.Dimension; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.font.FontRenderContext; import java.awt.font.LineMetrics; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.util.prefs.Preferences; import static java.lang.System.*; /** * Displays a text field as a png, useful for masking email addresses. *

* Displays both on the screen and saves as a PNG. * * @author Roedy Green, Canadian Mind Products * @version 1.7 2009-04-04 get rid of artifacts on screen. Suggest lower case filename. * @since 2005 */ final class ShroudedImage extends JPanel { /** * the text to be displayed */ private String text; /** * height of text above baseline */ private int ascent; /** * height of image */ private int height; /** * width of image */ private int width; /** * constructor * * @param text the text to display */ public ShroudedImage( String text ) { // This makes no sense, but it only works if set false. this.setOpaque( false ); setText( text ); } /** * calculate size needed for image, and refresh it. */ private void refresh() { if ( this.text == null ) { return; } Font font = this.getFont(); FontMetrics fm = this.getFontMetrics( font ); width = fm.stringWidth( text ); // ideally no space at all around text. // FontMetrics getAscent getHeight, getDescent only approximate, have a // lot of white space. // We want more accurate LineMetrics. // We need a Graphics object in order to do line metrics. // This seems like over kill but here we go: // create a BufferedImage BufferedImage bufferedImage = new BufferedImage( 200 /* dummy */, 200 /* dummy */, BufferedImage.TYPE_4BYTE_ABGR_PRE ); Graphics2D g2d = bufferedImage.createGraphics(); FontRenderContext fr = g2d.getFontRenderContext(); LineMetrics lm = font.getLineMetrics( text, fr ); ascent = ( int ) ( lm.getAscent() + .5 ); height = ( int ) ( lm.getDescent() + lm.getAscent() + .5 ); Dimension d = new Dimension( width, height ); this.setPreferredSize( d ); this.setMinimumSize( d ); this.setMaximumSize( d ); invalidate(); repaint(); } /** * draws the text * * @param g graphics region where we paint */ public void paintComponent( Graphics g ) { // if call super.paintComponent generates artifacts -- the default rendering of a JPanel which we do not want. // super.paintComponent( g ); Graphics2D g2d = ( Graphics2D ) g; g2d.addRenderingHints( new RenderingHints( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON ) ); // we don't clear the background, but oddly all works ok. g2d.setFont( this.getFont() ); g2d.setColor( this.getForeground() ); // x,y is bottom left corner of text g2d.drawString( text, 0, ascent ); // y increases going down. } /** * save current image as a png. * * @param saveName file name to save under, without directory. */ public void saveImage( String saveName ) { // ask user where to save. // persisted in registry directory last used Preferences userPrefs = Preferences.userRoot().node( "/com/mindprod/masker" ); final File suggestedFile = new File( userPrefs.get( "SAVEDIR", "C:" ), saveName ); JFileChooser fc = new JFileChooser(); fc.setSelectedFile( suggestedFile ); // filter out all but PNG file from view fc.addChoosableFileFilter( new PNGFileFilter() ); int result = fc.showSaveDialog( this ); switch ( result ) { case JFileChooser.APPROVE_OPTION: final File file = fc.getSelectedFile(); try { // repaint onto a BufferedImage BufferedImage bufferedImage = new BufferedImage( width, height, BufferedImage.TYPE_4BYTE_ABGR_PRE ); Graphics2D g2d = bufferedImage .createGraphics(); // redraw using our paintComponent paintComponent( g2d ); // write out the BufferedImage as a PNG ImageIO.write( bufferedImage, "png" , file ); } catch ( IOException e ) { err.println( "image not saved successfully" ); } // save same directory for next time. // persisted in registry directory last used userPrefs.put( "SAVEDIR", fc.getCurrentDirectory() .getAbsolutePath() ); break; case JFileChooser.CANCEL_OPTION: case JFileChooser.ERROR_OPTION: break; default: } } /** * overide standard setFont * * @param font new font to use in display */ public void setFont( Font font ) { super.setFont( font ); refresh(); } /** * Sets text to be displayed * * @param text Text to display */ public void setText( String text ) { this.text = text; refresh(); } }