#include "IconDes.h" namespace Upp { void IconDes::Interpolate() { if(!IsCurrent()) return; FinishPaste(); SaveUndo(); Slot& c = Current(); c.base_image = c.image; UPP::InterpolateImage(c.image, c.image.GetSize()); MaskSelection(); } bool IconDes::BeginTransform() { SaveUndo(); Refresh(); SyncShow(); if(!IsPasting()) { if(SelectionRect() == GetImageSize()) return false; Move(); } return true; } void IconDes::KeyMove(int dx, int dy) { if(!IsCurrent()) return; Slot& c = Current(); if(BeginTransform()) { c.pastepos.x += dx; c.pastepos.y += dy; MakePaste(); } else { Image h = c.image; c.image = CreateImage(h.GetSize(), Null); UPP::Copy(c.image, Point(dx, dy), h, h.GetSize()); } Sync(); } void IconDes::MirrorX() { if(!IsCurrent()) return; Slot& c = Current(); if(BeginTransform()) { MirrorHorz(c.paste_image, c.paste_image.GetSize()); MakePaste(); } else MirrorHorz(c.image, c.image.GetSize()); SyncShow(); } void IconDes::SymmX() { if(!IsCurrent()) return; Slot& c = Current(); if(BeginTransform()) { if(c.paste_image.GetLength() > 1024 * 1024) return; Image m = c.paste_image; Size sz = m.GetSize(); MirrorHorz(m, m.GetSize()); Image h = CreateImage(Size(2 * sz.cx, sz.cy), Null); UPP::Copy(h, Point(0, 0), c.paste_image, sz); UPP::Copy(h, Point(sz.cx, 0), m, sz); c.paste_image = h; MakePaste(); } else { Size sz = c.image.GetSize(); if(sz.cx < 2) return; UPP::Copy(c.image, Point(sz.cx - sz.cx / 2, 0), c.image, Size(sz.cx / 2, sz.cy)); MirrorHorz(c.image, RectC(sz.cx - sz.cx / 2, 0, sz.cx / 2, sz.cy)); } SyncShow(); } void IconDes::MirrorY() { if(!IsCurrent()) return; Slot& c = Current(); if(BeginTransform()) { MirrorVert(c.paste_image, c.paste_image.GetSize()); MakePaste(); } else MirrorVert(c.image, c.image.GetSize()); SyncShow(); } void IconDes::SymmY() { if(!IsCurrent()) return; Slot& c = Current(); if(BeginTransform()) { if(c.paste_image.GetLength() > 1024 * 1024) return; Image m = c.paste_image; Size sz = m.GetSize(); MirrorVert(m, m.GetSize()); Image h = CreateImage(Size(sz.cx, 2 * sz.cy), Null); UPP::Copy(h, Point(0, 0), c.paste_image, sz); UPP::Copy(h, Point(0, sz.cy), m, sz); c.paste_image = h; MakePaste(); } else { Size sz = c.image.GetSize(); if(sz.cy < 2) return; UPP::Copy(c.image, Point(0, sz.cy - sz.cy / 2), c.image, Size(sz.cx, sz.cy / 2)); MirrorVert(c.image, RectC(0, sz.cy - sz.cy / 2, sz.cx, sz.cy / 2)); } SyncShow(); } void IconDes::Rotate() { if(!IsCurrent()) return; Slot& c = Current(); if(BeginTransform()) { c.paste_image = RotateClockwise(c.paste_image); MakePaste(); } else { c.image = RotateClockwise(c.image); SetSelect(255); } SyncShow(); } void IconDes::SmoothRescale() { if(!IsCurrent()) return; WithRescaleLayout dlg; CtrlLayoutOKCancel(dlg, "Rescale"); dlg.cx <<= dlg.cy <<= dlg.method <<= dlg.Breaker(); Slot& c = Current(); BeginTransform(); Image bk = IsPasting() ? c.paste_image : c.image; dlg.cx <<= bk.GetWidth(); dlg.cy <<= bk.GetHeight(); dlg.keep <<= true; dlg.method.Add(Null, "Rylek"); dlg.method.Add(FILTER_NEAREST, "Nearest"); dlg.method.Add(FILTER_BILINEAR, "Bilinear"); dlg.method.Add(FILTER_BSPLINE, "Bspline"); dlg.method.Add(FILTER_COSTELLO, "Costello"); dlg.method.Add(FILTER_BICUBIC_MITCHELL, "Bicubic Mitchell"); dlg.method.Add(FILTER_BICUBIC_CATMULLROM, "Bicubic Catmull Rom"); dlg.method.Add(FILTER_LANCZOS2, "Lanczos 2"); dlg.method.Add(FILTER_LANCZOS3, "Lanczos 3"); dlg.method.Add(FILTER_LANCZOS4, "Lanczos 4"); // dlg.method.Add(FILTER_LANCZOS5, "Lanczos 5"); for(;;) { Size sz(minmax((int)~dlg.cx, 1, 9999), minmax((int)~dlg.cy, 1, 9999)); Image m = RescaleFilter(bk, sz, ~dlg.method); SetRes(m, bk.GetResolution()); if(IsPasting()) { c.paste_image = m; MakePaste(); } else { c.image = m; Refresh(); } SyncImage(); SyncShow(); switch(dlg.Run()) { case IDCANCEL: if(IsPasting()) { c.paste_image = bk; MakePaste(); } else { c.image = bk; Refresh(); } SyncImage(); SyncShow(); return; case IDOK: SyncList(); return; } if(dlg.keep) { if(dlg.cx.HasFocus() && bk.GetWidth() > 0) dlg.cy <<= (int)~dlg.cx * bk.GetHeight() / bk.GetWidth(); if(dlg.cy.HasFocus() && bk.GetHeight() > 0) dlg.cx <<= (int)~dlg.cy * bk.GetWidth() / bk.GetHeight(); } } } Image IconDes::ImageStart() { if(!IsCurrent()) return CreateImage(Size(1, 1), Black); SaveUndo(); Refresh(); SyncShow(); Slot& c = Current(); if(!IsPasting()) c.base_image = c.image; return IsPasting() ? c.paste_image : c.image; } void IconDes::ImageSet(const Image& m) { if(!IsCurrent()) return; Slot& c = Current(); if(IsPasting()) { c.paste_image = m; MakePaste(); } else { c.image = m; MaskSelection(); } Refresh(); SyncShow(); } void IconDes::BlurSharpen() { WithSharpenLayout dlg; CtrlLayoutOKCancel(dlg, "Blur/Sharpen"); PlaceDlg(dlg); dlg.level <<= 0; dlg.level <<= dlg.Breaker(); dlg.passes <<= 1; dlg.passes <<= dlg.Breaker(); Image bk = ImageStart(); for(;;) { Image m = bk; for(int q = 0; q < (int)~dlg.passes; q++) m = Sharpen(m, -int(256 * (double)~dlg.level)); ImageSet(m); switch(dlg.Run()) { case IDCANCEL: ImageSet(bk); return; case IDOK: return; } } } Image Colorize2(const Image& img, Color color, int alpha, int gray) { const RGBA *s = ~img; const RGBA *e = s + img.GetLength(); ImageBuffer w(img.GetSize()); Unmultiply(w); RGBA *t = w; byte r0 = color.GetR(); byte g0 = color.GetG(); byte b0 = color.GetB(); alpha = alpha + (alpha >> 7); if(gray == 0) gray = 1; while(s < e) { int ga = Grayscale(*s); if(gray >= 255) { ga = ga + (ga >> 7); t->r = (alpha * (((ga * r0) >> 8) - s->r) >> 8) + s->r; t->g = (alpha * (((ga * g0) >> 8) - s->g) >> 8) + s->g; t->b = (alpha * (((ga * b0) >> 8) - s->b) >> 8) + s->b; } else { int r, g, b; if(ga <= gray) { r = ga * r0 / gray; g = ga * g0 / gray; b = ga * b0 / gray; } else { int div = 255 - gray; int ao = ga - gray; int ac = div - ao; r = (ao * s->r + ac * r0) / div; g = (ao * s->g + ac * g0) / div; b = (ao * s->b + ac * b0) / div; } t->r = (alpha * (r - s->r) >> 8) + s->r; t->g = (alpha * (g - s->g) >> 8) + s->g; t->b = (alpha * (b - s->b) >> 8) + s->b; } t->a = s->a; t++; s++; } Premultiply(w); w.SetHotSpots(img); return w; } void IconDes::Colorize() { WithColorize2Layout dlg; CtrlLayoutOKCancel(dlg, "Colorize"); PlaceDlg(dlg); dlg.level.MinMax(0, 1); dlg.level <<= 1; dlg.level <<= dlg.Breaker(); dlg.gray.MinMax(0, 1); dlg.gray <<= 1; dlg.gray <<= dlg.Breaker(); Image bk = ImageStart(); for(;;) { ImageSet(Colorize2(bk, CurrentColor(), (int)(minmax((double)~dlg.level, 0.0, 1.0) * 255), (int)(minmax((double)~dlg.gray, 0.0, 1.0) * 255))); switch(dlg.Run()) { case IDCANCEL: ImageSet(bk); return; case IDOK: return; } } } void IconDes::FreeRotate() { WithFreeRotateLayout dlg; CtrlLayoutOKCancel(dlg, "Rotate"); PlaceDlg(dlg); dlg.angle <<= 0; dlg.angle <<= dlg.Breaker(); Image bk = ImageStart(); Size tsz = bk.GetSize(); Image src = Magnify(bk, 3, 3); for(;;) { Image h = DownSample3x(UPP::Rotate(src, (int)~dlg.angle * 10)); Size sz = h.GetSize(); ImageSet(Crop(h, (sz.cx - tsz.cx) / 2, (sz.cy - tsz.cy) / 2, tsz.cx, tsz.cy)); switch(dlg.Run()) { case IDCANCEL: ImageSet(bk); return; case IDOK: return; } } } void IconDes::Chroma() { WithColorizeLayout dlg; CtrlLayoutOKCancel(dlg, "Chroma"); PlaceDlg(dlg); dlg.level.Max(10); dlg.level <<= 1; dlg.level <<= dlg.Breaker(); Image bk = ImageStart(); for(;;) { ImageSet(UPP::Grayscale(bk, 256 - (int)(minmax((double)~dlg.level, 0.0, 4.0) * 255))); switch(dlg.Run()) { case IDCANCEL: ImageSet(bk); return; case IDOK: return; } } } void IconDes::Contrast() { WithColorizeLayout dlg; CtrlLayoutOKCancel(dlg, "Contrast"); PlaceDlg(dlg); dlg.level.Max(10); dlg.level <<= 1; dlg.level <<= dlg.Breaker(); Image bk = ImageStart(); for(;;) { ImageSet(UPP::Contrast(bk, (int)(minmax((double)~dlg.level, 0.0, 4.0) * 255))); switch(dlg.Run()) { case IDCANCEL: ImageSet(bk); return; case IDOK: return; } } } void IconDes::Alpha() { WithColorizeLayout dlg; CtrlLayoutOKCancel(dlg, "Alpha"); PlaceDlg(dlg); dlg.level.Max(4); dlg.level <<= 1; dlg.level <<= dlg.Breaker(); Image bk = ImageStart(); for(;;) { int a = (int)(minmax((double)~dlg.level, 0.0, 4.0) * 255); ImageBuffer ib(bk.GetSize()); RGBA *t = ib; const RGBA *s = bk; const RGBA *e = bk + bk.GetLength(); while(s < e) { *t = *s; t->a = Saturate255((s->a * a) >> 8); s++; t++; } ImageSet(ib); switch(dlg.Run()) { case IDCANCEL: ImageSet(bk); return; case IDOK: return; } } } void IconDes::Colors() { WithImgColorLayout dlg; CtrlLayoutOKCancel(dlg, "Alpha"); PlaceDlg(dlg); dlg.r_mul <<= dlg.g_mul <<= dlg.b_mul <<= dlg.a_mul <<= 1; dlg.r_add <<= dlg.g_add <<= dlg.b_add <<= dlg.a_add <<= 0; dlg.all = true; dlg.r_mul <<= dlg.g_mul <<= dlg.b_mul <<= dlg.a_mul <<= dlg.r_add <<= dlg.g_add <<= dlg.b_add <<= dlg.a_add <<= dlg.all <<= dlg.Breaker(); Image bk = ImageStart(); for(;;) { bool all = dlg.all; dlg.g_mul.Enable(!all); dlg.g_add.Enable(!all); dlg.b_mul.Enable(!all); dlg.b_add.Enable(!all); if(all) { dlg.g_mul <<= dlg.b_mul <<= ~dlg.r_mul; dlg.g_add <<= dlg.b_add <<= ~dlg.r_add; } ImageBuffer ib(bk.GetSize()); RGBA *t = ib; const RGBA *s = bk; const RGBA *e = bk + bk.GetLength(); int r_mul = int(256 * (double)~dlg.r_mul); int r_add = int(256 * (double)~dlg.r_add); int g_mul = int(256 * (double)~dlg.g_mul); int g_add = int(256 * (double)~dlg.g_add); int b_mul = int(256 * (double)~dlg.b_mul); int b_add = int(256 * (double)~dlg.b_add); int a_mul = int(256 * (double)~dlg.a_mul); int a_add = int(256 * (double)~dlg.a_add); while(s < e) { Unmultiply(t, t, 1); t->r = Saturate255(((r_mul * s->r) >> 8) + r_add); t->g = Saturate255(((g_mul * s->g) >> 8) + g_add); t->b = Saturate255(((b_mul * s->b) >> 8) + b_add); t->a = Saturate255(((a_mul * s->a) >> 8) + a_add); Premultiply(t, t, 1); s++; t++; } ImageSet(ib); switch(dlg.Run()) { case IDCANCEL: ImageSet(bk); return; case IDOK: return; } } } }