/** Marvin Project <2007-2009> Initial version by: Danilo Rosetto Munoz Fabio Andrijauskas Gabriel Ambrosio Archanjo site: http://marvinproject.sourceforge.net GPL Copyright (C) <2007> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ package org.marvinproject.image.transform.skew; import marvin.gui.MarvinFilterWindow; import marvin.image.MarvinImage; import marvin.image.MarvinImageMask; import marvin.plugin.MarvinAbstractImagePlugin; import marvin.util.MarvinAttributes; /** * Perform a vertical OR horizontal skew of an image. * @author Barry McCullagh * @version 01/30/2009 */ public class Skew extends MarvinAbstractImagePlugin { private final static String HORIZONTAL = "Horizontal"; private final static String VERTICAL = "Vertical"; private int SELECTEDANGLE = 0; MarvinAttributes attributes; public void load(){ attributes = getAttributes(); attributes.set("skew", "horizontal"); attributes.set("selected", String.valueOf(SELECTEDANGLE)); } /** * Displays the interface to the Skew plug-in. * Adds a horizontal/vertical combo box so the direction can be selected. * Adds a slider so the magnitude of the angle can be selected. * * @param - none. * @return - void. */ public void show(){ MarvinFilterWindow l_filterWindow = new MarvinFilterWindow("Skew", 400,350, getImagePanel(), this); l_filterWindow.addLabel("labelSkew", "Skew:"); l_filterWindow.addComboBox("combpSkew", "skew", new Object[]{HORIZONTAL, VERTICAL}, attributes); l_filterWindow.newComponentRow(); l_filterWindow.addLabel("lblSkewAngle", "SkewAngle"); l_filterWindow.addHorizontalSlider("sliderSkewAngle", "SkewAngle", -89, 89, 0, attributes); l_filterWindow.newComponentRow(); /* //In future versions it would be nice to be able to tell the user the selected //skew angle, but at present, I can't set the value for a text field added here //in other methods l_filterWindow.addLabel("lblSelectedAngle", "Selected Angle: "); l_filterWindow.addTextField("txtfieldSelectedAngle", "selected", attributes); */ l_filterWindow.setVisible(true); } /** * Handles the 'Process' button being pressed. * Determines the angle to skew and if the user wants * a horizontal or vertical skew. * * @param MarvinImage - the image to be skewed * @param boolean - if a preview is being performed * @return - void */ public void process ( MarvinImage a_imageIn, MarvinImage a_imageOut, MarvinAttributes a_attributesOut, MarvinImageMask a_mask, boolean a_previewMode ) { //find the desired direction String l_operation = (String)attributes.get("skew"); //find the desired angle and convert from degrees to rads int s_angle = (Integer)attributes.get("SkewAngle"); double s_angle_rad = (double)(Math.toRadians(s_angle)); if(l_operation.equals(HORIZONTAL)) { skewHorizontal(a_imageIn, a_imageOut, s_angle_rad); } else { skewVertical(a_imageIn, a_imageOut, s_angle_rad); } } /** * Perform a horizontal skew of the input image (a_image). The maximum skew in each direction is 89 degrees. * * @param a_image The input image to be skewed. * @param skew_angle_rad The amount of skew to be performed. * @return void * @see MarvinImage */ private void skewHorizontal(MarvinImage a_imageIn, MarvinImage a_imageOut, double a_skewAngleRad) { int r,g,b; //get image dimensions int l_aHeight = a_imageIn.getHeight(); int l_aWidth = a_imageIn.getWidth(); //a local copy of the image, used to store a copy of the original image. //MarvinImage l_image = (MarvinImage)a_image.clone(); //Calculate the width of the new image. //l_extraWidth is not made absolute as it tells us if the skew is to be performed //to the left or right. int l_extraWidth = (int)(Math.ceil(l_aHeight * Math.tan(a_skewAngleRad))); int l_newWidth = l_aWidth + Math.abs(l_extraWidth); //The modifications must be performed on a_image so erase the contents //of a_image so the skewed image can be put there. for(int xx = 0; xx < l_aWidth; xx++) { for(int yy = 0; yy < l_aHeight; yy++) { a_imageOut.setIntColor(xx, yy, 000000); } } a_imageOut.resize(l_newWidth, l_aHeight); //The top of the image is being moved to the right. //The amount each row moves depends on its height, calculated as l_newXcoordinate. if(l_extraWidth > 0) { for (int x = 0; x < l_aWidth; x++) { for (int y = 0; y < l_aHeight; y++){ int l_newXcoordinate = x + (int)(Math.abs((y - l_aHeight) * Math.tan(a_skewAngleRad))); r = a_imageIn.getIntComponent0(x, y); g = a_imageIn.getIntComponent1(x, y); b = a_imageIn.getIntComponent2(x, y); a_imageOut.setIntColor(l_newXcoordinate, y, r, g, b); } } } //The top of the image is being moved to the left. //The amount each row moves depends on its height, calculated as l_newXcoordinate else { for (int x = 0; x < l_aWidth; x++) { for (int y = l_aHeight-1; y >= 0; y--){ int new_xcoordinate = x + (int)(Math.abs((y) * Math.tan(a_skewAngleRad))); r = a_imageIn.getIntComponent0(x, y); g = a_imageIn.getIntComponent1(x, y); b = a_imageIn.getIntComponent2(x, y); a_imageOut.setIntColor(new_xcoordinate, y, r, g, b); } } } } /** * Perform a vertical skew of the input image * @param MarvinImage a_image * @param double skew_angle_rad * @return void * @see MarvinImage */ private void skewVertical(MarvinImage a_imageIn, MarvinImage a_imageOut, double a_skewAngleRad) { //The modifications must be applied to the image passed to the function (a_image). //Make a local copy of the image to store the data and modify the passed image. //MarvinImage l_image = (MarvinImage)(a_image.clone()); int r, g, b; int l_newYcoordinate; //Get the image dimensions int l_aWidth = a_imageIn.getWidth(); int l_aHeight = a_imageIn.getHeight(); //Calculate the dimensions of the modified image then resize a_image so that //can store the skewed image. The contents are also empties. int l_extraHeight = (int)Math.ceil(l_aWidth * Math.tan(a_skewAngleRad)); int l_newHeight = l_aHeight + Math.abs(l_extraHeight); for(int xx = 0; xx < l_aWidth; xx++) { for(int yy = 0; yy < l_aHeight; yy++) { a_imageOut.setIntColor(xx, yy, 000000); } } a_imageOut.resize(l_aWidth, l_newHeight); //Calculate the new coordinate of each pixel. If the image is being skewed //up or down (relative to the left hand column of pixels) a different calculation //must be performed for (int x = 0; x < l_aWidth; x++) { for (int y = 0; y < l_aHeight; y++){ //for a skew 'down' if (l_extraHeight > 0) { l_newYcoordinate = y + (int)((x) * Math.tan(a_skewAngleRad)); } //for a skew 'up' else { l_newYcoordinate = (l_newHeight) -(l_aHeight) + y - (int)Math.abs(((x) * Math.tan(a_skewAngleRad))); } r = a_imageIn.getIntComponent0(x, y); g = a_imageIn.getIntComponent1(x, y); b = a_imageIn.getIntComponent2(x, y); a_imageOut.setIntColor(x, l_newYcoordinate, r, g, b); } } } }