/*
JWildfire - an image and animation processor written in Java
Copyright (C) 1995-2011 Andreas Maschke
This is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser
General Public License as published by the Free Software Foundation; either version 2.1 of the
License, or (at your option) any later version.
This software 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along with this software;
if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jwildfire.transform;
import java.awt.Color;
import org.jwildfire.base.Property;
import org.jwildfire.base.PropertyMax;
import org.jwildfire.base.PropertyMin;
import org.jwildfire.base.Tools;
import org.jwildfire.image.Pixel;
import org.jwildfire.image.SimpleImage;
import org.jwildfire.image.WFImage;
import com.l2fprod.common.beans.editor.ComboBoxPropertyEditor;
public class PixelizeTransformer extends Mesh2DTransformer {
public enum Grid {
OFF, XY, X, Y
}
@Property(description = "Rectangle width")
@PropertyMin(2)
private int width = 20;
@Property(description = "Rectangle height")
@PropertyMin(2)
private int height = 20;
@Property(description = "Grid color")
private Color gridColor = new Color(240, 240, 222);
@Property(description = "Grid mode", editorClass = GridEditor.class)
private Grid grid = Grid.XY;
@Property(description = "Centre rectangles")
private boolean centre = true;
@Property(description = "Grid size")
@PropertyMin(1)
private int gridSize = 2;
@Property(description = "Color falloff at the left side")
@PropertyMin(0.0)
@PropertyMax(1.0)
private double gridFallOffLeft = 0.8;
@Property(description = "Color falloff at the right side")
@PropertyMin(0.0)
@PropertyMax(1.0)
private double gridFallOffRight = 0.1;
@Property(description = "Color falloff at the top side")
@PropertyMin(0.0)
@PropertyMax(1.0)
private double gridFallOffTop = 0.7;
@Property(description = "Color falloff at the bottom side")
@PropertyMin(0.0)
@PropertyMax(1.0)
private double gridFallOffBottom = 0.3;
@Override
protected void performPixelTransformation(WFImage pImg) {
// Init
SimpleImage img = (SimpleImage) pImg;
int width = pImg.getImageWidth();
int height = pImg.getImageHeight();
int gridSize = this.gridSize;
Grid grid = (gridSize < 1) ? Grid.OFF : this.grid;
Pixel pixel = new Pixel();
int pw = this.width;
int ph = this.height;
if (pw < 1)
pw = 1;
else if (pw > width)
pw = width;
if (ph < 1)
ph = 1;
else if (ph > height)
ph = height;
if ((pw == 1) && (ph == 1))
return;
int pwo = pw;
int pho = ph;
int hc = width / pw;
if ((width % pw) != 0)
hc += 2;
int vc = height / ph;
if ((height % ph) != 0)
vc += 2;
int pwa[] = new int[hc];
int pha[] = new int[vc];
int gSize = 0;
if (grid != Grid.OFF) {
gSize = gridSize;
if ((gSize > pwo) || (gSize > pho)) {
if (pwo > pho)
gSize = pho;
else
gSize = pwo;
}
}
int grUp[] = null, ggUp[] = null, gbUp[] = null;
int grDown[] = null, ggDown[] = null, gbDown[] = null;
int grLeft[] = null, ggLeft[] = null, gbLeft[] = null;
int grRight[] = null, ggRight[] = null, gbRight[] = null;
if (((grid) != Grid.OFF) && (gSize >= 1)) {
if ((gSize % 2) == 0)
gSize++;
int s = (gSize / 2 + 1);
if (gSize > 1) {
grUp = new int[s];
ggUp = new int[s];
gbUp = new int[s];
grDown = new int[s];
ggDown = new int[s];
gbDown = new int[s];
grLeft = new int[s];
ggLeft = new int[s];
gbLeft = new int[s];
grRight = new int[s];
ggRight = new int[s];
gbRight = new int[s];
}
}
//
if ((width % pw) == 0) {
for (int i = 0; i < hc; i++)
pwa[i] = pw;
}
else {
if (this.centre) {
pwa[0] = (width % pw) / 2;
if (pwa[0] == 0)
pwa[0] = 1;
for (int i = 1; i < (hc - 1); i++)
pwa[i] = pw;
pwa[hc - 1] = width - pwa[0] - (hc - 2) * pw;
if (pwa[hc - 1] == 0)
hc--;
}
else {
hc--;
for (int i = 0; i < (hc - 1); i++)
pwa[i] = pw;
pwa[hc - 1] = width - (hc - 1) * pw;
}
}
if ((height % ph) == 0) {
for (int i = 0; i < vc; i++)
pha[i] = ph;
}
else {
if (this.centre) {
pha[0] = (height % ph) / 2;
if (pha[0] == 0)
pha[0] = 1;
for (int i = 1; i < (vc - 1); i++)
pha[i] = ph;
pha[vc - 1] = height - pha[0] - (vc - 2) * ph;
if (pha[vc - 1] == 0)
vc--;
}
else {
vc--;
for (int i = 0; i < (vc - 1); i++)
pha[i] = ph;
pha[vc - 1] = height - (vc - 1) * ph;
}
}
{
int topOffset = 0;
for (int i = 0; i < vc; i++) {
ph = pha[i];
int leftOffset = 0;
for (int j = 0; j < hc; j++) {
pw = pwa[j];
int pc = pw * ph;
/* compute the average-color */
int ra = 0, ga = 0, ba = 0;
for (int k = 0; k < ph; k++) {
for (int l = 0; l < pw; l++) {
int x = leftOffset + l;
int y = topOffset + k;
pixel.setARGBValue(srcImg.getARGBValue(x, y));
ra += pixel.r;
ga += pixel.g;
ba += pixel.b;
}
}
ra = Tools.limitColor(ra / pc);
ga = Tools.limitColor(ga / pc);
ba = Tools.limitColor(ba / pc);
// set this color in the current box
for (int k = 0; k < ph; k++) {
for (int l = 0; l < pw; l++) {
int x = leftOffset + l;
int y = topOffset + k;
img.setRGB(x, y, pixel);
}
}
leftOffset += pw;
}
topOffset += ph;
}
}
if ((grid != Grid.OFF) && (gSize >= 1)) {
double gFallOffUp = this.gridFallOffTop;
double gFallOffDown = this.gridFallOffBottom;
double gFallOffLeft = this.gridFallOffLeft;
double gFallOffRight = this.gridFallOffRight;
if (gFallOffUp < 0.0)
gFallOffUp = 0.0;
if (gFallOffDown < 0.0)
gFallOffDown = 0.0;
if (gFallOffLeft < 0.0)
gFallOffLeft = 0.0;
if (gFallOffRight < 0.0)
gFallOffRight = 0.0;
int s = (gSize / 2 + 1);
int n = s - 1;
if (gSize > 1) {
if ((gFallOffUp < 0.0001) && (gFallOffDown < 0.0001) && (gFallOffLeft < 0.0001)
&& (gFallOffRight < 0.0001))
{
for (int k = 0; k < s; k++) {
grUp[k] = grDown[k] = grLeft[k] = grRight[k] = this.gridColor.getRed();
ggUp[k] = ggDown[k] = ggLeft[k] = ggRight[k] = this.gridColor.getGreen();
gbUp[k] = gbDown[k] = gbLeft[k] = gbRight[k] = this.gridColor.getBlue();
}
}
else {
calcCArray(grUp, s, gFallOffUp, this.gridColor.getRed());
calcCArray(ggUp, s, gFallOffUp, this.gridColor.getGreen());
calcCArray(gbUp, s, gFallOffUp, this.gridColor.getBlue());
calcCArray(grDown, s, gFallOffDown, this.gridColor.getRed());
calcCArray(ggDown, s, gFallOffDown, this.gridColor.getGreen());
calcCArray(gbDown, s, gFallOffDown, this.gridColor.getBlue());
calcCArray(grLeft, s, gFallOffLeft, this.gridColor.getRed());
calcCArray(ggLeft, s, gFallOffLeft, this.gridColor.getGreen());
calcCArray(gbLeft, s, gFallOffLeft, this.gridColor.getBlue());
calcCArray(grRight, s, gFallOffRight, this.gridColor.getRed());
calcCArray(ggRight, s, gFallOffRight, this.gridColor.getGreen());
calcCArray(gbRight, s, gFallOffRight, this.gridColor.getBlue());
}
}
else
n = 0;
// horizontal grid
if ((grid == Grid.XY) || (grid == Grid.X)) {
int topOffset = 0;
int r, g, b;
for (int i = 0; i < (vc - 1); i++) {
ph = pha[i];
topOffset += ph;
// base grid
r = this.gridColor.getRed();
g = this.gridColor.getGreen();
b = this.gridColor.getBlue();
for (int j = 0; j < width; j++) {
img.setRGB(j, topOffset, r, g, b);
}
// up
for (int kk = 1; kk <= n; kk++) {
r = grUp[kk];
g = ggUp[kk];
b = gbUp[kk];
for (int j = 0; j < width; j++) {
int y = topOffset - kk;
if (y >= 0)
img.setRGB(j, y, r, g, b);
}
}
// down
for (int kk = 1; kk <= n; kk++) {
r = grDown[kk];
g = ggDown[kk];
b = gbDown[kk];
for (int j = 0; j < width; j++) {
int y = topOffset + kk;
if (y < height)
img.setRGB(j, y, r, g, b);
}
}
}
}
// vertical grid
if ((grid == Grid.XY) || (grid == Grid.Y)) {
int r, g, b;
int leftOffset = 0;
for (int i = 0; i < (hc - 1); i++) {
pw = pwa[i];
leftOffset += pw;
// base grid
r = this.gridColor.getRed();
g = this.gridColor.getGreen();
b = this.gridColor.getBlue();
for (int j = 0; j < height; j++) {
img.setRGB(leftOffset, j, r, g, b);
}
// left
for (int kk = 1; kk <= n; kk++) {
r = grLeft[kk];
g = ggLeft[kk];
b = gbLeft[kk];
for (int j = 0; j < height; j++) {
int x = leftOffset - kk;
if (x >= 0)
img.setRGB(x, j, r, g, b);
}
}
// right
for (int kk = 1; kk <= n; kk++) {
r = grRight[kk];
g = ggRight[kk];
b = gbRight[kk];
for (int j = 0; j < height; j++) {
int x = leftOffset + kk;
if (x < width)
img.setRGB(x, j, r, g, b);
}
}
}
}
// connections
if (grid == Grid.XY) {
int topOffset = 0;
for (int i = 0; i < (vc - 1); i++) {
ph = pha[i];
topOffset += ph;
int leftOffset = 0;
for (int j = 0; j < (hc - 1); j++) {
pw = pwa[j];
leftOffset += pw;
int r, g, b;
// base grid
r = this.gridColor.getRed();
g = this.gridColor.getGreen();
b = this.gridColor.getBlue();
for (int kk = -n; kk <= +n; kk++) {
int x = leftOffset + kk;
int y = topOffset;
if ((x >= 0) && (x < width) && (y >= 0) && (y < height))
img.setRGB(x, y, r, g, b);
}
// up
for (int kk = 1; kk <= n; kk++) {
r = grUp[kk];
g = ggUp[kk];
b = gbUp[kk];
for (int ll = kk; ll <= n; ll++) {
int x = leftOffset - ll;
int y = topOffset - kk;
if ((x >= 0) && (x < width) && (y >= 0) && (y < height))
img.setRGB(x, y, r, g, b);
x = leftOffset + ll;
if ((x >= 0) && (x < width) && (y >= 0) && (y < height))
img.setRGB(x, y, r, g, b);
}
}
// down
for (int kk = 1; kk <= n; kk++) {
r = grDown[kk];
g = ggDown[kk];
b = gbDown[kk];
for (int ll = kk; ll <= n; ll++) {
int x = leftOffset - ll;
int y = topOffset + kk;
if ((x >= 0) && (x < width) && (y >= 0) && (y < height))
img.setRGB(x, y, r, g, b);
x = leftOffset + ll;
if ((x >= 0) && (x < width) && (y >= 0) && (y < height))
img.setRGB(x, y, r, g, b);
}
}
}
}
}
}
}
private void calcCArray(int[] pColors, int pSize, double pFallOff, int pColor) {
double ttf, ttf2, m;
int ttw, k;
pColors[0] = pColor;
if (pSize == 1) {
ttf = pFallOff * (double) pColor;
ttw = (int) (ttf + 0.5);
if (ttw > 255)
ttw = 255;
else if (ttw < 0)
ttw = 0;
pColors[1] = ttw;
}
else {
ttf = pFallOff * (double) pColor;
m = (double) (pColor - ttf) / ((float) (pSize - 1));
for (k = 1; k < pSize; k++) {
ttf2 = (float) pColor - (float) k * m;
ttw = (int) (ttf2 + 0.5);
if (ttw > 255)
ttw = 255;
else if (ttw < 0)
ttw = 0;
pColors[k] = ttw;
}
}
}
@Override
public void initDefaultParams(WFImage pImg) {
centre = true;
width = pImg.getImageWidth() / 50;
height = pImg.getImageHeight() / 50;
gridColor = new Color(204, 204, 204);
gridSize = 3;
grid = Grid.XY;
gridFallOffLeft = 0.8;
gridFallOffRight = 0.1;
gridFallOffTop = 0.5;
gridFallOffBottom = 0.2;
}
public static class GridEditor extends ComboBoxPropertyEditor {
public GridEditor() {
super();
setAvailableValues(new Grid[] { Grid.OFF, Grid.XY, Grid.X, Grid.Y });
}
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public Color getGridColor() {
return gridColor;
}
public void setGridColor(Color gridColor) {
this.gridColor = gridColor;
}
public Grid getGrid() {
return grid;
}
public void setGrid(Grid grid) {
this.grid = grid;
}
public boolean isCentre() {
return centre;
}
public void setCentre(boolean centre) {
this.centre = centre;
}
public int getGridSize() {
return gridSize;
}
public void setGridSize(int gridSize) {
this.gridSize = gridSize;
}
public double getGridFallOffLeft() {
return gridFallOffLeft;
}
public void setGridFallOffLeft(double gridFallOffLeft) {
this.gridFallOffLeft = gridFallOffLeft;
}
public double getGridFallOffRight() {
return gridFallOffRight;
}
public void setGridFallOffRight(double gridFallOffRight) {
this.gridFallOffRight = gridFallOffRight;
}
public double getGridFallOffTop() {
return gridFallOffTop;
}
public void setGridFallOffTop(double gridFallOffTop) {
this.gridFallOffTop = gridFallOffTop;
}
public double getGridFallOffBottom() {
return gridFallOffBottom;
}
public void setGridFallOffBottom(double gridFallOffBottom) {
this.gridFallOffBottom = gridFallOffBottom;
}
}