From e2be04a552e18f060d852746a0b71823574264c0 Mon Sep 17 00:00:00 2001 From: RKrom Date: Sun, 10 Feb 2013 14:40:01 +0000 Subject: [PATCH] Code cleanup: 1) AbstractFilter: why did we serialize the bitmapbuffer? 2) Bitmapbuffer: removed serialization code, this object should NEVER be serialized as it's just a view which makes access faster. 3) QuantizerHelper.cs: Refactored to use the FastBitmap git-svn-id: http://svn.code.sf.net/p/greenshot/code/trunk@2474 7dccd23d-a4a3-4e1f-8c07-b4c1b4018ab4 --- Greenshot/Drawing/Filters/AbstractFilter.cs | 2 + GreenshotPlugin/Core/BitmapBuffer.cs | 126 +------------------- GreenshotPlugin/Core/FastBitmap.cs | 23 ++-- GreenshotPlugin/Core/ImageHelper.cs | 48 ++++---- GreenshotPlugin/Core/QuantizerHelper.cs | 59 ++++----- 5 files changed, 59 insertions(+), 199 deletions(-) diff --git a/Greenshot/Drawing/Filters/AbstractFilter.cs b/Greenshot/Drawing/Filters/AbstractFilter.cs index 4ce539b17..ef47a50c0 100644 --- a/Greenshot/Drawing/Filters/AbstractFilter.cs +++ b/Greenshot/Drawing/Filters/AbstractFilter.cs @@ -47,7 +47,9 @@ namespace Greenshot.Drawing.Filters { get { return invert; } set { invert=value; OnPropertyChanged("Invert"); } } + [NonSerialized] protected BitmapBuffer bbb; + protected Rectangle applyRect; protected DrawableContainer parent; public DrawableContainer Parent { diff --git a/GreenshotPlugin/Core/BitmapBuffer.cs b/GreenshotPlugin/Core/BitmapBuffer.cs index ea5d755be..6a99c499d 100644 --- a/GreenshotPlugin/Core/BitmapBuffer.cs +++ b/GreenshotPlugin/Core/BitmapBuffer.cs @@ -28,7 +28,6 @@ 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 /// - [Serializable()] public unsafe class BitmapBuffer : IDisposable { private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(BitmapBuffer)); private bool clone; @@ -36,6 +35,7 @@ namespace GreenshotPlugin.Core { // Used for indexed images private Color[] colorEntries; + public static Color BackgroundBlendColor { get; set; @@ -70,35 +70,21 @@ namespace GreenshotPlugin.Core { } } - [NonSerialized] private BitmapData bmData; - [NonSerialized] private Rectangle rect; - [NonSerialized] private byte* pointer; - [NonSerialized] private int* intPointer; - [NonSerialized] private int stride; /* bytes per pixel row */ - [NonSerialized] private int aIndex = -1; - [NonSerialized] private int rIndex = -1; - [NonSerialized] private int gIndex = -1; - [NonSerialized] private int bIndex = -1; - [NonSerialized] private int bytesPerPixel; - [NonSerialized] private bool bitsLocked = false; public Size Size { get {return rect.Size;} } - public int Length { - get {return rect.Width*rect.Height;} - } public int Width { get {return rect.Width;} } @@ -204,29 +190,6 @@ namespace GreenshotPlugin.Core { bmData = null; pointer = null; } - - /** - * This is called when deserializing the object - */ - public BitmapBuffer(SerializationInfo info, StreamingContext ctxt) { - this.bitmap = (Bitmap)info.GetValue("bitmap", typeof(Bitmap)); - this.rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height); - // The rest will be set when Lock is called - } - - /** - * This is called when serializing the object - */ - public void GetObjectData(SerializationInfo info, StreamingContext ctxt) { - bool isLocked = bitsLocked; - if (isLocked) { - Unlock(); - } - info.AddValue("bitmap", this.bitmap); - if (isLocked) { - Lock(); - } - } /** * Lock the bitmap so we have direct access to the memory @@ -297,51 +260,6 @@ namespace GreenshotPlugin.Core { } } - /// - /// Retrieve the color index, for 8BPP, at location x,y - /// - /// X coordinate - /// Y Coordinate - /// color index - public byte GetColorIndexAt(int x, int y) { - int offset = x*bytesPerPixel+y*stride; - return pointer[offset]; - } - - /// - /// Get the color for an 8-bit image - /// - /// - /// - /// Color from the palette - public Color GetColor(int x, int y) { - int offset = x * bytesPerPixel + y * stride; - byte colorIndex = pointer[offset]; - return colorEntries[colorIndex]; - } - - /// - /// Set the color index, for 8BPP, at location x,y - /// - /// X coordinate - /// Y Coordinate - /// Color index to set - public void SetColorIndexAt(int x, int y, byte colorIndex) { - int offset = x * bytesPerPixel + y * stride; - pointer[offset] = colorIndex; - } - - /// - /// Use only when 32-bit bitmap! - /// - /// x - /// y - /// int with argb value - public int GetARGB(int x, int y) { - int offset = (y * (stride >> 2)) + x; - return intPointer[offset]; - } - /// /// Use only when 32-bit bitmap! /// @@ -370,34 +288,6 @@ namespace GreenshotPlugin.Core { } } - /// - /// Retrieve the color, without alpha (is blended), at location x,y - /// Before the first time this is called the Lock() should be called once! - /// - /// X coordinate - /// Y Coordinate - /// Color - public Color GetColorAtWithoutAlpha(int x, int y) { - if (x >= 0 && y >= 0 && x < rect.Width && y < rect.Height) { - int offset = x * bytesPerPixel + y * stride; - int a = (aIndex == -1) ? (byte)255 : pointer[aIndex + offset]; - int red = pointer[rIndex + offset]; - int green = pointer[gIndex + offset]; - int blue = pointer[bIndex + offset]; - - if (a < 255) { - // As the request is to get without alpha, we blend. - int rem = 255 - a; - red = (red * a + BackgroundBlendColor.R * rem) / 255; - green = (green * a + BackgroundBlendColor.G * rem) / 255; - blue = (blue * a + BackgroundBlendColor.B * rem) / 255; - } - return Color.FromArgb(255, red, green, blue); - } else { - return Color.Empty; - } - } - /** * Set the color at location x,y * Before the first time this is called the Lock() should be called once! @@ -412,20 +302,6 @@ namespace GreenshotPlugin.Core { } } - /** - * Retrieve the color at location x,y as an array - * Before the first time this is called the Lock() should be called once! - */ - public byte[] GetColorArrayAt(int x, int y) { - if(x>=0 && y>=0 && x public bool NeedsDispose { get; - protected set; + set; } /// @@ -116,7 +115,7 @@ namespace GreenshotPlugin.Core { public static IFastBitmap CreateEmpty(Size newSize, PixelFormat pixelFormat, Color backgroundColor) { Bitmap destination = ImageHelper.CreateEmpty(newSize.Width, newSize.Height, pixelFormat, backgroundColor, 96f, 96f); IFastBitmap fastBitmap = Create(destination); - ((FastBitmap)fastBitmap).NeedsDispose = true; + fastBitmap.NeedsDispose = true; return fastBitmap; } @@ -152,15 +151,15 @@ namespace GreenshotPlugin.Core { } /// - /// Returns the underlying bitmap, do not dispose... if it's created for the FastBitmap it will be disposed! + /// Returns the underlying bitmap, unlocks it and prevents that it will be disposed /// - public Bitmap Bitmap { - get { - if (bitsLocked) { - throw new NotSupportedException("Can't get a locked bitmap!"); - } - return bitmap; + public Bitmap UnlockAndReturnBitmap() { + if (bitsLocked) { + LOG.Warn("Unlocking the bitmap"); + Unlock(); } + NeedsDispose = false; + return bitmap; } /// diff --git a/GreenshotPlugin/Core/ImageHelper.cs b/GreenshotPlugin/Core/ImageHelper.cs index f6d234546..12996f461 100644 --- a/GreenshotPlugin/Core/ImageHelper.cs +++ b/GreenshotPlugin/Core/ImageHelper.cs @@ -111,19 +111,19 @@ namespace GreenshotPlugin.Core { /// /// Private helper method for the FindAutoCropRectangle /// - /// + /// /// /// Rectangle - private static Rectangle FindAutoCropRectangle(BitmapBuffer buffer, Point colorPoint, int cropDifference) { + private static Rectangle FindAutoCropRectangle(IFastBitmap fastBitmap, Point colorPoint, int cropDifference) { Rectangle cropRectangle = Rectangle.Empty; - Color referenceColor = buffer.GetColorAtWithoutAlpha(colorPoint.X,colorPoint.Y); + Color referenceColor = fastBitmap.GetColorAt(colorPoint.X, colorPoint.Y); Point min = new Point(int.MaxValue, int.MaxValue); Point max = new Point(int.MinValue, int.MinValue); if (cropDifference > 0) { - for(int y = 0; y < buffer.Height; y++) { - for(int x = 0; x < buffer.Width; x++) { - Color currentColor = buffer.GetColorAt(x, y); + for (int y = 0; y < fastBitmap.Height; y++) { + for (int x = 0; x < fastBitmap.Width; x++) { + Color currentColor = fastBitmap.GetColorAt(x, y); int diffR = Math.Abs(currentColor.R - referenceColor.R); int diffG = Math.Abs(currentColor.G - referenceColor.G); int diffB = Math.Abs(currentColor.B - referenceColor.B); @@ -136,9 +136,9 @@ namespace GreenshotPlugin.Core { } } } else { - for(int y = 0; y < buffer.Height; y++) { - for(int x = 0; x < buffer.Width; x++) { - Color currentColor = buffer.GetColorAtWithoutAlpha(x, y); + for (int y = 0; y < fastBitmap.Height; y++) { + for (int x = 0; x < fastBitmap.Width; x++) { + Color currentColor = fastBitmap.GetColorAt(x, y); if (referenceColor.Equals(currentColor)) { if (x < min.X) min.X = x; if (y < min.Y) min.Y = y; @@ -149,7 +149,7 @@ namespace GreenshotPlugin.Core { } } - if (!(Point.Empty.Equals(min) && max.Equals(new Point(buffer.Width-1, buffer.Height-1)))) { + if (!(Point.Empty.Equals(min) && max.Equals(new Point(fastBitmap.Width - 1, fastBitmap.Height - 1)))) { if (!(min.X == int.MaxValue || min.Y == int.MaxValue || max.X == int.MinValue || min.X == int.MinValue)) { cropRectangle = new Rectangle(min.X, min.Y, max.X - min.X + 1, max.Y - min.Y + 1); } @@ -164,22 +164,22 @@ namespace GreenshotPlugin.Core { /// Rectangle public static Rectangle FindAutoCropRectangle(Image image, int cropDifference) { Rectangle cropRectangle = Rectangle.Empty; - using (BitmapBuffer buffer = new BitmapBuffer((Bitmap)image, false)) { - buffer.Lock(); - Rectangle currentRectangle = Rectangle.Empty; - List checkPoints = new List(); - // Top Left - checkPoints.Add(new Point(0, 0)); - // Bottom Left - checkPoints.Add(new Point(0, image.Height-1)); - // Top Right - checkPoints.Add(new Point(image.Width-1, 0)); - // Bottom Right - checkPoints.Add( new Point(image.Width-1, image.Height-1)); + Rectangle currentRectangle = Rectangle.Empty; + List checkPoints = new List(); + // Top Left + checkPoints.Add(new Point(0, 0)); + // Bottom Left + checkPoints.Add(new Point(0, image.Height - 1)); + // Top Right + checkPoints.Add(new Point(image.Width - 1, 0)); + // 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(buffer, checkPoint, cropDifference); + currentRectangle = FindAutoCropRectangle(fastBitmap, checkPoint, cropDifference); if (currentRectangle.Width * currentRectangle.Height > cropRectangle.Width * cropRectangle.Height) { cropRectangle = currentRectangle; } @@ -1344,7 +1344,7 @@ namespace GreenshotPlugin.Core { if (!includeAlpha) { toCount = toCount & 0xffffff; } - using (BitmapBuffer bb = new BitmapBuffer(sourceImage)) { + using (BitmapBuffer bb = new BitmapBuffer(sourceImage, false)) { bb.Lock(); for (int y = 0; y < bb.Height; y++) { for (int x = 0; x < bb.Width; x++) { diff --git a/GreenshotPlugin/Core/QuantizerHelper.cs b/GreenshotPlugin/Core/QuantizerHelper.cs index acb9ee10c..313388bc7 100644 --- a/GreenshotPlugin/Core/QuantizerHelper.cs +++ b/GreenshotPlugin/Core/QuantizerHelper.cs @@ -147,21 +147,13 @@ namespace GreenshotPlugin.Core { } // Use a bitmap to store the initial match, which is just as good as an array and saves us 2x the storage - resultBitmap = new Bitmap(sourceBitmap.Width, sourceBitmap.Height, PixelFormat.Format8bppIndexed); - resultBitmap.SetResolution(sourceBitmap.HorizontalResolution, sourceBitmap.VerticalResolution); - bool is8Bit = sourceBitmap.PixelFormat == PixelFormat.Format8bppIndexed; - using (BitmapBuffer bbbSrc = new BitmapBuffer(sourceBitmap, false)) { - bbbSrc.Lock(); - using (BitmapBuffer bbbDest = new BitmapBuffer(resultBitmap, false)) { - bbbDest.Lock(); - for (int y = 0; y < bbbSrc.Height; y++) { - for (int x = 0; x < bbbSrc.Width; x++) { - Color color; - if (is8Bit) { - color = bbbSrc.GetColor(x, y); - } else { - color = bbbSrc.GetColorAtWithoutAlpha(x, y); - } + using (IFastBitmap sourceFastBitmap = FastBitmap.Create(sourceBitmap)) { + sourceFastBitmap.Lock(); + using (FastChunkyBitmap destinationFastBitmap = FastBitmap.CreateEmpty(sourceBitmap.Size, PixelFormat.Format8bppIndexed, Color.White) as FastChunkyBitmap) { + destinationFastBitmap.Lock(); + for (int y = 0; y < sourceFastBitmap.Height; y++) { + for (int x = 0; x < sourceFastBitmap.Width; x++) { + Color color = sourceFastBitmap.GetColorAt(x, y); // To count the colors int index = color.ToArgb() & 0x00ffffff; // Check if we already have this color @@ -183,9 +175,10 @@ namespace GreenshotPlugin.Core { // Store the initial "match" Int32 paletteIndex = (indexRed << 10) + (indexRed << 6) + indexRed + (indexGreen << 5) + indexGreen + indexBlue; - bbbDest.SetColorIndexAt(x, y, (byte)(paletteIndex & 0xff)); + destinationFastBitmap.SetColorIndexAt(x, y, (byte)(paletteIndex & 0xff)); } } + resultBitmap = destinationFastBitmap.UnlockAndReturnBitmap(); } } } @@ -204,20 +197,14 @@ namespace GreenshotPlugin.Core { public Bitmap SimpleReindex() { List colors = new List(); Dictionary lookup = new Dictionary(); - using (BitmapBuffer bbbDest = new BitmapBuffer(resultBitmap, false)) { + using (FastChunkyBitmap bbbDest = FastBitmap.Create(resultBitmap) as FastChunkyBitmap) { bbbDest.Lock(); - using (BitmapBuffer bbbSrc = new BitmapBuffer(sourceBitmap, false)) { + using (IFastBitmap bbbSrc = FastBitmap.Create(sourceBitmap)) { bbbSrc.Lock(); byte index; - bool is8Bit = sourceBitmap.PixelFormat == PixelFormat.Format8bppIndexed; for (int y = 0; y < bbbSrc.Height; y++) { for (int x = 0; x < bbbSrc.Width; x++) { - Color color; - if (is8Bit) { - color = bbbSrc.GetColor(x, y); - } else { - color = bbbSrc.GetColorAt(x, y); - } + Color color = bbbSrc.GetColorAt(x, y); if (lookup.ContainsKey(color)) { index = lookup[color]; } else { @@ -233,11 +220,12 @@ namespace GreenshotPlugin.Core { // generates palette ColorPalette imagePalette = resultBitmap.Palette; + Color[] entries = imagePalette.Entries; for (Int32 paletteIndex = 0; paletteIndex < 256; paletteIndex++) { if (paletteIndex < colorCount) { - imagePalette.Entries[paletteIndex] = colors[paletteIndex]; + entries[paletteIndex] = colors[paletteIndex]; } else { - imagePalette.Entries[paletteIndex] = Color.Black; + entries[paletteIndex] = Color.Black; } } resultBitmap.Palette = imagePalette; @@ -324,22 +312,16 @@ namespace GreenshotPlugin.Core { LOG.Info("Starting bitmap reconstruction..."); - using (BitmapBuffer bbbDest = new BitmapBuffer(resultBitmap, false)) { + using (FastChunkyBitmap bbbDest = FastBitmap.Create(resultBitmap) as FastChunkyBitmap) { bbbDest.Lock(); - using (BitmapBuffer bbbSrc = new BitmapBuffer(sourceBitmap, false)) { + using (IFastBitmap bbbSrc = FastBitmap.Create(sourceBitmap)) { bbbSrc.Lock(); Dictionary lookup = new Dictionary(); byte bestMatch; - bool is8Bit = sourceBitmap.PixelFormat == PixelFormat.Format8bppIndexed; for (int y = 0; y < bbbSrc.Height; y++) { for (int x = 0; x < bbbSrc.Width; x++) { - Color color; - if (is8Bit) { - color = bbbSrc.GetColor(x, y); - } else { - color = bbbSrc.GetColorAtWithoutAlpha(x, y); - } - + // Consider WithoutAlpha + Color color = bbbSrc.GetColorAt(x, y); // No need to a strip the alpha as before // Check if we already matched the color @@ -386,6 +368,7 @@ namespace GreenshotPlugin.Core { // generates palette ColorPalette imagePalette = resultBitmap.Palette; + Color[] entries = imagePalette.Entries; for (Int32 paletteIndex = 0; paletteIndex < allowedColorCount; paletteIndex++) { if (sums[paletteIndex] > 0) { reds[paletteIndex] /= sums[paletteIndex]; @@ -393,7 +376,7 @@ namespace GreenshotPlugin.Core { blues[paletteIndex] /= sums[paletteIndex]; } - imagePalette.Entries[paletteIndex] = Color.FromArgb(255, reds[paletteIndex], greens[paletteIndex], blues[paletteIndex]); + entries[paletteIndex] = Color.FromArgb(255, reds[paletteIndex], greens[paletteIndex], blues[paletteIndex]); } resultBitmap.Palette = imagePalette;