summaryrefslogtreecommitdiff
path: root/xBRZ/src/xbrz.cpp
diff options
context:
space:
mode:
authorB Stack <bgstack15@gmail.com>2021-03-03 01:18:05 +0000
committerB Stack <bgstack15@gmail.com>2021-03-03 01:18:05 +0000
commit320f1ae680d73da35a0cfe4846eb687d8616bcac (patch)
tree6fb17404841b30822a2d9204e3e0932e55f05ebb /xBRZ/src/xbrz.cpp
parentMerge branch '11.6' into 'master' (diff)
parentadd upstream 11.7 (diff)
downloadFreeFileSync-320f1ae680d73da35a0cfe4846eb687d8616bcac.tar.gz
FreeFileSync-320f1ae680d73da35a0cfe4846eb687d8616bcac.tar.bz2
FreeFileSync-320f1ae680d73da35a0cfe4846eb687d8616bcac.zip
Merge branch '11.7' into 'master'11.7
add upstream 11.7 See merge request opensource-tracking/FreeFileSync!31
Diffstat (limited to 'xBRZ/src/xbrz.cpp')
-rw-r--r--xBRZ/src/xbrz.cpp60
1 files changed, 38 insertions, 22 deletions
diff --git a/xBRZ/src/xbrz.cpp b/xBRZ/src/xbrz.cpp
index 50660b84..6c015aa1 100644
--- a/xBRZ/src/xbrz.cpp
+++ b/xBRZ/src/xbrz.cpp
@@ -32,7 +32,10 @@ uint32_t gradientRGB(uint32_t pixFront, uint32_t pixBack) //blend front color wi
{
static_assert(0 < M && M < N && N <= 1000);
- auto calcColor = [](unsigned char colFront, unsigned char colBack) -> unsigned char { return (colFront * M + colBack * (N - M)) / N; };
+ auto calcColor = [](unsigned char colFront, unsigned char colBack)
+ {
+ return static_cast<unsigned char>(uintDivRound(colFront * M + colBack * (N - M), N));
+ };
return makePixel(calcColor(getRed (pixFront), getRed (pixBack)),
calcColor(getGreen(pixFront), getGreen(pixBack)),
@@ -53,10 +56,10 @@ uint32_t gradientARGB(uint32_t pixFront, uint32_t pixBack) //find intermediate c
auto calcColor = [=](unsigned char colFront, unsigned char colBack)
{
- return static_cast<unsigned char>((colFront * weightFront + colBack * weightBack) / weightSum);
+ return static_cast<unsigned char>(uintDivRound(colFront * weightFront + colBack * weightBack, weightSum));
};
- return makePixel(static_cast<unsigned char>(weightSum / N),
+ return makePixel(static_cast<unsigned char>(uintDivRound(weightSum, N)),
calcColor(getRed (pixFront), getRed (pixBack)),
calcColor(getGreen(pixFront), getGreen(pixBack)),
calcColor(getBlue (pixFront), getBlue (pixBack)));
@@ -154,7 +157,7 @@ double distYCbCr(uint32_t pix1, uint32_t pix2, double lumaWeight)
{
//https://en.wikipedia.org/wiki/YCbCr#ITU-R_BT.601_conversion
//YCbCr conversion is a matrix multiplication => take advantage of linearity by subtracting first!
- const int r_diff = static_cast<int>(getRed (pix1)) - getRed (pix2); //we may delay division by 255 to after matrix multiplication
+ const int r_diff = static_cast<int>(getRed (pix1)) - getRed (pix2); //defer division by 255 to after matrix multiplication
const int g_diff = static_cast<int>(getGreen(pix1)) - getGreen(pix2); //
const int b_diff = static_cast<int>(getBlue (pix1)) - getBlue (pix2); //substraction for int is noticeable faster than for double!
@@ -1094,23 +1097,23 @@ struct ColorDistanceARGB
{
const double a1 = getAlpha(pix1) / 255.0 ;
const double a2 = getAlpha(pix2) / 255.0 ;
- /*
- Requirements for a color distance handling alpha channel: with a1, a2 in [0, 1]
+
+ /* Requirements for a color distance handling alpha channel: with a1, a2 in [0, 1]
1. if a1 = a2, distance should be: a1 * distYCbCr()
2. if a1 = 0, distance should be: a2 * distYCbCr(black, white) = a2 * 255
3. if a1 = 1, ??? maybe: 255 * (1 - a2) + a2 * distYCbCr()
- */
- //return std::min(a1, a2) * distYCbCrBuffered(pix1, pix2) + 255 * abs(a1 - a2);
+ std::min(a1, a2) * distYCbCrBuffered(pix1, pix2) + 255 * abs(a1 - a2);
+
+ alternative? std::sqrt(a1 * a2 * square(distYCbCrBuffered(pix1, pix2)) + square(255 * (a1 - a2))); */
+
//=> following code is 15% faster:
const double d = distYCbCrBuffered(pix1, pix2);
if (a1 < a2)
return a1 * d + 255 * (a2 - a1);
else
return a2 * d + 255 * (a1 - a2);
-
- //alternative? return std::sqrt(a1 * a2 * square(distYCbCrBuffered(pix1, pix2)) + square(255 * (a1 - a2)));
}
};
@@ -1163,7 +1166,7 @@ void xbrz::scale(size_t factor, const uint32_t* src, uint32_t* trg, int srcWidth
switch (colFmt)
{
//*INDENT-OFF*
- case ColorFormat::RGB:
+ case ColorFormat::rgb:
switch (factor)
{
case 2: return scaleImage<Scaler2x<ColorGradientRGB>, ColorDistanceRGB, OobReaderDuplicate>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
@@ -1174,7 +1177,7 @@ void xbrz::scale(size_t factor, const uint32_t* src, uint32_t* trg, int srcWidth
}
break;
- case ColorFormat::ARGB:
+ case ColorFormat::argb:
switch (factor)
{
case 2: return scaleImage<Scaler2x<ColorGradientARGB>, ColorDistanceARGB, OobReaderTransparent>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
@@ -1185,7 +1188,7 @@ void xbrz::scale(size_t factor, const uint32_t* src, uint32_t* trg, int srcWidth
}
break;
- case ColorFormat::ARGB_UNBUFFERED:
+ case ColorFormat::argbUnbuffered:
switch (factor)
{
case 2: return scaleImage<Scaler2x<ColorGradientARGB>, ColorDistanceUnbufferedARGB, OobReaderTransparent>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
@@ -1205,11 +1208,11 @@ bool xbrz::equalColorTest(uint32_t col1, uint32_t col2, ColorFormat colFmt, doub
{
switch (colFmt)
{
- case ColorFormat::RGB:
+ case ColorFormat::rgb:
return ColorDistanceRGB::dist(col1, col2, luminanceWeight) < equalColorTolerance;
- case ColorFormat::ARGB:
+ case ColorFormat::argb:
return ColorDistanceARGB::dist(col1, col2, luminanceWeight) < equalColorTolerance;
- case ColorFormat::ARGB_UNBUFFERED:
+ case ColorFormat::argbUnbuffered:
return ColorDistanceUnbufferedARGB::dist(col1, col2, luminanceWeight) < equalColorTolerance;
}
assert(false);
@@ -1223,13 +1226,26 @@ void xbrz::bilinearScale(const uint32_t* src, int srcWidth, int srcHeight,
const auto imgReader = [src, srcWidth](int x, int y, BytePixel& pix)
{
static_assert(sizeof(pix) == sizeof(uint32_t));
- std::memcpy(pix, src + y * srcWidth + x, sizeof(pix));
+ const uint32_t pixSrc = src[y * srcWidth + x];
+
+ const unsigned char a = getAlpha(pixSrc);
+ pix[0] = a;
+ pix[1] = xbrz::premultiply(getRed (pixSrc), a); //r
+ pix[2] = xbrz::premultiply(getGreen(pixSrc), a); //g
+ pix[3] = xbrz::premultiply(getBlue (pixSrc), a); //b
};
- const auto imgWriter = [trg](const xbrz::BytePixel& pix) mutable { std::memcpy(trg++, pix, sizeof(pix)); };
+ const auto imgWriter = [trg](const xbrz::BytePixel& pix) mutable
+ {
+ const unsigned char a = pix[0];
+ * trg++ = makePixel(a,
+ xbrz::demultiply(pix[1], a), //r
+ xbrz::demultiply(pix[2], a), //g
+ xbrz::demultiply(pix[3], a)); //b
+ };
- bilinearScale(imgReader, srcWidth, srcHeight,
- imgWriter, trgWidth, trgHeight, 0, trgHeight);
+ bilinearScaleSimple(imgReader, srcWidth, srcHeight,
+ imgWriter, trgWidth, trgHeight, 0, trgHeight);
}
@@ -1262,8 +1278,8 @@ void bilinearScaleCpu(const uint32_t* src, int srcWidth, int srcHeight,
tg.run([=]
{
const int iLast = std::min(i + TASK_GRANULARITY, trgHeight);
- xbrz::bilinearScale(src, srcWidth, srcHeight, srcWidth * sizeof(uint32_t),
- trg, trgWidth, trgHeight, trgWidth * sizeof(uint32_t),
+ xbrz::bilinearScaleSimple(src, srcWidth, srcHeight, srcWidth * sizeof(uint32_t),
+ trg, trgWidth, trgHeight, trgWidth * sizeof(uint32_t),
i, iLast, [](uint32_t pix) { return pix; });
});
tg.wait();
bgstack15