001 /* 002 * Shear 003 * 004 * Copyright (c) 2001, 2002 Marco Schmidt <marcoschmidt@users.sourceforge.net> 005 * All rights reserved. 006 */ 007 008 package net.sourceforge.jiu.geometry; 009 010 import net.sourceforge.jiu.data.PixelImage; 011 import net.sourceforge.jiu.data.IntegerImage; 012 import net.sourceforge.jiu.ops.ImageToImageOperation; 013 import net.sourceforge.jiu.ops.MissingParameterException; 014 import net.sourceforge.jiu.ops.WrongParameterException; 015 016 /** 017 * Shears an image by a given angle. 018 * The angle must be larger than -90 and smaller than 90 degrees. 019 * Shearing works with all image types that implement {@link net.sourceforge.jiu.data.IntegerImage}. 020 * <h3>Usage example</h3> 021 * <pre> 022 * Shear shear = new Shear(); 023 * shear.setInputImage(image); // some IntegerImage 024 * shear.setAngle(5.0); 025 * shear.process(); 026 * PixelImage shearedImage = shear.getOutputImage(); 027 * </pre> 028 * <p> 029 * This is an adjusted version of Jef Poskanzer's shearing code from his ACME 030 * package; see the 031 * <a target="_top" href="http://www.acme.com/java/software/Acme.JPM.Filters.Shear.html">API 032 * documentation page</a> of ACME's Shear class. 033 * 034 * @author Jef Poskanzer 035 * @author Marco Schmidt 036 */ 037 public class Shear extends ImageToImageOperation 038 { 039 private double angle; 040 041 /** 042 * For a given image width and shearing angle this method 043 * computes the width of the resulting image. 044 * This method is static so that it can be called easily from a GUI dialog 045 * or other objects that want to present the width of a sheared image. 046 * @param oldImageWidth horizontal resolution of the image to be sheared 047 * @param height height of the image to be sheared 048 * @param angle the angle to be used in the shearing operation 049 * @return width of the sheared image 050 */ 051 public static int computeNewImageWidth(int oldImageWidth, int height, double angle) 052 { 053 double shearfac = Math.tan(angle * Math.PI / 180.0); 054 if (shearfac < 0.0) 055 { 056 shearfac = -shearfac; 057 } 058 return (int)(height * shearfac + oldImageWidth + 0.999999); 059 } 060 061 /** 062 * Returns the angle associated with this shearing operation object. 063 * @return shearing angle, between -90 and 90 064 * @see #setAngle 065 */ 066 public double getAngle() 067 { 068 return angle; 069 } 070 071 private void process(IntegerImage in, IntegerImage out) 072 { 073 final int WIDTH = in.getWidth(); 074 final int HEIGHT = in.getHeight(); 075 int totalItems = in.getNumChannels() * HEIGHT; 076 int processedItems = 0; 077 double angle = getAngle() * Math.PI / 180.0; 078 double shearfac = Math.tan(angle); 079 if (shearfac < 0.0) 080 { 081 shearfac = -shearfac; 082 } 083 int NEW_WIDTH = (int)(HEIGHT * shearfac + WIDTH + 0.999999); 084 if (out == null) 085 { 086 out = (IntegerImage)in.createCompatibleImage(NEW_WIDTH, HEIGHT); 087 setOutputImage(out); 088 } 089 for (int c = 0; c < in.getNumChannels(); c++) 090 { 091 for (int y = 0; y < HEIGHT; y++) 092 { 093 double new0; 094 if (angle > 0.0) 095 { 096 new0 = y * shearfac; 097 } 098 else 099 { 100 new0 = (HEIGHT - y) * shearfac; 101 } 102 int intnew0 = (int)new0; 103 double fracnew0 = new0 - intnew0; 104 double omfracnew0 = 1.0 - fracnew0; 105 int prev = 0; 106 for (int x = 0; x < WIDTH; x++) 107 { 108 int value = in.getSample(c, x, y); 109 out.putSample(c, intnew0 + x, y, (int)(fracnew0 * prev + omfracnew0 * value)); 110 prev = value; 111 } 112 out.putSample(c, intnew0 + WIDTH, y, (int)(fracnew0 * prev)); 113 setProgress(processedItems++, totalItems); 114 } 115 } 116 } 117 118 public void process() throws 119 MissingParameterException, 120 WrongParameterException 121 { 122 ensureInputImageIsAvailable(); 123 PixelImage in = getInputImage(); 124 ensureOutputImageResolution(computeNewImageWidth(in.getWidth(), in.getHeight(), getAngle()), in.getHeight()); 125 if (in instanceof IntegerImage) 126 { 127 process((IntegerImage)in, (IntegerImage)getOutputImage()); 128 } 129 else 130 { 131 throw new WrongParameterException("Input image must implement IntegerImage."); 132 } 133 } 134 135 /** 136 * Sets the angle to be used in the shearing operation to the argument value. 137 * The angle must be larger than -90.0 and smaller than 90.0. 138 * @param newAngle the angle to be used in this operation 139 * @throws IllegalArgumentException if the argument is not in the above mentioned interval 140 * @see #getAngle 141 */ 142 public void setAngle(double newAngle) 143 { 144 if (newAngle <= -90.0 || newAngle >= 90.0) 145 { 146 throw new IllegalArgumentException("Angle must be > -90 and < 90; got " + newAngle); 147 } 148 else 149 { 150 angle = newAngle; 151 } 152 } 153 }