mirror of
https://github.com/greenshot/greenshot
synced 2025-07-15 01:23:47 -07:00
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:
parent
a52e83dc45
commit
ab7522d743
7 changed files with 360 additions and 253 deletions
|
@ -63,25 +63,8 @@ namespace Greenshot.Drawing.Filters {
|
|||
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) {
|
||||
applyRect = IntersectRectangle(applyBitmap.Size, rect);
|
||||
applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert);
|
||||
|
||||
if (applyRect.Width == 0 || applyRect.Height == 0) {
|
||||
// nothing to do
|
||||
|
|
|
@ -20,9 +20,10 @@ using System.Drawing;
|
|||
using Greenshot.Drawing.Fields;
|
||||
using Greenshot.Plugin.Drawing;
|
||||
using GreenshotPlugin.Core;
|
||||
using System.Drawing.Imaging;
|
||||
|
||||
namespace Greenshot.Drawing.Filters {
|
||||
[Serializable()]
|
||||
[Serializable()]
|
||||
public class BlurFilter : AbstractFilter {
|
||||
public double previewQuality;
|
||||
public double PreviewQuality {
|
||||
|
@ -35,201 +36,12 @@ namespace Greenshot.Drawing.Filters {
|
|||
AddField(GetType(), FieldType.PREVIEW_QUALITY, 1.0d);
|
||||
}
|
||||
|
||||
public static int[] CreateGaussianBlurRow(int amount) {
|
||||
int size = 1 + (amount * 2);
|
||||
int[] weights = new int[size];
|
||||
public unsafe override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) {
|
||||
int blurRadius = GetFieldValueAsInt(FieldType.BLUR_RADIUS);
|
||||
double previewQuality = GetFieldValueAsDouble(FieldType.PREVIEW_QUALITY);
|
||||
|
||||
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) {
|
||||
applyRect = IntersectRectangle(applyBitmap.Size, rect);
|
||||
|
||||
if (applyRect.Height <= 0 || applyRect.Width <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int blurRadius = GetFieldValueAsInt(FieldType.BLUR_RADIUS);
|
||||
double previewQuality = GetFieldValueAsDouble(FieldType.PREVIEW_QUALITY);
|
||||
|
||||
// do nothing when nothing can be done!
|
||||
if (blurRadius < 1) {
|
||||
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);
|
||||
}
|
||||
ImageHelper.ApplyBlur(graphics, applyBitmap, rect, renderMode == RenderMode.EXPORT, blurRadius, previewQuality, Invert, parent.Bounds);
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ namespace Greenshot.Drawing.Filters {
|
|||
|
||||
public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) {
|
||||
magnificationFactor = GetFieldValueAsInt(FieldType.MAGNIFICATION_FACTOR);
|
||||
applyRect = IntersectRectangle(applyBitmap.Size, rect);
|
||||
applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert);
|
||||
|
||||
bbbSrc = new BitmapBuffer(applyBitmap, applyRect);
|
||||
try {
|
||||
|
|
|
@ -77,7 +77,7 @@ namespace Greenshot.Drawing.Filters {
|
|||
|
||||
public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) {
|
||||
int pixelSize = GetFieldValueAsInt(FieldType.PIXEL_SIZE);
|
||||
applyRect = IntersectRectangle(applyBitmap.Size, rect);
|
||||
applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert);
|
||||
|
||||
Apply(graphics, applyBitmap, applyRect, pixelSize);
|
||||
}
|
||||
|
|
|
@ -34,12 +34,16 @@ using Greenshot.Plugin.Drawing;
|
|||
using GreenshotPlugin.Core;
|
||||
using Greenshot.Memento;
|
||||
using IniFile;
|
||||
using Greenshot.Drawing.Filters;
|
||||
using System.Drawing.Drawing2D;
|
||||
|
||||
namespace Greenshot.Drawing {
|
||||
public delegate void SurfaceElementEventHandler(object source, DrawableContainerList element);
|
||||
public delegate void SurfaceDrawingModeEventHandler(object source, DrawingModes drawingMode);
|
||||
|
||||
public enum DrawingModes { None, Rect, Ellipse, Text, Line, Arrow, Crop, Highlight, Obfuscate, Bitmap, Path }
|
||||
public enum Effects { Shadow, TornEdge }
|
||||
|
||||
/// <summary>
|
||||
/// Description of Surface.
|
||||
/// </summary>
|
||||
|
@ -522,17 +526,29 @@ namespace Greenshot.Drawing {
|
|||
return false;
|
||||
}
|
||||
|
||||
public void ApplyBitmapEffect() {
|
||||
Rectangle cropRectangle = new Rectangle(Point.Empty, Image.Size);
|
||||
Bitmap tmpImage = ((Bitmap)Image).Clone(cropRectangle, Image.PixelFormat);
|
||||
tmpImage.SetResolution(Image.HorizontalResolution, Image.VerticalResolution);
|
||||
public void ApplyBitmapEffect(Effects effect) {
|
||||
Rectangle imageRectangle = new Rectangle(Point.Empty, Image.Size);
|
||||
Bitmap newImage = null;
|
||||
|
||||
// Currently only one effect exists, others could follow
|
||||
ImageHelper.ApplyTornEdge(tmpImage);
|
||||
Point offset = Point.Empty;
|
||||
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;
|
||||
}
|
||||
|
||||
// Make undoable
|
||||
MakeUndoable(new SurfaceCropMemento(this, cropRectangle), false);
|
||||
SetImage(tmpImage, false);
|
||||
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
|
||||
MakeUndoable(new SurfaceCropMemento(this, imageRectangle), false);
|
||||
SetImage(newImage, false);
|
||||
}
|
||||
}
|
||||
|
||||
public bool isCropPossible(ref Rectangle cropRectangle) {
|
||||
|
@ -757,6 +773,10 @@ namespace Greenshot.Drawing {
|
|||
Bitmap clone = ImageHelper.CloneImageToBitmap(Image);
|
||||
// otherwise we would have a problem drawing the image to the surface... :(
|
||||
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));
|
||||
}
|
||||
return clone;
|
||||
|
@ -792,6 +812,10 @@ namespace Greenshot.Drawing {
|
|||
}
|
||||
// Elements might need the bitmap, so we copy the part we need
|
||||
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.SetClip(targetGraphics);
|
||||
elements.Draw(graphics, buffer, RenderMode.EDIT, clipRectangle);
|
||||
|
|
|
@ -26,6 +26,7 @@ using System.Net;
|
|||
using System.Text;
|
||||
|
||||
using Greenshot.Plugin;
|
||||
using GreenshotPlugin.Core;
|
||||
|
||||
namespace GreenshotNetworkImportPlugin {
|
||||
public class HTTPReceiver {
|
||||
|
@ -127,10 +128,11 @@ namespace GreenshotNetworkImportPlugin {
|
|||
using (MemoryStream memoryStream = new MemoryStream(imageBytes, 0, imageBytes.Length)) {
|
||||
// Convert byte[] to Image
|
||||
memoryStream.Write(imageBytes, 0, imageBytes.Length);
|
||||
Image image = Image.FromStream(memoryStream, true);
|
||||
ICapture capture = host.GetCapture(image);
|
||||
capture.CaptureDetails.Title = title;
|
||||
host.ImportCapture(capture);
|
||||
using (Image image = Bitmap.FromStream(memoryStream, true)) {
|
||||
ICapture capture = host.GetCapture(ImageHelper.CloneImageToBitmap(image));
|
||||
capture.CaptureDetails.Title = title;
|
||||
host.ImportCapture(capture);
|
||||
}
|
||||
response.StatusCode = (int)HttpStatusCode.OK;
|
||||
byte[] content = Encoding.UTF8.GetBytes("Greenshot-OK");
|
||||
response.ContentType = "text";
|
||||
|
|
|
@ -59,12 +59,13 @@ namespace GreenshotPlugin.Core {
|
|||
}
|
||||
|
||||
Bitmap bmp = new Bitmap(thumbWidth, thumbHeight);
|
||||
using (Graphics gr = System.Drawing.Graphics.FromImage(bmp)) {
|
||||
gr.SmoothingMode = SmoothingMode.HighQuality ;
|
||||
gr.CompositingQuality = CompositingQuality.HighQuality;
|
||||
gr.InterpolationMode = InterpolationMode.High;
|
||||
System.Drawing.Rectangle rectDestination = new System.Drawing.Rectangle(0, 0, thumbWidth, thumbHeight);
|
||||
gr.DrawImage(image, rectDestination, 0, 0, srcWidth, srcHeight, GraphicsUnit.Pixel);
|
||||
using (Graphics graphics = System.Drawing.Graphics.FromImage(bmp)) {
|
||||
graphics.SmoothingMode = SmoothingMode.HighQuality;
|
||||
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
|
||||
graphics.CompositingQuality = CompositingQuality.HighQuality;
|
||||
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
|
||||
Rectangle rectDestination = new Rectangle(0, 0, thumbWidth, thumbHeight);
|
||||
graphics.DrawImage(image, rectDestination, 0, 0, srcWidth, srcHeight, GraphicsUnit.Pixel);
|
||||
}
|
||||
return bmp;
|
||||
}
|
||||
|
@ -301,44 +302,52 @@ namespace GreenshotPlugin.Core {
|
|||
/// <summary>
|
||||
/// Make the picture look like it's torn
|
||||
/// </summary>
|
||||
/// <param name="bitmap">Bitmap to modify</param>
|
||||
public static void ApplyTornEdge(Bitmap bitmap) {
|
||||
/// <param name="sourceBitmap">Bitmap to make torn edge off</param>
|
||||
/// <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();
|
||||
Random random = new Random();
|
||||
int regionWidth = 14;
|
||||
int regionHeight = 14;
|
||||
int HorizontalRegions = (int)(bitmap.Width / regionWidth);
|
||||
int VerticalRegions = (int)(bitmap.Height / regionHeight);
|
||||
int regionWidth = 20;
|
||||
int regionHeight = 20;
|
||||
int HorizontalRegions = (int)(sourceBitmap.Width / regionWidth);
|
||||
int VerticalRegions = (int)(sourceBitmap.Height / regionHeight);
|
||||
int distance = 12;
|
||||
|
||||
// Start
|
||||
Point previousEndingPoint = Point.Empty;
|
||||
Point newEndingPoint = Point.Empty;
|
||||
|
||||
path.AddLine(new Point(sourceBitmap.Width, 0), Point.Empty);
|
||||
// Top
|
||||
for (int i = 0; i < HorizontalRegions; i++) {
|
||||
int x = (int)previousEndingPoint.X + regionWidth;
|
||||
int y = random.Next(0, distance);
|
||||
int y = random.Next(1, distance);
|
||||
newEndingPoint = new Point(x, y);
|
||||
path.AddLine(previousEndingPoint, newEndingPoint);
|
||||
previousEndingPoint = newEndingPoint;
|
||||
}
|
||||
// end top
|
||||
newEndingPoint = new Point(bitmap.Width, 0);
|
||||
newEndingPoint = new Point(sourceBitmap.Width, 0);
|
||||
path.AddLine(previousEndingPoint, newEndingPoint);
|
||||
previousEndingPoint = newEndingPoint;
|
||||
path.CloseFigure();
|
||||
|
||||
// Right
|
||||
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;
|
||||
newEndingPoint = new Point(x, y);
|
||||
path.AddLine(previousEndingPoint, newEndingPoint);
|
||||
previousEndingPoint = newEndingPoint;
|
||||
}
|
||||
// end right
|
||||
newEndingPoint = new Point(bitmap.Width, bitmap.Height);
|
||||
newEndingPoint = new Point(sourceBitmap.Width, sourceBitmap.Height);
|
||||
path.AddLine(previousEndingPoint, newEndingPoint);
|
||||
previousEndingPoint = newEndingPoint;
|
||||
path.CloseFigure();
|
||||
|
@ -346,20 +355,20 @@ namespace GreenshotPlugin.Core {
|
|||
// Bottom
|
||||
for (int i = 0; i < HorizontalRegions; i++) {
|
||||
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);
|
||||
path.AddLine(previousEndingPoint, newEndingPoint);
|
||||
previousEndingPoint = newEndingPoint;
|
||||
}
|
||||
// end Bottom
|
||||
newEndingPoint = new Point(0, bitmap.Height);
|
||||
newEndingPoint = new Point(0, sourceBitmap.Height);
|
||||
path.AddLine(previousEndingPoint, newEndingPoint);
|
||||
previousEndingPoint = newEndingPoint;
|
||||
path.CloseFigure();
|
||||
|
||||
// Left
|
||||
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;
|
||||
newEndingPoint = new Point(x, y);
|
||||
path.AddLine(previousEndingPoint, newEndingPoint);
|
||||
|
@ -372,17 +381,294 @@ namespace GreenshotPlugin.Core {
|
|||
path.CloseFigure();
|
||||
|
||||
// Draw
|
||||
using (Graphics graphics = Graphics.FromImage(bitmap)) {
|
||||
Color fillColor = Color.White;
|
||||
if (bitmap.PixelFormat == PixelFormat.Format32bppArgb) {
|
||||
using (Graphics graphics = Graphics.FromImage(returnImage)) {
|
||||
graphics.SmoothingMode = SmoothingMode.HighQuality;
|
||||
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.Clear(Color.Transparent);
|
||||
} else {
|
||||
using (Brush brush = new SolidBrush( Color.White)) {
|
||||
using (Brush brush = new SolidBrush(Color.White)) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue