#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, RGBA bg) { 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] = xx >= 0 && xx < isz.cx && yy >= 0 && yy < isz.cy ? src[yy][xx] : bg; } 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) { Size isz = src.GetSize(); Image s = RecreateAlpha(Upscale2x(GetOver(CreateImage(isz, White()), src), White()), Upscale2x(GetOver(CreateImage(isz, Black()), src), Black())); ImageBuffer h(s); h.SetResolution(IMAGE_RESOLUTION_UHD); h.SetHotSpot(src.GetHotSpot() * 2); h.Set2ndSpot(src.Get2ndSpot() * 2); return h; } Image Downscale2x(const Image& src) { Image m = RescaleFilter(src, src.GetSize() / 2, FILTER_LANCZOS3); ImageBuffer h(m); h.SetResolution(IMAGE_RESOLUTION_STANDARD); h.SetHotSpot(src.GetHotSpot() / 2); h.Set2ndSpot(src.Get2ndSpot() / 2); return h; } static bool sUHDMode; void SetUHDMode(bool b) { for(int i = 0; i < GetImlCount(); i++) GetIml(i).Reset(); sUHDMode = b; } bool IsUHDMode() { return sUHDMode; } void SyncUHDMode() { bool uhd = GetStdFontCy() > 22; if(uhd != IsUHDMode()) SetUHDMode(uhd); } Image DPI(const Image& img) { if(IsUHDMode()) { if(img.GetResolution() == IMAGE_RESOLUTION_STANDARD) return MakeImage(img, Upscale2x); } else { if(img.GetResolution() == IMAGE_RESOLUTION_UHD) return MakeImage(img, Downscale2x); } return img; } Image DPI(const Image& img, int expected) { if(img.GetSize().cy <= expected && IsUHDMode()) return MakeImage(img, Upscale2x); return img; } };