Transferring an Image over the network

Serialization won’t work here because the actual contents of the image (the colors of the pixels) is kept in native code and Serialization only works on Java objects.

The solution is to obtain pixel values and write them into a socket. On the other side, the pixel values must be read and converted into an Image again. Here’s a method that takes an Image and writes its pixel color values into the given OutputStream:

/**
 * Grabs the pixels of the given Image object and returns the array of those
 * pixels. Note that the Image needs to be preloaded in order for this
 * method to work correctly.
 * 
 * @param Image img: The image whose pixels to grab.
 * 
 * @return The values of the pixels encoded in 4 bytes each
 * in aRGB format.
 */

public static int [] grabPixels(Image img){
  int width = img.getWidth(null);
  int height = img.getHeight(null);
  int [] pixels = new int[width*height];
  PixelGrabber grabber = new PixelGrabber(img,0,0,width,height,pixels,0,width);
  try{
    if (!grabber.grabPixels())
      return null;
  } catch (InterruptedException e){
      return null;
    }
  return pixels;
}
 
public static void writeImage(Image img, OutputStream out) throws IOException{
  int [] pixelValues = grabPixels(img);
  ObjectOutputStream objectOut = new ObjectOutputStream(out);  
  objectOut.writeObject(pixelValues); // Arrays are Serializable
}

And here is code that reads the pixel values from the given InputStream, creates and returns an Image object representing the image:

/**
 * Creates an Image object from the given array of pixels.
 * Note that the returned Image is created using an ImageProducer
 * (MemoryImageSource), and such Images are painted much slower than
 * offscreen Images created via Component.createImage(int,int) and you can't
 * draw on these Images as their getGraphics() method will return null. If
 * you need an Image that will be drawn fast and/or you need to paint
 * additional things on the Image, create an offscreen Image using
 * Component.createImage(int,int) and paint the Image returned by this method
 * on that Image.
 * Parameters:
 *   int [] pixels: The pixels array.
 *   int width: The width of the Image.
 *   int height: The height of the Image.
 */
 
public static Image createImage(int [] pixels, int width, int height){
  MemoryImageSource imageSource = new MemoryImageSource(width,height,pixels,
                                                        0,width);
  return Toolkit.getDefaultToolkit().createImage(imageSource);
}
 
 
public static Image readImage(InputStream in) throws IOException{
  ObjectInputStream objectIn = new ObjectInputStream(in);
  try{
    int [] pixelValues = (int [])objectIn.readObject();
  } catch (ClassNotFoundException e){} // This can't happen
    // since the class for (int []) must be present on every JVM
}

Drawing a rectangle with dashed lines in Swing

Main.java:

import java.awt.event.*;
import javax.swing.*;
import java.awt.*;
 
public class Main extends JFrame {
   public Main() {
      addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent we) {
            System.exit(1);
         }
      });
   }
 
   public void paint(Graphics g) {
      Graphics2D g2d = (Graphics2D) g;

      BasicStroke bs = new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER,
                                       10, new float[] {10}, 0);
      g2d.setStroke(bs);
      g2d.drawRect(20, 50, 80, 80);
 
      bs = new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER,
                           10, new float[] {1, 2, 4, 8, 16, 32}, 0);
      g2d.setStroke(bs);
      g2d.drawRect(140, 50, 80, 80);
 
      bs = new BasicStroke(5, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER,
                           5, new float[] {10}, 0);
      g2d.setStroke(bs);
      g2d.drawRect(260, 50, 80, 80);
 
      bs = new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER,
                           10, new float[] {1}, 0);
      g2d.setStroke(bs);
      g2d.drawRect(380, 50, 80, 80);
   }
 
   public static void main(String []args) {
      Main main = new Main();
      main.setSize(480, 160);
      main.setVisible(true);
   }
}

Drawing an underlined string in Swing

Use the class AttributedString as shown in following example.

Main.java:

import java.awt.event.*;
import java.awt.font.*;
import javax.swing.*;
import java.text.*;
import java.awt.*;
 
public class Main extends JFrame {
 
   public Main() {
      addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent we) {
            System.exit(1);
         }
      });
   }
 
   public void paint(Graphics g) {
      Graphics2D g2d = (Graphics2D) g;
 
      AttributedString as = new AttributedString("Easter Island");
      as.addAttribute(TextAttribute.FONT, new Font("Helvetica", Font.PLAIN, 36));
      as.addAttribute(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON, 0, 6);
     
      g2d.drawString(as.getIterator(), 50, 100);
   }
 
   public static void main(String []args) {
      Main main = new Main();
      main.setSize(300, 150);
      main.setVisible(true);
   }
}

Clip an image to be rendered with a text in Swing



Main.java:

import java.awt.image.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.awt.font.*;
import javax.swing.*;
import java.awt.*;
 
public class Main extends JFrame {
   private BufferedImage image; 
   private boolean clip = false;
 
   public Main() {
      addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent we) {
            System.exit(1);
         }
      });
 
      image = toBufferedImage(new javax.swing.ImageIcon("djkrush.jpg").getImage());
      JButton button = new JButton("Clip to Text");
      button.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent ae) {
            clip = true;
            repaint();
         }
      });
 
      getContentPane().setLayout(new BorderLayout());
      getContentPane().add(BorderLayout.SOUTH, button);
   }
 
   public void paint(Graphics g) {
      super.paint(g);
 
      Graphics2D g2d = (Graphics2D) g;
 
      if (clip) {
         int w = getSize().width;
         int h = getSize().height;
 
         FontRenderContext frc = g2d.getFontRenderContext();
         Font font = new Font("Helvetica", Font.PLAIN, 12);
         TextLayout tl = new TextLayout("ALICIA", font, frc);
 
         double stringWidth = tl.getBounds().getWidth();
         double stringHeight = tl.getBounds().getHeight();
 
         // determine to what extend the string should be 
         // scaled in order to fill the window
         double scalex = (w - 50) / stringWidth;
         double scaley = (h - 50) / stringHeight;
         AffineTransform ta = AffineTransform.getScaleInstance(scalex, scaley);
 
         // transform the string in a shape
         Shape shape = tl.getOutline(ta);
 
         // position the shape
         double shapeWidth  = shape.getBounds().getWidth();
         double shapeHeight = shape.getBounds().getHeight();
         AffineTransform at = AffineTransform.getTranslateInstance(
                                                w / 2 - shapeWidth / 2, 
                                                h / 2 + shapeHeight / 2);
         shape = at.createTransformedShape(shape);
 
         g2d.clip(shape);
      }
 
      g2d.setColor(Color.red);
      g2d.fillRect(20, 50, 100, 140);
 
      Rectangle2D tr = new Rectangle2D.Double(0, 0, image.getWidth(), image.getHeight());
      TexturePaint tp = new TexturePaint(image, tr);
      g2d.setPaint(tp);
      g2d.fillRect(120, 50, 100, 140);
       
      g2d.setColor(Color.blue);
      g2d.fillRect(220, 50, 100, 140);
 
      g2d.setColor(Color.yellow);
      g2d.fillOval(320, 50, 100, 140);
   }
 
   public BufferedImage toBufferedImage(Image image) {
      BufferedImage bi = new BufferedImage(image.getWidth(null), image.getHeight(null), 
                                           BufferedImage.TYPE_INT_RGB); 
 
      // copy the original image
      Graphics g = bi.createGraphics();
    
      g.drawImage(image, 0, 0, null);
      g.dispose();
 
      return bi;
   }
 
   public static void main(String []args) {
      Main main = new Main();
      main.setSize(440, 240);
      main.setVisible(true);
   }
}

Image used:

Sharpening an Image in Swing

Use the class ConvolveOp and apply a sharpen filter.

Main.java:

import java.awt.image.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.*;
 
public class Main extends JFrame {
   private boolean firstTime = true;
   private BufferedImage sourceBi;
   private BufferedImage destBi;
 
   public Main() {
      addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent we) {
            System.exit(1);
         }
      }); 
   } 
 
   public void paint(Graphics graphics) {
      Graphics2D g2d = (Graphics2D) graphics;
  
      if (firstTime) {
         Image img = new javax.swing.ImageIcon("djkrush.jpg").getImage(); 
         sourceBi = toBufferedImage(img);
         destBi = new BufferedImage(sourceBi.getWidth(), sourceBi.getHeight(), 
                                    BufferedImage.TYPE_INT_RGB);
         setSize(sourceBi.getWidth(), sourceBi.getHeight()*2);
 
         Kernel kernel = new Kernel(3, 3, new float[] 
                                            { -1, -1, -1,
                                              -1,  9, -1,
                                              -1, -1, -1 });
         ConvolveOp cOp = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null);
         cOp.filter(sourceBi, destBi);
 
         firstTime = false;
      }
 
      g2d.drawImage(sourceBi, 0, 0, this);
      g2d.drawImage(destBi, 0, sourceBi.getHeight(), this);
   }
 
   public static BufferedImage toBufferedImage(Image image) {
      BufferedImage bi = new BufferedImage(image.getWidth(null), image.getHeight(null), 
                                           BufferedImage.TYPE_INT_RGB); 
 
      // copy the original image
      Graphics g = bi.createGraphics();
    
      g.drawImage(image, 0, 0, null);
      g.dispose();
 
      return bi;
   }
 
   public static void main(String []args) {
      Main main = new Main();
      main.setVisible(true);
      main.setSize(300, 150);
   }
}

Image used:

To learn more about image processing,
check out this expensive but excellent book:

Determining what formats are supported by ImageIO

ImageIO is extensible. You can add third party plug-ins for other image formats than the standard ones.

Main.java:

import javax.imageio.*;
 
public class Main
{
   public static void main(String []args) {
      String[] formatNames = ImageIO.getReaderFormatNames();
 
      for (int i=0; i<formatNames.length; i++) {
         System.out.println(formatNames[i]);
      }
   }
}

outputs:

png
jpeg
JPEG
gif
jpg
JPG

Setting the top-left icon of a JDialog

You can’t directly set the top-left icon of a JDialog. It inherits its icon from the owner JFrame. What you could do is pass a dummy JFrame as the owner when you create the JDialog. This example shows you:

import javax.swing.event.*; 
import java.awt.event.*; 
import javax.swing.*; 
import java.awt.*; 
 
public class Main extends JFrame 
{ 
   private AboutBox about; 
   
   public Main() { 
      super("Main test"); 
 
      setSize(450, 350); 
 
      ImageIcon icon = new ImageIcon("first.gif"); 
      setIconImage(icon.getImage()); 
    
      JButton button = new JButton("Open dialog");
      getContentPane().setLayout(new FlowLayout());
      getContentPane().add(button);
      button.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent ae) {
            about = new AboutBox(new JFrame()); 
            about.setVisible(true);
         }
      });
 
      addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent we) {
            System.exit(0);
         }
      });
   } 
 
   public static void main(String []args) {
      Main main = new Main();
      main.setVisible(true);
   }
}
 
class AboutBox extends JDialog 
{ 
   public AboutBox(JFrame owner) { 
      super(owner, "About Swing Menu", true); 
   
      ImageIcon icon = new ImageIcon("second.gif"); 
      owner.setIconImage(icon.getImage()); 

      JButton button = new JButton("Close");
      getContentPane().setLayout(new FlowLayout());
      getContentPane().add(button);
      button.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent ae) {
            dispose();
         }
      });
 
      setSize(250, 150); 
   }
}

Setting the JSplitPane divider location

Use the method setDividerLocation to set the divider. You can either set the new position by pixel or specify a percentage:

   // sets the divider at pixel 100
   splitPane.setDividerLocation(100);
   // sets the divider in the middle
   splitPane.setDividerLocation(.5);

The JSplitPane MUST be visible invoking this method
otherwise it will not have the desired effect. Here’s an example on how to set the divider location the moment when the JFrame becomes visible:

import java.awt.event.*;
import javax.swing.*;
import java.awt.*;
 
public class Main extends JFrame
{
   JSplitPane splitPane;
  
   public Main() {
      addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent we) {
            System.exit(0);
         }
      });
 
      splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, 
                                 new JPanel(), new JPanel());
 
      createMainMenuBar();
 
      getContentPane().add(splitPane);
 
      addComponentListener(new ComponentAdapter() {
         public void componentShown(ComponentEvent event) {
            splitPane.setDividerLocation(0.5); 
                
            removeComponentListener(this);
         }
      });
   }
 
   public void createMainMenuBar() {
      JMenuBar mainBar = new JMenuBar();
      JMenu menu = new JMenu("JSplitPane");
      JMenuItem item1 = new JMenuItem("HORIZONTAL_SPLIT");
      JMenuItem item2 = new JMenuItem("VERTICAL_SPLIT");
      menu.add(item1);
      menu.add(item2);
      mainBar.add(menu);
      setJMenuBar(mainBar);
 
      item1.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent ae) {
            splitPane.setOrientation(JSplitPane.HORIZONTAL_SPLIT);
         }
      });
 
      item2.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent ae) {
            splitPane.setOrientation(JSplitPane.VERTICAL_SPLIT);
         }
      });
   }
 
   public static void main(String []args) {
      Main main = new Main();
      main.setSize(300, 300);
      main.setVisible(true);
   }
}

Number of rows the JTabbedPane is using to display its tabs

According to the javax.swing.JTabbedPane.getTabRunCount() API documentation:

Returns the number of tab runs currently used to display the tabs.

Returns:

an integer giving the number of rows if the tabPlacement is TOP or BOTTOM and the number of columns if tabPlacement is LEFT or RIGHT, or 0 if there is no UI set on this tabbedpane

This is basically a convenience method for javax.swing.plaf.TabbedPaneUI.getTabRunCount(), which has no API documentation.

The code for TabRunTest takes the following command line params:

  1. TOP (default) | BOTTOM (1) | LEFT (2) | RIGHT (3)

  • creates the specified number of tabs or 10 (if not specified or negative).

    There is a Get Info button at the bottom of the window to display the tab count and tab run count

    TabRowTest.java:

    import java.awt.BorderLayout;
    import java.awt.Container;
    import java.awt.GridLayout;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
     
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    import javax.swing.JTabbedPane;
     
    /**
     *@author     Administrator
     *@created    February 4, 2002
     */
    public class TabRowTest extends JPanel {
     
       public static void main(String[] args) {
          JFrame frame = new JFrame("Multiple Colors...");
     
          java.awt.Container contentPane = frame.getContentPane();
          contentPane.setLayout(new BorderLayout());
     
          int tabPlacement = JTabbedPane.TOP;
          if (args.length > 0) {
             try {
                int temp = Integer.parseInt(args[0]);
                switch (temp) {
                   case 1:
                      tabPlacement = JTabbedPane.BOTTOM;
                      break;
                   case 2:
                      tabPlacement = JTabbedPane.LEFT;
                      break;
                   case 3:
                      tabPlacement = JTabbedPane.RIGHT;
                      break;
                }
             } catch (Exception ex) {
                ex.printStackTrace();
                System.out.println();
                System.out.println("------------------CONTINUING--------------------");
                System.out.println();
             }
          }
     
          int numberOfTabs = 10;
          if (args.length > 1) {
             try {
                numberOfTabs = Integer.parseInt(args[1]);
                if (numberOfTabs < 0) {
                   numberOfTabs = 10;
                }
             } catch (Exception ex) {
                ex.printStackTrace();
                System.out.println();
                System.out.println("------------------CONTINUING--------------------");
                System.out.println();
             }
          }
     
          contentPane.add(new TabRowTest(tabPlacement, numberOfTabs));
     
          frame.setSize(800, 600);
     
          frame.addWindowListener(
             new java.awt.event.WindowAdapter() {
                public void windowClosing(java.awt.event.WindowEvent ev) {
                   System.exit(0);
                }
             });
     
          frame.show();
       }
       // main
     
       public TabRowTest(int tabPlacement, int numberOfTabs) {
          super(new BorderLayout());
     
          final JTabbedPane tabbedPane = new JTabbedPane(tabPlacement);
          add(tabbedPane, BorderLayout.CENTER);
     
          for (int idx = 1; idx < (numberOfTabs + 1); idx++) {
             tabbedPane.addTab("Tab #" + idx, new JLabel("Tab #" + idx + " stuff"));
          }
     
          JPanel infopanel = new JPanel(new GridLayout(1, 0));
          add(infopanel, BorderLayout.SOUTH);
     
          final JLabel tabCountLabel = new JLabel("<tab count>");
          final JLabel runCountLabel = new JLabel("<run count>");
     
          JButton button = new JButton("Get Info");
          infopanel.add(button);
          infopanel.add(new JLabel("# Tabs:"));
          infopanel.add(tabCountLabel);
          infopanel.add(new JLabel("Run Count:"));
          infopanel.add(runCountLabel);
     
          button.addActionListener(
             new ActionListener() {
                public void actionPerformed(ActionEvent ev) {
                   int tabCount = tabbedPane.getTabCount();
                   int runCount = tabbedPane.getTabRunCount();
                   tabCountLabel.setText("" + tabCount);
                   runCountLabel.setText("" + runCount);
                }
             });
       }
       // TabRowTest
    }