/*
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 org.jwildfire.base.Property;
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 org.jwildfire.swing.Buffer.BufferType;
import org.jwildfire.swing.ScaleAspectEditor;
import com.l2fprod.common.beans.editor.ComboBoxPropertyEditor;
public class ScaleTransformer extends Transformer {
public enum Unit {
PIXELS, PERCENT
}
@Property(description = "Scale unit", editorClass = UnitEditor.class)
private Unit unit = Unit.PIXELS;
@Property(description = "How to treat the aspect ratio of the original", editorClass = ScaleAspectEditor.class)
private ScaleAspect aspect = ScaleAspect.KEEP_WIDTH;
@Property(description = "Width of the scaled image")
@PropertyMin(1)
private int scaleWidth = 320;
@Property(description = "Height of the scaled image")
@PropertyMin(1)
private int scaleHeight = 256;
public static class UnitEditor extends ComboBoxPropertyEditor {
public UnitEditor() {
super();
setAvailableValues(new Unit[] { Unit.PERCENT, Unit.PIXELS });
}
}
public Unit getUnit() {
return unit;
}
public void setUnit(Unit unit) {
this.unit = unit;
}
public ScaleAspect getAspect() {
return aspect;
}
public void setAspect(ScaleAspect aspect) {
this.aspect = aspect;
}
public int getScaleWidth() {
return scaleWidth;
}
public void setScaleWidth(int scaleWidth) {
this.scaleWidth = scaleWidth;
}
public int getScaleHeight() {
return scaleHeight;
}
public void setScaleHeight(int scaleHeight) {
this.scaleHeight = scaleHeight;
}
@Override
public boolean supports3DOutput() {
return false;
}
@Override
protected void performImageTransformation(WFImage pImg) {
SimpleImage img = (SimpleImage) pImg;
int srcWidth = pImg.getImageWidth();
int srcHeight = pImg.getImageHeight();
double width, height;
if (unit == Unit.PIXELS) {
width = (double) scaleWidth;
height = (double) scaleHeight;
}
else {
width = (double) scaleWidth / 100.0 * (double) srcWidth;
height = (double) scaleHeight / 100.0 * (double) srcHeight;
}
if (aspect == ScaleAspect.KEEP_WIDTH) {
double scl = width / (double) srcWidth;
height = (double) srcHeight * scl;
}
else if (aspect == ScaleAspect.KEEP_HEIGHT) {
double scl = height / (double) srcHeight;
width = (double) srcWidth * scl;
}
int dstWidth = (int) (width + 0.5);
if (dstWidth < 1)
dstWidth = 1;
int dstHeight = (int) (height + 0.5);
if (dstHeight < 1)
dstHeight = 1;
SimpleImage srcImg = img.clone();
img.resetImage(dstWidth, dstHeight);
if ((dstWidth >= srcWidth) && (dstHeight >= srcHeight))
scale_up_up(srcImg, img);
else if ((dstWidth < srcWidth) && (dstHeight >= srcHeight))
scale_down_up(srcImg, img);
else if ((dstWidth >= srcWidth) && (dstHeight < srcHeight))
scale_up_down(srcImg, img);
else if ((dstWidth < srcWidth) && (dstHeight < srcHeight))
scale_down_down(srcImg, img);
}
private void scale_up_up(SimpleImage srcImg, SimpleImage dstImg) {
int swidth = srcImg.getImageWidth();
int sheight = srcImg.getImageHeight();
int width = dstImg.getImageWidth();
int height = dstImg.getImageHeight();
double sclX, sclY;
if (width > 1) {
sclX = (double) (swidth - 1) / (double) (width - 1);
}
else
sclX = 1.0;
if (height > 1) {
sclY = (double) (sheight - 1) / (double) (height - 1);
}
else
sclY = 1.0;
double cxD = (double) (width - 1) * 0.5;
double cyD = (double) (height - 1) * 0.5;
double cxS = (double) (swidth - 1) * 0.5;
double cyS = (double) (sheight - 1) * 0.5;
Pixel pPixel = new Pixel();
for (int i = 0; i < height; i++) {
double y0 = (double) i - cyD;
double y = y0 * sclY + cyS;
for (int j = 0; j < width; j++) {
// transform the point
double x0 = (double) j - cxD;
double x = x0 * sclX + cxS;
// render it
if (((int) x < 0) || ((int) x >= swidth) || ((int) y < 0) || ((int) y >= sheight)) {
pPixel.r = pPixel.g = pPixel.b = 0;
}
else {
double xi = Tools.fmod33(x);
double yi = Tools.fmod33(y);
readSrcPixels(srcImg, x, y);
pPixel.r = roundColor(((1.0 - yi) * ((1.0 - xi) * (srcP.r) + xi * (srcQ.r)) + yi
* ((1.0 - xi) * (srcR.r) + xi * (srcS.r))));
pPixel.g = roundColor(((1.0 - yi) * ((1.0 - xi) * (srcP.g) + xi * (srcQ.g)) + yi
* ((1.0 - xi) * (srcR.g) + xi * (srcS.g))));
pPixel.b = roundColor(((1.0 - yi) * ((1.0 - xi) * (srcP.b) + xi * (srcQ.b)) + yi
* ((1.0 - xi) * (srcR.b) + xi * (srcS.b))));
}
dstImg.setRGB(j, i, pPixel.r, pPixel.g, pPixel.b);
}
}
}
private void scale_down_up(SimpleImage srcImg, SimpleImage dstImg) {
int swidth = srcImg.getImageWidth();
int sheight = srcImg.getImageHeight();
int width = dstImg.getImageWidth();
int height = dstImg.getImageHeight();
double sclX, sclY;
if (width > 1) {
sclX = (double) (swidth - 1) / (double) (width - 1);
}
else
sclX = 1.0;
if (height > 1) {
sclY = (double) (sheight - 1) / (double) (height - 1);
}
else
sclY = 1.0;
double cxD = (double) (width - 1) * 0.5;
double cyD = (double) (height - 1) * 0.5;
double cxS = (double) (swidth - 1) * 0.5;
double cyS = (double) (sheight - 1) * 0.5;
Pixel pPixel = new Pixel();
for (int i = 0; i < height; i++) {
double y0 = (double) i - cyD;
double y = y0 * sclY + cyS;
for (int j = 0; j < width; j++) {
// transform the point
double x0 = (double) j - cxD;
double x = x0 * sclX + cxS;
double xn = (x0 + 1.0) * sclX + cxS;
if (xn >= (swidth - 0.5))
xn = swidth - 1.0;
if (((int) x < 0) || ((int) x >= swidth) || ((int) y < 0) || ((int) y >= sheight)) {
pPixel.r = pPixel.g = pPixel.b = 0;
}
else {
double xi = Tools.fmod33(x);
double yi = Tools.fmod33(y);
readSrcPixels(srcImg, x, y);
int cvalR = roundColor(((1.0 - yi) * ((1.0 - xi) * (srcP.r) + xi * (srcQ.r)) + yi
* ((1.0 - xi) * (srcR.r) + xi * (srcS.r))));
int cvalG = roundColor(((1.0 - yi) * ((1.0 - xi) * (srcP.g) + xi * (srcQ.g)) + yi
* ((1.0 - xi) * (srcR.g) + xi * (srcS.g))));
int cvalB = roundColor(((1.0 - yi) * ((1.0 - xi) * (srcP.b) + xi * (srcQ.b)) + yi
* ((1.0 - xi) * (srcR.b) + xi * (srcS.b))));
x = x - xi + 1.0;
int cnt = 1;
while (x < xn) {
readSrcPixels(srcImg, x, y);
cvalR += (1.0 - yi) * srcP.r + yi * srcR.r;
cvalG += (1.0 - yi) * srcP.g + yi * srcR.g;
cvalB += (1.0 - yi) * srcP.b + yi * srcR.b;
x += 1.0;
cnt++;
}
pPixel.r = roundColor(cvalR / (double) cnt);
pPixel.g = roundColor(cvalG / (double) cnt);
pPixel.b = roundColor(cvalB / (double) cnt);
}
dstImg.setRGB(j, i, pPixel.r, pPixel.g, pPixel.b);
}
}
}
private void scale_up_down(SimpleImage srcImg, SimpleImage dstImg) {
int swidth = srcImg.getImageWidth();
int sheight = srcImg.getImageHeight();
int width = dstImg.getImageWidth();
int height = dstImg.getImageHeight();
double sclX, sclY;
if (width > 1) {
sclX = (double) (swidth - 1) / (double) (width - 1);
}
else
sclX = 1.0;
if (height > 1) {
sclY = (double) (sheight - 1) / (double) (height - 1);
}
else
sclY = 1.0;
double cxD = (double) (width - 1) * 0.5;
double cyD = (double) (height - 1) * 0.5;
double cxS = (double) (swidth - 1) * 0.5;
double cyS = (double) (sheight - 1) * 0.5;
Pixel pPixel = new Pixel();
for (int i = 0; i < height; i++) {
double y0 = (double) i - cyD;
double yn = (y0 + 1.0) * sclY + cyS;
if (yn >= (sheight - 0.5))
yn = sheight - 1.0;
for (int j = 0; j < width; j++) {
// transform the point
double x0 = (double) j - cxD;
double x = x0 * sclX + cxS;
double y = y0 * sclY + cyS;
if (((int) x < 0) || ((int) x >= swidth) || ((int) y < 0) || ((int) y >= sheight)) {
pPixel.r = pPixel.g = pPixel.b = 0;
}
else {
double xi = Tools.fmod33(x);
double yi = Tools.fmod33(y);
readSrcPixels(srcImg, x, y);
int cvalR = roundColor(((1.0 - yi) * ((1.0 - xi) * (srcP.r) + xi * (srcQ.r)) + yi
* ((1.0 - xi) * (srcR.r) + xi * (srcS.r))));
int cvalG = roundColor(((1.0 - yi) * ((1.0 - xi) * (srcP.g) + xi * (srcQ.g)) + yi
* ((1.0 - xi) * (srcR.g) + xi * (srcS.g))));
int cvalB = roundColor(((1.0 - yi) * ((1.0 - xi) * (srcP.b) + xi * (srcQ.b)) + yi
* ((1.0 - xi) * (srcR.b) + xi * (srcS.b))));
y = y - yi + 1.0;
int cnt = 1;
while (y < yn) {
readSrcPixels(srcImg, x, y);
cvalR += (1.0 - xi) * srcP.r + xi * srcQ.r;
cvalG += (1.0 - xi) * srcP.g + xi * srcQ.g;
cvalB += (1.0 - xi) * srcP.b + xi * srcQ.b;
y += 1.0;
cnt++;
}
pPixel.r = roundColor(cvalR / (double) cnt);
pPixel.g = roundColor(cvalG / (double) cnt);
pPixel.b = roundColor(cvalB / (double) cnt);
}
dstImg.setRGB(j, i, pPixel.r, pPixel.g, pPixel.b);
}
}
}
private void scale_down_down(SimpleImage srcImg, SimpleImage dstImg) {
int swidth = srcImg.getImageWidth();
int sheight = srcImg.getImageHeight();
int width = dstImg.getImageWidth();
int height = dstImg.getImageHeight();
double sclX, sclY;
if (width > 1) {
sclX = (double) (swidth - 1) / (double) (width - 1);
}
else
sclX = 1.0;
if (height > 1) {
sclY = (double) (sheight - 1) / (double) (height - 1);
}
else
sclY = 1.0;
double cxD = (double) (width - 1) * 0.5;
double cyD = (double) (height - 1) * 0.5;
double cxS = (double) (swidth - 1) * 0.5;
double cyS = (double) (sheight - 1) * 0.5;
Pixel pPixel = new Pixel();
for (int i = 0; i < height; i++) {
double y0 = (double) i - cyD;
for (int j = 0; j < width; j++) {
// transform the point
double x0 = (double) j - cxD;
double x = x0 * sclX + cxS;
double xn = (x0 + 1.0) * sclX + cxS;
if (xn >= (swidth - 0.5))
xn = swidth - 1.0;
double y = y0 * sclY + cyS;
double yn = (y0 + 1.0) * sclY + cyS;
if (yn >= (sheight - 0.5))
yn = sheight - 1.0;
// render it
if (((int) x < 0) || ((int) x >= swidth) || ((int) y < 0) || ((int) y >= sheight)) {
pPixel.r = pPixel.g = pPixel.b = 0;
}
else {
double xi = Tools.fmod33(x);
double yi = Tools.fmod33(y);
readSrcPixels(srcImg, x, y);
// 1st line
readSrcPixels(srcImg, x, y);
int cvalR = roundColor(((1.0 - yi) * ((1.0 - xi) * (srcP.r) + xi * (srcQ.r)) + yi
* ((1.0 - xi) * (srcR.r) + xi * (srcS.r))));
int cvalG = roundColor(((1.0 - yi) * ((1.0 - xi) * (srcP.g) + xi * (srcQ.g)) + yi
* ((1.0 - xi) * (srcR.g) + xi * (srcS.g))));
int cvalB = roundColor(((1.0 - yi) * ((1.0 - xi) * (srcP.b) + xi * (srcQ.b)) + yi
* ((1.0 - xi) * (srcR.b) + xi * (srcS.b))));
double xc = x - xi + 1.0;
int cnt = 1;
while (xc < xn) {
readSrcPixels(srcImg, x, y);
cvalR += (1.0 - yi) * srcP.r + yi * srcR.r;
cvalG += (1.0 - yi) * srcP.g + yi * srcR.g;
cvalB += (1.0 - yi) * srcP.b + yi * srcR.b;
xc += 1.0;
cnt++;
}
// remaining lines
y = y - yi + 1.0;
while (y < yn) {
// 1st point
readSrcPixels(srcImg, x, y);
cvalR += (1.0 - xi) * srcP.r + xi * srcQ.r;
cvalG += (1.0 - xi) * srcP.g + xi * srcQ.g;
cvalB += (1.0 - xi) * srcP.b + xi * srcQ.b;
// remaining points
xc = x - xi + 1.0;
cnt++;
while (xc < xn) {
readSrcPixels(srcImg, x, y);
cvalR += srcP.r;
cvalG += srcP.g;
cvalB += srcP.b;
xc += 1.0;
cnt++;
}
y += 1.0;
}
pPixel.r = roundColor(cvalR / (double) cnt);
pPixel.g = roundColor(cvalG / (double) cnt);
pPixel.b = roundColor(cvalB / (double) cnt);
}
dstImg.setRGB(j, i, pPixel.r, pPixel.g, pPixel.b);
}
}
}
double fmod33(double arg) {
return (arg - (double) ((int) arg));
}
@Override
public void initDefaultParams(WFImage pImg) {
unit = Unit.PIXELS;
aspect = ScaleAspect.KEEP_WIDTH;
scaleWidth = 320;
scaleHeight = 256;
}
public boolean acceptsInputBufferType(BufferType pBufferType) {
return (pBufferType == BufferType.IMAGE);
}
protected Pixel srcP = new Pixel();
protected Pixel srcQ = new Pixel();
protected Pixel srcR = new Pixel();
protected Pixel srcS = new Pixel();
protected void readSrcPixels(SimpleImage srcImg, double pX, double pY) {
int x = (int) (pX + 0.5);
int y = (int) (pY + 0.5);
int w = srcImg.getImageWidth();
int h = srcImg.getImageHeight();
if ((x < 0) || (x >= w) || (y < 0) || (y >= h)) {
srcP.clear();
srcQ.clear();
srcR.clear();
srcS.clear();
}
else {
srcP.setARGBValue(srcImg.getBufferedImg().getRGB(x, y));
if (x < w - 1)
srcQ.setARGBValue(srcImg.getBufferedImg().getRGB(x + 1, y));
else
srcQ.assign(srcP);
if (y < h - 1) {
srcR.setARGBValue(srcImg.getBufferedImg().getRGB(x, y + 1));
if (x < w - 1)
srcS.setARGBValue(srcImg.getBufferedImg().getRGB(x + 1, y + 1));
else
srcS.assign(srcQ);
}
else {
srcR.assign(srcP);
srcS.assign(srcQ);
}
}
}
@Override
protected boolean allowShowStats() {
return false;
}
}