[Java] How do I save a bunch of images as one?

  • Context: Java 
  • Thread starter Thread starter Yoyo_Guru
  • Start date Start date
  • Tags Tags
    Images Java
Click For Summary
SUMMARY

The discussion focuses on saving a collection of images from a JPanel in Java as a single .gif file to improve performance by reducing lag during repainting. The user has implemented a program using Java Swing, specifically utilizing classes like JFrame and JPanel, but struggles with the image saving functionality. Key components include the Map and Selection classes, which manage the user interface and image selection, and the need for a method to consolidate the images into a single BufferedImage before saving.

PREREQUISITES
  • Java Swing for GUI development
  • BufferedImage manipulation in Java
  • Understanding of event handling in Java (MouseListener, MouseMotionListener)
  • File I/O operations in Java for saving images
NEXT STEPS
  • Implement a method to combine multiple BufferedImages into one using Graphics2D
  • Research Java ImageIO.write() for saving BufferedImages as .gif files
  • Explore Java's AWT and Swing libraries for advanced image rendering techniques
  • Learn about performance optimization techniques in Java GUI applications
USEFUL FOR

Java developers, particularly those working on GUI applications, game developers needing to manage and save graphical assets, and anyone looking to optimize image handling in Java Swing applications.

Yoyo_Guru
Messages
32
Reaction score
0
I have a program where the user selects image icons in one JPanel and can place them in another JPanel. The program saves the position of the icons as an array of integers where each integer represents the different icons. I need to also save the final result as a .gif image because otherwise it will repaint the icons everytime paint method is called and creates a lot of lag. Basically I want to take the image icons in the JPanel and save them as one .gif file. I've tried googling it but have not been able to determine how. Does anyone have any advice or could show me how to do it? I've gotten it to save the text file but not the image of all the icons together. Here is the code:
Here is the JPanel and JFrame where the tiles can be placed

Code:
public class Map extends JFrame
{
  final int AREA_SIZE_X = 100;
  final int AREA_SIZE_Y = 100;
  JFrame sWindow;
  mapPanel mPanel;
 JScrollPane scrollPane;
  Map() throws IOException
  {
    sWindow = new Selection(this);
    sWindow.setDefaultCloseOperation(EXIT_ON_CLOSE);
    sWindow.setSize(270,700);
    sWindow.setVisible(true);
    mPanel = new mapPanel(sWindow);
    this.getContentPane().setLayout(new BorderLayout());
    scrollPane = new JScrollPane(mPanel);
    this.getContentPane().add(scrollPane, BorderLayout.WEST);
    mPanel.requestFocus();      // Give the panel focus.
    this.setTitle("Map maker");
    this.setLocation(400, 0);
    this.setResizable(false);
    
    this.pack();
  }
}
class mapPanel extends JPanel implements MouseListener, MouseMotionListener
{
  //int[][][] back1;
 // int[][][] back2;
  boolean topLayer=false;
  final int AREA_SIZE_X = 100;
  final int AREA_SIZE_Y = 100;
  Point mouseLocation;
  Point myMouse;
  int[][][] tiles = new int[AREA_SIZE_X][AREA_SIZE_Y][4];
  ArrayList<BufferedImage> bFS;
  //ArrayList<ImageIcon> icons=new <ImageIcon>ArrayList();
  BufferedImage tempImage;
  Selection sWindow;

  public mapPanel(JFrame selWindow)
  {
    this.addMouseMotionListener(this);
    sWindow = (Selection) selWindow;
    bFS = sWindow.getBuffered();
    for (int i = 0; i < AREA_SIZE_X; i++)
    {
      for (int j = 0; j < AREA_SIZE_Y; j++)
      {
        for (int k = 0; k < 4; k++)
        {
          tiles[i][j][k] = -1;
        }
      }
    }
  //  back1= tiles.clone();
   // back2=tiles.clone();
    this.setBackground(Color.white);
    this.setPreferredSize(new Dimension(10*AREA_SIZE_X, 10*AREA_SIZE_Y));
    this.addMouseListener(this);
   // this.addKeyListener(this);  // This class has its own key listeners.
    this.setFocusable(true);    // Allow panel to get focus
    sWindow.updateTiles(tiles);
  }
  public void fillBackground()
  {
     for (int i = 0; i < AREA_SIZE_X; i++)
    {
      for (int j = 0; j < AREA_SIZE_Y; j++)
      {
        tiles[i][j][0]= sWindow.getSelected();
        for (int k = 1; k < 4; k++)
        {
          tiles[i][j][k] = -1;
        }
      }
    }
  }
  public void paintComponent(Graphics g)
  {

    super.paintComponent(g);
    g.setColor(Color.white);
    g.fillRect(0, 0, AREA_SIZE_X * 20, AREA_SIZE_Y * 20);
    mouseLocation = this.getMousePosition();

    for (int i = 0; i < AREA_SIZE_X; i++)
    {
      for (int j = 0; j < AREA_SIZE_Y; j++)
      {
        for (int k = 0; k < 4; k++)
        {
          if (tiles[i][j][k] != -1)
          {
            g.drawImage(bFS.get(tiles[i][j][k]), i * 20, j * 20, this);
          }
        }
      }
    }
//System.out.println(this.hasFocus());
    if (this.hasFocus()&&this.contains(mouseLocation))
    {
      g.drawImage(bFS.get(sWindow.getSelected()), mouseLocation.x - 20, mouseLocation.y - 20, this);
      // g.drawImage(bFS.get(sWindow.getSelected()), mouseLocation.x - 20, mouseLocation.y - 20, this);
      g.setColor(Color.red);
      g.drawRect(((mouseLocation.x - 10) / 20) * 20, ((mouseLocation.y - 10) / 20) * 20, 20, 20);
    }
  }

  @Override
  public void mouseClicked(MouseEvent e)
  {
    // updateHistogram(tiles);
    topLayer=sWindow.isLayered();
    // System.out.println(this.hasFocus());
    myMouse = this.getMousePosition();
    // System.out.println((myMouse.x - 10) / 20+"  "+(myMouse.y) / 20);
   if(topLayer)
   {
    for(int k=0;k<4;k++)
    {
      if(tiles[(myMouse.x - 10) / 20][(myMouse.y - 10) / 20][k]==-1)
      {
        tiles[(myMouse.x - 10) / 20][(myMouse.y - 10) / 20][k] = sWindow.getSelected();
        break;
      }
    }
    //System.out.println(tiles[(myMouse.x - 10) / 20][(myMouse.y - 10) / 20][0]);
   // System.out.println(tiles[(myMouse.x - 10) / 20][(myMouse.y - 10) / 20][1]);
   }
   else
   {
     tiles[(myMouse.x - 10) / 20][(myMouse.y - 10) / 20][0] = sWindow.getSelected();
     tiles[(myMouse.x - 10) / 20][(myMouse.y - 10) / 20][1] = -1;
     tiles[(myMouse.x - 10) / 20][(myMouse.y - 10) / 20][2] = -1;
     tiles[(myMouse.x - 10) / 20][(myMouse.y - 10) / 20][3] = -1;
   }
    //tiles[1][1] = sWindow.getSelected();
    //System.out.println(sWindow.getSelected());
    this.repaint();
  }

  @Override
  public void mousePressed(MouseEvent e)
  {
  }

  @Override
  public void mouseReleased(MouseEvent e)
  {
  }

  @Override
  public void mouseEntered(MouseEvent e)
  {
    this.requestFocus();
  }

  @Override
  public void mouseExited(MouseEvent e)
  {
    //sWindow.requestFocusInWindow()
    sWindow.updateTiles(tiles);
    sWindow.requestFocus();
  }

  @Override
  public void mouseDragged(MouseEvent e)
  {
  //  updateHistogram(tiles);
    myMouse = this.getMousePosition();
    topLayer=sWindow.isLayered();
    
    if(topLayer)
   {
    for(int k=0;k<4;k++)
    {
      if(tiles[(myMouse.x - 10) / 20][(myMouse.y - 10) / 20][k]==-1)
      {
        tiles[(myMouse.x - 10) / 20][(myMouse.y - 10) / 20][k] = sWindow.getSelected();
        break;
      }
    }
   }
   else
   {
     tiles[(myMouse.x - 10) / 20][(myMouse.y - 10) / 20][0] = sWindow.getSelected();
     tiles[(myMouse.x - 10) / 20][(myMouse.y - 10) / 20][1] = -1;
     tiles[(myMouse.x - 10) / 20][(myMouse.y - 10) / 20][2] = -1;
     tiles[(myMouse.x - 10) / 20][(myMouse.y - 10) / 20][3] = -1;
   }
    this.repaint();
  }

  @Override
  public void mouseMoved(MouseEvent e)
  {
    // System.out.println("moved");
    this.repaint();
  }

Here is the code for the selector
Code:
public class Selection extends JFrame
{

  selectionPanel panel;
  JScrollPane scrollPane;

  public Selection(Map mapFrame) throws IOException
  {
    panel = new selectionPanel(this, mapFrame);
    //  panel.setLayout(new BorderLayout());
    this.getContentPane().setLayout(new BorderLayout());
    //   JLabel instructions = new JLabel("<html><ul><li>Type text.</li>"
    //           + "<li>Use arrow keys to move text.</li>"
    //           + "<li>Press shift arrows to move faster.</li></html>");
    //   this.getContentPane().add(instructions, BorderLayout.NORTH);
    this.setResizable(false);
    scrollPane = new JScrollPane(panel);
    //setViewport(panel);
    scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
    this.getContentPane().add(scrollPane, BorderLayout.WEST);
    panel.requestFocus();      // Give the panel focus.
    this.setTitle("Texture Selecter");
    this.pack();
  }

  public int getSelected()
  {
    //System.out.println(panel.selected);
    return panel.selected;
  }

  public ArrayList<BufferedImage> getBuffered()
  {
    return panel.bFS;
  }

  public boolean isLayered()
  {
    return panel.layerB.isSelected();
  }

  public void updateTiles(int[][][] updatedTiles)
  {
    panel.updatePanelTiles(updatedTiles);
  }
}

class selectionPanel extends JPanel implements MouseListener
{

  Map map;
  boolean layered = false;
  ArrayList<ImageIcon> icons = new ArrayList<ImageIcon>();
  protected ArrayList<JButton> buttons = new ArrayList<JButton>();
  ArrayList<BufferedImage> bFS = new ArrayList<BufferedImage>();
  int selected = 1;
  File file;
  BufferedImage tempImage;
  JRadioButton layerB;
  JButton bSave;
  JButton bBackground;
  JButton bOpen;
  int tiles[][][];
  Selection select;

  selectionPanel(Selection sel, Map mapFrame) throws IOException
  {
    map = mapFrame;
    select = sel;
    this.setBackground(Color.white);
    this.addMouseListener(this);
    this.setFocusable(true);    // Allow panel to get focus

    layerB = new JRadioButton("Layer");
    this.add(layerB);
    layerB.addMouseListener(this);
    bSave = new JButton("SAVE");
    bSave.addMouseListener(this);
    this.add(bSave);
    bOpen = new JButton("OPEN");
    bOpen.addMouseListener(this);
    this.add(bOpen);
    bBackground=new JButton("BACKGROUND");
    bBackground.addMouseListener(this);
    this.add(bBackground);
    

    icons.add(createImageIcon("textures/0.gif"));
    JButton tempButton = new JButton("DELETE", icons.get(0));
    buttons.add(tempButton);
    buttons.get(0).addMouseListener(this);

    buttons.get(0).setVerticalTextPosition(AbstractButton.BOTTOM);
    buttons.get(0).setHorizontalTextPosition(AbstractButton.CENTER);
    file = new File("textures/0.gif");
    tempImage = ImageIO.read(file);
    bFS.add(tempImage);
    this.add(buttons.get(0));

    int counter = 1;

    while (!(createImageIcon("textures/" + (counter) + ".gif") == null))
    {
      icons.add(createImageIcon("textures/" + (counter) + ".gif"));

      tempButton = new JButton("" + counter, icons.get(counter));
      buttons.add(tempButton);
      buttons.get(counter).addMouseListener(this);

      buttons.get(counter).setVerticalTextPosition(AbstractButton.BOTTOM);
      buttons.get(counter).setHorizontalTextPosition(AbstractButton.CENTER);
      //file=new File(RouteBuilderv2.class.getResource("textures/" + (counter) + ".gif").getFile());
      file = new File("textures/" + (counter) + ".gif");
    // System.out.println("textures/" + (counter) + ".gif");
    //System.out.println(file.canRead());
    //  System.out.println(file.getAbsoluteFile());
      tempImage = ImageIO.read(file);
      bFS.add(tempImage);
      this.add(buttons.get(counter));
      counter++;
      //adds each icon to array without hardcoding number of icons in
    }
    this.setPreferredSize(new Dimension(250, 15 * buttons.size()));
  }

  protected static ImageIcon createImageIcon(String path) throws MalformedURLException
  {
    //java.net.URL imgURL = RouteBuilderv2.class.getResource(path);
    //java.net.URL imgURL=new URL(path);
    File someFile=new File(path);
    if (someFile.exists())
    {
     //System.out.println(path);
      return new ImageIcon(path);
    }
    else
    {
      return null;
    }
  }

  public void updatePanelTiles(int[][][] updatedTiles)
  {
    tiles = updatedTiles;
  }

  @Override
  public void mouseClicked(MouseEvent e)
  {

    for (int i = 0; i < buttons.size(); i++)
    {
      if (buttons.get(i).equals(e.getComponent()))
      {
        selected = i;
        //System.out.println(selected);
      }
    }
    if(e.getComponent().equals(bBackground))
    {
      map.mPanel.fillBackground();
    }
    if (e.getComponent().equals(bSave))
    {
      Saver saver = new Saver(tiles);
      saver.setVisible(true);
      saver.requestFocus();
    }
    if (e.getComponent().equals(bOpen))
    {
      Opener opener = new Opener(select);
      opener.setVisible(true);
      opener.requestFocus();

    }
  }

  public void updateFileTiles(int[][][] fileTiles)
  {
    tiles = fileTiles;
    map.mPanel.tiles = tiles;
    map.mPanel.repaint();
  }

  @Override
  public void mousePressed(MouseEvent e)
  {
  }

  @Override
  public void mouseReleased(MouseEvent e)
  {
  }

  @Override
  public void mouseEntered(MouseEvent e)
  {
  }

  @Override
  public void mouseExited(MouseEvent e)
  {
  }
}

and here is the code where it is saved
Code:
public class Saver extends JFrame
{

  SaverPanel filePanel;

  public Saver(int[][][] tiles)
  {
    filePanel = new SaverPanel(tiles,this);
    this.getContentPane().setLayout(new BorderLayout());
    //   JLabel instructions = new JLabel("<html><ul><li>Type text.</li>"
    //           + "<li>Use arrow keys to move text.</li>"
    //           + "<li>Press shift arrows to move faster.</li></html>");
    //   this.getContentPane().add(instructions, BorderLayout.NORTH);
    this.getContentPane().add(filePanel, BorderLayout.WEST);
    filePanel.requestFocus();      // Give the panel focus.
    this.setTitle("Save");
    this.setAlwaysOnTop(rootPaneCheckingEnabled);
    this.pack();
  }
}

class SaverPanel extends JPanel implements MouseListener, ActionListener
{
  final int AREA_SIZE_X = 100;
  final int AREA_SIZE_Y = 100;
  final JTextField x = new JTextField(20);
  final JTextField y = new JTextField(20);
  JButton done;
  int[][][] saveTiles;
  Saver closeReference;
  public SaverPanel(int[][][] tiles,Saver closeR)
  {
    closeReference=closeR;
    done=new JButton("SAVE");
   done.addMouseListener(this);
   JLabel xLabel=new JLabel();
   xLabel.setText("x: ");
   xLabel.setBounds(0, 50, 50, 30);
   this.add(xLabel);
    saveTiles = tiles;
    x.setBounds(50, 50, 50, 20);
    x.addActionListener(this);
    this.add(x);

   JLabel yLabel=new JLabel();
   yLabel.setText("y: ");
   yLabel.setBounds(0, 100, 50, 30);
   this.add(yLabel);
    y.setBounds(50, 100, 50, 20);
    y.addActionListener(this);
    this.add(y);
    this.add(done);

    this.addMouseListener(this);
    this.setBackground(Color.white);
    this.setPreferredSize(new Dimension(250, 250));
    this.setFocusable(true);    // Allow panel to get focus 
  }

  public void save(int[][][] tiles) throws IOException
  {
    String fName = x.getText() + " x " + y.getText();
   // Writer writer = null;
    File fileNew = new File(fName);
    //make variable for name to be saved
    FileWriter fWriter=new FileWriter(fileNew);
    BufferedWriter writer = new BufferedWriter(fWriter);
    for (int i = 0; i < AREA_SIZE_X; i++)
    {
      for (int j = 0; j < AREA_SIZE_Y; j++)
      {
        String toBeSaved=""+tiles[i][j][0];
        writer.write(toBeSaved + ' ');
        for (int k = 1; k < 4; k++)
        {
            toBeSaved=""+tiles[i][j][k];
            writer.write(toBeSaved + ' ');
        }
        writer.flush();
        //fWriter.flush();
    //    System.out.println(i+"   "+j);
      }
    }
    writer.close();
    //fWriter.close();
//    writer.close();
  }

  @Override
  public void mouseClicked(MouseEvent e)
  {
    if (e.getComponent().equals(done))
    {
      if (x.getText() != null && y.getText() != null)
      {
        try
        {
          this.save(saveTiles);
          closeReference.dispose();
        }
        catch (IOException ex)
        {
          Logger.getLogger(SaverPanel.class.getName()).log(Level.SEVERE, null, ex);
        }
      }
      else
      {
        //display message to fill ouy x and y
      }

    }
  }

  @Override
  public void mousePressed(MouseEvent e)
  {
  }

  @Override
  public void mouseReleased(MouseEvent e)
  {
  }

  @Override
  public void mouseEntered(MouseEvent e)
  {
  }

  @Override
  public void mouseExited(MouseEvent e)
  {
  }

  @Override
  public void actionPerformed(ActionEvent e)
  {
   // throw new UnsupportedOperationException("Not supported yet.");
  }
}
 
Technology news on Phys.org
Do you want to create the tiled image in code, or can you use a stand-alone program?
 
I'd prefer to do it in the program. Make it all in one. And how would i do it with another program? all the program saves is a bunch of numbers that correspond to images. no actual images.
 
If you go the route of a standalone program, you basically make a system call and run the screenshot program of your choice that you should be to pass the coordinates of the shot as (command line) arguments as well as the name of the output file...or take a shot of the entire monitor and then open the image from within your Java program and crop the image to the coordinates of interest...you should know where your program's canvas is in screen coordinates.
 
Its a JScrollPane though. Can't get all of it on screen at once.
 
Doesn't JScrollPane have a 'print' method? maybe you can print the entire content even though it does not show up entirely in the screen...but print to a file, instead of to the printer or some trick like that.
 
Hey Yoyo_Guru and welcome to the forums.

I haven't used Java in roughly 10 years but I would recommend that you find if you can access to the screen buffer for your UI object. It might be in Graphics structures or something like that.

Once you get access to the screen-buffer, convert this to the format you need for GIF/JPEG/Whatever conversion and then pass it to a library (or your own code) to convert the whole thing.

Also if you have the images and the index array, just create a new 2D array and use a routine to get the output uncompressed memory representation of the image and tile them together. Then take this raw form and pass this to your image library.

The last method is going to definitely be implemented and will take a lot less time as well.
 
Last edited:

Similar threads

  • · Replies 14 ·
Replies
14
Views
6K
  • · Replies 1 ·
Replies
1
Views
909
  • · Replies 1 ·
Replies
1
Views
2K
Replies
1
Views
2K
  • · Replies 5 ·
Replies
5
Views
2K
  • · Replies 4 ·
Replies
4
Views
5K
  • · Replies 2 ·
Replies
2
Views
2K
  • · Replies 15 ·
Replies
15
Views
3K
  • · Replies 19 ·
Replies
19
Views
3K
  • · Replies 1 ·
Replies
1
Views
3K