/*
* $Id$
*
* Copyright (C) 2003-2014 JNode.org
*
* This library 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 library 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 library; If not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.jnode.awt.font.renderer;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
import java.awt.image.ColorModel;
import java.awt.image.ComponentSampleModel;
import java.awt.image.DataBuffer;
import java.awt.image.ImagingOpException;
import java.awt.image.Kernel;
import java.awt.image.Raster;
import java.awt.image.RasterOp;
import java.awt.image.SampleModel;
import java.awt.image.WritableRaster;
import java.util.Arrays;
/**
* @author Ewout Prangsma (epr@users.sourceforge.net)
*/
public class FontScaleOp implements BufferedImageOp, RasterOp {
private final int dstHeight;
private final int dstWidth;
private final Kernel kernel;
public FontScaleOp(int dstWidth, int dstHeight, Kernel kernel) {
this.dstHeight = dstHeight;
this.dstWidth = dstWidth;
this.kernel = kernel;
}
/**
* @see java.awt.image.BufferedImageOp#createCompatibleDestImage(java.awt.image.BufferedImage,
* java.awt.image.ColorModel)
*/
public BufferedImage createCompatibleDestImage(BufferedImage src,
ColorModel dstCM) {
return new BufferedImage(dstWidth, dstHeight,
BufferedImage.TYPE_BYTE_GRAY);
}
/**
* @see java.awt.image.RasterOp#createCompatibleDestRaster(java.awt.image.Raster)
*/
public WritableRaster createCompatibleDestRaster(Raster src) {
SampleModel sm = new ComponentSampleModel(DataBuffer.TYPE_BYTE,
dstWidth, dstHeight, 0, 0, new int[]{0});
return Raster.createWritableRaster(sm, sm.createDataBuffer(),
new Point(0, 0));
}
/**
* @see java.awt.image.BufferedImageOp#filter(java.awt.image.BufferedImage,
* java.awt.image.BufferedImage)
*/
public BufferedImage filter(BufferedImage src, BufferedImage dst) {
if (src == dst) {
throw new IllegalArgumentException("src == dst");
}
if (dst == null) {
dst = createCompatibleDestImage(src, src.getColorModel());
}
filter(src.getRaster(), dst.getRaster());
return dst;
}
/**
* @see java.awt.image.RasterOp#filter(java.awt.image.Raster,
* java.awt.image.WritableRaster)
*/
public WritableRaster filter(Raster src, WritableRaster dest) {
if (src == dest) {
throw new IllegalArgumentException("src == dest");
}
if ((src.getWidth() < kernel.getWidth()) || (src.getHeight() < kernel.getHeight())) {
throw new ImagingOpException("src.bounds < kernel.bounds");
}
if (dest == null) {
dest = createCompatibleDestRaster(src);
}
final int srcWidth = src.getWidth();
final int srcHeight = src.getHeight();
final double sx = srcWidth / (double) dstWidth;
final double sy = srcHeight / (double) dstHeight;
final int kw = kernel.getWidth();
final int kh = kernel.getHeight();
final float[] kData = kernel.getKernelData(null);
final float[] tmp = new float[kw * kh];
final int tmpLength = tmp.length;
for (int y = 0; y < dstHeight; y++) {
final int srcY = (int) (y * sy);
for (int x = 0; x < dstWidth; x++) {
final int srcX = (int) (x * sx);
getSamples(src, srcWidth, srcHeight, srcX, srcY, kw, kh, tmp);
float v = 0.0f;
for (int i = 0; i < tmpLength; i++) {
v += tmp[i] * kData[i];
}
dest.setSample(x, y, 0, v);
}
}
return dest;
}
private final void getSamples(Raster src, int srcWidth, int srcHeight,
int x, int y, int w, int h, float[] data) {
if ((x < 0) || (x + w > srcWidth) || (y < 0) || (y + h > srcHeight)) {
// Somewhere out of bounds
Arrays.fill(data, 0.0f);
for (int yy = y; yy < y + h; yy++) {
if ((yy >= 0) && (yy < srcHeight)) {
for (int xx = x; xx < x + w; xx++) {
if ((xx >= 0) && (xx < srcWidth)) {
float v = src.getSampleFloat(xx, yy, 0);
data[(yy - y) * w + (xx - x)] = v;
}
}
}
}
} else {
// All samples visible
src.getSamples(x, y, w, h, 0, data);
}
}
/**
* @see java.awt.image.BufferedImageOp#getBounds2D(java.awt.image.BufferedImage)
*/
public Rectangle2D getBounds2D(BufferedImage src) {
return new Rectangle(0, 0, dstWidth, dstHeight);
}
/**
* @see java.awt.image.RasterOp#getBounds2D(java.awt.image.Raster)
*/
public Rectangle2D getBounds2D(Raster src) {
return new Rectangle(0, 0, dstWidth, dstHeight);
}
/**
* @see java.awt.image.RasterOp#getPoint2D(java.awt.geom.Point2D,
* java.awt.geom.Point2D)
*/
public Point2D getPoint2D(Point2D srcPoint, Point2D destPoint) {
return srcPoint;
}
/**
* @see java.awt.image.RasterOp#getRenderingHints()
*/
public RenderingHints getRenderingHints() {
return null;
}
}