#include "IconDes.h" void IconDes::Interpolate() { if(!IsCurrent()) return; FinishPaste(); SaveUndo(); Slot& c = Current(); c.base_image = c.image; ::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(), true); } 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::MirrorD(bool symm) { if(!IsCurrent()) return; Slot& c = Current(); if(BeginTransform()) { MirrorDiag(c.paste_image, c.paste_image.GetSize(), symm); MakePaste(); } else MirrorDiag(c.image, c.image.GetSize(), symm); 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; if(~dlg.method == FILTER_NEAREST) { Size isz = bk.GetSize(); ImageBuffer t(sz); for(int x = 0; x < sz.cx; x++) for(int y = 0; y < sz.cy; y++) t[y][x] = bk[y * isz.cy / sz.cy][x * isz.cx / sz.cx]; m = t; } else m = RescaleFilter(bk, sz, ~dlg.method); 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); Couple(dlg, dlg.level, dlg.slider2, 1); Couple(dlg, dlg.radius, dlg.slider, 10, 1); Image bk = ImageStart(); for(;;) { Image m = bk; for(int q = 0; q < (int)~dlg.radius; q++) m = Sharpen(m, -int(256 * (double)~dlg.level)); ImageSet(m); switch(dlg.Run()) { case IDCANCEL: ImageSet(bk); return; case IDOK: return; } } } void IconDes::Colorize() { WithImageDblLayout dlg; CtrlLayoutOKCancel(dlg, "Colorize"); PlaceDlg(dlg); Couple(dlg, dlg.level, dlg.slider, 1, 1); Image bk = ImageStart(); for(;;) { RGBA c = rgbactrl.GetColor(); int l = int(255 * Nvl(dlg.level, 1.0)); ImageSet(ForEachPixelStraight(bk, [&](RGBA& t) { int a = t.a; t.a = 255; t = Blend(t, c, l); t.a = a; })); switch(dlg.Run()) { case IDCANCEL: ImageSet(bk); return; case IDOK: return; } } } void IconDes::FreeRotate() { WithFreeRotateLayout dlg; CtrlLayoutOKCancel(dlg, "Rotate"); PlaceDlg(dlg); Couple(dlg, dlg.angle, dlg.slider, 360); 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() { WithImageDblLayout dlg; CtrlLayoutOKCancel(dlg, "Chroma"); PlaceDlg(dlg); Couple(dlg, dlg.level, dlg.slider, 2, 0); 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::Couple(TopWindow& dlg, EditDouble& level, SliderCtrl& slider, double max, double init, double offset) { level.Max(max); level <<= init; slider.MinMax(0, 1000); slider <<= init * 1000 / max; slider << [=, &dlg, &level, &slider] { level <<= (int)~slider / 1000.0 * max + offset; dlg.Break(); }; level << [=, &dlg, &level, &slider] { slider <<= Nvl(int(((double)~level - offset) * 1000 / max), 500); dlg.Break(); }; } void IconDes::Couple(TopWindow& dlg, EditInt& level, SliderCtrl& slider, int max, int init) { level.Max(max); level <<= init; slider.MinMax(0, max); slider <<= init; slider << [=, &dlg, &level, &slider] { level <<= (int)~slider; dlg.Break(); }; level << [=, &dlg, &level, &slider] { slider <<= Nvl(int((double)~level), init); dlg.Break(); }; } void IconDes::Contrast() { WithImageDblLayout dlg; CtrlLayoutOKCancel(dlg, "Contrast"); PlaceDlg(dlg); Couple(dlg, dlg.level, dlg.slider, 2, 1); 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() { WithImageDblLayout dlg; CtrlLayoutOKCancel(dlg, "Alpha"); PlaceDlg(dlg); Couple(dlg, dlg.level, dlg.slider, 2, 1); Image bk = ImageStart(); for(;;) { int a = (int)(minmax((double)~dlg.level, 0.0, 2.0) * 256); ImageSet(ForEachPixelStraight(bk, [&](RGBA& t) { t.a = Saturate255((t.a * a) >> 8); })); switch(dlg.Run()) { case IDCANCEL: ImageSet(bk); return; case IDOK: return; } } } void IconDes::RemoveAlpha() { WithRemoveAlphaLayout dlg; CtrlLayoutOKCancel(dlg, "Remove Alpha"); PlaceDlg(dlg); Couple(dlg, dlg.thres, dlg.slider, 255, 128); Image bk = ImageStart(); for(;;) { int thres = ~dlg.thres; ImageSet(ForEachPixel(bk, [&](RGBA& t) { if(t.a != 255) { if(t.a < thres) t = RGBAZero(); else { t = Unmultiply(t); t.a = 255; t = Premultiply(t); } } })); 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; } } } void IconDes::RestoreAlpha() { if(!IsCurrent()) return; Slot& c = Current(); auto Restore = [&](Image& m) { ImageBuffer ib(m); int maxg = 0; for(RGBA& rgba : ib) maxg = max(Grayscale(rgba), maxg); if(maxg) for(RGBA& rgba : ib) { rgba.a = 255 - 255 * Grayscale(rgba) / maxg; rgba.r = rgba.g = rgba.b = 0; } m = ib; }; if(BeginTransform()) { Restore(c.paste_image); MakePaste(); } else Restore(c.image); SyncShow(); }