package org.jcodec.scale;
import org.jcodec.common.model.Size;
/**
* Resamples image interpolating points using Lanczos sinc over sine windowed
* filter.
*
* @author Stanislav Vitvitskiy
*/
public class LanczosResampler extends BaseResampler {
private int nTaps = 6;
private int precision = 256;
private short[][] tapsXs;
private short[][] tapsYs;
private double scaleFactorX;
private double scaleFactorY;
public LanczosResampler(Size from, Size to) {
super(from, to);
scaleFactorX = (double) to.getWidth() / from.getWidth();
scaleFactorY = (double) to.getHeight() / from.getHeight();
tapsXs = new short[precision][nTaps];
tapsYs = new short[precision][nTaps];
buildTaps(nTaps, precision, scaleFactorX, tapsXs);
buildTaps(nTaps, precision, scaleFactorY, tapsYs);
}
private static double sinc(double x) {
return x == 0 ? 1f : (Math.sin(x) / x);
}
private static void buildTaps(int nTaps, int precision, double scaleFactor, short[][] tapsOut) {
double[] taps = new double[nTaps];
for (int i = 0; i < precision; i++) {
double o = (double) (i) / precision;
for (int j = -nTaps / 2 + 1, t = 0; j < nTaps / 2 + 1; j++, t++) {
double x = -o + j;
double sinc_val = scaleFactor * sinc(scaleFactor * x * Math.PI);
double wnd_val = Math.sin((x * Math.PI) / (nTaps - 1) + Math.PI / 2);
taps[t] = sinc_val * wnd_val;
}
normalizeAndGenerateFixedPrecision(taps, 7, tapsOut[i]);
}
}
@Override
protected short[] getTapsX(int dstX) {
int oi = (int) ((float) (dstX * precision) / scaleFactorX);
int sub_pel = oi % precision;
return tapsXs[sub_pel];
}
@Override
protected short[] getTapsY(int dstY) {
int oy = (int) ((float) (dstY * precision) / scaleFactorY);
int sub_pel = oy % precision;
return tapsYs[sub_pel];
}
@Override
protected int nTaps() {
return nTaps;
}
}