in cpp/spectrum/core/proc/ScalingScanlineProcessingBlock.cpp [226:330]
std::unique_ptr<image::Scanline> BicubicScalingBlockImpl::produce() {
if (outputScanline == outputSize.height) {
return nullptr;
}
auto result =
std::make_unique<image::Scanline>(_pixelSpecification, outputSize.width);
const float middleY = 0.5f * invScalingY *
static_cast<float>(outputScanline + outputScanline + 1);
// shift from pixel center to logical index
const float logicalMiddleY = clamp(middleY - 0.5f, 0.0f, inputSize.height);
const int y1 = static_cast<int>(floor(logicalMiddleY));
const int y2 = y1 < inputSize.height - 1 ? y1 + 1 : y1;
SPECTRUM_ENFORCE_IF_NOT(y1 >= 0 && y1 <= y2 && y2 < inputSize.height);
const float deltaY = (y1 == y2) ? 0 : (logicalMiddleY - y1) / (y2 - y1);
SPECTRUM_ENFORCE_IF_NOT(deltaY >= 0.0f && deltaY <= 1.0f);
const int y0 = y1 == 0 ? 0 : y1 - 1;
const int y3 = y2 < inputSize.height - 1 ? y2 + 1 : y2;
SPECTRUM_ENFORCE_IF_NOT(y0 >= 0 && y0 <= y3 && y3 < inputSize.height);
if (static_cast<size_t>(y3) >= input.size()) {
return nullptr;
}
for (int xOffset = 0; xOffset < outputSize.width; xOffset++) {
const float middleX =
0.5f * invScalingX * static_cast<float>(xOffset + xOffset + 1);
// shift from pixel center to logical index
const float logicalMiddleX = clamp(middleX - 0.5f, 0.0f, inputSize.width);
const int x1 = static_cast<int>(floor(logicalMiddleX));
const int x2 = x1 < inputSize.width - 1 ? x1 + 1 : x1;
SPECTRUM_ENFORCE_IF_NOT(x1 >= 0 && x1 <= x2 && x2 < inputSize.width);
const float deltaX = (x1 == x2) ? 0 : (logicalMiddleX - x1) / (x2 - x1);
SPECTRUM_ENFORCE_IF_NOT(deltaX >= 0.0f && deltaX <= 1.0f);
const int x0 = x1 == 0 ? 0 : x1 - 1;
const int x3 = x2 < inputSize.width - 1 ? x2 + 1 : x2;
SPECTRUM_ENFORCE_IF_NOT(x0 >= 0 && x0 <= x3 && x3 < inputSize.width);
const auto numberOfComponents = _pixelSpecification.numberOfComponents();
const auto bicubicSum0 = bicubicComputeAndClamp(
numberOfComponents,
deltaX,
(*input[y0]).dataAtPixel(x0),
(*input[y0]).dataAtPixel(x1),
(*input[y0]).dataAtPixel(x2),
(*input[y0]).dataAtPixel(x3));
const auto bicubicSum1 = bicubicComputeAndClamp(
numberOfComponents,
deltaX,
(*input[y1]).dataAtPixel(x0),
(*input[y1]).dataAtPixel(x1),
(*input[y1]).dataAtPixel(x2),
(*input[y1]).dataAtPixel(x3));
const auto bicubicSum2 = bicubicComputeAndClamp(
numberOfComponents,
deltaX,
(*input[y2]).dataAtPixel(x0),
(*input[y2]).dataAtPixel(x1),
(*input[y2]).dataAtPixel(x2),
(*input[y2]).dataAtPixel(x3));
const auto bicubicSum3 = bicubicComputeAndClamp(
numberOfComponents,
deltaX,
(*input[y3]).dataAtPixel(x0),
(*input[y3]).dataAtPixel(x1),
(*input[y3]).dataAtPixel(x2),
(*input[y3]).dataAtPixel(x3));
const auto pxl = bicubicComputeAndClamp(
numberOfComponents,
deltaY,
bicubicSum0.data(),
bicubicSum1.data(),
bicubicSum2.data(),
bicubicSum3.data());
auto dst = result->dataAtPixel(xOffset);
for (std::uint8_t componentOffset = 0; componentOffset < numberOfComponents;
componentOffset++) {
*(dst + componentOffset) = pxl[componentOffset];
}
}
// free scanlines that will not be touched again
for (int i = nextLineToRelease; i < y0; i++) {
SPECTRUM_ENFORCE_IF(input[i] == nullptr);
input[i].reset();
}
nextLineToRelease = y0;
++outputScanline;
return result;
}