diff --git a/GreenshotPlugin/Core/FastBitmap.cs b/GreenshotPlugin/Core/FastBitmap.cs
new file mode 100644
index 000000000..4a7838d37
--- /dev/null
+++ b/GreenshotPlugin/Core/FastBitmap.cs
@@ -0,0 +1,481 @@
+/*
+ * 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.Collections.Generic;
+using System.Drawing;
+using System.Drawing.Imaging;
+
+namespace GreenshotPlugin.Core {
+
+ ///
+ /// The interface for the FastBitmap
+ ///
+ public interface IFastBitmap : IDisposable {
+ Color GetColorAt(int x, int y);
+ void SetColorAt(int x, int y, Color color);
+ void Lock();
+ void Unlock();
+ Bitmap Bitmap {
+ get;
+ }
+ Size Size {
+ get;
+ }
+ int Height {
+ get;
+ }
+ int Width {
+ get;
+ }
+ bool NeedsDispose {
+ get;
+ }
+ }
+
+ ///
+ /// The base class for the fast bitmap implementation
+ ///
+ public unsafe abstract class FastBitmap : IFastBitmap {
+ private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(FastBitmap));
+
+ ///
+ /// If this is set to true, the bitmap will be disposed when disposing the IFastBitmap
+ ///
+ public bool NeedsDispose {
+ get;
+ protected set;
+ }
+
+ ///
+ /// The bitmap for which the FastBitmap is creating access
+ ///
+ protected Bitmap bitmap;
+ protected BitmapData bmData;
+ protected int stride; /* bytes per pixel row */
+ protected bool bitsLocked = false;
+ protected byte* pointer;
+
+ ///
+ /// Factory for creating a FastBitmap depending on the pixelformat of the source
+ ///
+ /// Bitmap to access
+ /// IFastBitmap
+ public static IFastBitmap Create(Bitmap source) {
+ switch (source.PixelFormat) {
+ case PixelFormat.Format8bppIndexed:
+ return new FastChunkyBitmap(source);
+ case PixelFormat.Format24bppRgb:
+ return new Fast24RGBBitmap(source);
+ case PixelFormat.Format32bppRgb:
+ return new Fast32RGBBitmap(source);
+ case PixelFormat.Format32bppArgb:
+ return new Fast32ARGBBitmap(source);
+ default:
+ throw new NotSupportedException(string.Format("Not supported Pixelformat {0}", source.PixelFormat));
+ }
+ }
+
+ ///
+ /// Factory for creating a FastBitmap as a destination for the source
+ ///
+ /// Bitmap to access
+ /// IFastBitmap
+ public static IFastBitmap CreateDestinationFor(Bitmap source, PixelFormat pixelFormat) {
+ Bitmap destination = ImageHelper.CloneArea(source, Rectangle.Empty, pixelFormat);
+ IFastBitmap fastBitmap = Create(destination);
+ ((FastBitmap)fastBitmap).NeedsDispose = true;
+ return fastBitmap;
+ }
+
+
+ ///
+ /// Factory for creating a FastBitmap as a destination
+ ///
+ ///
+ ///
+ ///
+ /// IFastBitmap
+ 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;
+ return fastBitmap;
+ }
+
+ protected FastBitmap(Bitmap bitmap) {
+ this.bitmap = bitmap;
+ }
+
+ ///
+ /// Return the size of the image
+ ///
+ public Size Size {
+ get {
+ return bitmap.Size;
+ }
+ }
+
+ ///
+ /// Return the width of the image
+ ///
+ public int Width {
+ get {
+ return bitmap.Width;
+ }
+ }
+
+ ///
+ /// Return the height of the image
+ ///
+ public int Height {
+ get {
+ return bitmap.Height;
+ }
+ }
+
+ ///
+ /// Returns the underlying bitmap, do not dispose... if it's created for the FastBitmap it will be disposed!
+ ///
+ public Bitmap Bitmap {
+ get {
+ if (bitsLocked) {
+ throw new NotSupportedException("Can't get a locked bitmap!");
+ }
+ return bitmap;
+ }
+ }
+
+ ///
+ /// Destructor
+ ///
+ ~FastBitmap() {
+ 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 && NeedsDispose) {
+ bitmap.Dispose();
+ }
+ }
+ bitmap = null;
+ bmData = null;
+ pointer = null;
+ }
+
+ ///
+ /// Lock the bitmap so we have direct access to the memory
+ ///
+ public void Lock() {
+ if (Width > 0 && Height > 0 && !bitsLocked) {
+ bmData = bitmap.LockBits(new Rectangle(Point.Empty, Size), ImageLockMode.ReadWrite, bitmap.PixelFormat);
+ bitsLocked = true;
+
+ IntPtr Scan0 = bmData.Scan0;
+ pointer = (byte*)(void*)Scan0;
+ 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();
+ }
+ }
+
+ public abstract Color GetColorAt(int x, int y);
+ public abstract void SetColorAt(int x, int y, Color color);
+ }
+
+ public unsafe class FastChunkyBitmap : FastBitmap {
+ // Used for indexed images
+ private Color[] colorEntries;
+ private Dictionary colorCache = new Dictionary();
+
+ public FastChunkyBitmap(Bitmap source) : base(source) {
+ colorEntries = bitmap.Palette.Entries;
+ }
+
+ ///
+ /// Get the color from the specified location
+ ///
+ ///
+ ///
+ /// Color
+ public override Color GetColorAt(int x, int y) {
+ int offset = x + (y * stride);
+ byte colorIndex = pointer[offset];
+ return colorEntries[colorIndex];
+ }
+
+ ///
+ /// Get the color-index from the specified location
+ ///
+ ///
+ ///
+ /// byte with index
+ public byte GetColorIndexAt(int x, int y) {
+ int offset = x + (y * stride);
+ return pointer[offset];
+ }
+
+ ///
+ /// Set the color-index at the specified location
+ ///
+ ///
+ ///
+ ///
+ public void SetColorIndexAt(int x, int y, byte colorIndex) {
+ int offset = x + (y * stride);
+ pointer[offset] = colorIndex;
+ }
+
+ ///
+ /// Set the supplied color at the specified location.
+ /// Throws an ArgumentException if the color is not in the palette
+ ///
+ ///
+ ///
+ /// Color to set
+ public override void SetColorAt(int x, int y, Color color) {
+ int offset = x + (y * stride);
+ byte colorIndex;
+ if (!colorCache.TryGetValue(color, out colorIndex)) {
+ bool foundColor = false;
+ for (colorIndex = 0; colorIndex < colorEntries.Length; colorIndex++) {
+ if (color == colorEntries[colorIndex]) {
+ colorCache.Add(color, colorIndex);
+ foundColor = true;
+ break;
+ }
+ }
+ if (!foundColor) {
+ throw new ArgumentException("No such color!");
+ }
+ }
+ pointer[offset] = colorIndex;
+ }
+ }
+
+ ///
+ /// This is the implementation of the IFastBitmap for 24 bit images (no Alpha)
+ ///
+ public unsafe class Fast24RGBBitmap : FastBitmap {
+
+ public Fast24RGBBitmap(Bitmap source) : base(source) {
+ }
+
+ ///
+ /// 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 override Color GetColorAt(int x, int y) {
+ int offset = (x * 3) + (y * stride);
+ return Color.FromArgb(255, pointer[2 + offset], pointer[1 + offset], pointer[offset]);
+ }
+
+ ///
+ /// Set the color at location x,y
+ /// Before the first time this is called the Lock() should be called once!
+ ///
+ ///
+ ///
+ ///
+ public override void SetColorAt(int x, int y, Color color) {
+ int offset = (x * 3) + (y * stride);
+ pointer[2 + offset] = color.R;
+ pointer[1 + offset] = color.G;
+ pointer[offset] = color.B;
+ }
+ }
+
+ ///
+ /// This is the implementation of the IFastBitmap for 32 bit images (no Alpha)
+ ///
+ public unsafe class Fast32RGBBitmap : FastBitmap {
+ public Fast32RGBBitmap(Bitmap source) : base(source) {
+
+ }
+
+ ///
+ /// 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 override Color GetColorAt(int x, int y) {
+ int offset = (x * 4) + (y * stride);
+ return Color.FromArgb(255, pointer[2 + offset], pointer[1 + offset], pointer[offset]);
+ }
+
+ ///
+ /// Set the color at location x,y
+ /// Before the first time this is called the Lock() should be called once!
+ ///
+ ///
+ ///
+ ///
+ public override void SetColorAt(int x, int y, Color color) {
+ int offset = (x * 4) + (y * stride);
+ pointer[2 + offset] = color.R;
+ pointer[1 + offset] = color.G;
+ pointer[offset] = color.B;
+ }
+ }
+
+ ///
+ /// This is the implementation of the IFastBitmap for 32 bit images with Alpha
+ ///
+ public unsafe class Fast32ARGBBitmap : FastBitmap {
+ public Color BackgroundBlendColor {
+ get;
+ set;
+ }
+ public Fast32ARGBBitmap(Bitmap source) : base(source) {
+ BackgroundBlendColor = Color.White;
+ }
+
+ ///
+ /// Retrieve the color at location x,y
+ ///
+ /// X coordinate
+ /// Y Coordinate
+ /// Color
+ public override Color GetColorAt(int x, int y) {
+ int offset = (x * 4) + (y * stride);
+ return Color.FromArgb(pointer[3 + offset], pointer[2 + offset], pointer[1 + offset], pointer[offset]);
+ }
+
+ ///
+ /// Set the color at location x,y
+ /// Before the first time this is called the Lock() should be called once!
+ ///
+ ///
+ ///
+ ///
+ public override void SetColorAt(int x, int y, Color color) {
+ int offset = (x * 4) + (y * stride);
+ pointer[3 + offset] = color.A;
+ pointer[2 + offset] = color.R;
+ pointer[1 + offset] = color.G;
+ pointer[offset] = color.B;
+ }
+
+ ///
+ /// 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) {
+ int offset = (x * 4) + (y * stride);
+ int a = pointer[3 + offset];
+ int red = pointer[2 + offset];
+ int green = pointer[1 + offset];
+ int blue = pointer[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);
+ }
+
+ }
+}
diff --git a/GreenshotPlugin/GreenshotPlugin.csproj b/GreenshotPlugin/GreenshotPlugin.csproj
index 6ddf4b4d2..31e9ff7f6 100644
--- a/GreenshotPlugin/GreenshotPlugin.csproj
+++ b/GreenshotPlugin/GreenshotPlugin.csproj
@@ -31,6 +31,7 @@
Form
+