All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.day.image.DistortOp Maven / Gradle / Ivy

/*************************************************************************
 *
 * ADOBE CONFIDENTIAL
 * __________________
 *
 *  Copyright 2012 Adobe Systems Incorporated
 *  All Rights Reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of Adobe Systems Incorporated and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to Adobe Systems Incorporated and its
 * suppliers and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from Adobe Systems Incorporated.
 **************************************************************************/
package com.day.image;

import java.awt.Color;
import java.awt.Rectangle;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;

/**
 * The DistortOp class implements the distortion operation on a
 * BufferedImage. The rectangular image is distorted such that the
 * orignal corners of the image are at four new coordinate locations. This
 * distortion is generally not linear and requires quite some calculation.
 * 

* * NOTE: This operation works uses copies of the full image to caclulate the * new image. This takes an amount of memory relative to the size of the image. * To calculate the needed space let srcWidth and srcHeight be the width and * height, resp., of the source and dstWidth and dstHeight be the width and * height, resp., of the destination image. Then the the source image needs : * srcWidth * srcHeight * 4 channels * 4 bytes per sample bytes and the * destination image needs dstWidth * dstHeight * 4 channels * 4 bytes. * * * @version $Revision$ * @author fmeschbe * @since coati * @audience wad */ public class DistortOp extends AbstractBufferedImageOp { /** The coordinates */ private final double x00; private final double x01; private final double x10; private final double x11; private final double y00; private final double y01; private final double y10; private final double y11; /** Whether to crop the result to the current size */ private final boolean crop; /** the background color for unlit pixels */ private final Color bgColor; /** * Creates the DistortOp object by supplying the coordinates * of the new corners of the image, where the result is not cropped and * pixels not filled with any part of the distorted image is replaced with * black. * * @param coords 4x2 matrix describing an array of 4 scale factors by which * to transform each corner of an image distorted image in order * top/left, top/right, bottom/left, bottom/right. * * @throws IllegalArgumentException if not enough - namely four - coordinate * pairs are supplied to the constructor. * @throws NullPointerException if the coords parameter is null * or if any of the coordinates is null. */ public DistortOp(float[][] coords) { this(coords, false, Color.black); } /** * Creates the DistortOp object by supplying the coordinates * of the new corners of the image. * * @param coords 4x2 matrix describing an array of 4 scale factors by which * to transform each corner of an image distorted image in order * top/left, top/right, bottom/left, bottom/right. * @param crop true if the result should be cropped to the * size of the source image. * @param bgColor The color to use for pixels not covered by the distorted * part of the image. * * @throws IllegalArgumentException if not enough - namely four - coordinate * pairs are supplied to the constructor. * @throws NullPointerException if the coords parameter is null * or if any of the coordinates is null. */ public DistortOp(float[][] coords, boolean crop, Color bgColor) { super(null); // check arguments if (coords == null) { throw new NullPointerException("coords"); } if (coords.length < 3) { throw new IllegalArgumentException("need 4 coordinate pairs"); } for (int i=0; i < 4; i++) { if (coords[i] == null) { throw new NullPointerException("coords[" + i + "]"); } if (coords[i].length < 2) { throw new IllegalArgumentException("missing value on coords[" + i + "]"); } } // assign values this.x00 = coords[0][0]; this.y00 = coords[0][1]; this.x10 = coords[1][0]; this.y10 = coords[1][1]; this.x01 = coords[2][0]; this.y01 = coords[2][1]; this.x11 = coords[3][0]; this.y11 = coords[3][1]; this.crop = crop; this.bgColor = bgColor; } //----------- BufferedImageOp interface ------------------------------------ /** * Returns the bounding box of the filtered destination image. * The IllegalArgumentException may be thrown if the source * image is incompatible with the types of images allowed * by the class implementing this filter. */ public Rectangle2D getBounds2D(BufferedImage src) { if (crop) { double x0 = x00 < x01 ? x00 : x01; double y0 = y00 < y10 ? y00 : y10; double x1 = x10 > x11 ? x10 : x11; double y1 = y01 > y11 ? y01 : y11; return new Rectangle((int) Math.ceil((x1-x0) * src.getWidth()), (int) Math.ceil((y1-y0) * src.getHeight())); } else { return super.getBounds2D(src); } } /** * Returns the location of the destination point given a * point in the source image. If dstPt is non-null, it * will be used to hold the return value. */ public Point2D getPoint2D(Point2D srcPt, Point2D dstPt) { return super.getPoint2D(srcPt, dstPt); } //---------- protected ----------------------------------------------------- protected void doFilter(BufferedImage src, BufferedImage dst) { // get dimensions int sw = src.getWidth(); int sh = src.getHeight(); int dw = dst.getWidth(); int dh = dst.getHeight(); // get local copies of the field values double x00 = this.x00; double y00 = this.y00; double x01 = this.x01; double y01 = this.y01; double x10 = this.x10; double y10 = this.y10; double x11 = this.x11; double y11 = this.y11; // calculate crop if (crop) { double x0 = x00 < x01 ? x00 : x01; double y0 = y00 < y10 ? y00 : y10; x00 -= x0; x01 -= x0; x10 -= x0; x11 -= x0; y00 -= y0; y01 -= y0; y10 -= y0; y11 -= y0; } // coefficients double b00, b01, b02, b10, b11, b12, b20, b21, b22; b00 = ((-y00 + y01)*(x10*y00 - x11*y00 - x00*y10 + x11*y10 + x00*y11 - x10*y11)*(x10*y01 - x11*y01 - x01*y10 + x11*y10 + x01*y11 - x10*y11)); b10 = ((y00 - y10)*(x01*y00 - x11*y00 - x00*y01 + x11*y01 + x00*y11 - x01*y11)*(-(x10*y01) + x11*y01 + x01*y10 - x11*y10 - x01*y11 + x10*y11)); b20 = (-(x10*x10*y00*y00*y01) + 2*x10*x11*y00*y00*y01 - x11*x11*y00*y00*y01 + x10*x10*y00*y01*y01 - 2*x10*x11*y00*y01*y01 + x11*x11*y00*y01*y01 + x01*x01*y00*y00*y10 - 2*x01*x11*y00*y00*y10 + x11*x11*y00*y00*y10 - 2*x00*x01*y00*y01*y10 + 2*x00*x10*y00*y01*y10 + 2*x01*x11*y00*y01*y10 - 2*x10*x11*y00*y01*y10 + x00*x00*y01*y01*y10 - 2*x00*x10*y01*y01*y10 + 2*x10*x11*y01*y01*y10 - x11*x11*y01*y01*y10 - x01*x01*y00*y10*y10 + 2*x01*x11*y00*y10*y10 - x11*x11*y00*y10*y10 - x00*x00*y01*y10*y10 + 2*x00*x01*y01*y10*y10 - 2*x01*x11*y01*y10*y10 + x11*x11*y01*y10*y10 - x01*x01*y00*y00*y11 + x10*x10*y00*y00*y11 + 2*x01*x11*y00*y00*y11 - 2*x10*x11*y00*y00*y11 + 2*x00*x01*y00*y01*y11 - 2*x00*x10*y00*y01*y11 - 2*x01*x11*y00*y01*y11 + 2*x10*x11*y00*y01*y11 - x00*x00*y01*y01*y11 + 2*x00*x10*y01*y01*y11 - x10*x10*y01*y01*y11 + 2*x00*x01*y00*y10*y11 - 2*x00*x10*y00*y10*y11 - 2*x01*x11*y00*y10*y11 + 2*x10*x11*y00*y10*y11 - 2*x00*x01*y01*y10*y11 + 2*x00*x10*y01*y10*y11 + 2*x01*x11*y01*y10*y11 - 2*x10*x11*y01*y10*y11 + x00*x00*y10*y10*y11 - 2*x00*x01*y10*y10*y11 + x01*x01*y10*y10*y11 - 2*x00*x01*y00*y11*y11 + x01*x01*y00*y11*y11 + 2*x00*x10*y00*y11*y11 - x10*x10*y00*y11*y11 + x00*x00*y01*y11*y11 - 2*x00*x10*y01*y11*y11 + x10*x10*y01*y11*y11 - x00*x00*y10*y11*y11 + 2*x00*x01*y10*y11*y11 - x01*x01*y10*y11*y11); b01 = ((-x00 + x01)*(x10*y01 - x11*y01 - x01*y10 + x11*y10 + x01*y11 - x10*y11)*(-(x10*y00) + x11*y00 + x00*y10 - x11*y10 - x00*y11 + x10*y11)); b11 = ((-x00 + x10)*(-(x01*y00) + x11*y00 + x00*y01 - x11*y01 - x00*y11 + x01*y11)*(x10*y01 - x11*y01 - x01*y10 + x11*y10 + x01*y11 - x10*y11)); b21 = (-(x01*x01*x10*y00*y00) + x01*x10*x10*y00*y00 + x01*x01*x11*y00*y00 - x10*x10*x11*y00*y00 - x01*x11*x11*y00*y00 + x10*x11*x11*y00*y00 + 2*x00*x01*x10*y00*y01 - 2*x01*x10*x10*y00*y01 - 2*x00*x01*x11*y00*y01 - 2*x00*x10*x11*y00*y01 + 2*x01*x10*x11*y00*y01 + 2*x10*x10*x11*y00*y01 + 2*x00*x11*x11*y00*y01 - 2*x10*x11*x11*y00*y01 - x00*x00*x10*y01*y01 + x00*x10*x10*y01*y01 + x00*x00*x11*y01*y01 - x10*x10*x11*y01*y01 - x00*x11*x11*y01*y01 + x10*x11*x11*y01*y01 - 2*x00*x01*x10*y00*y10 + 2*x01*x01*x10*y00*y10 + 2*x00*x01*x11*y00*y10 - 2*x01*x01*x11*y00*y10 + 2*x00*x10*x11*y00*y10 - 2*x01*x10*x11*y00*y10 - 2*x00*x11*x11*y00*y10 + 2*x01*x11*x11*y00*y10 + x00*x00*x01*y10*y10 - x00*x01*x01*y10*y10 - x00*x00*x11*y10*y10 + x01*x01*x11*y10*y10 + x00*x11*x11*y10*y10 - x01*x11*x11*y10*y10 + 2*x00*x00*x10*y01*y11 - 2*x00*x01*x10*y01*y11 - 2*x00*x10*x10*y01*y11 + 2*x01*x10*x10*y01*y11 - 2*x00*x00*x11*y01*y11 + 2*x00*x01*x11*y01*y11 + 2*x00*x10*x11*y01*y11 - 2*x01*x10*x11*y01*y11 - 2*x00*x00*x01*y10*y11 + 2*x00*x01*x01*y10*y11 + 2*x00*x01*x10*y10*y11 - 2*x01*x01*x10*y10*y11 + 2*x00*x00*x11*y10*y11 - 2*x00*x01*x11*y10*y11 - 2*x00*x10*x11*y10*y11 + 2*x01*x10*x11*y10*y11 + x00*x00*x01*y11*y11 - x00*x01*x01*y11*y11 - x00*x00*x10*y11*y11 + x01*x01*x10*y11*y11 + x00*x10*x10*y11*y11 - x01*x10*x10*y11*y11); b02 = ((-(x01*y00) + x00*y01)*(x10*y01 - x11*y01 - x01*y10 + x11*y10 + x01*y11 - x10*y11)*(-(x10*y00) + x11*y00 + x00*y10 - x11*y10 - x00*y11 + x10*y11)); b12 = ((-(x10*y00) + x00*y10)*(x01*y00 - x11*y00 - x00*y01 + x11*y01 + x00*y11 - x01*y11)*(-(x10*y01) + x11*y01 + x01*y10 - x11*y10 - x01*y11 + x10*y11)); b22 = (x01*x10*x10*y00*y00*y01 - 2*x01*x10*x11*y00*y00*y01 + x01*x11*x11*y00*y00*y01 - x00*x10*x10*y00*y01*y01 + 2*x00*x10*x11*y00*y01*y01 - x00*x11*x11*y00*y01*y01 - x01*x01*x10*y00*y00*y10 + 2*x01*x10*x11*y00*y00*y10 - x10*x11*x11*y00*y00*y10 + 2*x00*x01*x11*y00*y01*y10 - 2*x00*x10*x11*y00*y01*y10 - 2*x01*x11*x11*y00*y01*y10 + 2*x10*x11*x11*y00*y01*y10 + x00*x00*x10*y01*y01*y10 - 2*x00*x00*x11*y01*y01*y10 + 2*x00*x11*x11*y01*y01*y10 - x10*x11*x11*y01*y01*y10 + x00*x01*x01*y00*y10*y10 - 2*x00*x01*x11*y00*y10*y10 + x00*x11*x11*y00*y10*y10 - x00*x00*x01*y01*y10*y10 + 2*x00*x00*x11*y01*y10*y10 - 2*x00*x11*x11*y01*y10*y10 + x01*x11*x11*y01*y10*y10 + 2*x01*x01*x10*y00*y00*y11 - 2*x01*x10*x10*y00*y00*y11 - x01*x01*x11*y00*y00*y11 + x10*x10*x11*y00*y00*y11 - 2*x00*x01*x10*y00*y01*y11 + 2*x00*x10*x10*y00*y01*y11 + 2*x01*x10*x11*y00*y01*y11 - 2*x10*x10*x11*y00*y01*y11 + x00*x00*x11*y01*y01*y11 - 2*x00*x10*x11*y01*y01*y11 + x10*x10*x11*y01*y01*y11 - 2*x00*x01*x01*y00*y10*y11 + 2*x00*x01*x10*y00*y10*y11 + 2*x01*x01*x11*y00*y10*y11 - 2*x01*x10*x11*y00*y10*y11 + 2*x00*x00*x01*y01*y10*y11 - 2*x00*x00*x10*y01*y10*y11 - 2*x00*x01*x11*y01*y10*y11 + 2*x00*x10*x11*y01*y10*y11 - x00*x00*x11*y10*y10*y11 + 2*x00*x01*x11*y10*y10*y11 - x01*x01*x11*y10*y10*y11 + x00*x01*x01*y00*y11*y11 - 2*x01*x01*x10*y00*y11*y11 - x00*x10*x10*y00*y11*y11 + 2*x01*x10*x10*y00*y11*y11 - x00*x00*x01*y01*y11*y11 + 2*x00*x01*x10*y01*y11*y11 - x01*x10*x10*y01*y11*y11 + x00*x00*x10*y10*y11*y11 - 2*x00*x01*x10*y10*y11*y11 + x01*x01*x10*y10*y11*y11); // adjust coeefs // b00/=(double) sw; b01 *= (double) sw / (double) sh; b02 *= sw; b10 *= (double) sh / (double) sw; //b11/=(double) sh; b12 *= sh; b20 /= sw; b21 /= sh; int[] s0 = src.getRaster().getSamples(0, 0, sw, sh, 0, (int[]) null); int[] s1 = src.getRaster().getSamples(0, 0, sw, sh, 1, (int[]) null); int[] s2 = src.getRaster().getSamples(0, 0, sw, sh, 2, (int[]) null); int[] s3 = src.getRaster().getSamples(0, 0, sw, sh, 3, (int[]) null); int doff = 0; int[] d0 = new int[s0.length]; int[] d1 = new int[s1.length]; int[] d2 = new int[s2.length]; int[] d3 = new int[s3.length]; for (int dy=0; dy < dh; dy++) { for (int dx=0; dx < dw; dx++) { double t0 = 0.0; double t1 = 0.0; double t2 = 0.0; double t3 = 0.0; double vv = dy; for (int sy2=4; sy2 > 0; sy2--) { double uu = dx; for (int sx2=4; sx2 > 0; sx2--) { double v0 = b00 * uu + b01 * vv + b02; double v1 = b10 * uu + b11 * vv + b12; double v2 = b20 * uu + b21 * vv + b22; int sx1 = (int) Math.floor(v0 / v2); int sy1 = (int) Math.floor(v1 / v2); if ((sx1 >= 0) && (sx1 < sw) && (sy1 >= 0) && (sy1 < sh)) { int soff = sx1 + sy1 * sw; t0 += s0[soff]; t1 += s1[soff]; t2 += s2[soff]; t3 += s3[soff]; } else { t0 += bgColor.getRed(); t1 += bgColor.getGreen(); t2 += bgColor.getBlue(); t3 += bgColor.getAlpha(); } uu += 0.25; } vv += 0.25; } d0[doff] = (int) (t0 / 16.0); d1[doff] = (int) (t1 / 16.0); d2[doff] = (int) (t2 / 16.0); d3[doff] = (int) (t3 / 16.0); doff++; } } dst.getRaster().setSamples(0, 0, dw, dh, 0, d0); dst.getRaster().setSamples(0, 0, dw, dh, 1, d1); dst.getRaster().setSamples(0, 0, dw, dh, 2, d2); dst.getRaster().setSamples(0, 0, dw, dh, 3, d3); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy