/* * [Masker.java] * * Summary: Produces pngs with email address in them to deter spam harvesting from websites. * * 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.2 2005-06-24 documents align="top" to handle gif and text alignment. * RELEASE_DATE, made vars static final. * 1.3 2006-03-06 reformat with IntelliJ, add Javadoc. * 1.4 2007-07-18 standard swing buttons. Courier removed as preferred font. * trim email entered, change name generated to not use mailto. * Fix problem with background not getting cleared all the time. * Changed list of preferred fonts. * 1.5 2008-01-22 JDK 1.3 to 1.4 since that is needed for Preferences. * 1.6 2008-03-11 add build number to title. * 1.7 2009-04-04 get rid of artifacts on screen. Suggest lower case filename. * 1.8 2009-04-04 Mask, command line version of Masker. * 1.9 2010-03-23 user selectable look and feel. */ package com.mindprod.masker; import com.mindprod.common18.Build; import com.mindprod.common18.CMPAboutJBox; import com.mindprod.common18.FontFactory; import com.mindprod.common18.HybridJ; import com.mindprod.common18.JEButton; import com.mindprod.common18.Laf; import com.mindprod.common18.VersionCheck; import javax.swing.JApplet; import javax.swing.JButton; import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JTextField; import javax.swing.event.CaretEvent; import javax.swing.event.CaretListener; import java.awt.Color; import java.awt.Container; import java.awt.Font; import java.awt.GraphicsEnvironment; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Arrays; import java.util.HashSet; /** * Produces pngs with email address in them to deter spam harvesting from websites. *

* This is both an Applet and a standalone application. *

* * @author Roedy Green, Canadian Mind Products * @version 1.9 2010-03-23 user selectable look and feel. * @noinspection FieldCanBeLocal * @since 2005 */ public final class Masker extends JApplet { /** * height of Applet in pixels. Does not include bar at top, but does include menu bar. */ private static final int APPLET_HEIGHT = 275; /** * Width of Applet in pixels. */ private static final int APPLET_WIDTH = 636; private static final int FIRST_COPYRIGHT_YEAR = 2005; /** * font size to use in the generated PNG images. */ private static final int pngFontSize = 18; /** * undisplayed copyright notice * * @noinspection UnusedDeclaration */ private static final String EMBEDDED_COPYRIGHT = "Copyright: (c) 2005-2017 Roedy Green, Canadian Mind Products, http://mindprod.com"; /** * date this version released. */ private static final String RELEASE_DATE = "2010-03-23"; /** * Title of the Applet */ private static final String TITLE_STRING = "CMP Email Masker"; /** * Version of the Applet */ private static final String VERSION_STRING = "1.9"; /** * Best fonts to use. Takes the first one that is supported on the given system. For official names * see http://mindprod.com/fontshower.html */ private static final String[] pngFonts = new String[] { "Tiresias PCfont Z", "Tiresias PCfont", "TiresiasScreenfont", "Verdana", "Lucida Console", "Lucida Sans" };// if none of these supported, will use Dialog. /** * Applet background */ private static final Color BACKGROUND_FOR_APPLET = new Color( 0xfff4ff ); /** * background colour for input fields */ private static final Color BACKGROUND_FOR_INPUT = new Color( 0xffffff ); /** * default foreground colour for images */ private static final Color FOREGROUND_FOR_DEFAULT = new Color( 0x777777 )/* grey */; /** * foreground colour for input fields */ private static final Color FOREGROUND_FOR_INPUT = new Color( 0x1e90ff )/* dodger blue */; private static final Color FOREGROUND_FOR_LABEL = new Color( 0x0000b0 ); /** * for titles */ private static final Color FOREGROUND_FOR_TITLE = new Color( 0xdc143c ); /** * default transparent background colour for images. */ private static final Color transparent = new Color( 0x00ffffff, true ); /** * font for input fields */ private static final Font FONT_FOR_EDITABLE_FIELDS = FontFactory.build( "Dialog", Font.BOLD, 17 ); /** * for for titles and About buttons */ private static final Font FONT_FOR_TITLE = FontFactory.build( "Dialog", Font.BOLD, 16 ); /** * for for titles and About buttons */ private static final Font FONT_FOR_TITLE2 = FontFactory.build( "Dialog", Font.PLAIN, 14 ); /** * HashSet of names of all supported font families */ private static final HashSet allFontFamilies; static { String[] names = ( GraphicsEnvironment.getLocalGraphicsEnvironment() ) .getAvailableFontFamilyNames(); // convert to lower case for case-insensitive lookup for ( int i = 0, n = names.length; i < n; i++ ) { names[ i ] = names[ i ].toLowerCase(); } allFontFamilies = new HashSet<>( Arrays.asList( names ) ); } /** * save button */ private JButton save; /** * "email:" */ private JLabel emailLabel; /** * instruction on how to use the program */ private JLabel instructions; /** * title on screen */ private JLabel title; /** * title, second line */ private JLabel title2; /** * where you fill in email address on screen */ private JTextField email; /** * where PNG image is displayed on screen. */ private ShroudedImage png; /** * Constructor */ public Masker() { } /** * Get the most preferred supported font from a list * * @param preferredFontNames list of font names, best one first. * @param fontStyle e.g. Font.PLAIN * @param fontSize size of font in points. * * @return best font that is supported, or a Dialog font if none are. * @noinspection SameParameterValue */ private static Font bestFont( String[] preferredFontNames, int fontStyle, int fontSize ) { // find first font in that is supported for ( String preferredFontName : preferredFontNames ) { if ( allFontFamilies.contains( preferredFontName.toLowerCase() ) ) { return FontFactory.build( preferredFontName, fontStyle, fontSize ); } } // end for return FontFactory.build( "Dialog", fontStyle, fontSize ); } /** * allocate all the components */ private void buildComponents() { title = new JLabel( TITLE_STRING + " " + VERSION_STRING ); title.setForeground( FOREGROUND_FOR_TITLE ); title.setFont( FONT_FOR_TITLE ); title2 = new JLabel( "released:" + RELEASE_DATE + " build:" + Build.BUILD_NUMBER ); title2.setFont( FONT_FOR_TITLE2 ); title2.setForeground( FOREGROUND_FOR_TITLE ); emailLabel = new JLabel( "email:" ); emailLabel.setForeground( FOREGROUND_FOR_LABEL ); email = new JTextField( "roedyg@mindprod.com", 40 ); email.setEditable( true ); email.setMargin( new Insets( 2, 2, 2, 2 ) ); email.setFont( FONT_FOR_EDITABLE_FIELDS ); email.setBackground( BACKGROUND_FOR_INPUT ); email.setForeground( FOREGROUND_FOR_INPUT ); email.addCaretListener( new CaretListener() { /** * Called when the caret position is updated. * @param e the caret event */ public void caretUpdate( CaretEvent e ) { // text changed png.setText( email.getText().trim() ); validate(); } } ); png = new ShroudedImage( email.getText().trim() ); png.setForeground( FOREGROUND_FOR_DEFAULT ); png.setBackground( transparent ); png.setFont( bestFont( pngFonts, Font.PLAIN, pngFontSize ) ); save = new JEButton( "Save" ); save.setToolTipText( "Save Email image as a PNG file" ); save.addActionListener( new ActionListener() { /** * called when the save button hit. * @param e not used. */ public void actionPerformed( ActionEvent e ) { // save hit String text = email.getText().trim(); png.setText( text ); int place = text.indexOf( '@' ); if ( place < 0 ) { // take whole thing. place = text.length(); } String saveName = text.substring( 0, place ).toLowerCase() + ".png"; png.saveImage( saveName ); } } ); instructions = new JLabel( "Fill in your email address and hit Save to create a png image of your email address." ); instructions.setForeground( FOREGROUND_FOR_LABEL ); } /** * build a menu with Look & Feel and About across the top */ private void buildMenu() { // turn on anti-alias System.setProperty( "swing.aatext", "true" ); final JMenuBar menubar = new JMenuBar(); setJMenuBar( menubar ); final JMenu lafMenu = Laf.buildLookAndFeelMenu(); if ( lafMenu != null ) { menubar.add( lafMenu ); } final JMenu menuHelp = new JMenu( "Help" ); menubar.add( menuHelp ); final JMenuItem aboutItem = new JMenuItem( "About" ); menuHelp.add( aboutItem ); aboutItem.addActionListener( new ActionListener() { public void actionPerformed( ActionEvent e ) { // open about frame new CMPAboutJBox( TITLE_STRING, VERSION_STRING, "Creates png files (like gifs but smaller)", "to hide your email address from spam harvesters.", "freeware", RELEASE_DATE, FIRST_COPYRIGHT_YEAR, "Roedy Green", "MASKER", "1.8" ); } } ); } /** * layout fields in GridBag * * @param contentPane where to place the components */ private void layoutFields( Container contentPane ) { // 0________1_____ 2 // title ------------- 0 // title2 ------------ 1 // label email address 2 // what png looks like 3 // -------SAVE ------- 4 // instructions 5 // // x y w h wtx wty anchor fill T L B R padx pady contentPane.add( title, new GridBagConstraints( 1, 0, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets( 5, 2, 0, 2 ), 0, 0 ) ); // x y w h wtx wty anchor fill T L B R padx pady contentPane.add( title2, new GridBagConstraints( 1, 1, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets( 0, 2, 0, 2 ), 0, 0 ) ); // x y w h wtx wty anchor fill T L B R padx pady contentPane.add( emailLabel, new GridBagConstraints( 0, 2, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets( 7, 5, 0, 5 ), 0, 0 ) ); // x y w h wtx wty anchor fill T L B R padx pady contentPane.add( email, new GridBagConstraints( 1, 2, 2, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets( 7, 2, 0, 5 ), 0, 0 ) ); // x y w h wtx wty anchor fill T L B R padx pady contentPane.add( png, new GridBagConstraints( 1, 3, 2, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets( 7, 2, 0, 5 ), 0, 0 ) ); // x y w h wtx wty anchor fill T L B R padx pady contentPane.add( save, new GridBagConstraints( 2, 4, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets( 5, 2, 0, 5 ), 0, 0 ) ); // x y w h wtx wty anchor fill T L B R padx pady contentPane.add( instructions, new GridBagConstraints( 1, 5, 2, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets( 5, 2, 5, 5 ), 0, 0 ) ); } /** * Allow this Applet to run as as application as well. * * @param args command line arguments ignored. */ public static void main( String args[] ) { HybridJ.fireup( new Masker(), TITLE_STRING + " " + VERSION_STRING, APPLET_WIDTH, APPLET_HEIGHT ); } // end main /** * Called by the browser or Applet viewer to inform * this Applet that it has been loaded into the system. */ @Override public void init() { Container contentPane = this.getContentPane(); if ( !VersionCheck.isJavaVersionOK( 1, 7, 0, contentPane ) ) { // effectively abort return; } buildMenu(); // also initial L&F contentPane.setLayout( new GridBagLayout() ); contentPane.setBackground( BACKGROUND_FOR_APPLET ); buildComponents(); layoutFields( contentPane ); this.validate(); this.setVisible( true ); } } // end Masker