Skip to content

Commit

Permalink
Feature/transform refactor (#33)
Browse files Browse the repository at this point in the history
* Refactored transforms

* Code cleanups

* Bumping version
  • Loading branch information
defano authored Dec 15, 2018
1 parent 8819c37 commit e2affc0
Show file tree
Hide file tree
Showing 56 changed files with 375 additions and 165 deletions.
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,26 @@ currentTool.deactivate(); // ... but currentTool is still active.

When morphing a Lasso selection to a transform tool, the selection bounds will become rectangular, but only the pixels originally encircled by the Lasso will be affected by the transform.

#### Does this library support image filters like blur, emboss, or edge tracing?

Support? Absolutely! Provide? No.

Any selection on the canvas, or the entire canvas itself, can be filtered by invoking the `.operate()` method (to apply a `BufferedImageOp` on the canvas object or selection tool). The folks at [JH Labs](http://www.jhlabs.com) produce an outstanding library of image filters that integrate easily with JMonet if you'd rather not author your own. As an example, here's how to use their Solarize filter:

Include the JH Labs filter library (from Maven Central) as a dependency in your project:

```
dependencies {
compile group: 'com.jhlabs', name: 'filters', version: '2.0.235'
}
```

Then, apply [one of their filters](http://www.jhlabs.com/ip/filters/index.html) to your canvas or selection (in this example, their `SolarizeFilter` class):

```
myCanvas.operate(new SolarizeFilter());
```

#### Can I create my own tools?

Of course! Tools are typically subclassed from one of the abstract tool classes in the `paint.tools.base` package. These abstract classes handle UI events for the most common tool behaviors:
Expand Down
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
<packaging>jar</packaging>
<groupId>com.defano.jmonet</groupId>
<artifactId>jmonet</artifactId>
<version>0.3.2</version>
<version>0.3.3</version>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
Expand All @@ -53,7 +53,7 @@
<dependency>
<groupId>io.reactivex.rxjava2</groupId>
<artifactId>rxjava</artifactId>
<version>2.1.8</version>
<version>2.1.16</version>
</dependency>

</dependencies>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
/**
* An implementation of Bill Atkinson's dithering algorithm.
*/
@SuppressWarnings("PointlessArithmeticExpression")
public class AtkinsonDitherer extends AbstractDitherer {

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
/**
* An implementation of the Burkes dithering algorithm.
*/
@SuppressWarnings("PointlessArithmeticExpression")
public class BurkesDitherer extends AbstractDitherer {

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
/**
* An implementation of the Floyd-Steinberg dithering algorithm.
*/
@SuppressWarnings("PointlessArithmeticExpression")
public class FloydSteinbergDitherer extends AbstractDitherer {

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
/**
* An implementation of the Jarvis-Judice-Ninke dithering algorithm.
*/
@SuppressWarnings("PointlessArithmeticExpression")
public class JarvisJudiceNinkeDitherer extends AbstractDitherer {

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
/**
* An implementation of the Sierra-3 dithering algorithm.
*/
@SuppressWarnings("PointlessArithmeticExpression")
public class SierraDitherer extends AbstractDitherer {

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
/**
* An implementation of the Sierra-Lite dithering algorithm.
*/
@SuppressWarnings("PointlessArithmeticExpression")
public class SierraLiteDitherer extends AbstractDitherer {

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
/**
* An implementation of the Sierra-Two (row) dithering algorithm.
*/
@SuppressWarnings("PointlessArithmeticExpression")
public class SierraTwoDitherer extends AbstractDitherer {

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
/**
* An implementation of the Stucki dithering algorithm.
*/
@SuppressWarnings("PointlessArithmeticExpression")
public class StuckiDitherer extends AbstractDitherer {

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,6 @@ public interface BoundaryFunction {
* @return True if the given point in the image should be filled, false otherwise (i.e., the pixel represents a
* boundary)
*/
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
boolean isBoundary(BufferedImage canvas, BufferedImage scratch, int x, int y);
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ public class RotateLeftTransform extends AffineTransform {
* @param height The height of the shape or image to be rotated
*/
public RotateLeftTransform(int width, int height) {
setToTranslation(height / 2, width / 2);
setToTranslation(height / 2.0, width / 2.0);
quadrantRotate(3);
translate(-width / 2, -height / 2);
translate(-width / 2.0, -height / 2.0);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ public class RotateRightTransform extends AffineTransform {
* @param height The height of the shape or image to be rotated
*/
public RotateRightTransform(int width, int height) {
setToTranslation(height / 2, width / 2);
setToTranslation(height / 2.0, width / 2.0);
quadrantRotate(1);
translate(-width / 2, -height / 2);
translate(-width / 2.0, -height / 2.0);
}

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.defano.jmonet.algo.transform.image;

import com.defano.jmonet.algo.transform.ImageTransform;
import com.defano.jmonet.model.Interpolation;

import java.awt.geom.AffineTransform;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package com.defano.jmonet.algo.transform.image;

import com.defano.jmonet.algo.transform.StaticImageTransform;
import com.defano.jmonet.algo.transform.PixelTransform;
import com.defano.jmonet.tools.util.ImageUtils;

import java.awt.*;
Expand All @@ -27,6 +25,16 @@ public ApplyPixelTransform(PixelTransform transform, Shape mask) {
this.mask = mask;
}

/**
* Creates a transform that applies a {@link PixelTransform} to each pixel in the image.
*
* @param transform The pixel transform to apply
*/
public ApplyPixelTransform(PixelTransform transform) {
this.transform = transform;
this.mask = null;
}

/**
* {@inheritDoc}
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.defano.jmonet.algo.transform.image;

import com.defano.jmonet.tools.util.ImageUtils;

import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;

/**
* Transforms an image by applying a {@link BufferedImageOp} to it.
*/
public class BufferedImageOpTransform implements StaticImageTransform {

private final BufferedImageOp operation;

public BufferedImageOpTransform(BufferedImageOp operation) {
this.operation = operation;
}

@Override
public BufferedImage apply(BufferedImage source) {
BufferedImage destination = ImageUtils.newArgbOfSize(source);
operation.filter(source, destination);
return destination;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import com.defano.jmonet.algo.dither.FloydSteinbergDitherer;
import com.defano.jmonet.algo.dither.quant.ColorReductionQuantizer;
import com.defano.jmonet.algo.dither.quant.MonochromaticQuantizer;
import com.defano.jmonet.algo.transform.StaticImageTransform;

import java.awt.image.BufferedImage;

Expand All @@ -25,7 +24,7 @@ public class ColorReductionTransform implements StaticImageTransform {
*
* @param colorDepth The maximum number of unique colors that should appear in the resultant selection image; zero
* produces a black and white (monochrome) image. Note that color depth should be cubic; if
* the cubed root of colorDepth is not an integer, the cube of the floor of the cubed root
* the cubed root of colorDepth is not an integer, the the floor of the cubed root
* will be assumed.
* @param ditherer The dithering algorithm to use, for example, {@link FloydSteinbergDitherer}.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.defano.jmonet.algo.transform.image;

import com.defano.jmonet.tools.util.ImageUtils;

import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
import java.awt.image.ConvolveOp;
import java.awt.image.Kernel;

/**
* Convolves an image by applying an image {@link Kernel} to each pixel.
*/
public class ConvolutionTransform implements StaticImageTransform {

private final Kernel kernel;

public ConvolutionTransform(Kernel kernel) {
this.kernel = kernel;
}

@Override
public BufferedImage apply(BufferedImage source) {
BufferedImage destination = ImageUtils.newArgbOfSize(source);

BufferedImageOp convolution = new ConvolveOp(kernel, ConvolveOp.EDGE_ZERO_FILL, null);
convolution.filter(source, destination);

return destination;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import com.defano.jmonet.algo.fill.DefaultFillFunction;
import com.defano.jmonet.algo.fill.FillFunction;
import com.defano.jmonet.algo.transform.StaticImageTransform;
import com.defano.jmonet.tools.util.ImageUtils;

import java.awt.*;
Expand All @@ -21,7 +20,7 @@ public class FillTransform implements StaticImageTransform {
private final FillFunction fillFunction;

/**
* Creates a fill transform.
* Creates a fill transform that fills only pixels bounded by mask.
*
* @param mask The shape determining which transparent pixels to fill; null to adjust all transparent pixels.
* @param paint The {@link Paint} with which to fill
Expand All @@ -34,6 +33,19 @@ public FillTransform(Shape mask, Paint paint, FillFunction fillFunction) {
this.fillFunction = fillFunction;
}

/**
* Creates a fill transform that fills all pixels in the raster.
*
* @param paint The {@link Paint} with which to fill
* @param fillFunction An function that applies the paint to each affected pixel. Most users should simply supply
* an instance of {@link DefaultFillFunction}.
*/
public FillTransform(Paint paint, FillFunction fillFunction) {
this.mask = null;
this.paint = paint;
this.fillFunction = fillFunction;
}

/**
* {@inheritDoc}
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import com.defano.jmonet.algo.fill.BoundaryFunction;
import com.defano.jmonet.algo.fill.FillFunction;
import com.defano.jmonet.algo.transform.ImageTransform;

import java.awt.*;
import java.awt.image.BufferedImage;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import com.defano.jmonet.algo.dither.FloydSteinbergDitherer;
import com.defano.jmonet.algo.dither.quant.GrayscaleQuantizer;
import com.defano.jmonet.algo.dither.quant.MonochromaticQuantizer;
import com.defano.jmonet.algo.transform.StaticImageTransform;

import java.awt.image.BufferedImage;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.defano.jmonet.algo.transform;
package com.defano.jmonet.algo.transform.image;

import java.awt.image.BufferedImage;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.defano.jmonet.algo.transform;
package com.defano.jmonet.algo.transform.image;

/**
* A transform that can be applied to an individual pixel, like invert, or brightness adjustment.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.defano.jmonet.algo.transform.image;

import Jama.Matrix;
import com.defano.jmonet.algo.transform.ImageTransform;
import com.defano.jmonet.model.Quadrilateral;

import java.awt.*;
Expand Down Expand Up @@ -35,6 +34,7 @@ public ProjectionTransform(Quadrilateral projection) {
/**
* {@inheritDoc}
*/
@SuppressWarnings("DuplicateExpressions")
@Override
public BufferedImage apply(BufferedImage input) {

Expand Down Expand Up @@ -66,7 +66,7 @@ public BufferedImage apply(BufferedImage input) {
X4 = 0;
Y4 = imageHeight - 1;

double M_a[][] =
double[][] M_a =
{{x1, y1, 1, 0, 0, 0, -x1 * X1, -y1 * X1},
{x2, y2, 1, 0, 0, 0, -x2 * X2, -y2 * X2},
{x3, y3, 1, 0, 0, 0, -x3 * X3, -y3 * X3},
Expand All @@ -77,7 +77,7 @@ public BufferedImage apply(BufferedImage input) {
{0, 0, 0, x4, y4, 1, -x4 * Y4, -y4 * Y4}
};

double M_b[][] = {{X1}, {X2}, {X3}, {X4}, {Y1}, {Y2}, {Y3}, {Y4}};
double[][] M_b = {{X1}, {X2}, {X3}, {X4}, {Y1}, {Y2}, {Y3}, {Y4}};

Matrix A = new Matrix(M_a);
Matrix B = new Matrix(M_b);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.defano.jmonet.algo.transform.image;

import Jama.Matrix;
import com.defano.jmonet.algo.transform.ImageTransform;
import com.defano.jmonet.model.Quadrilateral;

import java.awt.*;
Expand Down Expand Up @@ -65,7 +64,7 @@ public BufferedImage apply(BufferedImage input) {
X4 = 0;
Y4 = sourceHeight - 1;

double M_a[][] =
double[][] M_a =
{{x1 * y1, x1, y1, 1, 0, 0, 0, 0},
{x2 * y2, x2, y2, 1, 0, 0, 0, 0},
{x3 * y3, x3, y3, 1, 0, 0, 0, 0},
Expand All @@ -76,7 +75,7 @@ public BufferedImage apply(BufferedImage input) {
{0, 0, 0, 0, x4 * y4, x4, y4, 1}
};

double M_b[][] = {{X1}, {X2}, {X3}, {X4}, {Y1}, {Y2}, {Y3}, {Y4}};
double[][] M_b = {{X1}, {X2}, {X3}, {X4}, {Y1}, {Y2}, {Y3}, {Y4}};

Matrix A = new Matrix(M_a);
Matrix B = new Matrix(M_b);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package com.defano.jmonet.algo.transform.image;

import com.defano.jmonet.algo.transform.ImageTransform;

import java.awt.*;
import java.awt.image.BufferedImage;

Expand All @@ -10,7 +8,7 @@
*/
public class ScaleTransform implements ImageTransform {

private Dimension size;
private final Dimension size;

/**
* Creates a scale transform.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package com.defano.jmonet.algo.transform.image;

import com.defano.jmonet.algo.transform.ImageTransform;

import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
Expand Down
Loading

0 comments on commit e2affc0

Please sign in to comment.