megak function
Megak Algorithm
Megak algorithm is taking a window of the input image for every pixel, then it will determine a weight for the pixel. To calculate the weight for the pixel, it uses a simulated Lanczos kernel that produces a output simular to lanczos. Difference to Lanczos is that it only uses a conditional move and a single multiplication, instead of multiple sin and multiplication operations.
Advantages:
-
Faster than lanczos.
-
Most images can be scaled in a quality similar to lanczos.
-
AreaSize can be adjusted without particle-issues (like lanczos currently has).
Limitations:
-
Really slow
-
Maybe not compatible with all images / sizes.
Implementation
ScaleArguments megak(ScaleArguments args) {
final oXScale = args.iSize.width / args.oSize.width;
final oYScale = args.iSize.height / args.oSize.height;
final mkXScale = args.iSize.width > args.oSize.width ? oXScale : 1;
final mkYScale = args.iSize.height > args.oSize.height ? oYScale : 1;
final maxAreaDiameter = (args.areaSize*2)+1;
double iX;
double iY;
int oByteBufIndex;
int iByteBufIndex;
_Vector iAreaTLAnchor;
_Vector iAreaBRAnchor;
double tWeight;
Uint32List rgbStack;
double dx;
double dy;
double d;
double curWeight;
for (int x = 0; x < args.oSize.width; x++) {
iX = x * oXScale;
for (int y = 0; y < args.oSize.height; y++) {
iY = y * oYScale;
oByteBufIndex = (y * args.oSize.width + x) * args.colorBlockSize;
// Top Left Area Anchor
iAreaTLAnchor = _Vector(
(iX-args.areaSize<0 ? 0 : iX-args.areaSize).toInt(),
(iY-args.areaSize<0 ? 0 : iY-args.areaSize).toInt()
);
// Bottom Right Area Anchor
iAreaBRAnchor = _Vector(
(iAreaTLAnchor.x+maxAreaDiameter).clamp(0, args.iSize.width),
(iAreaTLAnchor.y+maxAreaDiameter).clamp(0, args.iSize.height),
);
tWeight = 0;
rgbStack = Uint32List(args.colorBlockSize);
for (int iXArea = iAreaTLAnchor.x; iXArea < iAreaBRAnchor.x; iXArea++) {
for (int iYArea = iAreaTLAnchor.y; iYArea < iAreaBRAnchor.y; iYArea++) {
iByteBufIndex = (iYArea * args.iSize.width + iXArea) * args.colorBlockSize;
dx = (iXArea - iX).abs() / mkXScale;
dy = (iYArea - iY).abs() / mkYScale;
d = sqrt(dx * dx + dy * dy);
curWeight = _kernel(d, args.areaSize);
for (int i = 0; i < args.colorBlockSize; i++) {
rgbStack[i] += (args.iByteBuf[iByteBufIndex + i] * curWeight).round();
}
tWeight += curWeight;
}
}
for (int i = 0; i < args.colorBlockSize; i++) {
args.oByteBuf[oByteBufIndex + i] = (rgbStack[i] / tWeight).clamp(0, 255).round();
}
}
}
return args;
}