Home  Contents

Clipping

In this part of the Java 2D tutorial, we will talk about clipping.

Clipping

Clipping is restricting of drawing to a certain area. This is done for efficiency reasons and to create various effects.

In the following example we will be clipping an image.

Clipping.java
package com.zetcode;

import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;


public class Clipping extends JPanel implements ActionListener {


    private int pos_x = 8;
    private int pos_y = 8;
    private int radius = 90;

    Timer timer;
    Image image;

    private double delta[] = { 3, 3 };

    public Clipping() {

        image = new ImageIcon("bardejov.png").getImage();

        timer = new Timer(15, this);
        timer.start();
    }

    public void paint(Graphics g) {
        super.paint(g);

        Graphics2D g2d = (Graphics2D) g;

        RenderingHints rh = new RenderingHints(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);


        rh.put(RenderingHints.KEY_RENDERING,
               RenderingHints.VALUE_RENDER_QUALITY);

        g2d.setClip(new Ellipse2D.Double(pos_x, pos_y, radius, radius));

        g2d.drawImage(image,  5, 5, null);
    }

    public static void main(String[] args) {

        JFrame frame = new JFrame("Clipping");
        frame.add(new Clipping());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(400, 300);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public void actionPerformed(ActionEvent e) {

        int w = getWidth();
        int h = getHeight();

        if (pos_x < 0) {
            delta[0] = Math.random() % 4 + 5;
        } else if (pos_x > w - radius) {
            delta[0] = -(Math.random() % 4 + 5);
        }

        if (pos_y < 0 ) {
            delta[1] = Math.random() % 4 + 5;
        } else if (pos_y > h - radius) {
            delta[1] = -(Math.random() % 4 + 5);
        }

        pos_x += delta[0];
        pos_y += delta[1];

        repaint();
    }
}

In this example, we will clip an image. A circle is moving on the screen and showing a part of the underlying image. This is as if we looked through a hole.

 g2d.setClip(new Ellipse2D.Double(pos_x, pos_y, radius, radius));

This is the key part of the code. Here we restrict drawing to a specific shape. In our case it is a circle.

 if (pos_x < 0) {
     delta[0] = Math.random() % 4 + 5;
 } else if (pos_x > w - radius) {
     delta[0] = -(Math.random() % 4 + 5);
 }

If the circle hits the left or the right side of the window, the direction of the circle movement changes randomly. Same for the top and bottom sides.


Clipping
Figure: Clipping

Clipping shapes

In the following example, we will be clipping two shapes. A rectangle and a circle.

ClippingShapes.java
package com.zetcode;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import java.awt.geom.GeneralPath;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;


public class ClippingShapes extends JPanel implements ActionListener {

    private Timer timer;

    private double rotate = 1;
    private int pos_x = 8;
    private int pos_y = 8;
    private int radius = 60;

    private double delta[] = { 1, 1 };


    public ClippingShapes() {
        timer = new Timer(10, this);
        timer.start();
    }


    public void paint(Graphics g) {

        super.paint(g);

        Graphics2D g2d = (Graphics2D)g;

        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                             RenderingHints.VALUE_ANTIALIAS_ON);

        g2d.setRenderingHint(RenderingHints.KEY_RENDERING,
                             RenderingHints.VALUE_RENDER_QUALITY);


        int w = getWidth();
        int h = getHeight();

        Rectangle rect1 = new Rectangle(0, 0, 200, 80);

        AffineTransform tx = new AffineTransform();
        tx.rotate(Math.toRadians(rotate), w / 2, h / 2);
        tx.translate(w / 2 - 100, h / 2 - 40);

        Ellipse2D circle = new Ellipse2D.Double(pos_x, pos_y, radius, radius);

        step();

        GeneralPath path = new GeneralPath();
        path.append(tx.createTransformedShape(rect1), false);

        g2d.setColor(new Color(110, 110, 110));
        g2d.clip(circle);
        g2d.clip(path);

        g2d.fill(circle);

        g2d.setClip(new Rectangle(0, 0, w, h));

        g2d.draw(circle);
        g2d.draw(path);

    }


    public void step() {
        int w = getWidth();
        int h = getHeight();

        if (pos_x < 0) {
            delta[0] = 1;
        } else if (pos_x > w - radius) {
            delta[0] = -1;
        }

        if (pos_y < 0) {
            delta[1] = 1;
        } else if (pos_y > h - radius) {
            delta[1] = -1;
        }

        pos_x += delta[0];
        pos_y += delta[1];
    }


    public static void main(String[] args) {
        JFrame frame = new JFrame("Clipping shapes");
        frame.add(new ClippingShapes());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(350, 300);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }


    public void actionPerformed(ActionEvent e) {
        rotate += 1;
        repaint();
    }
}

In our example, we have a bouncing circle and a rotating rectangle. When these shapes overlap, the resulting area is filled with color.

 Rectangle rect1 = new Rectangle(0, 0, 200, 80);

 AffineTransform tx = new AffineTransform();
 tx.rotate(Math.toRadians(rotate), w / 2, h / 2);
 tx.translate(w / 2 - 100, h / 2 - 40);

The rectangle is being rotated. It is always positioned in the middle of the panel.

 GeneralPath path = new GeneralPath();
 path.append(tx.createTransformedShape(rect1), false);

Here we get the shape of the rotated rectangle.

 g2d.clip(circle);
 g2d.clip(path);

 g2d.fill(circle)

Here we restrict drawing to these two shapes. If they overlap, the interior of the resulting shape is filled with color.

 g2d.setClip(new Rectangle(0, 0, w, h));

We reset the clip areas, before we draw the shapes.


Clipping Shapes
Figure: Clipping Shapes

In this part of the Java 2D tutorial, we have talked about clipping.