For those of you that want to add some additional filters and not sure how to do it, here is a "detail" explanation of how to for eg add the
Weave Filter:
1. Download the Java Code that I have posted in post #1.
2. Down the B4J project in post #3
3. Add a new class in the B4J project called
weaveFilter (Project -> Add New Module -> Class Module)
4. Copy the entire code of class
gammaFilter to class
weaveFilter
5. Class
weaveFilter should now look like this:
Code:
'Class module
Sub Class_Globals
Private fx As JFX
Private nativeMe As JavaObject
End Sub
'Initializes the object. You can add parameters to this method if needed.
Public Sub Initialize
nativeMe = Me
End Sub
public Sub applyGammaFilter_1(img As Image) As Image
Return nativeMe.RunMethod("applyGammaFilter_1", Array(img))
End Sub
public Sub applyGammaFilter_2(img As Image) As Image
Return nativeMe.RunMethod("applyGammaFilter_2", Array(img))
End Sub
'Set the gamma levels.
'r = the gamma level For the red channel
'g = the gamma level For the blue channel
'b = the gamma level For the green channel
public Sub setGamma_1(r As Float, g As Float, b As Float)
nativeMe.RunMethod("setGamma_1", Array(r,g,b))
End Sub
public Sub setGamma_2(rgb As Float)
nativeMe.RunMethod("setGamma_2", Array(rgb))
End Sub
#If Java
import java.awt.image.BufferedImage;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import java.awt.Graphics2D;
import javafx.embed.swing.SwingFXUtils;
import com.jhlabs.image.GammaFilter;
import com.jhlabs.image.ImageMath;
import java.awt.image.*;
import java.awt.*;
import java.awt.geom.*;
private float rGamma, gGamma, bGamma, gamma = 0.0f;
public Image applyGammaFilter_1(Image img) {
BufferedImage bmp = SwingFXUtils.fromFXImage(img, null);
BufferedImage srcImage = bmp;
GammaFilter gf = new GammaFilter();
gf.setGamma(rGamma, gGamma, bGamma);
srcImage = gf.filter(srcImage, srcImage);
img = SwingFXUtils.toFXImage(srcImage, null);
return img;
}
public Image applyGammaFilter_2(Image img) {
BufferedImage bmp = SwingFXUtils.fromFXImage(img, null);
BufferedImage srcImage = bmp;
GammaFilter gf = new GammaFilter();
gf.setGamma(gamma);
srcImage = gf.filter(srcImage, srcImage);
img = SwingFXUtils.toFXImage(srcImage, null);
return img;
}
/**
* Set the gamma levels.
* @param rGamma the gamma level for the red channel
* @param gGamma the gamma level for the blue channel
* @param bGamma the gamma level for the green channel
* @see #getGamma
*/
public void setGamma_1(float rGamma, float gGamma, float bGamma) {
this.rGamma = rGamma;
this.gGamma = gGamma;
this.bGamma = bGamma;
}
/**
* Set the gamma level.
* @param gamma the gamma level for all RGB channels
* @see #getGamma
*/
public void setGamma_2(float gamma) {
this.gamma = gamma;
}
#End If
6. Now you need open the Java code and browse to folder
src\com\jhlabs\image. In this folder is a java class called
WeaveFilter.java. Open it with something such as Notepad or Notepad++.
7. The code inside this java class looks as follows:
Code:
/*
Copyright 2006 Jerry Huxtable
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package com.jhlabs.image;
import java.awt.*;
import java.awt.image.*;
public class WeaveFilter extends PointFilter {
private float xWidth = 16;
private float yWidth = 16;
private float xGap = 6;
private float yGap = 6;
private int rows = 4;
private int cols = 4;
private int rgbX = 0xffff8080;
private int rgbY = 0xff8080ff;
private boolean useImageColors = true;
private boolean roundThreads = false;
private boolean shadeCrossings = true;
public int[][] matrix = {
{ 0, 1, 0, 1 },
{ 1, 0, 1, 0 },
{ 0, 1, 0, 1 },
{ 1, 0, 1, 0 },
};
public WeaveFilter() {
}
public void setXGap(float xGap) {
this.xGap = xGap;
}
public void setXWidth(float xWidth) {
this.xWidth = xWidth;
}
public float getXWidth() {
return xWidth;
}
public void setYWidth(float yWidth) {
this.yWidth = yWidth;
}
public float getYWidth() {
return yWidth;
}
public float getXGap() {
return xGap;
}
public void setYGap(float yGap) {
this.yGap = yGap;
}
public float getYGap() {
return yGap;
}
public void setCrossings(int[][] matrix) {
this.matrix = matrix;
}
public int[][] getCrossings() {
return matrix;
}
public void setUseImageColors(boolean useImageColors) {
this.useImageColors = useImageColors;
}
public boolean getUseImageColors() {
return useImageColors;
}
public void setRoundThreads(boolean roundThreads) {
this.roundThreads = roundThreads;
}
public boolean getRoundThreads() {
return roundThreads;
}
public void setShadeCrossings(boolean shadeCrossings) {
this.shadeCrossings = shadeCrossings;
}
public boolean getShadeCrossings() {
return shadeCrossings;
}
public int filterRGB(int x, int y, int rgb) {
x += xWidth+xGap/2;
y += yWidth+yGap/2;
float nx = ImageMath.mod(x, xWidth+xGap);
float ny = ImageMath.mod(y, yWidth+yGap);
int ix = (int)(x / (xWidth+xGap));
int iy = (int)(y / (yWidth+yGap));
boolean inX = nx < xWidth;
boolean inY = ny < yWidth;
float dX, dY;
float cX, cY;
int lrgbX, lrgbY;
if (roundThreads) {
dX = Math.abs(xWidth/2-nx) / xWidth / 2;
dY = Math.abs(yWidth/2-ny) / yWidth / 2;
} else {
dX = dY = 0;
}
if (shadeCrossings) {
cX = ImageMath.smoothStep(xWidth/2, xWidth/2+xGap, Math.abs(xWidth/2-nx));
cY = ImageMath.smoothStep(yWidth/2, yWidth/2+yGap, Math.abs(yWidth/2-ny));
} else {
cX = cY = 0;
}
if (useImageColors) {
lrgbX = lrgbY = rgb;
} else {
lrgbX = rgbX;
lrgbY = rgbY;
}
int v;
int ixc = ix % cols;
int iyr = iy % rows;
int m = matrix[iyr][ixc];
if (inX) {
if (inY) {
v = m == 1 ? lrgbX : lrgbY;
v = ImageMath.mixColors(2 * (m == 1 ? dX : dY), v, 0xff000000);
} else {
if (shadeCrossings) {
if (m != matrix[(iy+1) % rows][ixc]) {
if (m == 0)
cY = 1-cY;
cY *= 0.5f;
lrgbX = ImageMath.mixColors(cY, lrgbX, 0xff000000);
} else if (m == 0)
lrgbX = ImageMath.mixColors(0.5f, lrgbX, 0xff000000);
}
v = ImageMath.mixColors(2 * dX, lrgbX, 0xff000000);
}
} else if (inY) {
if (shadeCrossings) {
if (m != matrix[iyr][(ix+1) % cols]) {
if (m == 1)
cX = 1-cX;
cX *= 0.5f;
lrgbY = ImageMath.mixColors(cX, lrgbY, 0xff000000);
} else if (m == 1)
lrgbY = ImageMath.mixColors(0.5f, lrgbY, 0xff000000);
}
v = ImageMath.mixColors(2 * dY, lrgbY, 0xff000000);
} else
v = 0x00000000;
return v;
}
public String toString() {
return "Texture/Weave...";
}
}
8. In this class we are interested in the private variables that have been declared as well as some of the public methods:
Private variables:
Code:
private float xWidth = 16;
private float yWidth = 16;
private float xGap = 6;
private float yGap = 6;
private int rows = 4;
private int cols = 4;
private int rgbX = 0xffff8080;
private int rgbY = 0xff8080ff;
private boolean useImageColors = true;
private boolean roundThreads = false;
private boolean shadeCrossings = true;
Public methods (getters and setters):
Code:
public void setXGap(float xGap) { //WILL USE
this.xGap = xGap;
}
public void setXWidth(float xWidth) { //WILL USE
this.xWidth = xWidth;
}
public float getXWidth() {
return xWidth;
}
public void setYWidth(float yWidth) { //WILL USE
this.yWidth = yWidth;
}
public float getYWidth() {
return yWidth;
}
public float getXGap() {
return xGap;
}
public void setYGap(float yGap) { //WILL USE
this.yGap = yGap;
}
public float getYGap() {
return yGap;
}
public void setCrossings(int[][] matrix) {
this.matrix = matrix;
}
public int[][] getCrossings() {
return matrix;
}
public void setUseImageColors(boolean useImageColors) { //WILL USE
this.useImageColors = useImageColors;
}
public boolean getUseImageColors() {
return useImageColors;
}
public void setRoundThreads(boolean roundThreads) { //WILL USE
this.roundThreads = roundThreads;
}
public boolean getRoundThreads() {
return roundThreads;
}
public void setShadeCrossings(boolean shadeCrossings) { //WILL USE
this.shadeCrossings = shadeCrossings;
}
public boolean getShadeCrossings() {
return shadeCrossings;
}
9. We will not be using all the public methods. Only the 7 that have been marked as
//WILL USE.
10. Let's first start by cleaning up our new B4J class (
weaveFilter) that at present contains the code of B4J class
gammaFilter after the copy that we have done in point 4 above.
11. Remove/delete everything in red from B4J class
weaveFilter:
'Class module
Sub
Class_Globals
Private fx As JFX
Private nativeMe As JavaObject
End Sub
'Initializes the object. You can add parameters to this method if needed.
Public Sub Initialize
nativeMe = Me
End Sub
public Sub applyGammaFilter_1(img As Image) As Image
Return nativeMe.RunMethod("applyGammaFilter_1", Array(img))
End Sub
public Sub applyGammaFilter_2(img As Image) As Image
Return nativeMe.RunMethod("applyGammaFilter_2", Array(img))
End Sub
'Set the gamma levels.
'r = the gamma level For the red channel
'g = the gamma level For the blue channel
'b = the gamma level For the green channel
public Sub setGamma_1(r As Float, g As Float, b As Float)
nativeMe.RunMethod("setGamma_1", Array(r,g,b))
End Sub
public Sub setGamma_2(rgb As Float)
nativeMe.RunMethod("setGamma_2", Array(rgb))
End Sub
#If Java
import java.awt.image.BufferedImage;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import java.awt.Graphics2D;
import javafx.embed.swing.SwingFXUtils;
import com.jhlabs.image.GammaFilter;
import com.jhlabs.image.ImageMath;
import java.awt.image.*;
import java.awt.*;
import java.awt.geom.*;
private float rGamma, gGamma, bGamma, gamma = 0.0f;
public Image applyGammaFilter_1(Image img) {
BufferedImage bmp = SwingFXUtils.fromFXImage(img, null);
BufferedImage srcImage = bmp;
GammaFilter gf = new GammaFilter();
gf.setGamma(rGamma, gGamma, bGamma);
srcImage = gf.filter(srcImage, srcImage);
img = SwingFXUtils.toFXImage(srcImage, null);
return img;
}
public Image applyGammaFilter_2(Image img) {
BufferedImage bmp = SwingFXUtils.fromFXImage(img, null);
BufferedImage srcImage = bmp;
GammaFilter gf = new GammaFilter();
gf.setGamma(gamma);
srcImage = gf.filter(srcImage, srcImage);
img = SwingFXUtils.toFXImage(srcImage, null);
return img;
}
/**
* Set the gamma levels.
* @param rGamma the gamma level for the red channel
* @param gGamma the gamma level for the blue channel
* @param bGamma the gamma level for the green channel
* @see #getGamma
*/
public void setGamma_1(float rGamma, float gGamma, float bGamma) {
this.rGamma = rGamma;
this.gGamma = gGamma;
this.bGamma = bGamma;
}
/**
* Set the gamma level.
* @param gamma the gamma level for all RGB channels
* @see #getGamma
*/
public void setGamma_2(float gamma) {
this.gamma = gamma;
}
#End If
12. The class in the Java code that we are working with is called WeaveFilter. We need to import this class into our inline Java code. Replace
import com.jhlabs.image.GammaFilter;
with
import com.jhlabs.image.WeaveFilter;
in the inline Java code of B4J class
weaveFilter
13. Next we change method
applyGammaFilter_1 in our inline Java code from:
public Image
applyGammaFilter_1(Image img) {
BufferedImage bmp = SwingFXUtils.fromFXImage(img, null);
BufferedImage srcImage = bmp;
GammaFilter gf = new GammaFilter();
gf.setGamma(rGamma, gGamma, bGamma);
srcImage = gf.filter(srcImage, srcImage);
img = SwingFXUtils.toFXImage(srcImage, null);
return img;
}
to
public Image
applyWeaveFilter(Image img) {
BufferedImage bmp = SwingFXUtils.fromFXImage(img, null);
BufferedImage srcImage = bmp;
WeaveFilter wv = new WeaveFilter();
srcImage = wv.filter(srcImage, srcImage);
img = SwingFXUtils.toFXImage(srcImage, null);
return img;
}
15. We have now eliminated all the "noise" that was carried over from B4J class
gammaFilter when we copied it to B4J class
weaveFilter.
16. Now we need to go add our setter to the inline Java code so that we can set the properties of the weave filter from our B4J project's main activity.
....continuing in post #6....