/*
* [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