File: Shear.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 (153 lines) | stat: -rw-r--r-- 4,382 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
/*
 * Shear
 * 
 * Copyright (c) 2001, 2002, 2003, 2004, 2005 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;

/**
 * Shears an image by a given angle.
 * The angle must be larger than -90 and smaller than 90 degrees.
 * Shearing works with all image types that implement {@link net.sourceforge.jiu.data.IntegerImage}.
 * <h3>Usage example</h3>
 * <pre>
 * Shear shear = new Shear();
 * shear.setInputImage(image); // some IntegerImage
 * shear.setAngle(5.0);
 * shear.process();
 * PixelImage shearedImage = shear.getOutputImage();
 * </pre>
 * <p>
 * This is an adjusted version of Jef Poskanzer's shearing code from his ACME
 * package; see the
 * <a target="_top" href="http://www.acme.com/java/software/Acme.JPM.Filters.Shear.html">API
 * documentation page</a> of ACME's Shear class.
 *
 * @author Jef Poskanzer
 * @author Marco Schmidt
 */
public class Shear extends ImageToImageOperation
{
	private double angle;

	/**
	 * For a given image width and shearing angle this method
	 * computes the width of the resulting image.
	 * This method is static so that it can be called easily from a GUI dialog
	 * or other objects that want to present the width of a sheared image.
	 * @param oldImageWidth horizontal resolution of the image to be sheared
	 * @param height height of the image to be sheared
	 * @param angle the angle to be used in the shearing operation
	 * @return width of the sheared image
	 */
	public static int computeNewImageWidth(int oldImageWidth, int height, double angle)
	{
		double shearfac = Math.tan(angle * Math.PI / 180.0);
		if (shearfac < 0.0)
		{
			shearfac = -shearfac;
		}
		return (int)(height * shearfac + oldImageWidth + 0.999999);
	}

	/**
	 * Returns the angle associated with this shearing operation object.
	 * @return shearing angle, between -90 and 90
	 * @see #setAngle
	 */
	public double getAngle()
	{
		return angle;
	}

	private void process(IntegerImage in, IntegerImage out)
	{
		final int WIDTH = in.getWidth();
		final int HEIGHT = in.getHeight();
		int totalItems = in.getNumChannels() * HEIGHT;
		int processedItems = 0;
		double angle = getAngle() * Math.PI / 180.0;
		double shearfac = Math.tan(angle);
		if (shearfac < 0.0)
		{
			shearfac = -shearfac;
		}
		int NEW_WIDTH = (int)(HEIGHT * shearfac + WIDTH + 0.999999);
		if (out == null)
		{
			out = (IntegerImage)in.createCompatibleImage(NEW_WIDTH, HEIGHT);
			setOutputImage(out);
		}
		for (int c = 0; c < in.getNumChannels(); c++)
		{
			for (int y = 0; y < HEIGHT; y++)
			{
				double new0;
				if (angle > 0.0)
				{
					new0 = y * shearfac;
				}
				else
				{
					new0 = (HEIGHT - y) * shearfac;
				}
				int intnew0 = (int)new0;
				double fracnew0 = new0 - intnew0;
				double omfracnew0 = 1.0 - fracnew0;
				int prev = 0;
				for (int x = 0; x < WIDTH; x++)
				{
					int value = in.getSample(c, x, y);
					out.putSample(c, intnew0 + x, y, (int)(fracnew0 * prev + omfracnew0 * value));
					prev = value;
				}
				out.putSample(c, intnew0 + WIDTH, y, (int)(fracnew0 * prev));
				setProgress(processedItems++, totalItems);
			}
		}
	}

	public void process() throws
		MissingParameterException,
		WrongParameterException
	{
		ensureInputImageIsAvailable();
		PixelImage in = getInputImage();
		ensureOutputImageResolution(computeNewImageWidth(in.getWidth(), in.getHeight(), getAngle()), in.getHeight());
		if (in instanceof IntegerImage)
		{
			process((IntegerImage)in, (IntegerImage)getOutputImage());
		}
		else
		{
			throw new WrongParameterException("Input image must implement IntegerImage.");
		}
	}

	/**
	 * Sets the angle to be used in the shearing operation to the argument value.
	 * The angle must be larger than -90.0 and smaller than 90.0.
	 * @param newAngle the angle to be used in this operation
	 * @throws IllegalArgumentException if the argument is not in the above mentioned interval
	 * @see #getAngle
	 */
	public void setAngle(double newAngle)
	{
		if (newAngle <= -90.0 || newAngle >= 90.0)
		{
			throw new IllegalArgumentException("Angle must be > -90 and < 90; got " + newAngle);
		}
		else
		{
			angle = newAngle;
		}
	}
}