Implementing zoom >.<

I have a question on implementing zoom on my paint program. I dont understand how exactly it would be done.

you have your canvas, and you can draw each pixel (a fillRect with 1 pixel x 1 pixel) well, i want to be able to zoom in, so you can see each individual pixel and do pixel art, but this zoom also needs to be in a scroll pane.

So how exactly would i go about doing this?

Use the version of drawImage that allows you to set the desitnation rectangle and set it to whatever your zoom multiple is.

well… thats great if im wanting to zoom in on an image, but im working with an array of rectangles (the pixels that are drawn)

or should i convert that arraylist of rectangles to a jpg somehow, and just draw ontop of the jpeg (great except when they erase and area)

question: should i just figure out the size of my image, and do some math with that + the zoom ratio and then size the rectangles accordingly? or is there a easier way.

heres my code:

Main Class


package version01;

import java.awt.*;
import java.awt.image.*;
import javax.swing.*;

public class SeqyPaint{
	JFrame frame;
	JPanel panel;
	
	public SeqyPaint(){
		frame = new JFrame("Seqy Paint");
		frame.setSize(100,100);
		//panel = new JPanel(new FlowLayout());
		addWidgets(frame.getContentPane());
		//frame.getContentPane().add(panel);
		//frame.pack();
		frame.setSize(500,500);
		frame.setVisible(true);
	}
	public void addWidgets(Container container){
		DrawingArea drawing = new DrawingArea(this);
		container.add(drawing);
	}
	public static void createAndShowGUI(){
		SeqyPaint sp = new SeqyPaint();
	}
	public static void main(String[] args){
		javax.swing.SwingUtilities.invokeLater(new Runnable(){
			public void run(){
				createAndShowGUI();
			}
		});
	}
}

Drawing canvas


package version01;

import javax.swing.JComponent;
import java.awt.*;
import java.awt.event.*;
import java.util.*;

public class DrawingArea extends JComponent implements MouseListener{
	SeqyPaint controller;
	ArrayList pixels;
	public DrawingArea(SeqyPaint controller){
		this.controller = controller;
		pixels = new ArrayList();
		addMouseListener(this);
	}
	public void paintComponent(Graphics g){
		g.setColor(Color.BLUE);
		g.fillRect(0,0,getWidth(), getHeight());
		g.setColor(Color.GREEN);
		g.drawRect(0,0,100,100);
		
		drawPixels(g);
	}
	public void drawPixels(Graphics g){
		for(int i=0;i<pixels.size();i++){
			Pixel t = (Pixel)pixels.get(i);
			g.setColor(new Color(t.R, t.B, t.G));
			g.fillOval(t.p.x, t.p.y, 10, 10);
		}
	}
	public void addPixel(MouseEvent e){
		Pixel t = new Pixel();
		t.R = 100;
		t.G = 255;
		t.B = 45;
		t.p = e.getPoint();
		pixels.add(t);
	}
	public void mouseEntered(MouseEvent e){}
	public void mousePressed(MouseEvent e){}
	public void mouseReleased(MouseEvent e){}
	public void mouseClicked(MouseEvent e){
		addPixel(e);
		repaint();
	}
	public void mouseExited(MouseEvent e){}
}

Pixel (the rectangle)


package version01;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class Pixel{
	int R, B, G;
	Point p;
	
	public Pixel(){
	}
	
}

This might help:

import java.awt.*;
import java.awt.image.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import javax.imageio.*;
import javax.swing.*;

public class Test extends JPanel implements KeyListener {
    Color colors[][];
    double scale = 1.0;

    public Test() {
        colors = new Color[20][20];
        for(int x=0;x<20;x++) {
            for(int y=0;y<20;y++) {
                colors[x][y] = new Color((float)Math.random(), (float)Math.random(), (float)Math.random());
            }
        }
        addKeyListener(this);
    }
    public void keyTyped(KeyEvent e){}
    public void keyPressed(KeyEvent e){
        if(e.getKeyCode() == KeyEvent.VK_UP) {
            scale += 0.1;
            repaint();
        }
        else if(e.getKeyCode() == KeyEvent.VK_DOWN) {
            scale -= 0.1;
            repaint();
        }
    }
    public void keyReleased(KeyEvent e){}
    public Dimension getPreferredSize() {
        return new Dimension(400, 300);
    }
    public void paintComponent(Graphics g) {
        Graphics2D g2 = (Graphics2D)g;
        super.paintComponent(g2);
        g2.scale(scale, scale);
        for(int x=0;x<20;x++) {
            for(int y=0;y<20;y++) {
                g2.setColor(colors[x][y]);
                g2.drawLine(x, y, x, y);
            }
        }
    }
    public static void main(String args[]) {
        JFrame f = new JFrame();
        Test t = new Test();
        f.addKeyListener(t);
        f.getContentPane().add(t);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.pack();
        f.setVisible(true);
    }
}

that works nicely, but what about snapping the squares to grid, like you cant overlap them cause their the size of the pixel just inlarged? im guessing its time for math? if so i can figure that out.

Are you sure representing the image with an array of rectangles is the easiest way? just use a BufferedImage.

hehe as i just figured out it isnt (starts to lag incredibly after about 100 squares)
ive looked at bufferedimage api and i didnt know you could create something that you could draw on, how do you do that?

i got my zoom working perfectly thank youCaptainJester! =D

ive done some research into drawing on a buffered image and came up with some hits yay for google

basically you create the buffered image, use that to create a graphics, then draw on that, then you draw the image

but i still need to know where to draw new pixels and stuff…

what about still keeping my aray of pixels, but whenever i draw them to the image, remove them from the array, that way im only computing the newest pixels into the image.? doesnt sound that clean but cleaner that what i have atm lol

Im not sure I am fully understanding your design/issue BUT…

Are you aware that you can get a Raster from a buffered image and set/get your pixels directly in that?

Im not sure why you need another data structure at all…

The buffered image has a method setRGB(int x, int y, int argb) so you can modify directly the colors in the image.
Rafael.-

Hehe your right Jeff, i dont fully understand it, but thats why im doing this =) to learn.

hrmm… well i got it working perfectly last night, i could zoom, anddraw on my buffered image and everything, with no performance issues (that i saw)

but my way of doing it might be a bad design…

what i do currently is i put my bufferedImage into a HashMap, then i call it from the hashmap, use “bufferedimage.createGraphics()” to get the Graphics2D, then i tell my brush class to draw itself on the image given the Graphics2D, since i have different brushes i figured creating a class for each brush implementing a brush interface would work for that. after the brush is finished doing its thing, the main loop just paints it to the scrollpane.

so what would be better for drawing, setRBG/Raster, or just using the graphics2d class to draw ? (it seems it would be easier to implement flow and opacity using the Graphics2D class than using rasters/setrbg, or am i wrong?)

Using the higher level Graphcis commands are preferrable as they give you the best chance of getting hardware aceleration. So you are doing it right itr sounds like.

I only mentioned that you can set as well as get pixels witha Raster inc ase you were doing something that had to be software rendered on a per-pixel bases.