ultimatepp/uppsrc/ide/IconDes/ImageOp.cpp
2024-09-18 21:54:14 +02:00

195 lines
4.6 KiB
C++

#include "IconDes.h"
template <class Eq>
force_inline
void FloodFill(const Image& src, ImageBuffer& ib, RGBA fill, Point p, const Eq& eq)
{
Size isz = ib.GetSize();
if(!Rect(isz).Contains(p))
return;
Vector<Point> stack { p };
Buffer<byte> filled(isz.cx * isz.cy, 0);
auto Filled = [&](int y) -> byte * { return ~filled + y * isz.cx; };
RGBA color = src[p.y][p.x];
while(stack.GetCount()) {
Point p = stack.Pop();
const RGBA *l = src[p.y];
byte *f = Filled(p.y);
int xl = p.x;
while(xl > 0 && !f[xl - 1] && eq(l[xl - 1], color))
xl--;
int xh = p.x;
while(xh < isz.cx - 1 && !f[xh + 1] && eq(l[xh + 1], color))
xh++;
Fill(ib[p.y] + xl, fill, xh - xl + 1);
memset(f + xl, 1, xh - xl + 1);
Point q;
for(q.y = p.y - 1; q.y <= p.y + 1; q.y += 2)
if(q.y >= 0 && q.y < isz.cy) {
const RGBA *ql = src[q.y];
byte *qf = Filled(q.y);
bool flag = false;
for(q.x = xl; q.x <= xh; q.x++) {
bool f = !qf[q.x] && eq(ql[q.x], color);
if(f != flag) {
flag = f;
if(f) stack.Add(q);
}
}
}
}
}
void FloodFill(const Image& source, ImageBuffer& target, RGBA color, Point pt, int tolerance)
{
if(tolerance == 0)
FloodFill(source, target, color, pt,
[](RGBA a, RGBA b) { return a == b; });
else
if(tolerance < 0)
FloodFill(source, target, RGBAZero(), pt,
[&](RGBA a, RGBA b) { return a != color; });
else
FloodFill(source, target, color, pt,
[&](RGBA a, RGBA b) { return abs(a.a - b.a) <= tolerance &&
abs(a.r - b.r) + abs(a.g - b.g) + abs(a.b - b.b) <= tolerance; });
}
struct InterpolateFilter : ImageFilter9 {
int todo;
virtual RGBA operator()(const RGBA **mx);
};
RGBA InterpolateFilter::operator()(const RGBA **mx)
{
RGBA t = mx[1][1];
int na = mx[0][1].a, wa = mx[1][0].a, ea = mx[1][2].a, sa = mx[2][1].a;
int suma = na + wa + ea + sa, half = suma >> 1;
if(suma > 0) {
t.r = (mx[0][1].r * na + mx[1][0].r * wa + mx[1][2].r * ea + mx[2][1].r * sa + half) / suma;
t.g = (mx[0][1].g * na + mx[1][0].g * wa + mx[1][2].g * ea + mx[2][1].g * sa + half) / suma;
t.b = (mx[0][1].b * na + mx[1][0].b * wa + mx[1][2].b * ea + mx[2][1].b * sa + half) / suma;
t.a = max(max(na, sa), max(wa, ea));
if(t != mx[1][1])
todo++;
}
return t;
}
void InterpolateImage(Image& img, const Rect& _rc)
{
Rect rc = _rc & img.GetSize();
Image m = Crop(img, rc);
TimeStop tm;
Image imp = CreateImage(rc.GetSize(), Null);
Over(imp, Point(0, 0), m, m.GetSize());
Progress pi("Interpolating...");
for(int qq = 0; qq < 2000; qq++) {
InterpolateFilter f;
f.todo = 0;
imp = Filter(imp, f);
Over(imp, Point(0, 0), m, m.GetSize());
if(f.todo == 0)
break;
if(pi.SetCanceled(qq, 2000))
break;
}
Copy(img, rc.TopLeft(), imp, imp.GetSize());
}
void MirrorHorz(Image& img, const Rect& rect)
{
ImageBuffer ib(img);
Rect rc = rect & ib.GetSize();
for(int y = rc.top; y < rc.bottom; y++) {
RGBA *b = ib[y] + rc.left;
RGBA *e = ib[y] + rc.right - 1;
while(b < e) {
Swap(*b, *e);
b++;
e--;
}
}
img = ib;
}
void MirrorVert(Image& img, const Rect& rect)
{
ImageBuffer ib(img);
Rect rc = rect & ib.GetSize();
int b = rc.top;
int e = rc.bottom - 1;
int n = rc.right - rc.left;
if(n > 0) {
Buffer<RGBA> h(n);
n *= sizeof(RGBA);
while(b < e) {
memcpy(h, ib[b] + rc.left, n);
memcpy(ib[b] + rc.left, ib[e] + rc.left, n);
memcpy(ib[e] + rc.left, h, n);
b++;
e--;
}
}
img = ib;
}
void MirrorDiag(Image& img, const Rect& rect, bool symm)
{
ImageBuffer ib(img);
Size isz = ib.GetSize();
Rect rc = rect & isz;
int sz = min(rc.GetWidth(), rc.GetHeight());
for(int y = 0; y < sz - 1; y++) {
RGBA *h = ib[y + rect.top] + rect.left + y + 1;
RGBA *e = ib[y + rect.top] + rect.left + sz;
RGBA *v = ib[y + rect.top + 1] + rect.left + y;
while(h < e) {
if(symm)
*h = *v;
else
Swap(*h, *v);
h++;
v += isz.cx;
}
}
img = ib;
}
String PackImlDataUncompressed(const Vector<ImageIml>& image)
{
StringBuffer block;
for(const ImageIml& m : image) {
const Image& img = m.image;
StringStream ss;
ss.Put(m.flags);
Size sz = img.GetSize();
ss.Put16le(sz.cx);
ss.Put16le(sz.cy);
Point p = img.GetHotSpot();
ss.Put16le(p.x);
ss.Put16le(p.y);
p = img.Get2ndSpot();
ss.Put16le(p.x);
ss.Put16le(p.y);
block.Cat(ss.GetResult());
const RGBA *s = img;
const RGBA *e = s + img.GetLength();
while(s < e) {
block.Cat(s->r);
block.Cat(s->g);
block.Cat(s->b);
block.Cat(s->a);
s++;
}
}
return String(block);
}
String PackImlData(const Vector<ImageIml>& image)
{
return ZCompress(PackImlDataUncompressed(image));
}