File: Crop.java

package info (click to toggle)
java-imaging-utilities 0.14.3-7
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,556 kB
  • sloc: java: 31,233; python: 71; xml: 31; makefile: 26; sh: 5
file content (156 lines) | stat: -rw-r--r-- 5,015 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
/*
 * Crop
 *
 * Copyright (c) 2001, 2002, 2003 Marco Schmidt.
 * All rights reserved.
 */

package net.sourceforge.jiu.geometry;

import net.sourceforge.jiu.data.PixelImage;
import net.sourceforge.jiu.data.IntegerImage;
import net.sourceforge.jiu.ops.ImageToImageOperation;
import net.sourceforge.jiu.ops.MissingParameterException;
import net.sourceforge.jiu.ops.WrongParameterException;

/**
 * Copies a rectangular area of one image to another image that is exactly as large
 * as that rectangular area.
 * Works with all image data classes implementing {@link net.sourceforge.jiu.data.IntegerImage}.
 * <em>Make sure to use zero-based parameters when defining the bounds with
 * {@link #setBounds}!</em>
 * <h3>Usage example</h3>
 * In this example we assume that the input image is larger than 20 pixels in both directions.
 * Ten pixels will be removed from any of its four borders.
 * <pre>
 * PixelImage image = ...; // something implementing IntegerImage
 * Crop crop = new Crop();
 * crop.setInputImage(image);
 * crop.setBounds(10, 10, image.getWidth() - 9, image.getHeight() - 9);
 * crop.process();
 * PixelImage croppedImage = crop.getOutputImage();
 * </pre>
 * @author Marco Schmidt
 */
public class Crop extends ImageToImageOperation
{
	private int x1;
	private int y1;
	private int x2;
	private int y2;

	private void checkBounds() throws WrongParameterException
	{
		PixelImage in = getInputImage();
		if (x1 >= in.getWidth())
		{
			throw new WrongParameterException("x1 must be smaller than input image width.");
		}
		if (x2 >= in.getWidth())
		{
			throw new WrongParameterException("x2 must be smaller than input image width.");
		}
		if (y1 >= in.getHeight())
		{
			throw new WrongParameterException("y1 must be smaller than input image height.");
		}
		if (y2 >= in.getHeight())
		{
			throw new WrongParameterException("y2 must be smaller than input image height.");
		}
	}

	private void process(IntegerImage in, IntegerImage out)
	{
		final int OUT_WIDTH = x2 - x1 + 1;
		final int OUT_HEIGHT = y2 - y1 + 1;
		if (out == null)
		{
			out = (IntegerImage)in.createCompatibleImage(OUT_WIDTH, OUT_HEIGHT);
			setOutputImage(out);
		}
		int totalItems = in.getNumChannels() * OUT_HEIGHT;
		int processedItems = 0;
		for (int c = 0; c < in.getNumChannels(); c++)
		{
			for (int yfrom = y1, yto = 0; yto < OUT_HEIGHT; yfrom++, yto++)
			{
				for (int xfrom = x1, xto = 0; xto < OUT_WIDTH; xfrom++, xto++)
				{
					out.putSample(c, xto, yto, in.getSample(c, xfrom, yfrom));
				}
				setProgress(processedItems++, totalItems);
			}
		}
	}

	public void process() throws
		MissingParameterException,
		WrongParameterException
	{
		ensureInputImageIsAvailable();
		checkBounds();
		ensureOutputImageResolution(x2 - x1 + 1, y2 - y1 + 1);
		if (getInputImage() instanceof IntegerImage)
		{
			process((IntegerImage)getInputImage(), (IntegerImage)getOutputImage());
		}
		else
		{
			throw new WrongParameterException("Input image must implement IntegerImage.");
		}
	}

	/**
	 * Specify the rectangular section of the original image that is to be
	 * copied to the output image by this operation.
	 * Note that the arguments are not checked directly against any input image that may have
	 * been provided to this Crop object, that checking is done later in {@link #process()}.
	 * If any of the arguments provided here are outside of the input image's resolution
	 * (e.g. x1 == 100 although the input image's width is only 60), a 
	 * {@link net.sourceforge.jiu.ops.WrongParameterException} will be thrown from
	 * within {@link #process()}.
	 * <p>
	 * Note that the arguments to this method are zero-based, so the first column and row
	 * are 0, the second 1, the third 2, and so on.
	 * If you have a image that is 200 pixels wide and 100 pixels high,
	 * values from 0 to 199 are valid for the x arguments, and values from 0 to 99 are valid
	 * for the vertical direction.
	 * @param x1 horizontal position of upper left corner of the rectangle
	 * @param y1 vertical position of upper left corner of the rectangle
	 * @param x2 horizontal position of lower right corner of the rectangle
	 * @param y2 vertical position of lower right corner of the rectangle
	 * @throws IllegalArgumentException if any of the arguments is negative or x1 larger than x2 or y1 larger than y2
	 */
	public void setBounds(int x1, int y1, int x2, int y2) throws IllegalArgumentException
	{
		if (x1 < 0)
		{
			throw new IllegalArgumentException("x1 must not be negative.");
		}
		if (y1 < 0)
		{
			throw new IllegalArgumentException("y1 must not be negative.");
		}
		if (x2 < 0)
		{
			throw new IllegalArgumentException("x2 must not be negative.");
		}
		if (y2 < 0)
		{
			throw new IllegalArgumentException("y2 must not be negative.");
		}
		if (x1 > x2)
		{
			throw new IllegalArgumentException("x1 must not be larger than x2.");
		}
		if (y1 > y2)
		{
			throw new IllegalArgumentException("y1 must not be larger than y2.");
		}
		this.x1 = x1;
		this.y1 = y1;
		this.x2 = x2;
		this.y2 = y2;
	}
}