/*
* Copyright 2017 Laszlo Balazs-Csiki
*
* This file is part of Pixelitor. Pixelitor is free software: you
* can redistribute it and/or modify it under the terms of the GNU
* General Public License, version 3 as published by the Free
* Software Foundation.
*
* Pixelitor 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Pixelitor. If not, see <http://www.gnu.org/licenses/>.
*/
package pixelitor.filters.jhlabsproxies;
import com.jhlabs.image.ShadowFilter;
import pixelitor.filters.FilterWithParametrizedGUI;
import pixelitor.filters.ResizingFilterHelper;
import pixelitor.filters.gui.AngleParam;
import pixelitor.filters.gui.BooleanParam;
import pixelitor.filters.gui.ColorParam;
import pixelitor.filters.gui.ParamSet;
import pixelitor.filters.gui.RangeParam;
import pixelitor.filters.gui.ShowOriginal;
import pixelitor.utils.BasicProgressTracker;
import pixelitor.utils.ImageUtils;
import pixelitor.utils.ProgressTracker;
import java.awt.AlphaComposite;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import static java.awt.Color.BLACK;
import static pixelitor.filters.ResizingFilterHelper.ScaleUpQuality.BILINEAR_FAST;
import static pixelitor.filters.gui.ColorParam.OpacitySetting.NO_OPACITY;
/**
* Drop Shadow based on the JHLabs ShadowFilter
*/
public class JHDropShadow extends FilterWithParametrizedGUI {
public static final String NAME = "Drop Shadow";
private final AngleParam angle = new AngleParam("Angle", ImageUtils.DEG_315_IN_RADIANS);
private final RangeParam distance = new RangeParam("Distance", 0, 10, 100);
private final RangeParam opacity = new RangeParam("Opacity (%)", 0, 90, 100);
private final RangeParam softness = new RangeParam("Softness", 0, 10, 25);
private final BooleanParam shadowOnly = new BooleanParam("Shadow Only", false);
private final ColorParam color = new ColorParam("Color", BLACK, NO_OPACITY);
private ShadowFilter filter;
public JHDropShadow() {
super(ShowOriginal.YES);
setParamSet(new ParamSet(
angle,
distance.withAdjustedRange(0.1),
opacity,
softness.withAdjustedRange(0.025),
color,
shadowOnly
));
}
@Override
public BufferedImage doTransform(BufferedImage src, BufferedImage dest) {
if (filter == null) {
filter = new ShadowFilter(NAME);
}
filter.setAddMargins(false);
filter.setAngle((float) angle.getValueInIntuitiveRadians());
filter.setOpacity(opacity.getValueAsPercentage());
filter.setShadowColor(color.getColor().getRGB());
filter.setShadowOnly(shadowOnly.isChecked());
ResizingFilterHelper r = new ResizingFilterHelper(src);
boolean shouldResize = r.shouldResize();
if (shouldResize) {
boolean addSource = !shadowOnly.isChecked();
int resizeUnits = r.getResizeWorkUnits(BILINEAR_FAST);
int filterUnits = 2; // estimated
int workUnits = resizeUnits + filterUnits;
if (addSource) {
workUnits++;
}
ProgressTracker pt = new BasicProgressTracker(NAME, workUnits);
// ProgressTracker pt = new DebugProgressTracker(NAME, workUnits);
filter.setProgressTracker(ProgressTracker.NULL_TRACKER);
double resizeFactor = r.getResizeFactor();
filter.setDistance((float) (distance.getValueAsFloat() / resizeFactor));
filter.setRadius((float) (softness.getValueAsFloat() / resizeFactor));
filter.setShadowOnly(true); // we only want to resize the shadow
dest = r.invoke(BILINEAR_FAST, filter, pt, filterUnits);
if (addSource) {
Graphics2D g = dest.createGraphics();
g.setComposite(AlphaComposite.SrcOver);
g.drawRenderedImage(src, null);
g.dispose();
pt.unitDone();
}
pt.finish();
} else {
// normal case, no resizing
filter.setDistance(distance.getValueAsFloat());
filter.setRadius(softness.getValueAsFloat());
dest = filter.filter(src, dest);
}
return dest;
}
public void setSoftness(int newSoftness) {
softness.setValue(newSoftness);
}
public void setDistance(int newDistance) {
distance.setValue(newDistance);
}
public void setOpacity(float newValue) {
opacity.setValue((int) (100 * newValue));
}
@Override
public boolean supportsGray() {
return false;
}
}