Fixing some bitmap code to work, this should improve the quality a bit. Also re-factored some code so I could add more professionally shadows.

git-svn-id: http://svn.code.sf.net/p/greenshot/code/trunk@1639 7dccd23d-a4a3-4e1f-8c07-b4c1b4018ab4
This commit is contained in:
RKrom 2012-02-08 12:04:35 +00:00
parent a52e83dc45
commit ab7522d743
7 changed files with 360 additions and 253 deletions

View file

@ -63,25 +63,8 @@ namespace Greenshot.Drawing.Filters {
return parent; return parent;
} }
/**
* This method fixes the problem that we can't apply a filter outside the target bitmap,
* therefor the filtered-bitmap will be shifted if we try to draw it outside the target bitmap.
* It will also account for the Invert flag.
*/
protected Rectangle IntersectRectangle(Size applySize, Rectangle rect) {
Rectangle myRect;
if (Invert) {
myRect = new Rectangle(0, 0, applySize.Width, applySize.Height);
} else {
Rectangle applyRect = new Rectangle(0,0, applySize.Width, applySize.Height);
myRect = new Rectangle(rect.X, rect.Y, rect.Width, rect.Height);
myRect.Intersect(applyRect);
}
return myRect;
}
public virtual void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) { public virtual void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) {
applyRect = IntersectRectangle(applyBitmap.Size, rect); applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert);
if (applyRect.Width == 0 || applyRect.Height == 0) { if (applyRect.Width == 0 || applyRect.Height == 0) {
// nothing to do // nothing to do

View file

@ -20,6 +20,7 @@ using System.Drawing;
using Greenshot.Drawing.Fields; using Greenshot.Drawing.Fields;
using Greenshot.Plugin.Drawing; using Greenshot.Plugin.Drawing;
using GreenshotPlugin.Core; using GreenshotPlugin.Core;
using System.Drawing.Imaging;
namespace Greenshot.Drawing.Filters { namespace Greenshot.Drawing.Filters {
[Serializable()] [Serializable()]
@ -35,201 +36,12 @@ namespace Greenshot.Drawing.Filters {
AddField(GetType(), FieldType.PREVIEW_QUALITY, 1.0d); AddField(GetType(), FieldType.PREVIEW_QUALITY, 1.0d);
} }
public static int[] CreateGaussianBlurRow(int amount) {
int size = 1 + (amount * 2);
int[] weights = new int[size];
for (int i = 0; i <= amount; ++i)
{
// 1 + aa - aa + 2ai - ii
weights[i] = 16 * (i + 1);
weights[weights.Length - i - 1] = weights[i];
}
return weights;
}
public unsafe override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) { public unsafe override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) {
applyRect = IntersectRectangle(applyBitmap.Size, rect);
if (applyRect.Height <= 0 || applyRect.Width <= 0) {
return;
}
int blurRadius = GetFieldValueAsInt(FieldType.BLUR_RADIUS); int blurRadius = GetFieldValueAsInt(FieldType.BLUR_RADIUS);
double previewQuality = GetFieldValueAsDouble(FieldType.PREVIEW_QUALITY); double previewQuality = GetFieldValueAsDouble(FieldType.PREVIEW_QUALITY);
// do nothing when nothing can be done! ImageHelper.ApplyBlur(graphics, applyBitmap, rect, renderMode == RenderMode.EXPORT, blurRadius, previewQuality, Invert, parent.Bounds);
if (blurRadius < 1) {
return; return;
} }
using (BitmapBuffer bbbDest = new BitmapBuffer(applyBitmap, applyRect)) {
bbbDest.Lock();
using (BitmapBuffer bbbSrc = new BitmapBuffer(applyBitmap, applyRect)) {
bbbSrc.Lock();
Random rand = new Random();
int r = blurRadius;
int[] w = CreateGaussianBlurRow(r);
int wlen = w.Length;
long[] waSums = new long[wlen];
long[] wcSums = new long[wlen];
long[] aSums = new long[wlen];
long[] bSums = new long[wlen];
long[] gSums = new long[wlen];
long[] rSums = new long[wlen];
for (int y = 0; y < applyRect.Height; ++y) {
long waSum = 0;
long wcSum = 0;
long aSum = 0;
long bSum = 0;
long gSum = 0;
long rSum = 0;
for (int wx = 0; wx < wlen; ++wx) {
int srcX = wx - r;
waSums[wx] = 0;
wcSums[wx] = 0;
aSums[wx] = 0;
bSums[wx] = 0;
gSums[wx] = 0;
rSums[wx] = 0;
if (srcX >= 0 && srcX < bbbDest.Width) {
for (int wy = 0; wy < wlen; ++wy) {
int srcY = y + wy - r;
if (srcY >= 0 && srcY < bbbDest.Height) {
int[] colors = bbbSrc.GetColorArrayAt(srcX, srcY);
int wp = w[wy];
waSums[wx] += wp;
wp *= colors[0] + (colors[0] >> 7);
wcSums[wx] += wp;
wp >>= 8;
aSums[wx] += wp * colors[0];
bSums[wx] += wp * colors[3];
gSums[wx] += wp * colors[2];
rSums[wx] += wp * colors[1];
}
}
int wwx = w[wx];
waSum += wwx * waSums[wx];
wcSum += wwx * wcSums[wx];
aSum += wwx * aSums[wx];
bSum += wwx * bSums[wx];
gSum += wwx * gSums[wx];
rSum += wwx * rSums[wx];
}
}
wcSum >>= 8;
if (waSum == 0 || wcSum == 0) {
SetColorAt(bbbDest, 0, y, new int[]{0,0,0,0});
} else {
int alpha = (int)(aSum / waSum);
int blue = (int)(bSum / wcSum);
int green = (int)(gSum / wcSum);
int red = (int)(rSum / wcSum);
SetColorAt(bbbDest, 0, y, new int[]{alpha, red, green, blue});
}
for (int x = 1; x < applyRect.Width; ++x) {
for (int i = 0; i < wlen - 1; ++i) {
waSums[i] = waSums[i + 1];
wcSums[i] = wcSums[i + 1];
aSums[i] = aSums[i + 1];
bSums[i] = bSums[i + 1];
gSums[i] = gSums[i + 1];
rSums[i] = rSums[i + 1];
}
waSum = 0;
wcSum = 0;
aSum = 0;
bSum = 0;
gSum = 0;
rSum = 0;
int wx;
for (wx = 0; wx < wlen - 1; ++wx) {
long wwx = (long)w[wx];
waSum += wwx * waSums[wx];
wcSum += wwx * wcSums[wx];
aSum += wwx * aSums[wx];
bSum += wwx * bSums[wx];
gSum += wwx * gSums[wx];
rSum += wwx * rSums[wx];
}
wx = wlen - 1;
waSums[wx] = 0;
wcSums[wx] = 0;
aSums[wx] = 0;
bSums[wx] = 0;
gSums[wx] = 0;
rSums[wx] = 0;
int srcX = x + wx - r;
if (srcX >= 0 && srcX < applyRect.Width) {
for (int wy = 0; wy < wlen; ++wy) {
int srcY = y + wy - r;
// only when in EDIT mode, ignore some pixels depending on preview quality
if ((renderMode==RenderMode.EXPORT || rand.NextDouble()<previewQuality) && srcY >= 0 && srcY < applyRect.Height) {
int[] colors = bbbSrc.GetColorArrayAt(srcX, srcY);
int wp = w[wy];
waSums[wx] += wp;
wp *= colors[0] + (colors[0] >> 7);
wcSums[wx] += wp;
wp >>= 8;
aSums[wx] += wp * (long)colors[0];
bSums[wx] += wp * (long)colors[3];
gSums[wx] += wp * (long)colors[2];
rSums[wx] += wp * (long)colors[1];
}
}
int wr = w[wx];
waSum += (long)wr * waSums[wx];
wcSum += (long)wr * wcSums[wx];
aSum += (long)wr * aSums[wx];
bSum += (long)wr * bSums[wx];
gSum += (long)wr * gSums[wx];
rSum += (long)wr * rSums[wx];
}
wcSum >>= 8;
if (waSum == 0 || wcSum == 0) {
SetColorAt(bbbDest, x, y, new int[]{0,0,0,0});
} else {
int alpha = (int)(aSum / waSum);
int blue = (int)(bSum / wcSum);
int green = (int)(gSum / wcSum);
int red = (int)(rSum / wcSum);
SetColorAt(bbbDest, x, y, new int[]{alpha, red, green, blue});
}
}
}
}
bbbDest.DrawTo(graphics, applyRect.Location);
}
}
private void SetColorAt(BitmapBuffer bbb, int x, int y, int[] colors) {
if(parent.Contains(applyRect.Left+x, applyRect.Top+y) ^ Invert) {
bbb.SetColorArrayAt(x, y, colors);
}
}
} }
} }

View file

@ -37,7 +37,7 @@ namespace Greenshot.Drawing.Filters {
public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) { public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) {
magnificationFactor = GetFieldValueAsInt(FieldType.MAGNIFICATION_FACTOR); magnificationFactor = GetFieldValueAsInt(FieldType.MAGNIFICATION_FACTOR);
applyRect = IntersectRectangle(applyBitmap.Size, rect); applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert);
bbbSrc = new BitmapBuffer(applyBitmap, applyRect); bbbSrc = new BitmapBuffer(applyBitmap, applyRect);
try { try {

View file

@ -77,7 +77,7 @@ namespace Greenshot.Drawing.Filters {
public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) { public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) {
int pixelSize = GetFieldValueAsInt(FieldType.PIXEL_SIZE); int pixelSize = GetFieldValueAsInt(FieldType.PIXEL_SIZE);
applyRect = IntersectRectangle(applyBitmap.Size, rect); applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert);
Apply(graphics, applyBitmap, applyRect, pixelSize); Apply(graphics, applyBitmap, applyRect, pixelSize);
} }

View file

@ -34,12 +34,16 @@ using Greenshot.Plugin.Drawing;
using GreenshotPlugin.Core; using GreenshotPlugin.Core;
using Greenshot.Memento; using Greenshot.Memento;
using IniFile; using IniFile;
using Greenshot.Drawing.Filters;
using System.Drawing.Drawing2D;
namespace Greenshot.Drawing { namespace Greenshot.Drawing {
public delegate void SurfaceElementEventHandler(object source, DrawableContainerList element); public delegate void SurfaceElementEventHandler(object source, DrawableContainerList element);
public delegate void SurfaceDrawingModeEventHandler(object source, DrawingModes drawingMode); public delegate void SurfaceDrawingModeEventHandler(object source, DrawingModes drawingMode);
public enum DrawingModes { None, Rect, Ellipse, Text, Line, Arrow, Crop, Highlight, Obfuscate, Bitmap, Path } public enum DrawingModes { None, Rect, Ellipse, Text, Line, Arrow, Crop, Highlight, Obfuscate, Bitmap, Path }
public enum Effects { Shadow, TornEdge }
/// <summary> /// <summary>
/// Description of Surface. /// Description of Surface.
/// </summary> /// </summary>
@ -522,17 +526,29 @@ namespace Greenshot.Drawing {
return false; return false;
} }
public void ApplyBitmapEffect() { public void ApplyBitmapEffect(Effects effect) {
Rectangle cropRectangle = new Rectangle(Point.Empty, Image.Size); Rectangle imageRectangle = new Rectangle(Point.Empty, Image.Size);
Bitmap tmpImage = ((Bitmap)Image).Clone(cropRectangle, Image.PixelFormat); Bitmap newImage = null;
tmpImage.SetResolution(Image.HorizontalResolution, Image.VerticalResolution);
// Currently only one effect exists, others could follow Point offset = Point.Empty;
ImageHelper.ApplyTornEdge(tmpImage); switch (effect) {
case Effects.Shadow:
newImage = ImageHelper.CreateShadow((Bitmap)Image, 0.8f, 8, Image.PixelFormat, out offset);
break;
case Effects.TornEdge:
using (Bitmap tmpImage = ImageHelper.CreateTornEdge((Bitmap)Image)) {
newImage = ImageHelper.CreateShadow(tmpImage, 0.8f, 8, Image.PixelFormat, out offset);
}
break;
}
if (newImage != null) {
// Make sure the elements move according to the offset the effect made the bitmap move
elements.MoveBy(offset.X, offset.Y);
// Make undoable // Make undoable
MakeUndoable(new SurfaceCropMemento(this, cropRectangle), false); MakeUndoable(new SurfaceCropMemento(this, imageRectangle), false);
SetImage(tmpImage, false); SetImage(newImage, false);
}
} }
public bool isCropPossible(ref Rectangle cropRectangle) { public bool isCropPossible(ref Rectangle cropRectangle) {
@ -757,6 +773,10 @@ namespace Greenshot.Drawing {
Bitmap clone = ImageHelper.CloneImageToBitmap(Image); Bitmap clone = ImageHelper.CloneImageToBitmap(Image);
// otherwise we would have a problem drawing the image to the surface... :( // otherwise we would have a problem drawing the image to the surface... :(
using (Graphics graphics = Graphics.FromImage(clone)) { using (Graphics graphics = Graphics.FromImage(clone)) {
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
elements.Draw(graphics, (Bitmap)clone, renderMode, new Rectangle(Point.Empty, clone.Size)); elements.Draw(graphics, (Bitmap)clone, renderMode, new Rectangle(Point.Empty, clone.Size));
} }
return clone; return clone;
@ -792,6 +812,10 @@ namespace Greenshot.Drawing {
} }
// Elements might need the bitmap, so we copy the part we need // Elements might need the bitmap, so we copy the part we need
using (Graphics graphics = Graphics.FromImage(buffer)) { using (Graphics graphics = Graphics.FromImage(buffer)) {
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.DrawImage(Image, clipRectangle, clipRectangle, GraphicsUnit.Pixel); graphics.DrawImage(Image, clipRectangle, clipRectangle, GraphicsUnit.Pixel);
graphics.SetClip(targetGraphics); graphics.SetClip(targetGraphics);
elements.Draw(graphics, buffer, RenderMode.EDIT, clipRectangle); elements.Draw(graphics, buffer, RenderMode.EDIT, clipRectangle);

View file

@ -26,6 +26,7 @@ using System.Net;
using System.Text; using System.Text;
using Greenshot.Plugin; using Greenshot.Plugin;
using GreenshotPlugin.Core;
namespace GreenshotNetworkImportPlugin { namespace GreenshotNetworkImportPlugin {
public class HTTPReceiver { public class HTTPReceiver {
@ -127,10 +128,11 @@ namespace GreenshotNetworkImportPlugin {
using (MemoryStream memoryStream = new MemoryStream(imageBytes, 0, imageBytes.Length)) { using (MemoryStream memoryStream = new MemoryStream(imageBytes, 0, imageBytes.Length)) {
// Convert byte[] to Image // Convert byte[] to Image
memoryStream.Write(imageBytes, 0, imageBytes.Length); memoryStream.Write(imageBytes, 0, imageBytes.Length);
Image image = Image.FromStream(memoryStream, true); using (Image image = Bitmap.FromStream(memoryStream, true)) {
ICapture capture = host.GetCapture(image); ICapture capture = host.GetCapture(ImageHelper.CloneImageToBitmap(image));
capture.CaptureDetails.Title = title; capture.CaptureDetails.Title = title;
host.ImportCapture(capture); host.ImportCapture(capture);
}
response.StatusCode = (int)HttpStatusCode.OK; response.StatusCode = (int)HttpStatusCode.OK;
byte[] content = Encoding.UTF8.GetBytes("Greenshot-OK"); byte[] content = Encoding.UTF8.GetBytes("Greenshot-OK");
response.ContentType = "text"; response.ContentType = "text";

View file

@ -59,12 +59,13 @@ namespace GreenshotPlugin.Core {
} }
Bitmap bmp = new Bitmap(thumbWidth, thumbHeight); Bitmap bmp = new Bitmap(thumbWidth, thumbHeight);
using (Graphics gr = System.Drawing.Graphics.FromImage(bmp)) { using (Graphics graphics = System.Drawing.Graphics.FromImage(bmp)) {
gr.SmoothingMode = SmoothingMode.HighQuality ; graphics.SmoothingMode = SmoothingMode.HighQuality;
gr.CompositingQuality = CompositingQuality.HighQuality; graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
gr.InterpolationMode = InterpolationMode.High; graphics.CompositingQuality = CompositingQuality.HighQuality;
System.Drawing.Rectangle rectDestination = new System.Drawing.Rectangle(0, 0, thumbWidth, thumbHeight); graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
gr.DrawImage(image, rectDestination, 0, 0, srcWidth, srcHeight, GraphicsUnit.Pixel); Rectangle rectDestination = new Rectangle(0, 0, thumbWidth, thumbHeight);
graphics.DrawImage(image, rectDestination, 0, 0, srcWidth, srcHeight, GraphicsUnit.Pixel);
} }
return bmp; return bmp;
} }
@ -301,44 +302,52 @@ namespace GreenshotPlugin.Core {
/// <summary> /// <summary>
/// Make the picture look like it's torn /// Make the picture look like it's torn
/// </summary> /// </summary>
/// <param name="bitmap">Bitmap to modify</param> /// <param name="sourceBitmap">Bitmap to make torn edge off</param>
public static void ApplyTornEdge(Bitmap bitmap) { /// <returns>Changed bitmap</returns>
public static Bitmap CreateTornEdge(Bitmap sourceBitmap) {
Rectangle cropRectangle = new Rectangle(Point.Empty, sourceBitmap.Size);
Bitmap returnImage = sourceBitmap.Clone(cropRectangle, PixelFormat.Format32bppArgb);
try {
returnImage.SetResolution(sourceBitmap.HorizontalResolution, sourceBitmap.VerticalResolution);
} catch (Exception ex) {
LOG.Warn("An exception occured while setting the resolution.", ex);
}
GraphicsPath path = new GraphicsPath(); GraphicsPath path = new GraphicsPath();
Random random = new Random(); Random random = new Random();
int regionWidth = 14; int regionWidth = 20;
int regionHeight = 14; int regionHeight = 20;
int HorizontalRegions = (int)(bitmap.Width / regionWidth); int HorizontalRegions = (int)(sourceBitmap.Width / regionWidth);
int VerticalRegions = (int)(bitmap.Height / regionHeight); int VerticalRegions = (int)(sourceBitmap.Height / regionHeight);
int distance = 12; int distance = 12;
// Start // Start
Point previousEndingPoint = Point.Empty; Point previousEndingPoint = Point.Empty;
Point newEndingPoint = Point.Empty; Point newEndingPoint = Point.Empty;
path.AddLine(new Point(sourceBitmap.Width, 0), Point.Empty);
// Top // Top
for (int i = 0; i < HorizontalRegions; i++) { for (int i = 0; i < HorizontalRegions; i++) {
int x = (int)previousEndingPoint.X + regionWidth; int x = (int)previousEndingPoint.X + regionWidth;
int y = random.Next(0, distance); int y = random.Next(1, distance);
newEndingPoint = new Point(x, y); newEndingPoint = new Point(x, y);
path.AddLine(previousEndingPoint, newEndingPoint); path.AddLine(previousEndingPoint, newEndingPoint);
previousEndingPoint = newEndingPoint; previousEndingPoint = newEndingPoint;
} }
// end top // end top
newEndingPoint = new Point(bitmap.Width, 0); newEndingPoint = new Point(sourceBitmap.Width, 0);
path.AddLine(previousEndingPoint, newEndingPoint); path.AddLine(previousEndingPoint, newEndingPoint);
previousEndingPoint = newEndingPoint; previousEndingPoint = newEndingPoint;
path.CloseFigure(); path.CloseFigure();
// Right // Right
for (int i = 0; i < VerticalRegions; i++) { for (int i = 0; i < VerticalRegions; i++) {
int x = bitmap.Width - random.Next(0, distance); int x = sourceBitmap.Width - random.Next(1, distance);
int y = (int)previousEndingPoint.Y + regionHeight; int y = (int)previousEndingPoint.Y + regionHeight;
newEndingPoint = new Point(x, y); newEndingPoint = new Point(x, y);
path.AddLine(previousEndingPoint, newEndingPoint); path.AddLine(previousEndingPoint, newEndingPoint);
previousEndingPoint = newEndingPoint; previousEndingPoint = newEndingPoint;
} }
// end right // end right
newEndingPoint = new Point(bitmap.Width, bitmap.Height); newEndingPoint = new Point(sourceBitmap.Width, sourceBitmap.Height);
path.AddLine(previousEndingPoint, newEndingPoint); path.AddLine(previousEndingPoint, newEndingPoint);
previousEndingPoint = newEndingPoint; previousEndingPoint = newEndingPoint;
path.CloseFigure(); path.CloseFigure();
@ -346,20 +355,20 @@ namespace GreenshotPlugin.Core {
// Bottom // Bottom
for (int i = 0; i < HorizontalRegions; i++) { for (int i = 0; i < HorizontalRegions; i++) {
int x = (int)previousEndingPoint.X - regionWidth; int x = (int)previousEndingPoint.X - regionWidth;
int y = bitmap.Height - random.Next(0, distance); int y = sourceBitmap.Height - random.Next(1, distance);
newEndingPoint = new Point(x, y); newEndingPoint = new Point(x, y);
path.AddLine(previousEndingPoint, newEndingPoint); path.AddLine(previousEndingPoint, newEndingPoint);
previousEndingPoint = newEndingPoint; previousEndingPoint = newEndingPoint;
} }
// end Bottom // end Bottom
newEndingPoint = new Point(0, bitmap.Height); newEndingPoint = new Point(0, sourceBitmap.Height);
path.AddLine(previousEndingPoint, newEndingPoint); path.AddLine(previousEndingPoint, newEndingPoint);
previousEndingPoint = newEndingPoint; previousEndingPoint = newEndingPoint;
path.CloseFigure(); path.CloseFigure();
// Left // Left
for (int i = 0; i < VerticalRegions; i++) { for (int i = 0; i < VerticalRegions; i++) {
int x = random.Next(0, distance); int x = random.Next(1, distance);
int y = (int)previousEndingPoint.Y - regionHeight; int y = (int)previousEndingPoint.Y - regionHeight;
newEndingPoint = new Point(x, y); newEndingPoint = new Point(x, y);
path.AddLine(previousEndingPoint, newEndingPoint); path.AddLine(previousEndingPoint, newEndingPoint);
@ -372,17 +381,294 @@ namespace GreenshotPlugin.Core {
path.CloseFigure(); path.CloseFigure();
// Draw // Draw
using (Graphics graphics = Graphics.FromImage(bitmap)) { using (Graphics graphics = Graphics.FromImage(returnImage)) {
Color fillColor = Color.White; graphics.SmoothingMode = SmoothingMode.HighQuality;
if (bitmap.PixelFormat == PixelFormat.Format32bppArgb) { graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
if (Image.IsAlphaPixelFormat(returnImage.PixelFormat)) {
// When using transparency we can't draw with Color.Transparency so we clear
graphics.SetClip(path); graphics.SetClip(path);
graphics.Clear(Color.Transparent); graphics.Clear(Color.Transparent);
} else { } else {
using (Brush brush = new SolidBrush( Color.White)) { using (Brush brush = new SolidBrush(Color.White)) {
graphics.FillPath(brush, path); graphics.FillPath(brush, path);
} }
} }
} }
return returnImage;
}
/// <summary>
/// Helper Method for the ApplyBlur
/// </summary>
/// <param name="amount"></param>
/// <returns></returns>
private static int[] CreateGaussianBlurRow(int amount) {
int size = 1 + (amount * 2);
int[] weights = new int[size];
for (int i = 0; i <= amount; ++i) {
// 1 + aa - aa + 2ai - ii
weights[i] = 16 * (i + 1);
weights[weights.Length - i - 1] = weights[i];
}
return weights;
}
/// <summary>
/// Apply sourceBitmap with a blur to the targetGraphics
/// </summary>
/// <param name="targetGraphics">Target to draw to</param>
/// <param name="sourceBitmap">Source to blur</param>
/// <param name="rect">Area to blur</param>
/// <param name="export">Use full quality</param>
/// <param name="blurRadius">Radius of the blur</param>
/// <param name="previewQuality">Quality, use 1d for normal anything less skipps calculations</param>
/// <param name="invert">true if the blur needs to occur outside of the area</param>
/// <param name="parentBounds">Rectangle limiting the area when using invert</param>
public static void ApplyBlur(Graphics targetGraphics, Bitmap sourceBitmap, Rectangle rect, bool export, int blurRadius, double previewQuality, bool invert, Rectangle parentBounds) {
Rectangle applyRect = CreateIntersectRectangle(sourceBitmap.Size, rect, invert);
if (applyRect.Height <= 0 || applyRect.Width <= 0) {
return;
}
// do nothing when nothing can be done!
if (blurRadius < 1) {
return;
}
Color nullColor = Color.White;
if (sourceBitmap.PixelFormat == PixelFormat.Format32bppArgb) {
nullColor = Color.Transparent;
}
using (BitmapBuffer bbbDest = new BitmapBuffer(sourceBitmap, applyRect)) {
bbbDest.Lock();
using (BitmapBuffer bbbSrc = new BitmapBuffer(sourceBitmap, applyRect)) {
bbbSrc.Lock();
Random rand = new Random();
int r = blurRadius;
int[] w = CreateGaussianBlurRow(r);
int wlen = w.Length;
long[] waSums = new long[wlen];
long[] wcSums = new long[wlen];
long[] aSums = new long[wlen];
long[] bSums = new long[wlen];
long[] gSums = new long[wlen];
long[] rSums = new long[wlen];
for (int y = 0; y < applyRect.Height; ++y) {
long waSum = 0;
long wcSum = 0;
long aSum = 0;
long bSum = 0;
long gSum = 0;
long rSum = 0;
for (int wx = 0; wx < wlen; ++wx) {
int srcX = wx - r;
waSums[wx] = 0;
wcSums[wx] = 0;
aSums[wx] = 0;
bSums[wx] = 0;
gSums[wx] = 0;
rSums[wx] = 0;
if (srcX >= 0 && srcX < bbbDest.Width) {
for (int wy = 0; wy < wlen; ++wy) {
int srcY = y + wy - r;
if (srcY >= 0 && srcY < bbbDest.Height) {
int[] colors = bbbSrc.GetColorArrayAt(srcX, srcY);
int wp = w[wy];
waSums[wx] += wp;
wp *= colors[0] + (colors[0] >> 7);
wcSums[wx] += wp;
wp >>= 8;
aSums[wx] += wp * colors[0];
bSums[wx] += wp * colors[3];
gSums[wx] += wp * colors[2];
rSums[wx] += wp * colors[1];
}
}
int wwx = w[wx];
waSum += wwx * waSums[wx];
wcSum += wwx * wcSums[wx];
aSum += wwx * aSums[wx];
bSum += wwx * bSums[wx];
gSum += wwx * gSums[wx];
rSum += wwx * rSums[wx];
}
}
wcSum >>= 8;
if (waSum == 0 || wcSum == 0) {
if (parentBounds.Contains(applyRect.Left, applyRect.Top + y) ^ invert) {
bbbDest.SetColorAt(0, y, nullColor);
}
} else {
int alpha = (int)(aSum / waSum);
int blue = (int)(bSum / wcSum);
int green = (int)(gSum / wcSum);
int red = (int)(rSum / wcSum);
if (parentBounds.Contains(applyRect.Left, applyRect.Top + y) ^ invert) {
bbbDest.SetColorAt(0, y, Color.FromArgb(alpha, red, green, blue));
}
}
for (int x = 1; x < applyRect.Width; ++x) {
for (int i = 0; i < wlen - 1; ++i) {
waSums[i] = waSums[i + 1];
wcSums[i] = wcSums[i + 1];
aSums[i] = aSums[i + 1];
bSums[i] = bSums[i + 1];
gSums[i] = gSums[i + 1];
rSums[i] = rSums[i + 1];
}
waSum = 0;
wcSum = 0;
aSum = 0;
bSum = 0;
gSum = 0;
rSum = 0;
int wx;
for (wx = 0; wx < wlen - 1; ++wx) {
long wwx = (long)w[wx];
waSum += wwx * waSums[wx];
wcSum += wwx * wcSums[wx];
aSum += wwx * aSums[wx];
bSum += wwx * bSums[wx];
gSum += wwx * gSums[wx];
rSum += wwx * rSums[wx];
}
wx = wlen - 1;
waSums[wx] = 0;
wcSums[wx] = 0;
aSums[wx] = 0;
bSums[wx] = 0;
gSums[wx] = 0;
rSums[wx] = 0;
int srcX = x + wx - r;
if (srcX >= 0 && srcX < applyRect.Width) {
for (int wy = 0; wy < wlen; ++wy) {
int srcY = y + wy - r;
// only when in EDIT mode, ignore some pixels depending on preview quality
if ((export || rand.NextDouble() < previewQuality) && srcY >= 0 && srcY < applyRect.Height) {
int[] colors = bbbSrc.GetColorArrayAt(srcX, srcY);
int wp = w[wy];
waSums[wx] += wp;
wp *= colors[0] + (colors[0] >> 7);
wcSums[wx] += wp;
wp >>= 8;
aSums[wx] += wp * (long)colors[0];
bSums[wx] += wp * (long)colors[3];
gSums[wx] += wp * (long)colors[2];
rSums[wx] += wp * (long)colors[1];
}
}
int wr = w[wx];
waSum += (long)wr * waSums[wx];
wcSum += (long)wr * wcSums[wx];
aSum += (long)wr * aSums[wx];
bSum += (long)wr * bSums[wx];
gSum += (long)wr * gSums[wx];
rSum += (long)wr * rSums[wx];
}
wcSum >>= 8;
if (waSum == 0 || wcSum == 0) {
if (parentBounds.Contains(applyRect.Left + x, applyRect.Top + y) ^ invert) {
bbbDest.SetColorAt(x, y, nullColor);
}
} else {
int alpha = (int)(aSum / waSum);
int blue = (int)(bSum / wcSum);
int green = (int)(gSum / wcSum);
int red = (int)(rSum / wcSum);
if (parentBounds.Contains(applyRect.Left + x, applyRect.Top + y) ^ invert) {
bbbDest.SetColorAt(x, y, Color.FromArgb(alpha, red, green, blue));
}
}
}
}
}
bbbDest.DrawTo(targetGraphics, applyRect.Location);
}
}
/**
* This method fixes the problem that we can't apply a filter outside the target bitmap,
* therefor the filtered-bitmap will be shifted if we try to draw it outside the target bitmap.
* It will also account for the Invert flag.
*/
public static Rectangle CreateIntersectRectangle(Size applySize, Rectangle rect, bool invert) {
Rectangle myRect;
if (invert) {
myRect = new Rectangle(0, 0, applySize.Width, applySize.Height);
} else {
Rectangle applyRect = new Rectangle(0, 0, applySize.Width, applySize.Height);
myRect = new Rectangle(rect.X, rect.Y, rect.Width, rect.Height);
myRect.Intersect(applyRect);
}
return myRect;
}
/// <summary>
/// Create a new bitmap where the sourceBitmap has a shadow
/// </summary>
/// <param name="sourceBitmap">Bitmap to make a shadow on</param>
/// <param name="darkness">How dark is the shadow</param>
/// <param name="shadowSize">Size of the shadow</param>
/// <param name="targetPixelformat">What pixel format must the returning bitmap have</param>
/// <param name="offset">How many pixels is the original image moved?</param>
/// <returns>Bitmap with the shadow, is bigger than the sourceBitmap!!</returns>
public static Bitmap CreateShadow(Bitmap sourceBitmap, float darkness, int shadowSize, PixelFormat targetPixelformat, out Point offset) {
Bitmap newImage = new Bitmap(sourceBitmap.Width + (shadowSize * 2), sourceBitmap.Height + (shadowSize * 2), targetPixelformat);
using (Graphics graphics = Graphics.FromImage(newImage)) {
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
if (Image.IsAlphaPixelFormat(targetPixelformat)) {
graphics.Clear(Color.Transparent);
} else {
graphics.Clear(Color.White);
}
ImageAttributes ia = new ImageAttributes();
ColorMatrix cm = new ColorMatrix();
cm.Matrix00 = 0;
cm.Matrix11 = 0;
cm.Matrix22 = 0;
cm.Matrix33 = darkness;
ia.SetColorMatrix(cm);
// Draw "shadow" offsetted
graphics.DrawImage(sourceBitmap, new Rectangle(new Point(shadowSize, shadowSize), sourceBitmap.Size), 0, 0, sourceBitmap.Width, sourceBitmap.Height, GraphicsUnit.Pixel, ia);
// blur "shadow", apply to whole new image
Rectangle applyRectangle = new Rectangle(Point.Empty, newImage.Size);
ApplyBlur(graphics, newImage, applyRectangle, true, shadowSize, 1d, false, applyRectangle);
// draw original
offset = new Point(shadowSize - 2, shadowSize - 2);
graphics.DrawImage(sourceBitmap, offset);
}
return newImage;
} }
} }
} }