import java.applet.Applet;

import java.awt.*;
import java.awt.event.*;
import java.util.*;

import java.net.*;
import java.io.*;

/** How to produce screen shots from Java applications,
 * in either PostScript or JPEG or Gif or Bitmap format.
 * All types can be exported as files for later use,
 * the PostScript can also be printed immediately,
 * if you can direct output to the printer,
 * and if your printer can accept it.
 *
 * Because Applets are not allowed to print or save files,
 * this demonstration is written as an application.
 *
 * We completely avoid Sun's print machinery,
 * the PrintJob and PrintGraphics classes,
 * and the Component.printAll method.
 * They are buggy both in concept and implementation.
 *
 * Note that the PSGr,
 * GifEncoder, BitmapEncoder,
 * and JpegEncoder classes are work by others,
 * who deserve the full credit for developing and sharing them.
 * This code simply shows how they may be used.
 *
 * @author Morris Hirsch IPD 1998 (mhirsch@ipdinc.com) */

public class PrintDemo extends Frame
implements ActionListener
{

    private MenuBar menubar = new MenuBar ();

    private Menu
      File_Menu = new Menu ("File"),
      File_Export_Menu = new Menu ("Export");

    private MenuItem
      File_Print_MI = new MenuItem ("Print"),
      Export_JPEG_MI = new MenuItem ("JPEG Image File"),
      Export_GIF_MI = new MenuItem ("GIF Image File"),
      Export_BMP_MI = new MenuItem ("BMP Image File"),
      Export_Text_MI = new MenuItem ("Text Image File"),
      Export_PS_MI = new MenuItem ("PostScript Image File"),
      File_Exit_MI = new MenuItem ("Exit");

    private Button
	PrintButton = null,
	JPEGButton = null,
	GIFButton = null,
	BMPButton = null,
	TextButton = null,
	PostScriptButton = null,
	ExitButton = null;

    private TextArea textarea = new TextArea (12,50);

    public static void main (String []argv) {
        PrintDemo slf = new PrintDemo (argv);
        slf.resize (400, 500);
        slf.centerOnScreen ();

        slf.show ();
        slf.toFront ();
    }

    void moveCenter (Window ww) {
        Dimension screenSize = Toolkit.getDefaultToolkit ().getScreenSize ();
        int screen_width = screenSize.width;
        int screen_height = screenSize.height;

        Dimension wwSize = ww.getSize ();
        int ww_width = wwSize.width;
        int ww_height = wwSize.height;

        ww.move (screen_width/2 - ww_width/2,
		 screen_height/2 - ww_height/2);
    }

    void centerOnScreen() { moveCenter(this); }

/* Constructor */

    public PrintDemo (String []argv) {

        super ("PrintDemo");

/* menubar and menu buttons of demo choices */

        menubar.add (File_Menu);

        File_Menu.add (File_Export_Menu);
        File_Export_Menu.add (Export_JPEG_MI);
        File_Export_Menu.add (Export_GIF_MI);
        File_Export_Menu.add (Export_BMP_MI);
        File_Export_Menu.add (Export_Text_MI);
        File_Export_Menu.add (Export_PS_MI);
        File_Menu.add (File_Print_MI);
        File_Menu.add (new MenuItem ("-"));
        File_Menu.add (File_Exit_MI);

        setMenuBar (menubar);

	add ("North", textarea);

	textarea.append ("Print Demo");

/* buttons of demo choices */

        Panel SP;
	add ("South", SP = new Panel ());

	SP.add (PrintButton = new Button ("Print"));
	SP.add (JPEGButton = new Button ("JPEG"));
	SP.add (GIFButton = new Button ("GIF"));
	SP.add (BMPButton = new Button ("BMP"));
	SP.add (TextButton = new Button ("Text"));
	SP.add (PostScriptButton = new Button ("PostScript"));
	SP.add (ExitButton = new Button ("Exit"));

/* Because menubar is not a child of this the usual way,
 * need explicit mention to add listeners. */

        ListenerAdder.add_Listeners (this, menubar);

/* Everything else is a child of this */

        ListenerAdder.add_Listeners (this, this);

        pack ();
    }

/* Open a writable file as a PrintStream,
 * possibly replacing an existing file of the same name.
 * We do not test for that!
 * @return -- the writable PrintStream,
 * or null if unable to open the file.
 * <B>Note:</B>Caller is responsible to close the PrintStream. */

    PrintStream open_for_write (String fname) {

        textarea.append ("\nopen "+fname);

        try {

            PrintStream fos = new PrintStream
              (new FileOutputStream 
                (new File (fname)));

            return fos;
        }
        catch (Exception exc) { exc.printStackTrace(); return null; }
    }

/* Create a JPEG Image of this,
 * we started at the top but could start lower in the tree. */

    void do_JPEG (String fname) {

        PrintStream fos = open_for_write (fname);

        if (null != fos) {
            try {

/* Create an OffScreenImage same size as this,
 * will use OSI.getGraphics () to paint everything into it. */

                Dimension d = this.getSize ();
                Image OSI = createImage (d.width, d.height);
                Graphics osg = OSI.getGraphics ();

/* Fails deep inside AWT if we don't do this setClip first! */

                osg.setClip (0, 0, d.width, d.height);

/* More stuff it should inherit but does not... */

                Font myFont = getFont ();
                if (null == myFont)
                    myFont = new Font("Courier", Font.PLAIN, 14);

                osg.setFont(myFont);

                osg.setColor (getBackground ());
                osg.fillRect (0, 0, d.width-1, d.height-1);

/* Paint this itself and everything inside to the OSI,
 * Util.doPaint to avoid buggy printAll,
 * then dispose of the Graphics context. */

		Util.doPaint (osg, this);

                osg.dispose ();

/* Constructing the Encoder for this image does much of the work,
 * and the object is dedicated to the particular image,
 * encoding tables reflect our requested quality factor,
 * scale from 1 (smallest file) to 100 (best image quality).
 * Then we have the Encoder write the compressed image,
 * and close the file */

                new JpegEncoder (OSI, 90, fos).Compress ();
            }
            catch (Exception exc) { exc.printStackTrace(); }

            fos.close ();
        }
    }

/* Create a GIF Image of this,
 * we started at the top but could start lower in the tree. */

    void do_GIF (String fname) {

        PrintStream fos = open_for_write (fname);

        if (null != fos) {
            try {

/* Create an OffScreenImage same size as this,
 * will use OSI.getGraphics () to paint everything into it. */

                Dimension d = this.getSize ();
                Image OSI = createImage (d.width, d.height);
                Graphics osg = OSI.getGraphics ();

/* Fails deep inside AWT if we don't do this setClip first! */

                osg.setClip (0, 0, d.width, d.height);

/* More stuff it should inherit but does not... */

                Font myFont = getFont ();
                if (null == myFont)
                    myFont = new Font("Courier", Font.PLAIN, 14);

                osg.setFont(myFont);

                osg.setColor (getBackground ());
                osg.fillRect (0, 0, d.width-1, d.height-1);

/* Paint this itself and everything inside to the OSI,
 * Util.doPaint to avoid buggy printAll,
 * then dispose of the Graphics context. */

		Util.doPaint (osg, this);

                osg.dispose ();

/* Encoder built for the particular image,
 * but could be made more long-lived I think... */

                new GifEncoder (OSI, (OutputStream)fos).encode ();
            }
            catch (Exception exc) { exc.printStackTrace(); }

            fos.close ();
        }
    }

/* Create a BMP Image of this,
 * we started at the top but could start lower in the tree. */

    void do_BMP (String fname) {

        PrintStream fos = open_for_write (fname);

        if (null != fos) {
            try {

/* Create an OffScreenImage same size as this,
 * will use OSI.getGraphics () to paint everything into it. */

                Dimension d = this.getSize ();
                Image OSI = createImage (d.width, d.height);
                Graphics osg = OSI.getGraphics ();

/* Fails deep inside AWT if we don't do this setClip first! */

                osg.setClip (0, 0, d.width, d.height);

/* More stuff it should inherit but does not... */

                Font myFont = getFont ();
                if (null == myFont)
                    myFont = new Font("Courier", Font.PLAIN, 14);

                osg.setFont(myFont);

                osg.setColor (getBackground ());
                osg.fillRect (0, 0, d.width-1, d.height-1);

/* Paint this itself and everything inside to the OSI,
 * Util.doPaint to avoid buggy printAll,
 * then dispose of the Graphics context. */

		Util.doPaint (osg, this);

                osg.dispose ();

/* returns a boolean true=ok we are ignoring here... */

                new BitmapEncoder ().encode (OSI, (OutputStream)fos);
            }
            catch (Exception exc) { exc.printStackTrace(); }

            fos.close ();
        }
    }

/* Create a PostScript Image of this,
 * we started at the top but could start lower in the tree.
 * either Save it by name,
 * or Print it now via "lpt1" or such, */

    void do_PostScript (String fname) {

/* Open a file to hold the PostScript, */

        PrintStream fos = open_for_write (fname);

        if (null != fos) {
            try {

/* construct a PostScript Graphics Context for the file,
 * taking whatever it needs from our regular Graphics Context. */

                PSGr psg = new PSGr (fos, getGraphics ());

/* Have the PSGr compute a scale,
 * relating our bounds in pixels to page in points,
 * paint this and everything inside,
 * every graphics call causing some postscript commands,
 * then 'showpage' to finish up and dispose of the Graphics,
 * and close the file.
 *
 * Using Util.doPaint (psg, this)
 * instead of buggy this.paintAll (psg)
 * to avoid the paint methods of peer-based classes. */

		psg.scalePaint (this);
		Util.doPaint (psg, this);
                psg.showpage ();

                psg.dispose ();
            }
            catch (Exception exc) { exc.printStackTrace(); }

            fos.close ();
        }
    }

/* Create a PostScript Text file,
 * either Save it by name,
 * or Print it now via "lpt1" or such, */

    void do_Text (String fname) {

/* Open a file to hold the PostScript, */

        PrintStream fos = open_for_write (fname);

        if (null != fos) {
            try {

/* construct a PostScript Printer context for the file,
 * taking whatever it needs from our regular Graphics Context.
 * There is an alternate constructor,
 * with page and margin sizes. */

                PSPrint psg = new PSPrint (fos, getGraphics ());

		psg.setStriping (true);

/* some lines of example text... */

                for (int nn = 0; nn < 150; nn++)
		    psg.print ("Line "+nn+" square "+(nn * nn));

                psg.dispose ();
            }
            catch (Exception exc) { exc.printStackTrace(); }

            fos.close ();
        }
    }

/*** not yet calling this!  load and display a bmp file */

    Image load_Bitmap (String fname) {
      try {
         FileInputStream fis = new FileInputStream (fname);
         return LoadBitmap.loadbitmap (fis, this);
      }
      catch (Exception exc) { exc.printStackTrace(); }
      return null;
    }

/* One at a time */

    private boolean print_active = false;

    public void actionPerformed (ActionEvent e) {
        try {

/* PostScript Image for Export by given name */

            if ((e.getSource () == Export_PS_MI)
             || (e.getSource () == PostScriptButton)) {

                if (print_active) {
		    textarea.append ("\nBusy!");
		    return;
                }

                print_active = true;

                do_PostScript ("demo.ps");

                textarea.append ("\ndone");

                print_active = false;

                return;
            }

/* PostScript Image for immediate Print */

            if ((e.getSource () == File_Print_MI)
             || (e.getSource () == PrintButton)) {

                if (print_active) {
		    textarea.append ("\nBusy!");
		    return;
                }

                print_active = true;

/* Depends on platform,
 * e.g. "Windows NT" => "lpt1"
 * Documentation should make user aware of setup requirements,
 * e.g. "net use lpt1 \\fenrir\HP4SI /persistent:yes" on Windows NT,
 * and "setenv LPDEST lj4_2" on Unix.
 * ANYONE KNOWING A BETTER WAY PLEASE SHARE IT! */

                String osName = System.getProperties().getProperty("os.name");

/* Windows allows "lpt1" as file name
 * if "net use lpt1 \\fenrir\HP4SI /persistent:yes" has been done. */

/* Suggested but not yet tried menu for Windows,
 * "\\FENRIR\HP4SI"
 * "Popcorn5SI"
 * "HPColor"
 * Still question of how to know our choices. Windows knows them! */

///////// SEE awt.Toolkit.getPrintJob /////////////

                if (-1 < osName.indexOf ("Windows"))
                    do_PostScript ("lpt1");

/* Unix does not allow such a shortcut.
 * Using a temp file for now,
 * exec'ing the lp program to print it.
 * Note that lp goes to env $LPDEST if it has been set. */

                else {
                    do_PostScript ("temp.ps");

                    try { 
                        Runtime.getRuntime ().exec ("/bin/lp temp.ps"); 
                    }
                    catch (Exception exc) { exc.printStackTrace (); }
                }

                textarea.append ("\ndone");

                print_active = false;

                return;
            }

/* Create JPEG Image by given name */

            if ((e.getSource () == Export_JPEG_MI)
             || (e.getSource () == JPEGButton)) {

                if (print_active) {
		    textarea.append ("\nBusy!");
		    return;
                }

                print_active = true;

                do_JPEG ("demo.jpg");

                textarea.append ("\ndone");

                print_active = false;

                return;
            }

/* Create GIF Image by given name */

            if ((e.getSource () == Export_GIF_MI)
             || (e.getSource () == GIFButton)) {

                if (print_active) {
		    textarea.append ("\nBusy!");
		    return;
                }

                print_active = true;

                do_GIF ("demo.gif");

                textarea.append ("\ndone");

                print_active = false;

                return;
            }

/* Create BMP Image by given name */

            if ((e.getSource () == Export_BMP_MI)
             || (e.getSource () == BMPButton)) {

                if (print_active) {
		    textarea.append ("\nBusy!");
		    return;
                }

                print_active = true;

                do_BMP ("demo.bmp");

                textarea.append ("\ndone");

                print_active = false;

                return;
            }

/* Create PostScript Text file by given name */

            if ((e.getSource () == Export_Text_MI)
             || (e.getSource () == TextButton)) {

                if (print_active) {
		    textarea.append ("\nBusy!");
		    return;
                }

                print_active = true;

                do_Text ("text.ps");

                textarea.append ("\ndone");

                print_active = false;

                return;
            }

            if ((e.getSource () == File_Exit_MI)
             || (e.getSource () == ExitButton))  {

                if (print_active) {
		    textarea.append ("\nBusy!");
		    return;
                }

		 dispose ();
	         System.exit (0);
            }

        } 
        catch (Exception exc) { exc.printStackTrace (); }
    }
}
/* <IMG SRC="/cgi-bin/counter">*/
