///////////////////////////////////////////////////////////////////////////////// // Paint.NET // // Copyright (C) dotPDN LLC, Rick Brewster, Tom Jackson, and contributors. // // Portions Copyright (C) Microsoft Corporation. All Rights Reserved. // // See license-pdn.txt for full licensing and attribution details. // // // // Ported to Pinta by: Hanh Pham // ///////////////////////////////////////////////////////////////////////////////// using System; using Cairo; using Pinta.Gui.Widgets; using Pinta.Core; using Mono.Unix; namespace Pinta.Effects { //[System.ComponentModel.Composition (typeof (BaseEffect))] public class OutlineEffect : LocalHistogramEffect { private int thickness; private int intensity; public override string Icon { get { return "Menu.Effects.Stylize.Outline.png"; } } public override string Text { get { return Catalog.GetString ("Outline"); } } public override bool IsConfigurable { get { return true; } } public override string EffectMenuCategory { get { return Catalog.GetString ("Stylize"); } } public OutlineData Data { get { return EffectData as OutlineData; } } public OutlineEffect () { EffectData = new OutlineData (); } public override bool LaunchConfiguration () { return EffectHelper.LaunchSimpleEffectDialog (this); } #region Algorithm Code Ported From PDN public unsafe override ColorBgra Apply (ColorBgra src, int area, int* hb, int* hg, int* hr, int* ha) { int minCount1 = area * (100 - this.intensity) / 200; int minCount2 = area * (100 + this.intensity) / 200; int bCount = 0; int b1 = 0; while (b1 < 255 && hb[b1] == 0) ++b1; while (b1 < 255 && bCount < minCount1) { bCount += hb[b1]; ++b1; } int b2 = b1; while (b2 < 255 && bCount < minCount2) { bCount += hb[b2]; ++b2; } int gCount = 0; int g1 = 0; while (g1 < 255 && hg[g1] == 0) ++g1; while (g1 < 255 && gCount < minCount1) { gCount += hg[g1]; ++g1; } int g2 = g1; while (g2 < 255 && gCount < minCount2) { gCount += hg[g2]; ++g2; } int rCount = 0; int r1 = 0; while (r1 < 255 && hr[r1] == 0) ++r1; while (r1 < 255 && rCount < minCount1) { rCount += hr[r1]; ++r1; } int r2 = r1; while (r2 < 255 && rCount < minCount2) { rCount += hr[r2]; ++r2; } int aCount = 0; int a1 = 0; while (a1 < 255 && hb[a1] == 0) ++a1; while (a1 < 255 && aCount < minCount1) { aCount += ha[a1]; ++a1; } int a2 = a1; while (a2 < 255 && aCount < minCount2) { aCount += ha[a2]; ++a2; } return ColorBgra.FromBgra ( (byte)(255 - (b2 - b1)), (byte)(255 - (g2 - g1)), (byte)(255 - (r2 - r1)), (byte)(a2)); } public unsafe override void RenderEffect (ImageSurface src, ImageSurface dest, Gdk.Rectangle[] rois) { this.thickness = Data.Thickness; this.intensity = Data.Intensity; foreach (Gdk.Rectangle rect in rois) RenderRect (this.thickness, src, dest, rect); } #endregion public class OutlineData : EffectData { [MinimumValue (1), MaximumValue (200)] public int Thickness = 3; [MinimumValue (0), MaximumValue (100)] public int Intensity = 50; [Skip] public override bool IsDefault { get { return Thickness == 0; } } } } }