mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-15 14:16:07 -06:00
144 lines
No EOL
3.6 KiB
C++
144 lines
No EOL
3.6 KiB
C++
#include "Draw.h"
|
|
|
|
namespace Upp {
|
|
|
|
// Upscale2x is based on xBR filter idea by Hyllian, google search on 'xBR filter'
|
|
// should eventually lead you to a forum topic where he made the algorithm public:
|
|
// http://board.byuu.org/viewtopic.php?f=10&t=2248
|
|
|
|
namespace Upscale2x_helper {
|
|
int d(RGBA c1, RGBA c2)
|
|
{
|
|
int r = abs(c1.r - c2.r);
|
|
int g = abs(c1.g - c2.g);
|
|
int b = abs(c1.b - c2.b);
|
|
return 48 * (r * 299 + g * 587 + b * 114)
|
|
+ 7 * (r * -169 + g * -331 + b * 500)
|
|
+ 6 * (r * 500 + g * -419 + b * -81);
|
|
}
|
|
};
|
|
|
|
Image Upscale2x_(const Image& src)
|
|
{
|
|
using namespace Upscale2x_helper;
|
|
Size isz = src.GetSize();
|
|
ImageBuffer dst;
|
|
dst.Create(2 * isz);
|
|
for(int y = 0; y < isz.cy; y++)
|
|
for(int x = 0; x < isz.cx; x++) {
|
|
static const int8 cm[] = {
|
|
// -2 -1 0 +1 +2
|
|
-1, 0, 1, 2, -1, // -2
|
|
17, 19, 3, 4, 5, // -1
|
|
16, 18, -1, 8, 6, // 0
|
|
15, 14, 13, 9, 7, // +1
|
|
-1, 12, 11, 10, -1, // +2
|
|
};
|
|
|
|
RGBA pp[40];
|
|
const int8 *q = cm;
|
|
for(int dy = -2; dy <= 2; dy++)
|
|
for(int dx = -2; dx <= 2; dx++) {
|
|
if(*q >= 0) {
|
|
int xx = x + dx;
|
|
int yy = y + dy;
|
|
pp[*q] = pp[*q + 20] = src[clamp(yy, 0, isz.cy - 1)][clamp(xx, 0, isz.cx - 1)];
|
|
}
|
|
q++;
|
|
}
|
|
|
|
RGBA c = src[y][x];
|
|
RGBA *p = pp;
|
|
|
|
for(int rot = 0; rot < 4; rot++) {
|
|
RGBA t = c;
|
|
if(d(c, p[14]) + d(c, p[4]) + d(p[19], p[16]) + d(p[19], p[1]) + 4 * d(p[18], p[3])
|
|
< d(p[18], p[13]) + d(p[18], p[17]) + d(p[3], p[8]) + d(p[3], p[0]) + 4 * d(c, p[19])) {
|
|
RGBA nc = d(c, p[18]) <= d(c, p[3]) ? p[18] : p[3];
|
|
t.r = (nc.r + c.r) >> 1;
|
|
t.g = (nc.g + c.g) >> 1;
|
|
t.b = (nc.b + c.b) >> 1;
|
|
}
|
|
// 0 1
|
|
// 3 2
|
|
dst[2 * y + (rot >= 2)][2 * x + (rot == 1 || rot == 2)] = t;
|
|
p += 5;
|
|
}
|
|
}
|
|
return dst;
|
|
}
|
|
|
|
Image Upscale2x(const Image& src)
|
|
{
|
|
if(IsNull(src))
|
|
return src;
|
|
Size s2 = src.Get2ndSpot();
|
|
Image s;
|
|
if(s2.cx > 0 || s2.cy > 0) // When 2nd spot is defined, it is likely Chameleon rescaling item (e.g. button)
|
|
s = Magnify(src, 2, 2); // in that case, filtering by smart rescale methods could lead to artifacts
|
|
else {
|
|
Size isz = src.GetSize();
|
|
s = RecreateAlpha(Upscale2x_(GetOver(CreateImage(isz, White()), src)),
|
|
Upscale2x_(GetOver(CreateImage(isz, Black()), src)));
|
|
|
|
struct SFilter : ImageFilter9 { // Improve contours
|
|
virtual RGBA operator()(const RGBA **mx) {
|
|
RGBA s = mx[1][1];
|
|
dword l = mx[0][1].a;
|
|
dword r = mx[2][1].a;
|
|
dword t = mx[1][0].a;
|
|
dword b = mx[1][2].a;
|
|
int l1 = 110;
|
|
int l2 = 230;
|
|
return l * r * t * b != 0 || s.a > l1 || mx[0][1].a > l2 || mx[2][1].a > l2 || mx[1][0].a > l2 || mx[1][2].a > l2 ? s
|
|
: RGBAZero();
|
|
}
|
|
} ef;
|
|
s = Filter(s, ef);
|
|
}
|
|
ImageBuffer h(s);
|
|
h.SetHotSpot(src.GetHotSpot() * 2);
|
|
h.Set2ndSpot(s2 * 2);
|
|
return h;
|
|
}
|
|
|
|
Image Downscale2x(const Image& src)
|
|
{
|
|
if(IsNull(src))
|
|
return src;
|
|
Size s2 = src.Get2ndSpot(); // see above...
|
|
Image m = RescaleFilter(src, src.GetSize() / 2, s2.cx > 0 || s2.cy > 0 ? FILTER_BILINEAR : FILTER_LANCZOS3);
|
|
ImageBuffer h(m);
|
|
h.SetHotSpot(s2 / 2);
|
|
h.Set2ndSpot(src.Get2ndSpot() / 2);
|
|
return h;
|
|
}
|
|
|
|
static bool sUHDMode;
|
|
|
|
void SetUHDMode(bool b)
|
|
{
|
|
Iml::ResetAll();
|
|
sUHDMode = b;
|
|
}
|
|
|
|
bool IsUHDMode()
|
|
{
|
|
return sUHDMode;
|
|
}
|
|
|
|
void SyncUHDMode()
|
|
{
|
|
bool uhd = GetStdFontCy() > 24;
|
|
if(uhd != IsUHDMode())
|
|
SetUHDMode(uhd);
|
|
}
|
|
|
|
Image DPI(const Image& img, int expected)
|
|
{
|
|
if(img.GetSize().cy <= expected && IsUHDMode())
|
|
return MakeImage(img, Upscale2x);
|
|
return img;
|
|
}
|
|
|
|
}; |