mirror of https://github.com/adamdruppe/arsd.git
Templatize bilinear up/down scaler
This commit is contained in:
parent
7f91abfc0a
commit
31308e0777
557
pixmappaint.d
557
pixmappaint.d
|
@ -3019,237 +3019,108 @@ private void scaleToImpl(ScalingFilter filter)(const Pixmap source, Pixmap targe
|
||||||
|
|
||||||
// ==== Bilinear ====
|
// ==== Bilinear ====
|
||||||
static if ((filter == ScalingFilter.bilinear) || (filter == ScalingFilter.fauxLinear)) {
|
static if ((filter == ScalingFilter.bilinear) || (filter == ScalingFilter.fauxLinear)) {
|
||||||
const Size delta = (target.size - source.size);
|
void scaleToLinearImpl(ScalingDirection directionX, ScalingDirection directionY)() {
|
||||||
|
auto dst = PixmapScannerRW(target);
|
||||||
|
|
||||||
const ScalingDirection[2] directions = [
|
size_t y = 0;
|
||||||
scalingDirectionFromDelta(delta.width),
|
foreach (dstLine; dst) {
|
||||||
scalingDirectionFromDelta(delta.height),
|
foreach (x, ref pxDst; dstLine) {
|
||||||
];
|
const posDst = Point(x.castTo!int, y.castTo!int);
|
||||||
|
|
||||||
auto dst = PixmapScannerRW(target);
|
const UDecimal[2] posSrc = [
|
||||||
|
posDst.x * ratios[idxX],
|
||||||
|
posDst.y * ratios[idxY],
|
||||||
|
];
|
||||||
|
|
||||||
size_t y = 0;
|
const int[2] posSrcX = () {
|
||||||
foreach (dstLine; dst) {
|
int[2] result;
|
||||||
foreach (x, ref pxDst; dstLine) {
|
static if (directionX == none) {
|
||||||
const posDst = Point(x.castTo!int, y.castTo!int);
|
result = [
|
||||||
|
posSrc[idxX].castTo!int,
|
||||||
const UDecimal[2] posSrc = [
|
posSrc[idxX].castTo!int,
|
||||||
posDst.x * ratios[idxX],
|
];
|
||||||
posDst.y * ratios[idxY],
|
} else static if (directionX == up) {
|
||||||
];
|
result = [
|
||||||
|
min(sourceMaxX, posSrc[idxX].floor().castTo!int),
|
||||||
const int[2] posSrcX = () {
|
min(sourceMaxX, posSrc[idxX].ceil().castTo!int),
|
||||||
int[2] result;
|
];
|
||||||
if (directions[idxX] == none) {
|
} else /* if (directionX == down) */ {
|
||||||
result = [
|
const ratioXHalf = (ratios[idxX] >> 1);
|
||||||
posSrc[idxX].castTo!int,
|
result = [
|
||||||
posSrc[idxX].castTo!int,
|
max((posSrc[idxX] - ratioXHalf).roundEven().castTo!int, 0),
|
||||||
];
|
min((posSrc[idxX] + ratioXHalf).roundEven().castTo!int, sourceMaxX),
|
||||||
} else if (directions[idxX] == up) {
|
];
|
||||||
result = [
|
}
|
||||||
min(sourceMaxX, posSrc[idxX].floor().castTo!int),
|
return result;
|
||||||
min(sourceMaxX, posSrc[idxX].ceil().castTo!int),
|
}();
|
||||||
];
|
|
||||||
} else /* if (directions[0] == down) */ {
|
const int[2] posSrcY = () {
|
||||||
const ratioXHalf = (ratios[idxX] >> 1);
|
int[2] result;
|
||||||
result = [
|
static if (directionY == none) {
|
||||||
max((posSrc[idxX] - ratioXHalf).roundEven().castTo!int, 0),
|
result = [
|
||||||
min((posSrc[idxX] + ratioXHalf).roundEven().castTo!int, sourceMaxX),
|
posSrc[idxY].castTo!int,
|
||||||
];
|
posSrc[idxY].castTo!int,
|
||||||
}
|
];
|
||||||
return result;
|
} else static if (directionY == up) {
|
||||||
}();
|
result = [
|
||||||
|
min(sourceMaxY, posSrc[idxY].floor().castTo!int),
|
||||||
const int[2] posSrcY = () {
|
min(sourceMaxY, posSrc[idxY].ceil().castTo!int),
|
||||||
int[2] result;
|
];
|
||||||
if (directions[idxY] == none) {
|
} else /* if (directionY == down) */ {
|
||||||
result = [
|
const ratioHalf = (ratios[idxY] >> 1);
|
||||||
posSrc[idxY].castTo!int,
|
result = [
|
||||||
posSrc[idxY].castTo!int,
|
max((posSrc[idxY] - ratioHalf).roundEven().castTo!int, 0),
|
||||||
];
|
min((posSrc[idxY] + ratioHalf).roundEven().castTo!int, sourceMaxY),
|
||||||
} else if (directions[idxY] == up) {
|
];
|
||||||
result = [
|
}
|
||||||
min(sourceMaxY, posSrc[idxY].floor().castTo!int),
|
return result;
|
||||||
min(sourceMaxY, posSrc[idxY].ceil().castTo!int),
|
}();
|
||||||
];
|
|
||||||
} else /* if (directions[idxY] == down) */ {
|
enum idxL = 0, idxR = 1;
|
||||||
const ratioHalf = (ratios[idxY] >> 1);
|
enum idxT = 0, idxB = 1;
|
||||||
result = [
|
|
||||||
max((posSrc[idxY] - ratioHalf).roundEven().castTo!int, 0),
|
const Point[4] posNeighs = [
|
||||||
min((posSrc[idxY] + ratioHalf).roundEven().castTo!int, sourceMaxY),
|
Point(posSrcX[idxL], posSrcY[idxT]),
|
||||||
];
|
Point(posSrcX[idxR], posSrcY[idxT]),
|
||||||
}
|
Point(posSrcX[idxL], posSrcY[idxB]),
|
||||||
return result;
|
Point(posSrcX[idxR], posSrcY[idxB]),
|
||||||
}();
|
];
|
||||||
|
|
||||||
enum idxL = 0, idxR = 1;
|
const Color[4] pxNeighs = [
|
||||||
enum idxT = 0, idxB = 1;
|
source.getPixel(posNeighs[0]),
|
||||||
|
source.getPixel(posNeighs[1]),
|
||||||
const Point[4] posNeighs = [
|
source.getPixel(posNeighs[2]),
|
||||||
Point(posSrcX[idxL], posSrcY[idxT]),
|
source.getPixel(posNeighs[3]),
|
||||||
Point(posSrcX[idxR], posSrcY[idxT]),
|
];
|
||||||
Point(posSrcX[idxL], posSrcY[idxB]),
|
|
||||||
Point(posSrcX[idxR], posSrcY[idxB]),
|
enum idxTL = 0, idxTR = 1, idxBL = 2, idxBR = 3;
|
||||||
];
|
|
||||||
|
// ====== Faux bilinear ======
|
||||||
const Color[4] pxNeighs = [
|
static if (filter == ScalingFilter.fauxLinear) {
|
||||||
source.getPixel(posNeighs[0]),
|
auto pxInt = Pixel(0, 0, 0, 0);
|
||||||
source.getPixel(posNeighs[1]),
|
|
||||||
source.getPixel(posNeighs[2]),
|
foreach (immutable ib, ref c; pxInt.components) {
|
||||||
source.getPixel(posNeighs[3]),
|
uint sum = 0;
|
||||||
];
|
foreach (const pxNeigh; pxNeighs) {
|
||||||
|
sum += (() @trusted => pxNeigh.components.ptr[ib])();
|
||||||
enum idxTL = 0, idxTR = 1, idxBL = 2, idxBR = 3;
|
}
|
||||||
|
c = (sum >> 2).castTo!ubyte;
|
||||||
// ====== Faux bilinear ======
|
|
||||||
static if (filter == ScalingFilter.fauxLinear) {
|
|
||||||
auto pxInt = Pixel(0, 0, 0, 0);
|
|
||||||
|
|
||||||
foreach (immutable ib, ref c; pxInt.components) {
|
|
||||||
uint sum = 0;
|
|
||||||
foreach (const pxNeigh; pxNeighs) {
|
|
||||||
sum += (() @trusted => pxNeigh.components.ptr[ib])();
|
|
||||||
}
|
}
|
||||||
c = (sum >> 2).castTo!ubyte;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// ====== Proper bilinear (up) + Avg (down) ======
|
// ====== Proper bilinear (up) + Avg (down) ======
|
||||||
static if (filter == ScalingFilter.bilinear) {
|
static if (filter == ScalingFilter.bilinear) {
|
||||||
auto pxInt = Pixel(0, 0, 0, 0);
|
auto pxInt = Pixel(0, 0, 0, 0);
|
||||||
foreach (immutable ib, ref c; pxInt.components) {
|
foreach (immutable ib, ref c; pxInt.components) {
|
||||||
ulong sampleX() {
|
ulong sampleX() {
|
||||||
pragma(inline, true);
|
pragma(inline, true);
|
||||||
|
|
||||||
if (directions[0] == none) {
|
static if (directionX == none) {
|
||||||
return (() @trusted => pxNeighs[idxTL].components.ptr[ib])();
|
return (() @trusted => pxNeighs[idxTL].components.ptr[ib])();
|
||||||
} else if (directions[0] == down) {
|
} else static if (directionX == down) {
|
||||||
const nSamples = 1 + posSrcX[idxR] - posSrcX[idxL];
|
const nSamples = 1 + posSrcX[idxR] - posSrcX[idxL];
|
||||||
const posSampling = Point(posSrcX[idxL], posSrcY[idxT]);
|
const posSampling = Point(posSrcX[idxL], posSrcY[idxT]);
|
||||||
const samplingOffset = source.scanTo(posSampling);
|
const samplingOffset = source.scanTo(posSampling);
|
||||||
const srcSamples = () @trusted {
|
|
||||||
return source.data.ptr[samplingOffset .. (samplingOffset + nSamples)];
|
|
||||||
}();
|
|
||||||
|
|
||||||
ulong xSum = 0;
|
|
||||||
|
|
||||||
foreach (srcSample; srcSamples) {
|
|
||||||
xSum += (() @trusted => srcSample.components.ptr[ib])();
|
|
||||||
}
|
|
||||||
|
|
||||||
return (xSum / nSamples);
|
|
||||||
} else /* if (directions[0] == up) */ {
|
|
||||||
ulong xSum = 0;
|
|
||||||
|
|
||||||
const ulong[2] weightsX = () {
|
|
||||||
ulong[2] result;
|
|
||||||
result[1] = posSrc[0].fractionalDigits;
|
|
||||||
result[0] = ulong(uint.max) + 1 - result[1];
|
|
||||||
return result;
|
|
||||||
}();
|
|
||||||
|
|
||||||
() @trusted {
|
|
||||||
xSum += (pxNeighs[idxTL].components.ptr[ib] * weightsX[0]);
|
|
||||||
xSum += (pxNeighs[idxTR].components.ptr[ib] * weightsX[1]);
|
|
||||||
}();
|
|
||||||
|
|
||||||
return (xSum >> 32);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ulong[2] sampleXDual() {
|
|
||||||
pragma(inline, true);
|
|
||||||
|
|
||||||
if (directions[0] == none) {
|
|
||||||
return () @trusted {
|
|
||||||
ulong[2] result = [
|
|
||||||
pxNeighs[idxTL].components.ptr[ib],
|
|
||||||
pxNeighs[idxBL].components.ptr[ib],
|
|
||||||
];
|
|
||||||
return result;
|
|
||||||
}();
|
|
||||||
} else if (directions[0] == down) {
|
|
||||||
const nSamples = 1 + posSrcX[idxR] - posSrcX[idxL];
|
|
||||||
const Point[2] posSampling = [
|
|
||||||
Point(posSrcX[idxL], posSrcY[idxT]),
|
|
||||||
Point(posSrcX[idxL], posSrcY[idxB]),
|
|
||||||
];
|
|
||||||
|
|
||||||
const int[2] samplingOffsets = [
|
|
||||||
source.scanTo(posSampling[0]),
|
|
||||||
source.scanTo(posSampling[1]),
|
|
||||||
];
|
|
||||||
|
|
||||||
const srcSamples2 = () @trusted {
|
|
||||||
const(const(Pixel)[])[2] result = [
|
|
||||||
source.data.ptr[samplingOffsets[0] .. (samplingOffsets[0] + nSamples)],
|
|
||||||
source.data.ptr[samplingOffsets[1] .. (samplingOffsets[1] + nSamples)],
|
|
||||||
];
|
|
||||||
return result;
|
|
||||||
}();
|
|
||||||
|
|
||||||
ulong[2] xSums = [0, 0];
|
|
||||||
|
|
||||||
foreach (idx, srcSamples; srcSamples2) {
|
|
||||||
foreach (srcSample; srcSamples) {
|
|
||||||
() @trusted { xSums.ptr[idx] += srcSample.components.ptr[ib]; }();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
xSums[] /= nSamples;
|
|
||||||
return xSums;
|
|
||||||
} else /* if (directions[0] == up) */ {
|
|
||||||
ulong[2] xSums = [0, 0];
|
|
||||||
|
|
||||||
const ulong[2] weightsX = () {
|
|
||||||
ulong[2] result;
|
|
||||||
result[1] = posSrc[0].fractionalDigits;
|
|
||||||
result[0] = ulong(uint.max) + 1 - result[1];
|
|
||||||
return result;
|
|
||||||
}();
|
|
||||||
|
|
||||||
() @trusted {
|
|
||||||
xSums[0] += (pxNeighs[idxTL].components.ptr[ib] * weightsX[0]);
|
|
||||||
xSums[0] += (pxNeighs[idxTR].components.ptr[ib] * weightsX[1]);
|
|
||||||
|
|
||||||
xSums[1] += (pxNeighs[idxBL].components.ptr[ib] * weightsX[0]);
|
|
||||||
xSums[1] += (pxNeighs[idxBR].components.ptr[ib] * weightsX[1]);
|
|
||||||
}();
|
|
||||||
|
|
||||||
foreach (ref sum; xSums) {
|
|
||||||
sum >>= 32;
|
|
||||||
}
|
|
||||||
|
|
||||||
return xSums;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ulong sampleXMulti() {
|
|
||||||
pragma(inline, true);
|
|
||||||
|
|
||||||
const nLines = 1 + posSrcY[idxB] - posSrcY[idxT];
|
|
||||||
ulong ySum = 0;
|
|
||||||
|
|
||||||
alias ForeachLineCallback = ulong delegate(const Point posLine) @safe pure nothrow @nogc;
|
|
||||||
ulong foreachLine(scope ForeachLineCallback apply) {
|
|
||||||
ulong linesSum = 0;
|
|
||||||
foreach (lineY; posSrcY[idxT] .. (1 + posSrcY[idxB])) {
|
|
||||||
const posLine = Point(posSrcX[idxL], lineY);
|
|
||||||
linesSum += apply(posLine);
|
|
||||||
}
|
|
||||||
return linesSum;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (directions[0] == none) {
|
|
||||||
ySum = foreachLine(delegate(const Point posLine) {
|
|
||||||
const pxSrc = source.getPixel(posLine);
|
|
||||||
return ulong((() @trusted => pxSrc.components.ptr[ib])());
|
|
||||||
});
|
|
||||||
} else if (directions[0] == down) {
|
|
||||||
const nSamples = 1 + posSrcX[idxR] - posSrcX[idxL];
|
|
||||||
|
|
||||||
ySum = foreachLine(delegate(const Point posLine) {
|
|
||||||
const samplingOffset = source.scanTo(posLine);
|
|
||||||
const srcSamples = () @trusted {
|
const srcSamples = () @trusted {
|
||||||
return source.data.ptr[samplingOffset .. (samplingOffset + nSamples)];
|
return source.data.ptr[samplingOffset .. (samplingOffset + nSamples)];
|
||||||
}();
|
}();
|
||||||
|
@ -3260,14 +3131,8 @@ private void scaleToImpl(ScalingFilter filter)(const Pixmap source, Pixmap targe
|
||||||
xSum += (() @trusted => srcSample.components.ptr[ib])();
|
xSum += (() @trusted => srcSample.components.ptr[ib])();
|
||||||
}
|
}
|
||||||
|
|
||||||
return xSum;
|
return (xSum / nSamples);
|
||||||
});
|
} else /* if (directionX == up) */ {
|
||||||
|
|
||||||
ySum /= nSamples;
|
|
||||||
} else /* if (directions[0] == up) */ {
|
|
||||||
const nSamples = 1 + posSrcX[idxR] - posSrcX[idxL];
|
|
||||||
|
|
||||||
ySum = foreachLine(delegate(const Point posLine) {
|
|
||||||
ulong xSum = 0;
|
ulong xSum = 0;
|
||||||
|
|
||||||
const ulong[2] weightsX = () {
|
const ulong[2] weightsX = () {
|
||||||
|
@ -3277,55 +3142,221 @@ private void scaleToImpl(ScalingFilter filter)(const Pixmap source, Pixmap targe
|
||||||
return result;
|
return result;
|
||||||
}();
|
}();
|
||||||
|
|
||||||
const samplingOffset = source.scanTo(posLine);
|
() @trusted {
|
||||||
ubyte[2] pxcLR = () @trusted {
|
xSum += (pxNeighs[idxTL].components.ptr[ib] * weightsX[0]);
|
||||||
ubyte[2] result = [
|
xSum += (pxNeighs[idxTR].components.ptr[ib] * weightsX[1]);
|
||||||
source.data.ptr[samplingOffset].components.ptr[ib],
|
}();
|
||||||
source.data.ptr[samplingOffset + nSamples].components.ptr[ib],
|
|
||||||
|
return (xSum >> 32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ulong[2] sampleXDual() {
|
||||||
|
pragma(inline, true);
|
||||||
|
|
||||||
|
static if (directionX == none) {
|
||||||
|
return () @trusted {
|
||||||
|
ulong[2] result = [
|
||||||
|
pxNeighs[idxTL].components.ptr[ib],
|
||||||
|
pxNeighs[idxBL].components.ptr[ib],
|
||||||
|
];
|
||||||
|
return result;
|
||||||
|
}();
|
||||||
|
} else static if (directionX == down) {
|
||||||
|
const nSamples = 1 + posSrcX[idxR] - posSrcX[idxL];
|
||||||
|
const Point[2] posSampling = [
|
||||||
|
Point(posSrcX[idxL], posSrcY[idxT]),
|
||||||
|
Point(posSrcX[idxL], posSrcY[idxB]),
|
||||||
|
];
|
||||||
|
|
||||||
|
const int[2] samplingOffsets = [
|
||||||
|
source.scanTo(posSampling[0]),
|
||||||
|
source.scanTo(posSampling[1]),
|
||||||
|
];
|
||||||
|
|
||||||
|
const srcSamples2 = () @trusted {
|
||||||
|
const(const(Pixel)[])[2] result = [
|
||||||
|
source.data.ptr[samplingOffsets[0] .. (samplingOffsets[0] + nSamples)],
|
||||||
|
source.data.ptr[samplingOffsets[1] .. (samplingOffsets[1] + nSamples)],
|
||||||
];
|
];
|
||||||
return result;
|
return result;
|
||||||
}();
|
}();
|
||||||
|
|
||||||
xSum += (pxcLR[idxL] * weightsX[idxL]);
|
ulong[2] xSums = [0, 0];
|
||||||
xSum += (pxcLR[idxR] * weightsX[idxR]);
|
|
||||||
|
|
||||||
return (xSum >> 32);
|
foreach (idx, srcSamples; srcSamples2) {
|
||||||
});
|
foreach (srcSample; srcSamples) {
|
||||||
|
() @trusted { xSums.ptr[idx] += srcSample.components.ptr[ib]; }();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
xSums[] /= nSamples;
|
||||||
|
return xSums;
|
||||||
|
} else /* if (directionX == up) */ {
|
||||||
|
ulong[2] xSums = [0, 0];
|
||||||
|
|
||||||
|
const ulong[2] weightsX = () {
|
||||||
|
ulong[2] result;
|
||||||
|
result[1] = posSrc[0].fractionalDigits;
|
||||||
|
result[0] = ulong(uint.max) + 1 - result[1];
|
||||||
|
return result;
|
||||||
|
}();
|
||||||
|
|
||||||
|
() @trusted {
|
||||||
|
xSums[0] += (pxNeighs[idxTL].components.ptr[ib] * weightsX[0]);
|
||||||
|
xSums[0] += (pxNeighs[idxTR].components.ptr[ib] * weightsX[1]);
|
||||||
|
|
||||||
|
xSums[1] += (pxNeighs[idxBL].components.ptr[ib] * weightsX[0]);
|
||||||
|
xSums[1] += (pxNeighs[idxBR].components.ptr[ib] * weightsX[1]);
|
||||||
|
}();
|
||||||
|
|
||||||
|
foreach (ref sum; xSums) {
|
||||||
|
sum >>= 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
return xSums;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (ySum / nLines);
|
ulong sampleXMulti() {
|
||||||
}
|
pragma(inline, true);
|
||||||
|
|
||||||
if (directions[idxY] == none) {
|
const nLines = 1 + posSrcY[idxB] - posSrcY[idxT];
|
||||||
c = clamp255(sampleX());
|
ulong ySum = 0;
|
||||||
} else if (directions[idxY] == down) {
|
|
||||||
c = clamp255(sampleXMulti());
|
|
||||||
} else /* if (directions[idxY] == up) */ {
|
|
||||||
// looks ass
|
|
||||||
const ulong[2] weightsY = () {
|
|
||||||
ulong[2] result;
|
|
||||||
result[idxB] = posSrc[1].fractionalDigits;
|
|
||||||
result[idxT] = ulong(uint.max) + 1 - result[idxB];
|
|
||||||
return result;
|
|
||||||
}();
|
|
||||||
|
|
||||||
const xSums = sampleXDual();
|
alias ForeachLineCallback = ulong delegate(const Point posLine) @safe pure nothrow @nogc;
|
||||||
|
ulong foreachLine(scope ForeachLineCallback apply) {
|
||||||
|
ulong linesSum = 0;
|
||||||
|
foreach (lineY; posSrcY[idxT] .. (1 + posSrcY[idxB])) {
|
||||||
|
const posLine = Point(posSrcX[idxL], lineY);
|
||||||
|
linesSum += apply(posLine);
|
||||||
|
}
|
||||||
|
return linesSum;
|
||||||
|
}
|
||||||
|
|
||||||
ulong ySum = 0;
|
static if (directionX == none) {
|
||||||
ySum += (xSums[idxT] * weightsY[idxT]);
|
ySum = foreachLine(delegate(const Point posLine) {
|
||||||
ySum += (xSums[idxB] * weightsY[idxB]);
|
const pxSrc = source.getPixel(posLine);
|
||||||
|
return ulong((() @trusted => pxSrc.components.ptr[ib])());
|
||||||
|
});
|
||||||
|
} else static if (directionX == down) {
|
||||||
|
const nSamples = 1 + posSrcX[idxR] - posSrcX[idxL];
|
||||||
|
|
||||||
const xySum = (ySum >> 32);
|
ySum = foreachLine(delegate(const Point posLine) {
|
||||||
|
const samplingOffset = source.scanTo(posLine);
|
||||||
|
const srcSamples = () @trusted {
|
||||||
|
return source.data.ptr[samplingOffset .. (samplingOffset + nSamples)];
|
||||||
|
}();
|
||||||
|
|
||||||
c = clamp255(xySum);
|
ulong xSum = 0;
|
||||||
|
|
||||||
|
foreach (srcSample; srcSamples) {
|
||||||
|
xSum += (() @trusted => srcSample.components.ptr[ib])();
|
||||||
|
}
|
||||||
|
|
||||||
|
return xSum;
|
||||||
|
});
|
||||||
|
|
||||||
|
ySum /= nSamples;
|
||||||
|
} else /* if (directionX == up) */ {
|
||||||
|
const nSamples = 1 + posSrcX[idxR] - posSrcX[idxL];
|
||||||
|
|
||||||
|
ySum = foreachLine(delegate(const Point posLine) {
|
||||||
|
ulong xSum = 0;
|
||||||
|
|
||||||
|
const ulong[2] weightsX = () {
|
||||||
|
ulong[2] result;
|
||||||
|
result[1] = posSrc[0].fractionalDigits;
|
||||||
|
result[0] = ulong(uint.max) + 1 - result[1];
|
||||||
|
return result;
|
||||||
|
}();
|
||||||
|
|
||||||
|
const samplingOffset = source.scanTo(posLine);
|
||||||
|
ubyte[2] pxcLR = () @trusted {
|
||||||
|
ubyte[2] result = [
|
||||||
|
source.data.ptr[samplingOffset].components.ptr[ib],
|
||||||
|
source.data.ptr[samplingOffset + nSamples].components.ptr[ib],
|
||||||
|
];
|
||||||
|
return result;
|
||||||
|
}();
|
||||||
|
|
||||||
|
xSum += (pxcLR[idxL] * weightsX[idxL]);
|
||||||
|
xSum += (pxcLR[idxR] * weightsX[idxR]);
|
||||||
|
|
||||||
|
return (xSum >> 32);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return (ySum / nLines);
|
||||||
|
}
|
||||||
|
|
||||||
|
static if (directionY == none) {
|
||||||
|
c = clamp255(sampleX());
|
||||||
|
} else static if (directionY == down) {
|
||||||
|
c = clamp255(sampleXMulti());
|
||||||
|
} else /* if (directionY == up) */ {
|
||||||
|
// looks ass
|
||||||
|
const ulong[2] weightsY = () {
|
||||||
|
ulong[2] result;
|
||||||
|
result[idxB] = posSrc[1].fractionalDigits;
|
||||||
|
result[idxT] = ulong(uint.max) + 1 - result[idxB];
|
||||||
|
return result;
|
||||||
|
}();
|
||||||
|
|
||||||
|
const xSums = sampleXDual();
|
||||||
|
|
||||||
|
ulong ySum = 0;
|
||||||
|
ySum += (xSums[idxT] * weightsY[idxT]);
|
||||||
|
ySum += (xSums[idxB] * weightsY[idxB]);
|
||||||
|
|
||||||
|
const xySum = (ySum >> 32);
|
||||||
|
|
||||||
|
c = clamp255(xySum);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pxDst = pxInt;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxDst = pxInt;
|
++y;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
++y;
|
const Size delta = (target.size - source.size);
|
||||||
|
|
||||||
|
const ScalingDirection[2] directions = [
|
||||||
|
scalingDirectionFromDelta(delta.width),
|
||||||
|
scalingDirectionFromDelta(delta.height),
|
||||||
|
];
|
||||||
|
|
||||||
|
if (directions[0] == none) {
|
||||||
|
if (directions[1] == none) {
|
||||||
|
version (none)
|
||||||
|
scaleToLinearImpl!(none, none)();
|
||||||
|
else
|
||||||
|
return;
|
||||||
|
} else if (directions[1] == up) {
|
||||||
|
scaleToLinearImpl!(none, up)();
|
||||||
|
} else /* if (directions[1] == down) */ {
|
||||||
|
scaleToLinearImpl!(none, down)();
|
||||||
|
}
|
||||||
|
} else if (directions[0] == up) {
|
||||||
|
if (directions[1] == none) {
|
||||||
|
scaleToLinearImpl!(up, none)();
|
||||||
|
} else if (directions[1] == up) {
|
||||||
|
scaleToLinearImpl!(up, up)();
|
||||||
|
} else /* if (directions[1] == down) */ {
|
||||||
|
scaleToLinearImpl!(up, down)();
|
||||||
|
}
|
||||||
|
} else /* if (directions[0] == down) */ {
|
||||||
|
if (directions[1] == none) {
|
||||||
|
scaleToLinearImpl!(down, none)();
|
||||||
|
} else if (directions[1] == up) {
|
||||||
|
scaleToLinearImpl!(down, up)();
|
||||||
|
} else /* if (directions[1] == down) */ {
|
||||||
|
scaleToLinearImpl!(down, down)();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue