diff --git a/Greenshot/Drawing/Filters/BlurFilter.cs b/Greenshot/Drawing/Filters/BlurFilter.cs index 952584520..713052f2a 100644 --- a/Greenshot/Drawing/Filters/BlurFilter.cs +++ b/Greenshot/Drawing/Filters/BlurFilter.cs @@ -1,30 +1,37 @@ -/// -/// Parts of this class were taken from BlurEffect.cs of Paint.NET 3.0.1, -/// which was released under MIT license. -/// http://www.getpaint.net -/// Some of this code has been adapted for integration with Greenshot. -/// See Paint.NET copyright notice below. -/// - -///////////////////////////////////////////////////////////////////////////////// -// Paint.NET // -// Copyright (C) Rick Brewster, Tom Jackson, and past contributors. // -// Portions Copyright (C) Microsoft Corporation. All Rights Reserved. // -// See src/Resources/Files/License.txt for full licensing and attribution // -// details. // -// . // -///////////////////////////////////////////////////////////////////////////////// - +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2013 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ using System; using System.Drawing; using Greenshot.Drawing.Fields; using Greenshot.Plugin.Drawing; using GreenshotPlugin.Core; using System.Drawing.Imaging; +using GreenshotPlugin.UnmanagedHelpers; +using System.Drawing.Drawing2D; namespace Greenshot.Drawing.Filters { [Serializable()] public class BlurFilter : AbstractFilter { + private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(BlurFilter)); + public double previewQuality; public double PreviewQuality { get { return previewQuality; } @@ -40,11 +47,20 @@ namespace Greenshot.Drawing.Filters { int blurRadius = GetFieldValueAsInt(FieldType.BLUR_RADIUS); double previewQuality = GetFieldValueAsDouble(FieldType.PREVIEW_QUALITY); Rectangle applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert); - using (Bitmap blurImage = ImageHelper.CreateBlur(applyBitmap, applyRect, renderMode == RenderMode.EXPORT, blurRadius, previewQuality, Invert, parent.Bounds)) { - if (blurImage != null) { - graphics.DrawImageUnscaled(blurImage, applyRect.Location); + GraphicsState state = graphics.Save(); + if (Invert) { + graphics.SetClip(applyRect); + graphics.ExcludeClip(rect); + } + if (GDIplus.isBlurPossible(blurRadius)) { + GDIplus.DrawWithBlur(graphics, applyBitmap, applyRect, null, null, blurRadius, false); + } else { + using (IFastBitmap fastBitmap = FastBitmap.CreateCloneOf(applyBitmap, applyRect)) { + ImageHelper.ApplyBoxBlur(fastBitmap, blurRadius); + fastBitmap.DrawTo(graphics, applyRect); } } + graphics.Restore(state); return; } } diff --git a/Greenshot/Drawing/Filters/BrightnessFilter.cs b/Greenshot/Drawing/Filters/BrightnessFilter.cs index 6adbb83d6..5b0093768 100644 --- a/Greenshot/Drawing/Filters/BrightnessFilter.cs +++ b/Greenshot/Drawing/Filters/BrightnessFilter.cs @@ -24,6 +24,7 @@ using Greenshot.Drawing.Fields; using Greenshot.Plugin.Drawing; using GreenshotPlugin.Core; using System.Drawing.Imaging; +using System.Drawing.Drawing2D; namespace Greenshot.Drawing.Filters { [Serializable()] @@ -48,24 +49,14 @@ namespace Greenshot.Drawing.Filters { return; } - using (IFastBitmap fastBitmap = FastBitmap.CreateCloneOf(applyBitmap, applyRect)) { - double brightness = GetFieldValueAsDouble(FieldType.BRIGHTNESS); - for (int y = 0; y < fastBitmap.Height; y++) { - for (int x = 0; x < fastBitmap.Width; x++) { - if (parent.Contains(applyRect.Left + x, applyRect.Top + y) ^ Invert) { - Color color = fastBitmap.GetColorAt(x, y); - int r = Convert.ToInt16(color.R * brightness); - int g = Convert.ToInt16(color.G * brightness); - int b = Convert.ToInt16(color.B * brightness); - r = (r > 255) ? 255 : r; - g = (g > 255) ? 255 : g; - b = (b > 255) ? 255 : b; - fastBitmap.SetColorAt(x, y, Color.FromArgb(color.A, r, g, b)); - } - } - } - fastBitmap.DrawTo(graphics, applyRect.Location); + GraphicsState state = graphics.Save(); + if (Invert) { + graphics.SetClip(applyRect); + graphics.ExcludeClip(rect); } + ImageAttributes ia = ImageHelper.CreateAdjustAttributes(0.9f, 1f, 1f); + graphics.DrawImage(applyBitmap, applyRect, applyRect.X, applyRect.Y, applyRect.Width, applyRect.Height, GraphicsUnit.Pixel, ia); + graphics.Restore(state); } } } diff --git a/Greenshot/Drawing/Filters/GrayscaleFilter.cs b/Greenshot/Drawing/Filters/GrayscaleFilter.cs index 7a42d35a6..757cf8ddf 100644 --- a/Greenshot/Drawing/Filters/GrayscaleFilter.cs +++ b/Greenshot/Drawing/Filters/GrayscaleFilter.cs @@ -22,6 +22,8 @@ using System; using System.Drawing; using GreenshotPlugin.Core; using Greenshot.Plugin.Drawing; +using System.Drawing.Drawing2D; +using System.Drawing.Imaging; namespace Greenshot.Drawing.Filters { /// @@ -39,20 +41,23 @@ namespace Greenshot.Drawing.Filters { // nothing to do return; } - - using (IFastBitmap fastBitmap = FastBitmap.CreateCloneOf(applyBitmap, applyRect)) { - for (int y = 0; y < fastBitmap.Height; y++) { - for (int x = 0; x < fastBitmap.Width; x++) { - if (parent.Contains(applyRect.Left + x, applyRect.Top + y) ^ Invert) { - Color color = fastBitmap.GetColorAt(x, y); - int luma = (int)((0.3 * color.R) + (0.59 * color.G) + (0.11 * color.B)); - color = Color.FromArgb(luma, luma, luma); - fastBitmap.SetColorAt(x, y, color); - } - } - } - fastBitmap.DrawTo(graphics, applyRect.Location); + GraphicsState state = graphics.Save(); + if (Invert) { + graphics.SetClip(applyRect); + graphics.ExcludeClip(rect); } + ColorMatrix grayscaleMatrix = new ColorMatrix(new float[][] { + new float[] {.3f, .3f, .3f, 0, 0}, + new float[] {.59f, .59f, .59f, 0, 0}, + new float[] {.11f, .11f, .11f, 0, 0}, + new float[] {0, 0, 0, 1, 0}, + new float[] {0, 0, 0, 0, 1} + }); + ImageAttributes ia = new ImageAttributes(); + ia.SetColorMatrix(grayscaleMatrix); + graphics.DrawImage(applyBitmap, applyRect, applyRect.X, applyRect.Y, applyRect.Width, applyRect.Height, GraphicsUnit.Pixel, ia); + graphics.Restore(state); + } } } diff --git a/Greenshot/Drawing/Filters/HighlightFilter.cs b/Greenshot/Drawing/Filters/HighlightFilter.cs index 757c32348..0e98a5b23 100644 --- a/Greenshot/Drawing/Filters/HighlightFilter.cs +++ b/Greenshot/Drawing/Filters/HighlightFilter.cs @@ -24,6 +24,7 @@ using Greenshot.Drawing.Fields; using Greenshot.Plugin.Drawing; using GreenshotPlugin.Core; using System.Drawing.Imaging; +using System.Drawing.Drawing2D; namespace Greenshot.Drawing.Filters { [Serializable()] @@ -46,20 +47,23 @@ namespace Greenshot.Drawing.Filters { // nothing to do return; } - + GraphicsState state = graphics.Save(); + if (Invert) { + graphics.SetClip(applyRect); + graphics.ExcludeClip(rect); + } using (IFastBitmap fastBitmap = FastBitmap.CreateCloneOf(applyBitmap, applyRect)) { Color highlightColor = GetFieldValueAsColor(FieldType.FILL_COLOR); - for (int y = 0; y < fastBitmap.Height; y++) { - for (int x = 0; x < fastBitmap.Width; x++) { - if (parent.Contains(applyRect.Left + x, applyRect.Top + y) ^ Invert) { - Color color = fastBitmap.GetColorAt(x, y); - color = Color.FromArgb(color.A, Math.Min(highlightColor.R, color.R), Math.Min(highlightColor.G, color.G), Math.Min(highlightColor.B, color.B)); - fastBitmap.SetColorAt(x, y, color); - } + for (int y = fastBitmap.Top; y < fastBitmap.Bottom; y++) { + for (int x = fastBitmap.Left; x < fastBitmap.Right; x++) { + Color color = fastBitmap.GetColorAt(x, y); + color = Color.FromArgb(color.A, Math.Min(highlightColor.R, color.R), Math.Min(highlightColor.G, color.G), Math.Min(highlightColor.B, color.B)); + fastBitmap.SetColorAt(x, y, color); } } fastBitmap.DrawTo(graphics, applyRect.Location); } + graphics.Restore(state); } } } diff --git a/Greenshot/Drawing/Filters/MagnifierFilter.cs b/Greenshot/Drawing/Filters/MagnifierFilter.cs index c6993f994..73a3ff447 100644 --- a/Greenshot/Drawing/Filters/MagnifierFilter.cs +++ b/Greenshot/Drawing/Filters/MagnifierFilter.cs @@ -24,6 +24,7 @@ using Greenshot.Drawing.Fields; using Greenshot.Plugin.Drawing; using GreenshotPlugin.Core; using System.Drawing.Imaging; +using System.Drawing.Drawing2D; namespace Greenshot.Drawing.Filters { [Serializable] @@ -40,24 +41,22 @@ namespace Greenshot.Drawing.Filters { return; } int magnificationFactor = GetFieldValueAsInt(FieldType.MAGNIFICATION_FACTOR); - - using (IFastBitmap destFastBitmap = FastBitmap.CreateCloneOf(applyBitmap, applyRect)) { - int halfWidth = destFastBitmap.Size.Width / 2; - int halfHeight = destFastBitmap.Size.Height / 2; - using (IFastBitmap sourceFastBitmap = FastBitmap.Create(applyBitmap, applyRect)) { - for (int y = 0; y < destFastBitmap.Height; y++) { - int yDistanceFromCenter = halfHeight - y; - for (int x = 0; x < destFastBitmap.Width; x++) { - int xDistanceFromCenter = halfWidth - x; - if (parent.Contains(applyRect.Left + x, applyRect.Top + y) ^ Invert) { - Color color = sourceFastBitmap.GetColorAt(halfWidth - xDistanceFromCenter / magnificationFactor, halfHeight - yDistanceFromCenter / magnificationFactor); - destFastBitmap.SetColorAt(x, y, color); - } - } - } - } - destFastBitmap.DrawTo(graphics, applyRect.Location); + GraphicsState state = graphics.Save(); + if (Invert) { + graphics.SetClip(applyRect); + graphics.ExcludeClip(rect); } + graphics.SmoothingMode = SmoothingMode.None; + graphics.InterpolationMode = InterpolationMode.NearestNeighbor; + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.PixelOffsetMode = PixelOffsetMode.None; + int halfWidth = rect.Width / 2; + int halfHeight = rect.Height / 2; + int newWidth = rect.Width / magnificationFactor; + int newHeight = rect.Width / magnificationFactor; + Rectangle source = new Rectangle(rect.X + halfWidth - (newWidth / 2), rect.Y + halfHeight - (newHeight / 2), newWidth, newHeight); + graphics.DrawImage(applyBitmap, rect, source, GraphicsUnit.Pixel); + graphics.Restore(state); } } } diff --git a/Greenshot/Drawing/Filters/PixelizationFilter.cs b/Greenshot/Drawing/Filters/PixelizationFilter.cs index 14fc79dfb..9039184d1 100644 --- a/Greenshot/Drawing/Filters/PixelizationFilter.cs +++ b/Greenshot/Drawing/Filters/PixelizationFilter.cs @@ -48,35 +48,36 @@ namespace Greenshot.Drawing.Filters { if (rect.Height < pixelSize) { pixelSize = rect.Height; } - - using (BitmapBuffer bbbDest = new BitmapBuffer(applyBitmap, rect)) { - bbbDest.Lock(); - using (BitmapBuffer bbbSrc = new BitmapBuffer(applyBitmap, rect, false)) { - bbbSrc.Lock(); + using (IFastBitmap dest = FastBitmap.CreateCloneOf(applyBitmap, rect)) { + using (IFastBitmap src = FastBitmap.Create(applyBitmap, rect)) { List colors = new List(); int halbPixelSize = pixelSize / 2; - for (int y = -halbPixelSize; y < bbbSrc.Height + halbPixelSize; y = y + pixelSize) { - for (int x = -halbPixelSize; x <= bbbSrc.Width + halbPixelSize; x = x + pixelSize) { + for (int y = src.Top - halbPixelSize; y < src.Bottom + halbPixelSize; y = y + pixelSize) { + for (int x = src.Left - halbPixelSize; x <= src.Right + halbPixelSize; x = x + pixelSize) { colors.Clear(); for (int yy = y; yy < y + pixelSize; yy++) { - if (yy >= 0 && yy < bbbSrc.Height) { + if (yy >= src.Top && yy < src.Bottom) { for (int xx = x; xx < x + pixelSize; xx++) { - colors.Add(bbbSrc.GetColorAt(xx, yy)); + if (xx >= src.Left && xx < src.Right) { + colors.Add(src.GetColorAt(xx, yy)); + } } } } Color currentAvgColor = Colors.Mix(colors); for (int yy = y; yy <= y + pixelSize; yy++) { - if (yy >= 0 && yy < bbbSrc.Height) { + if (yy >= src.Top && yy < src.Bottom) { for (int xx = x; xx <= x + pixelSize; xx++) { - bbbDest.SetColorAt(xx, yy, currentAvgColor); + if (xx >= src.Left && xx < src.Right) { + dest.SetColorAt(xx, yy, currentAvgColor); + } } } } } } } - bbbDest.DrawTo(graphics, rect.Location); + dest.DrawTo(graphics, rect.Location); } } } diff --git a/GreenshotPlugin/Core/BitmapBuffer.cs b/GreenshotPlugin/Core/BitmapBuffer.cs deleted file mode 100644 index 04576203f..000000000 --- a/GreenshotPlugin/Core/BitmapBuffer.cs +++ /dev/null @@ -1,409 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2013 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.Drawing; -using System.Drawing.Imaging; -using System.Runtime.Serialization; - -namespace GreenshotPlugin.Core { - /// - /// The BitmapBuffer is exactly what it says, it buffers a Bitmap. - /// And it is possible to Draw on the Bitmap with direct memory access for better performance - /// - public unsafe class BitmapBuffer : IDisposable { - private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(BitmapBuffer)); - private bool clone; - private Bitmap bitmap; - // Used for indexed images - private Color[] colorEntries; - - - public static Color BackgroundBlendColor { - get; - set; - } - - static BitmapBuffer() { - BackgroundBlendColor = Color.White; - } - - /// - /// Get the bitmap, you will always need to dispose the returned bitmap!! - /// Only works, and makes sense, if cloned and not locked! - /// - public Bitmap Bitmap { - get { - if (bitsLocked) { - throw new NotSupportedException("Can't get a locked bitmap!"); - } - if (!clone) { - throw new NotSupportedException("Can't return a not cloned bitmap!"); - } else { - // Make sure the bitmap isn't disposed when this object is closed - clone = false; - return bitmap; - } - } - } - - public Bitmap UnlockAndReturnBitmap() { - Unlock(); - return Bitmap; - } - - public PixelFormat PixelFormat { - get { - return bitmap.PixelFormat; - } - } - - private BitmapData bmData; - private Rectangle rect; - private byte* pointer; - private int* intPointer; - private int stride; /* bytes per pixel row */ - private int aIndex = -1; - private int rIndex = -1; - private int gIndex = -1; - private int bIndex = -1; - private int bytesPerPixel; - private bool bitsLocked = false; - - public Size Size { - get {return rect.Size;} - } - public int Width { - get {return rect.Width;} - } - public int Height { - get {return rect.Height;} - } - - /// - /// Create a BitmapBuffer from a Bitmap - /// - /// Bitmap - public BitmapBuffer(Image sourceBmp) : this(sourceBmp, Rectangle.Empty) { - } - - /// - /// Create a BitmapBuffer from a Bitmap a flag if we need a clone - /// - /// Bitmap - /// bool specifying if the bitmap needs to be cloned - public BitmapBuffer(Image sourceBmp, bool clone) : this(sourceBmp, Rectangle.Empty, clone) { - } - - /// - /// Create a BitmapBuffer from a Bitmap and a Rectangle specifying what part from the Bitmap to take. - /// - /// Bitmap - /// Rectangle - public BitmapBuffer(Image sourceBmp, Rectangle applyRect) : this(sourceBmp, applyRect, true) { - } - - /// - /// Create a BitmapBuffer from a Bitmap, a Rectangle specifying what part from the Bitmap to take and a flag if we need a clone - /// - /// Image, will be cloned if it's not a bitmap!!! - /// Rectangle - /// bool specifying if the bitmap needs to be cloned - public BitmapBuffer(Image sourceImage, Rectangle applyRect, bool clone) { - this.clone = clone; - Rectangle sourceRect = new Rectangle(applyRect.X, applyRect.Y, applyRect.Width, applyRect.Height); - Rectangle bitmapRect = new Rectangle(0,0, sourceImage.Width, sourceImage.Height); - - if (sourceRect.IsEmpty) { - sourceRect = bitmapRect; - } else { - sourceRect.Intersect(bitmapRect); - } - // Does the rect have any pixels? - if (sourceRect.Height <= 0 || sourceRect.Width <= 0) { - return; - } - - if (!(sourceImage is Bitmap) && !clone) { - LOG.Warn("Chancing clone to true, as the image is not a bitmap"); - clone = true; - } - - if (clone) { - this.bitmap = ImageHelper.CloneArea(sourceImage, sourceRect, PixelFormat.DontCare); - // Set "this" rect to location 0,0 - // as the Cloned Bitmap is only the part we want to work with - this.rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height); - } else if (!ImageHelper.SupportsPixelFormat(sourceImage) && PixelFormat.Format8bppIndexed != sourceImage.PixelFormat) { - throw new ArgumentException("Unsupported pixel format: " + sourceImage.PixelFormat + " set clone to true!"); - } else { - this.bitmap = sourceImage as Bitmap; - this.rect = sourceRect; - } - if (bitmap.PixelFormat == PixelFormat.Format8bppIndexed) { - colorEntries = bitmap.Palette.Entries; - } - } - - /** - * Destructor - */ - ~BitmapBuffer() { - Dispose(false); - } - - /** - * The public accessible Dispose - * Will call the GarbageCollector to SuppressFinalize, preventing being cleaned twice - */ - public void Dispose() { - Dispose(true); - GC.SuppressFinalize(this); - } - - // The bulk of the clean-up code is implemented in Dispose(bool) - - /** - * This Dispose is called from the Dispose and the Destructor. - * When disposing==true all non-managed resources should be freed too! - */ - protected virtual void Dispose(bool disposing) { - Unlock(); - if (disposing) { - if (bitmap != null && clone) { - bitmap.Dispose(); - } - } - bitmap = null; - bmData = null; - pointer = null; - } - - /** - * Lock the bitmap so we have direct access to the memory - */ - public void Lock() { - if(rect.Width > 0 && rect.Height > 0 && !bitsLocked) { - bmData = bitmap.LockBits(rect, ImageLockMode.ReadWrite, bitmap.PixelFormat); - bitsLocked = true; - - IntPtr Scan0 = bmData.Scan0; - pointer = (byte*)(void*)Scan0; - intPointer = (int*)(void*)Scan0; - - PrepareForPixelFormat(); - stride = bmData.Stride; - } - } - - /// - /// Unlock the System Memory - /// - public void Unlock() { - if (bitsLocked) { - bitmap.UnlockBits(bmData); - bitsLocked = false; - } - } - - /// - /// Draw the stored bitmap to the destionation bitmap at the supplied point - /// - /// - /// - public void DrawTo(Graphics graphics, Point destination) { - DrawTo(graphics, null, destination); - } - - /// - /// Draw the stored Bitmap on the Destination bitmap with the specified rectangle - /// Be aware that the stored bitmap will be resized to the specified rectangle!! - /// - /// - /// - public void DrawTo(Graphics graphics, Rectangle destinationRect) { - DrawTo(graphics, destinationRect, null); - } - - /// - /// private helper to draw the bitmap - /// - /// - /// - /// - private void DrawTo(Graphics graphics, Rectangle? destinationRect, Point? destination) { - if (destinationRect.HasValue) { - // Does the rect have any pixels? - if (destinationRect.Value.Height <= 0 || destinationRect.Value.Width <= 0) { - return; - } - } - // Make sure this.bitmap is unlocked, if it was locked - bool isLocked = bitsLocked; - if (isLocked) { - Unlock(); - } - - if (destinationRect.HasValue) { - graphics.DrawImage(this.bitmap, destinationRect.Value); - } else if (destination.HasValue) { - graphics.DrawImageUnscaled(this.bitmap, destination.Value); - } - // If it was locked, lock it again - if (isLocked) { - Lock(); - } - } - - /// - /// Use only when 32-bit bitmap! - /// - /// x - /// y - /// argb value - public void SetARGB(int x, int y, int argb) { - int offset = (y * (stride>>2)) + x; - intPointer[offset] = argb; - } - - /// - /// Retrieve the color at location x,y - /// Before the first time this is called the Lock() should be called once! - /// - /// X coordinate - /// Y Coordinate - /// Color - public Color GetColorAt(int x, int y) { - if(x>=0 && y>=0 && x - /// Set the color at location x,y - /// Before the first time this is called the Lock() should be called once! - /// - /// - /// - /// - public void SetColorAt(int x, int y, Color color) { - if(x>=0 && y>=0 && x - /// Retrieve the color at location x,y to a byte[] - /// Before the first time this is called the Lock() should be called once! - /// - /// - /// - /// - public void GetUncheckedColorIn(int x, int y, byte[] color) { - int offset = x * bytesPerPixel + y * stride; - color[0] = (aIndex == -1) ? (byte)255 : (byte)pointer[aIndex + offset]; - color[1] = pointer[rIndex + offset]; - color[2] = pointer[gIndex + offset]; - color[3] = pointer[bIndex + offset]; - } - - /// - /// Retrieve the color at location x,y to a byte[] - /// Before the first time this is called the Lock() should be called once! - /// - /// - /// - /// - public void GetColorAt(int x, int y, byte[] color) { - if (x >= 0 && y >= 0 && x < rect.Width && y < rect.Height) { - int offset = x * bytesPerPixel + y * stride; - color[0] = (aIndex == -1) ? (byte)255 : (byte)pointer[aIndex + offset]; - color[1] = pointer[rIndex + offset]; - color[2] = pointer[gIndex + offset]; - color[3] = pointer[bIndex + offset]; - } else { - color[0] = 0; - color[1] = 0; - color[2] = 0; - color[3] = 0; - } - } - - /// - /// Set the color at location x,y as an array - /// Before the first time this is called the Lock() should be called once! - /// - /// - /// - /// - public void SetColorAt(int x, int y, byte[] colors) { - if(x>=0 && y>=0 && x - /// Set some internal values for accessing the bitmap according to the PixelFormat - /// - private void PrepareForPixelFormat() { - // aIndex is only set if the pixel format supports "A". - aIndex = -1; - switch(bitmap.PixelFormat) { - case PixelFormat.Format32bppPArgb: - case PixelFormat.Format32bppArgb: - bIndex = 0; - gIndex = 1; - rIndex = 2; - aIndex = 3; - bytesPerPixel = 4; - break; - case PixelFormat.Format32bppRgb: - bIndex = 0; - gIndex = 1; - rIndex = 2; - bytesPerPixel = 4; - break; - case PixelFormat.Format24bppRgb: - bIndex = 0; - gIndex = 1; - rIndex = 2; - bytesPerPixel = 3; - break; - case PixelFormat.Format8bppIndexed: - bytesPerPixel = 1; - break; - default: - throw new FormatException("Bitmap.Pixelformat."+bitmap.PixelFormat+" is currently not supported. Supported: Format32bpp(A)Rgb, Format24bppRgb"); - } - } - } -} diff --git a/GreenshotPlugin/Core/FastBitmap.cs b/GreenshotPlugin/Core/FastBitmap.cs index 07ceb8ef1..6f9b11931 100644 --- a/GreenshotPlugin/Core/FastBitmap.cs +++ b/GreenshotPlugin/Core/FastBitmap.cs @@ -86,19 +86,47 @@ namespace GreenshotPlugin.Core { } /// - /// Height of the underlying image + /// Height of the image area that this fastbitmap covers /// int Height { get; } /// - /// Width of the underlying image + /// Width of the image area that this fastbitmap covers /// int Width { get; } + /// + /// Top of the image area that this fastbitmap covers + /// + int Top { + get; + } + + /// + /// Left of the image area that this fastbitmap covers + /// + int Left { + get; + } + + /// + /// Right of the image area that this fastbitmap covers + /// + int Right { + get; + } + + /// + /// Bottom of the image area that this fastbitmap covers + /// + int Bottom { + get; + } + /// /// Does the underlying image need to be disposed /// @@ -136,6 +164,108 @@ namespace GreenshotPlugin.Core { /// /// bool Contains(int x, int y); + + /// + /// Set the bitmap resolution + /// + /// + /// + void SetResolution(float horizontal, float vertical); + } + + /// + /// This interface can be used for when offsetting is needed + /// + public interface IFastBitmapWithOffset : IFastBitmap { + /// + /// Return true if the coordinates are inside the FastBitmap + /// + /// + /// + /// + bool Contains(int x, int y); + + /// + /// Set the color at the specified location, using offsetting so the original coordinates can be used + /// + /// int x + /// int y + /// Color color + new void SetColorAt(int x, int y, Color color); + + /// + /// Set the color at the specified location, using offsetting so the original coordinates can be used + /// + /// int x + /// int y + /// byte[] color + new void SetColorAt(int x, int y, byte[] color); + + /// + /// Get the color at x,y + /// The returned Color object depends on the underlying pixel format + /// + /// int x + /// int y + /// Color + new Color GetColorAt(int x, int y); + + /// + /// Get the color at x,y, using offsetting so the original coordinates can be used + /// The returned byte[] color depends on the underlying pixel format + /// + /// int x + /// int y + /// This interface can be used for when clipping is needed + /// + public interface IFastBitmapWithClip : IFastBitmap { + Rectangle Clip { + get; + set; + } + + bool InvertClip { + get; + set; + } + + /// + /// Set the color at the specified location, this doesn't do anything if the location is excluded due to clipping + /// + /// int x + /// int y + /// Color color + new void SetColorAt(int x, int y, Color color); + + /// + /// Set the color at the specified location, this doesn't do anything if the location is excluded due to clipping + /// + /// int x + /// int y + /// byte[] color + new void SetColorAt(int x, int y, byte[] color); + + /// + /// Return true if the coordinates are inside the FastBitmap and not clipped + /// + /// + /// + /// + new bool Contains(int x, int y); } /// @@ -152,7 +282,7 @@ namespace GreenshotPlugin.Core { /// /// The base class for the fast bitmap implementation /// - public unsafe abstract class FastBitmap : IFastBitmap { + public unsafe abstract class FastBitmap : IFastBitmap, IFastBitmapWithClip, IFastBitmapWithOffset { private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(FastBitmap)); protected const int PIXELFORMAT_INDEX_A = 3; @@ -174,6 +304,16 @@ namespace GreenshotPlugin.Core { set; } + public Rectangle Clip { + get; + set; + } + + public bool InvertClip { + get; + set; + } + /// /// The bitmap for which the FastBitmap is creating access /// @@ -187,6 +327,11 @@ namespace GreenshotPlugin.Core { public static IFastBitmap Create(Bitmap source) { return Create(source, Rectangle.Empty); } + + public void SetResolution(float horizontal, float vertical) { + bitmap.SetResolution(horizontal, vertical); + } + /// /// Factory for creating a FastBitmap depending on the pixelformat of the source /// The supplied rectangle specifies the area for which the FastBitmap does its thing @@ -247,8 +392,10 @@ namespace GreenshotPlugin.Core { /// IFastBitmap public static IFastBitmap CreateCloneOf(Image source, PixelFormat pixelFormat, Rectangle area) { Bitmap destination = ImageHelper.CloneArea(source, area, pixelFormat); - IFastBitmap fastBitmap = Create(destination); - ((FastBitmap)fastBitmap).NeedsDispose = true; + FastBitmap fastBitmap = Create(destination) as FastBitmap; + fastBitmap.NeedsDispose = true; + fastBitmap.Left = area.Left; + fastBitmap.Top = area.Top; return fastBitmap; } @@ -279,6 +426,13 @@ namespace GreenshotPlugin.Core { } else { this.area = bitmapArea; } + // As the lock takes care that only the specified area is made available we need to calculate the offset + this.Left = area.Left; + this.Top = area.Top; + // Default cliping is done to the area without invert + this.Clip = this.area; + this.InvertClip = false; + // Always lock, so we don't need to do this ourselves Lock(); } @@ -318,12 +472,79 @@ namespace GreenshotPlugin.Core { } } + private int left; + /// + /// Return the left of the fastbitmap, this is also used as an offset + /// + public int Left { + get { + return 0; + } + set { + left = value; + } + } + + /// + /// Return the left of the fastbitmap, this is also used as an offset + /// + int IFastBitmapWithOffset.Left { + get { + return left; + } + set { + left = value; + } + } + + private int top; + /// + /// Return the top of the fastbitmap, this is also used as an offset + /// + public int Top { + get { + return 0; + } + set { + top = value; + } + } + + /// + /// Return the top of the fastbitmap, this is also used as an offset + /// + int IFastBitmapWithOffset.Top { + get { + return top; + } + set { + top = value; + } + } + + /// + /// Return the right of the fastbitmap + /// + public int Right { + get { + return Left + Width; + } + } + + /// + /// Return the bottom of the fastbitmap + /// + public int Bottom { + get { + return Top + Height; + } + } + /// /// Returns the underlying bitmap, unlocks it and prevents that it will be disposed /// public Bitmap UnlockAndReturnBitmap() { if (bitsLocked) { - LOG.Warn("Unlocking the bitmap"); Unlock(); } NeedsDispose = false; @@ -401,7 +622,7 @@ namespace GreenshotPlugin.Core { /// /// public void DrawTo(Graphics graphics, Point destination) { - DrawTo(graphics, null, destination); + DrawTo(graphics, new Rectangle(destination, area.Size)); } /// @@ -410,38 +631,15 @@ namespace GreenshotPlugin.Core { /// /// /// - public void DrawTo(Graphics graphics, Rectangle destinationRect) { - DrawTo(graphics, destinationRect, null); - } - - /// - /// private helper to draw the bitmap - /// - /// - /// /// - private void DrawTo(Graphics graphics, Rectangle? destinationRect, Point? destination) { - if (destinationRect.HasValue) { - // Does the rect have any pixels? - if (destinationRect.Value.Height <= 0 || destinationRect.Value.Width <= 0) { - return; - } - } + public void DrawTo(Graphics graphics, Rectangle destinationRect) { // Make sure this.bitmap is unlocked, if it was locked bool isLocked = bitsLocked; if (isLocked) { Unlock(); } - if (destinationRect.HasValue) { - graphics.DrawImage(this.bitmap, destinationRect.Value); - } else if (destination.HasValue) { - graphics.DrawImageUnscaled(this.bitmap, destination.Value); - } - // If it was locked, lock it again - if (isLocked) { - Lock(); - } + graphics.DrawImage(this.bitmap, destinationRect, area, GraphicsUnit.Pixel); } /// @@ -451,13 +649,75 @@ namespace GreenshotPlugin.Core { /// /// true if x & y are inside the FastBitmap public bool Contains(int x, int y) { - return x >= 0 && x < Width && y >= 0 && y < Height; + return area.Contains(x - Left, y - Top); } public abstract Color GetColorAt(int x, int y); public abstract void SetColorAt(int x, int y, Color color); public abstract void GetColorAt(int x, int y, byte[] color); public abstract void SetColorAt(int x, int y, byte[] color); + + #region IFastBitmapWithClip + bool IFastBitmapWithClip.Contains(int x, int y) { + bool contains = Clip.Contains(x, y); + if (InvertClip) { + return !contains; + } else { + return contains; + } + } + + void IFastBitmapWithClip.SetColorAt(int x, int y, byte[] color) { + bool contains = Clip.Contains(x, y); + if ((InvertClip && contains) || (!InvertClip && !contains)) { + return; + } + SetColorAt(x, y, color); + } + + void IFastBitmapWithClip.SetColorAt(int x, int y, Color color) { + bool contains = Clip.Contains(x, y); + if ((InvertClip && contains) || (!InvertClip && !contains)) { + return; + } + SetColorAt(x, y, color); + } + #endregion + + #region IFastBitmapWithOffset + /// + /// returns true if x & y are inside the FastBitmap + /// + /// + /// + /// true if x & y are inside the FastBitmap + bool IFastBitmapWithOffset.Contains(int x, int y) { + return area.Contains(x - Left, y - Top); + } + + Color IFastBitmapWithOffset.GetColorAt(int x, int y) { + x -= left; + y -= top; + return GetColorAt(x, y); + } + void IFastBitmapWithOffset.GetColorAt(int x, int y, byte[] color) { + x -= left; + y -= top; + GetColorAt(x, y, color); + } + + void IFastBitmapWithOffset.SetColorAt(int x, int y, byte[] color) { + x -= left; + y -= top; + SetColorAt(x, y, color); + } + + void IFastBitmapWithOffset.SetColorAt(int x, int y, Color color) { + x -= left; + y -= top; + SetColorAt(x, y, color); + } + #endregion } /// @@ -771,6 +1031,5 @@ namespace GreenshotPlugin.Core { } return Color.FromArgb(255, red, green, blue); } - } } diff --git a/GreenshotPlugin/Core/ImageHelper.cs b/GreenshotPlugin/Core/ImageHelper.cs index 37f89370b..630bc3186 100644 --- a/GreenshotPlugin/Core/ImageHelper.cs +++ b/GreenshotPlugin/Core/ImageHelper.cs @@ -175,8 +175,6 @@ namespace GreenshotPlugin.Core { // Bottom Right checkPoints.Add(new Point(image.Width - 1, image.Height - 1)); using (IFastBitmap fastBitmap = FastBitmap.Create((Bitmap)image)) { - fastBitmap.Lock(); - // find biggest area foreach(Point checkPoint in checkPoints) { currentRectangle = FindAutoCropRectangle(fastBitmap, checkPoint, cropDifference); @@ -461,197 +459,6 @@ namespace GreenshotPlugin.Core { return weights; } - /// - /// Create a new bitmap with the sourceBitmap blurred - /// - /// Source to blur - /// Area to blur - /// Use best quality - /// Radius of the blur - /// Quality, use 1d for normal anything less skipps calculations - /// true if the blur needs to occur outside of the area - /// Rectangle limiting the area when using invert - public static unsafe Bitmap CreateBlur(Bitmap sourceBitmap, Rectangle applyRect, bool useExportQuality, int blurRadius, double previewQuality, bool invert, Rectangle parentBounds) { - if (applyRect.Height <= 0 || applyRect.Width <= 0) { - return null; - } - // do nothing when nothing can be done! - if (blurRadius < 1) { - return null; - } - - byte[] nullColor = new byte[] { 255, 255, 255, 255 }; - if (sourceBitmap.PixelFormat == PixelFormat.Format32bppArgb || sourceBitmap.PixelFormat == PixelFormat.Format32bppPArgb) { - nullColor = new byte[] { 0, 0, 0, 0 }; - } - byte[] settingColor = new byte[4]; - byte[] readingColor = new byte[4]; - - using (BitmapBuffer dst = new BitmapBuffer(sourceBitmap, applyRect, true)) { - //using (IFastBitmap dst = FastBitmap.CreateEmpty(sourceBitmap.Size, sourceBitmap.PixelFormat, Color.Empty)) { - dst.Lock(); - using (BitmapBuffer src = new BitmapBuffer(sourceBitmap, applyRect, false)) { - //using (IFastBitmap src = FastBitmap.Create(sourceBitmap)) { - src.Lock(); - Random rand = new Random(); - unchecked { - int r = blurRadius; - int[] w = CreateGaussianBlurRow(r); - int wlen = w.Length; - long* waSums = stackalloc long[wlen]; - long* wcSums = stackalloc long[wlen]; - long* aSums = stackalloc long[wlen]; - long* rSums = stackalloc long[wlen]; - long* gSums = stackalloc long[wlen]; - long* bSums = stackalloc long[wlen]; - for (int y = 0; y < applyRect.Height; ++y) { - long waSum = 0; - long wcSum = 0; - long aSum = 0; - long rSum = 0; - long gSum = 0; - long bSum = 0; - - for (int wx = 0; wx < wlen; ++wx) { - int srcX = wx - r; - waSums[wx] = 0; - wcSums[wx] = 0; - aSums[wx] = 0; - rSums[wx] = 0; - gSums[wx] = 0; - bSums[wx] = 0; - - if (srcX >= 0 && srcX < src.Width) { - for (int wy = 0; wy < wlen; ++wy) { - int srcY = y + wy - r; - - if (srcY >= 0 && srcY < src.Height) { - src.GetColorAt(srcX, srcY, readingColor); - int wp = w[wy]; - - waSums[wx] += wp; - wp *= readingColor[0] + (readingColor[0] >> 7); - wcSums[wx] += wp; - wp >>= 8; - - aSums[wx] += wp * readingColor[0]; - rSums[wx] += wp * readingColor[1]; - gSums[wx] += wp * readingColor[2]; - bSums[wx] += wp * readingColor[3]; - } - } - - int wwx = w[wx]; - waSum += wwx * waSums[wx]; - wcSum += wwx * wcSums[wx]; - aSum += wwx * aSums[wx]; - rSum += wwx * rSums[wx]; - gSum += wwx * gSums[wx]; - bSum += wwx * bSums[wx]; - } - } - - wcSum >>= 8; - - if (parentBounds.Contains(applyRect.Left, applyRect.Top + y) ^ invert) { - if (waSum == 0 || wcSum == 0) { - dst.SetColorAt(0, y, nullColor); - } else { - settingColor[0] = (byte)(aSum / waSum); - settingColor[1] = (byte)(rSum / wcSum); - settingColor[2] = (byte)(gSum / wcSum); - settingColor[3] = (byte)(bSum / wcSum); - dst.SetColorAt(0, y, settingColor); - } - } - - 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]; - rSums[i] = rSums[i + 1]; - gSums[i] = gSums[i + 1]; - bSums[i] = bSums[i + 1]; - } - - waSum = 0; - wcSum = 0; - aSum = 0; - rSum = 0; - gSum = 0; - bSum = 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]; - rSum += wwx * rSums[wx]; - gSum += wwx * gSums[wx]; - bSum += wwx * bSums[wx]; - } - - wx = wlen - 1; - - waSums[wx] = 0; - wcSums[wx] = 0; - aSums[wx] = 0; - rSums[wx] = 0; - gSums[wx] = 0; - bSums[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 ((useExportQuality || rand.NextDouble() < previewQuality) && srcY >= 0 && srcY < applyRect.Height) { - int wp = w[wy]; - waSums[wx] += wp; - src.GetColorAt(srcX, srcY, readingColor); - wp *= readingColor[0] + (readingColor[0] >> 7); - wcSums[wx] += wp; - wp >>= 8; - - aSums[wx] += wp * readingColor[0]; - rSums[wx] += wp * readingColor[1]; - gSums[wx] += wp * readingColor[2]; - bSums[wx] += wp * readingColor[3]; - } - } - - int wr = w[wx]; - waSum += wr * waSums[wx]; - wcSum += wr * wcSums[wx]; - aSum += wr * aSums[wx]; - rSum += wr * rSums[wx]; - gSum += wr * gSums[wx]; - bSum += wr * bSums[wx]; - } - - wcSum >>= 8; - if (parentBounds.Contains(applyRect.Left + x, applyRect.Top + y) ^ invert) { - if (waSum == 0 || wcSum == 0) { - dst.SetColorAt(x, y, nullColor); - } else { - settingColor[0] = (byte)(aSum / waSum); - settingColor[1] = (byte)(rSum / wcSum); - settingColor[2] = (byte)(gSum / wcSum); - settingColor[3] = (byte)(bSum / wcSum); - dst.SetColorAt(x, y, settingColor); - } - } - } - } - } - } - return dst.UnlockAndReturnBitmap(); - } - } - /// /// Apply BoxBlur to the destinationBitmap /// @@ -674,6 +481,9 @@ namespace GreenshotPlugin.Core { if ((range & 1) == 0) { range++; } + if (range <= 1) { + return; + } // Box blurs are frequently used to approximate a Gaussian blur. // By the central limit theorem, if applied 3 times on the same image, a box blur approximates the Gaussian kernel to within about 3%, yielding the same result as a quadratic convolution kernel. // This might be true, but the GDI+ BlurEffect doesn't look the same, a 2x blur is more simular and we only make 2x Box-Blur. @@ -700,19 +510,17 @@ namespace GreenshotPlugin.Core { if (targetFastBitmap.hasAlphaChannel) { throw new NotSupportedException("BoxBlurHorizontal should NOT be called for bitmaps with alpha channel"); } - int w = targetFastBitmap.Width; - int h = targetFastBitmap.Height; int halfRange = range / 2; - Color[] newColors = new Color[w]; + Color[] newColors = new Color[targetFastBitmap.Width]; byte[] tmpColor = new byte[3]; - for (int y = 0; y < h; y++) { + for (int y = targetFastBitmap.Top; y < targetFastBitmap.Bottom; y++) { int hits = 0; int r = 0; int g = 0; int b = 0; - for (int x = -halfRange; x < w; x++) { + for (int x = targetFastBitmap.Left - halfRange; x < targetFastBitmap.Right; x++) { int oldPixel = x - halfRange - 1; - if (oldPixel >= 0) { + if (oldPixel >= targetFastBitmap.Left) { targetFastBitmap.GetColorAt(oldPixel, y, tmpColor); r -= tmpColor[FastBitmap.COLOR_INDEX_R]; g -= tmpColor[FastBitmap.COLOR_INDEX_G]; @@ -721,7 +529,7 @@ namespace GreenshotPlugin.Core { } int newPixel = x + halfRange; - if (newPixel < w) { + if (newPixel < targetFastBitmap.Right) { targetFastBitmap.GetColorAt(newPixel, y, tmpColor); r += tmpColor[FastBitmap.COLOR_INDEX_R]; g += tmpColor[FastBitmap.COLOR_INDEX_G]; @@ -729,12 +537,12 @@ namespace GreenshotPlugin.Core { hits++; } - if (x >= 0) { - newColors[x] = Color.FromArgb(255, (byte)(r / hits), (byte)(g / hits), (byte)(b / hits)); + if (x >= targetFastBitmap.Left) { + newColors[x - targetFastBitmap.Left] = Color.FromArgb(255, (byte)(r / hits), (byte)(g / hits), (byte)(b / hits)); } } - for (int x = 0; x < w; x++) { - targetFastBitmap.SetColorAt(x, y, newColors[x]); + for (int x = targetFastBitmap.Left; x < targetFastBitmap.Right; x++) { + targetFastBitmap.SetColorAt(x, y, newColors[x - targetFastBitmap.Left]); } } } @@ -748,20 +556,18 @@ namespace GreenshotPlugin.Core { if (!targetFastBitmap.hasAlphaChannel) { throw new NotSupportedException("BoxBlurHorizontalAlpha should be called for bitmaps with alpha channel"); } - int w = targetFastBitmap.Width; - int h = targetFastBitmap.Height; int halfRange = range / 2; - Color[] newColors = new Color[w]; + Color[] newColors = new Color[targetFastBitmap.Width]; byte[] tmpColor = new byte[4]; - for (int y = 0; y < h; y++) { + for (int y = targetFastBitmap.Top; y < targetFastBitmap.Bottom; y++) { int hits = 0; int a = 0; int r = 0; int g = 0; int b = 0; - for (int x = -halfRange; x < w; x++) { + for (int x = targetFastBitmap.Left - halfRange; x < targetFastBitmap.Right; x++) { int oldPixel = x - halfRange - 1; - if (oldPixel >= 0) { + if (oldPixel >= targetFastBitmap.Left) { targetFastBitmap.GetColorAt(oldPixel, y, tmpColor); a -= tmpColor[FastBitmap.COLOR_INDEX_A]; r -= tmpColor[FastBitmap.COLOR_INDEX_R]; @@ -771,7 +577,7 @@ namespace GreenshotPlugin.Core { } int newPixel = x + halfRange; - if (newPixel < w) { + if (newPixel < targetFastBitmap.Right) { targetFastBitmap.GetColorAt(newPixel, y, tmpColor); a += tmpColor[FastBitmap.COLOR_INDEX_A]; r += tmpColor[FastBitmap.COLOR_INDEX_R]; @@ -780,12 +586,12 @@ namespace GreenshotPlugin.Core { hits++; } - if (x >= 0) { - newColors[x] = Color.FromArgb((byte)(a / hits), (byte)(r / hits), (byte)(g / hits), (byte)(b / hits)); + if (x >= targetFastBitmap.Left) { + newColors[x - targetFastBitmap.Left] = Color.FromArgb((byte)(a / hits), (byte)(r / hits), (byte)(g / hits), (byte)(b / hits)); } } - for (int x = 0; x < w; x++) { - targetFastBitmap.SetColorAt(x, y, newColors[x]); + for (int x = targetFastBitmap.Left; x < targetFastBitmap.Right; x++) { + targetFastBitmap.SetColorAt(x, y, newColors[x - targetFastBitmap.Left]); } } } @@ -800,20 +606,19 @@ namespace GreenshotPlugin.Core { throw new NotSupportedException("BoxBlurVertical should NOT be called for bitmaps with alpha channel"); } int w = targetFastBitmap.Width; - int h = targetFastBitmap.Height; int halfRange = range / 2; - Color[] newColors = new Color[h]; + Color[] newColors = new Color[targetFastBitmap.Height]; int oldPixelOffset = -(halfRange + 1) * w; int newPixelOffset = (halfRange) * w; byte[] tmpColor = new byte[4]; - for (int x = 0; x < w; x++) { + for (int x = targetFastBitmap.Left; x < targetFastBitmap.Right; x++) { int hits = 0; int r = 0; int g = 0; int b = 0; - for (int y = -halfRange; y < h; y++) { + for (int y = targetFastBitmap.Top - halfRange; y < targetFastBitmap.Bottom; y++) { int oldPixel = y - halfRange - 1; - if (oldPixel >= 0) { + if (oldPixel >= targetFastBitmap.Top) { targetFastBitmap.GetColorAt(x, oldPixel, tmpColor); r -= tmpColor[FastBitmap.COLOR_INDEX_R]; g -= tmpColor[FastBitmap.COLOR_INDEX_G]; @@ -822,7 +627,7 @@ namespace GreenshotPlugin.Core { } int newPixel = y + halfRange; - if (newPixel < h) { + if (newPixel < targetFastBitmap.Bottom) { targetFastBitmap.GetColorAt(x, newPixel, tmpColor); r += tmpColor[FastBitmap.COLOR_INDEX_R]; g += tmpColor[FastBitmap.COLOR_INDEX_G]; @@ -830,13 +635,13 @@ namespace GreenshotPlugin.Core { hits++; } - if (y >= 0) { - newColors[y] = Color.FromArgb(255, (byte)(r / hits), (byte)(g / hits), (byte)(b / hits)); + if (y >= targetFastBitmap.Top) { + newColors[y - targetFastBitmap.Top] = Color.FromArgb(255, (byte)(r / hits), (byte)(g / hits), (byte)(b / hits)); } } - for (int y = 0; y < h; y++) { - targetFastBitmap.SetColorAt(x, y, newColors[y]); + for (int y = targetFastBitmap.Top; y < targetFastBitmap.Bottom; y++) { + targetFastBitmap.SetColorAt(x, y, newColors[y - targetFastBitmap.Top]); } } } @@ -852,22 +657,20 @@ namespace GreenshotPlugin.Core { } int w = targetFastBitmap.Width; - int h = targetFastBitmap.Height; int halfRange = range / 2; - Color[] newColors = new Color[h]; + Color[] newColors = new Color[targetFastBitmap.Height]; int oldPixelOffset = -(halfRange + 1) * w; int newPixelOffset = (halfRange) * w; byte[] tmpColor = new byte[4]; - for (int x = 0; x < w; x++) { + for (int x = targetFastBitmap.Left; x < targetFastBitmap.Right; x++) { int hits = 0; int a = 0; int r = 0; int g = 0; int b = 0; - for (int y = -halfRange; y < h; y++) { + for (int y = targetFastBitmap.Top - halfRange; y < targetFastBitmap.Bottom; y++) { int oldPixel = y - halfRange - 1; - if (oldPixel >= 0) { - //int colorg = pixels[index + oldPixelOffset]; + if (oldPixel >= targetFastBitmap.Top) { targetFastBitmap.GetColorAt(x, oldPixel, tmpColor); a -= tmpColor[FastBitmap.COLOR_INDEX_A]; r -= tmpColor[FastBitmap.COLOR_INDEX_R]; @@ -877,7 +680,7 @@ namespace GreenshotPlugin.Core { } int newPixel = y + halfRange; - if (newPixel < h) { + if (newPixel < targetFastBitmap.Bottom) { //int colorg = pixels[index + newPixelOffset]; targetFastBitmap.GetColorAt(x, newPixel, tmpColor); a += tmpColor[FastBitmap.COLOR_INDEX_A]; @@ -887,13 +690,13 @@ namespace GreenshotPlugin.Core { hits++; } - if (y >= 0) { - newColors[y] = Color.FromArgb((byte)(a / hits), (byte)(r / hits), (byte)(g / hits), (byte)(b / hits)); + if (y >= targetFastBitmap.Top) { + newColors[y - targetFastBitmap.Top] = Color.FromArgb((byte)(a / hits), (byte)(r / hits), (byte)(g / hits), (byte)(b / hits)); } } - for (int y = 0; y < h; y++) { - targetFastBitmap.SetColorAt(x, y, newColors[y]); + for (int y = targetFastBitmap.Top; y < targetFastBitmap.Bottom; y++) { + targetFastBitmap.SetColorAt(x, y, newColors[y - targetFastBitmap.Top]); } } } @@ -1068,7 +871,6 @@ namespace GreenshotPlugin.Core { /// b/w bitmap public static Bitmap CreateMonochrome(Image sourceImage, byte threshold) { using (IFastBitmap fastBitmap = FastBitmap.CreateCloneOf(sourceImage, sourceImage.PixelFormat)) { - fastBitmap.Lock(); for (int y = 0; y < fastBitmap.Height; y++) { for (int x = 0; x < fastBitmap.Width; x++) { Color color = fastBitmap.GetColorAt(x, y); @@ -1122,15 +924,13 @@ namespace GreenshotPlugin.Core { } /// - /// Adjust the brightness, contract or gamma of an image. - /// Use the value "1.0f" for no changes. + /// Create ImageAttributes to modify /// - /// Original bitmap - /// Bitmap with grayscale - public static Image Adjust(Image sourceImage, float brightness, float contrast, float gamma) { - //create a blank bitmap the same size as original - // If using 8bpp than the following exception comes: A Graphics object cannot be created from an image that has an indexed pixel format. - Bitmap newBitmap = CreateEmpty(sourceImage.Width, sourceImage.Height, PixelFormat.Format24bppRgb, Color.Empty, sourceImage.HorizontalResolution, sourceImage.VerticalResolution); + /// + /// + /// + /// ImageAttributes + public static ImageAttributes CreateAdjustAttributes(float brightness, float contrast, float gamma) { float adjustedBrightness = brightness - 1.0f; ColorMatrix applyColorMatrix = new ColorMatrix( new float[][] { @@ -1146,8 +946,19 @@ namespace GreenshotPlugin.Core { attributes.ClearColorMatrix(); attributes.SetColorMatrix(applyColorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap); attributes.SetGamma(gamma, ColorAdjustType.Bitmap); - ApplyImageAttributes((Bitmap)sourceImage, Rectangle.Empty, newBitmap, Rectangle.Empty, attributes); - + return attributes; + } + /// + /// Adjust the brightness, contract or gamma of an image. + /// Use the value "1.0f" for no changes. + /// + /// Original bitmap + /// Bitmap with grayscale + public static Image Adjust(Image sourceImage, float brightness, float contrast, float gamma) { + //create a blank bitmap the same size as original + // If using 8bpp than the following exception comes: A Graphics object cannot be created from an image that has an indexed pixel format. + Bitmap newBitmap = CreateEmpty(sourceImage.Width, sourceImage.Height, PixelFormat.Format24bppRgb, Color.Empty, sourceImage.HorizontalResolution, sourceImage.VerticalResolution); + ApplyImageAttributes((Bitmap)sourceImage, Rectangle.Empty, newBitmap, Rectangle.Empty, CreateAdjustAttributes(brightness, contrast, gamma)); return newBitmap; } @@ -1407,8 +1218,7 @@ namespace GreenshotPlugin.Core { if (!includeAlpha) { toCount = toCount & 0xffffff; } - using (BitmapBuffer bb = new BitmapBuffer(sourceImage, false)) { - bb.Lock(); + using (IFastBitmap bb = FastBitmap.Create((Bitmap)sourceImage)) { for (int y = 0; y < bb.Height; y++) { for (int x = 0; x < bb.Width; x++) { int bitmapcolor = bb.GetColorAt(x, y).ToArgb(); @@ -1420,7 +1230,6 @@ namespace GreenshotPlugin.Core { } } } - bb.Unlock(); return colors; } } diff --git a/GreenshotPlugin/Core/QuantizerHelper.cs b/GreenshotPlugin/Core/QuantizerHelper.cs index 80c723769..b61216146 100644 --- a/GreenshotPlugin/Core/QuantizerHelper.cs +++ b/GreenshotPlugin/Core/QuantizerHelper.cs @@ -332,21 +332,19 @@ namespace GreenshotPlugin.Core { LOG.Info("Starting bitmap reconstruction..."); - using (FastChunkyBitmap bbbDest = FastBitmap.Create(resultBitmap) as FastChunkyBitmap) { - bbbDest.Lock(); - using (IFastBitmap bbbSrc = FastBitmap.Create(sourceBitmap)) { - IFastBitmapWithBlend bbbSrcBlend = bbbSrc as IFastBitmapWithBlend; - bbbSrc.Lock(); + using (FastChunkyBitmap dest = FastBitmap.Create(resultBitmap) as FastChunkyBitmap) { + using (IFastBitmap src = FastBitmap.Create(sourceBitmap)) { + IFastBitmapWithBlend srcBlend = src as IFastBitmapWithBlend; Dictionary lookup = new Dictionary(); byte bestMatch; - for (int y = 0; y < bbbSrc.Height; y++) { - for (int x = 0; x < bbbSrc.Width; x++) { + for (int y = 0; y < src.Height; y++) { + for (int x = 0; x < src.Width; x++) { Color color; - if (bbbSrcBlend != null) { + if (srcBlend != null) { // WithoutAlpha, this makes it possible to ignore the alpha - color = bbbSrcBlend.GetBlendedColorAt(x, y); + color = srcBlend.GetBlendedColorAt(x, y); } else { - color = bbbSrc.GetColorAt(x, y); + color = src.GetColorAt(x, y); } // Check if we already matched the color @@ -354,7 +352,7 @@ namespace GreenshotPlugin.Core { // If not we need to find the best match // First get initial match - bestMatch = bbbDest.GetColorIndexAt(x, y); + bestMatch = dest.GetColorIndexAt(x, y); bestMatch = tag[bestMatch]; Int32 bestDistance = 100000000; @@ -384,7 +382,7 @@ namespace GreenshotPlugin.Core { blues[bestMatch] += color.B; sums[bestMatch]++; - bbbDest.SetColorIndexAt(x, y, bestMatch); + dest.SetColorIndexAt(x, y, bestMatch); } } } diff --git a/GreenshotPlugin/Core/WindowsHelper.cs b/GreenshotPlugin/Core/WindowsHelper.cs index f0dd294bb..9dc0e9b9c 100644 --- a/GreenshotPlugin/Core/WindowsHelper.cs +++ b/GreenshotPlugin/Core/WindowsHelper.cs @@ -1117,14 +1117,13 @@ namespace GreenshotPlugin.Core { /// /// The bitmap to remove the corners from. private void RemoveCorners(Bitmap image) { - using (BitmapBuffer buffer = new BitmapBuffer((Bitmap)image, false)) { - buffer.Lock(); + using (IFastBitmap fastBitmap = FastBitmap.Create(image)) { for (int y = 0; y < conf.WindowCornerCutShape.Count; y++) { for (int x = 0; x < conf.WindowCornerCutShape[y]; x++) { - buffer.SetColorAt(x, y, Color.Transparent); - buffer.SetColorAt(image.Width-1-x, y, Color.Transparent); - buffer.SetColorAt(image.Width-1-x, image.Height-1-y, Color.Transparent); - buffer.SetColorAt(x, image.Height-1-y, Color.Transparent); + fastBitmap.SetColorAt(x, y, Color.Transparent); + fastBitmap.SetColorAt(image.Width-1-x, y, Color.Transparent); + fastBitmap.SetColorAt(image.Width-1-x, image.Height-1-y, Color.Transparent); + fastBitmap.SetColorAt(x, image.Height-1-y, Color.Transparent); } } } @@ -1139,23 +1138,19 @@ namespace GreenshotPlugin.Core { /// Bitmap with the black image /// Bitmap with transparency private Bitmap ApplyTransparency(Bitmap blackBitmap, Bitmap whiteBitmap) { - Bitmap returnBitmap = new Bitmap(blackBitmap.Width, blackBitmap.Height, PixelFormat.Format32bppArgb); - returnBitmap.SetResolution(blackBitmap.HorizontalResolution, blackBitmap.VerticalResolution); - using (BitmapBuffer blackBuffer = new BitmapBuffer(blackBitmap, false)) { - blackBuffer.Lock(); - using (BitmapBuffer whiteBuffer = new BitmapBuffer(whiteBitmap, false)) { - whiteBuffer.Lock(); - using (BitmapBuffer targetBuffer = new BitmapBuffer(returnBitmap, false)) { - targetBuffer.Lock(); - for(int y=0; y diff --git a/GreenshotPlugin/GreenshotPlugin.csproj b/GreenshotPlugin/GreenshotPlugin.csproj index d0ee900e2..c06c4a09e 100644 --- a/GreenshotPlugin/GreenshotPlugin.csproj +++ b/GreenshotPlugin/GreenshotPlugin.csproj @@ -146,7 +146,6 @@ -