1

I need the simplest way to rescale a drawing in java (for example a rectangle...). I found a way to "stretch" them:

import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
import java.awt.Dimension;

public class Stretch extends JFrame {
    int originalHeight = 600;
    int originalWidth = 600;
    public Stretch() {
        super("Stretch");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(originalWidth, originalHeight);
    }
    public static void main(String[] args) {
        Stretch s = new Stretch();
        s.setVisible(true);
    }
    public void paint(Graphics g) {
        Dimension size = this.getBounds().getSize();
        int rectWidth = 100;
        int rectHeight = 130;

        g.setColor(Color.white);
        g.fillRect(0, 0, size.width, size.height);

        g.setColor(Color.black);
        g.drawRect(100, 100, rectWidth + size.width - originalWidth, rectHeight + size.height - originalHeight);

    }
}

As you can see the formula is like that:

g.drawRect(100, 100, rectWidth + size.width - originalWidth, rectHeight + size.height - originalHeight);

Now how can I rescale the drawing? Width and height have to maintain the same proportion. Thank you.

Cris
  • 549
  • 5
  • 21
  • I'm not sure what the drawing is. Is it the rectangle? or is the rectangle just a placeholder for a more complex drawing? – Itai Bar-Haim Mar 20 '16 at 14:30
  • Anyway, if you want to scale vector graphics such as the rectangle in question, and you want to maintain ratio, just recalculate the target size by maintaining the ratio: first calculate the ratio, then select a width (or height) and multiply (or divide) it by the ratio to get the other dimension. – Itai Bar-Haim Mar 20 '16 at 14:32
  • The simplest way is to use a `Rectangle` or `Rectangle2D` and simple apply a scaled `AffineTransform` to it. Otherwise you could scale the properties or the `Graphics` context – MadProgrammer Mar 20 '16 at 21:12
  • For [shape resizing example](http://stackoverflow.com/questions/29067700/how-can-i-change-the-size-of-a-figure-made-in-java-graphics2d-with-a-slider/29067753#29067753), [`Graphics` scaling](http://stackoverflow.com/questions/19643637/zoom-using-mouse-and-graphics/19646246#19646246) or if you're really adventures [this example](http://stackoverflow.com/questions/21174997/how-to-add-mouselistener-to-item-on-java-swing-canvas/21175125#21175125) – MadProgrammer Mar 20 '16 at 21:17
  • 1
    Given the comment to my answer, the question is obviously not about rescaling a drawing, but about computing some values so that it looks like you want it. Be more clear about that. – Marco13 Mar 21 '16 at 12:12

2 Answers2

1

There are bascially two different approaches for this:

  • You can "scale the whole Graphics"
  • You can scale the actual shapes

The difference may be subtle in some cases, but can be important: When you scale the whole Graphics, then everything will be scaled. Particularly, when you scale it about 2.0, and then draw a line with a width of 1.0, the line will be drawn 2 pixels wide. Whether or not this is desired depends on the application case.

In order to scale the actual shapes, you can not use the drawRect method. Instead you will have to create Shape instances that represent the geometric shapes. You can then create scaled versions of these shapes with AffineTransform#createTransformedShape.

Here is an example that compares both approaches (and corrects some of the other issues that have been in your code). In both cases, the same rectangle with an original size of (10,13) is painted, scaled by a factor of 5.0.

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class ScalingDrawnObjects
{
    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                createAndShowGUI();
            }
        });
    }

    private static void createAndShowGUI()
    {
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        ScalingDrawnObjectsPanel p = new ScalingDrawnObjectsPanel();
        f.getContentPane().add(p);
        f.setSize(600,400);
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }
}

class ScalingDrawnObjectsPanel extends JPanel
{
    @Override
    protected void paintComponent(Graphics gr)
    {
        super.paintComponent(gr);
        Graphics2D g = (Graphics2D)gr;

        Shape rectangle = new Rectangle2D.Double(2, 2, 10, 13);

        g.setColor(Color.RED);
        drawWithScaledGraphics(g, rectangle);

        g.translate(100, 0);

        drawScaledObject(g, rectangle);
    }

    private static void drawWithScaledGraphics(Graphics2D g, Shape shape)
    {
        AffineTransform oldAt = g.getTransform();
        g.scale(5.0, 5.0);
        g.draw(shape);
        g.setTransform(oldAt);
    }

    private static void drawScaledObject(Graphics2D g, Shape shape)
    {
        AffineTransform at = AffineTransform.getScaleInstance(5.0, 5.0);
        g.draw(at.createTransformedShape(shape));
    }

}

EDIT In response to the comment

The code that I posted is not "complicated". It is as compilcated as it has to be, but not more. You should not extend JFrame and you should not override paint. You should create the GUI on the EDT. You should ...

However, you should not use code like the following, but maybe this is what you're looking for

import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
import java.awt.Dimension;

public class Stretch extends JFrame {
    int originalHeight = 600;
    int originalWidth = 600;
    public Stretch() {
        super("Stretch");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(originalWidth, originalHeight);
    }
    public static void main(String[] args) {
        Stretch s = new Stretch();
        s.setVisible(true);
    }
    public void paint(Graphics g) {
        Dimension size = this.getBounds().getSize();
        int rectWidth = 100;
        int rectHeight = 130;

        g.setColor(Color.white);
        g.fillRect(0, 0, size.width, size.height);

        g.setColor(Color.black);

        int w = rectWidth + size.width - originalWidth;
        int h = rectHeight + size.height - originalHeight;
        double sx = (double)w / rectWidth;
        double sy = (double)h / rectHeight;
        double s = Math.min(sx, sy);
        int fw = (int)(s * rectWidth);
        int fh = (int)(s * rectHeight);
        g.drawRect(100, 100, fw, fh);

    }
}
Marco13
  • 53,703
  • 9
  • 80
  • 159
  • Thank you, but this is way too complicated for my purpose, the solution is just a formula I think – Cris Mar 21 '16 at 11:42
  • I'm sorry, could you please explain me the reasons why shouldn't I override paint and extend JFrame please? Thank you for your last code, perfect. – Cris Mar 21 '16 at 14:11
  • 1
    [Why you should not extend JFrame](http://stackoverflow.com/questions/1143923/why-shouldnt-you-extend-jframe-and-other-components). A `JFrame` is a complex top-level component, and its `paint` method does a lot of internal management (you may see that your drawing flickers when you resize the frame. That's because you have overridden `paint`, and it can no longer work correctly). If you only want to paint something, you should use "the simplest possible component", which would be a `JPanel` where you override `paintComponent` - as shown in the first code snippet. – Marco13 Mar 21 '16 at 14:28
0

How about multiplying the width and the height by the scale you want?

So if you want to scale it by 2:

g.drawRect(100, 100, 2 * (rectWidth + size.width - originalWidth), 2 * (rectHeight + size.height - originalHeight));
Reshun
  • 1
  • 1