mirror of
https://github.com/greenshot/greenshot
synced 2025-08-19 21:13:23 -07:00
Fixed an issue with the FastBitmap, renamed methods in the BitmapBuffer to be equal to the FastBitmap implementation. In general it's now very easy to switch from the BitmapBuffer to the FastBitmap implementation, but one should consider that the BitmapBuffer checks the x,y if they are inside... and supports a "apply rectangle". Had to "refactor" the CreateBlur for this. Changed the CreateShadow to work with the BoxBlur, this changes the time to create a shadow of a 1280x1024 from ~2.6 to ~1.2 seconds on my PC... which is still slow. The resulting effect seems to be extremely similar... good enough for me.
git-svn-id: http://svn.code.sf.net/p/greenshot/code/trunk@2480 7dccd23d-a4a3-4e1f-8c07-b4c1b4018ab4
This commit is contained in:
parent
c9e1ef30e4
commit
3f4d93f2b6
3 changed files with 315 additions and 215 deletions
|
@ -64,6 +64,11 @@ namespace GreenshotPlugin.Core {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Bitmap UnlockAndReturnBitmap() {
|
||||||
|
Unlock();
|
||||||
|
return Bitmap;
|
||||||
|
}
|
||||||
|
|
||||||
public PixelFormat PixelFormat {
|
public PixelFormat PixelFormat {
|
||||||
get {
|
get {
|
||||||
return bitmap.PixelFormat;
|
return bitmap.PixelFormat;
|
||||||
|
@ -208,9 +213,9 @@ namespace GreenshotPlugin.Core {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/// <summary>
|
||||||
* Unlock the System Memory
|
/// Unlock the System Memory
|
||||||
*/
|
/// </summary>
|
||||||
public void Unlock() {
|
public void Unlock() {
|
||||||
if (bitsLocked) {
|
if (bitsLocked) {
|
||||||
bitmap.UnlockBits(bmData);
|
bitmap.UnlockBits(bmData);
|
||||||
|
@ -218,24 +223,31 @@ namespace GreenshotPlugin.Core {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/// <summary>
|
||||||
* Draw the stored bitmap to the destionation bitmap at the supplied point
|
/// Draw the stored bitmap to the destionation bitmap at the supplied point
|
||||||
*/
|
/// </summary>
|
||||||
|
/// <param name="graphics"></param>
|
||||||
|
/// <param name="destination"></param>
|
||||||
public void DrawTo(Graphics graphics, Point destination) {
|
public void DrawTo(Graphics graphics, Point destination) {
|
||||||
DrawTo(graphics, null, destination);
|
DrawTo(graphics, null, destination);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/// <summary>
|
||||||
* Draw the stored Bitmap on the Destination bitmap with the specified rectangle
|
/// 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!!
|
/// Be aware that the stored bitmap will be resized to the specified rectangle!!
|
||||||
*/
|
/// </summary>
|
||||||
|
/// <param name="graphics"></param>
|
||||||
|
/// <param name="destinationRect"></param>
|
||||||
public void DrawTo(Graphics graphics, Rectangle destinationRect) {
|
public void DrawTo(Graphics graphics, Rectangle destinationRect) {
|
||||||
DrawTo(graphics, destinationRect, null);
|
DrawTo(graphics, destinationRect, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/// <summary>
|
||||||
* private helper to draw the bitmap
|
/// private helper to draw the bitmap
|
||||||
*/
|
/// </summary>
|
||||||
|
/// <param name="graphics"></param>
|
||||||
|
/// <param name="destinationRect"></param>
|
||||||
|
/// <param name="destination"></param>
|
||||||
private void DrawTo(Graphics graphics, Rectangle? destinationRect, Point? destination) {
|
private void DrawTo(Graphics graphics, Rectangle? destinationRect, Point? destination) {
|
||||||
if (destinationRect.HasValue) {
|
if (destinationRect.HasValue) {
|
||||||
// Does the rect have any pixels?
|
// Does the rect have any pixels?
|
||||||
|
@ -288,10 +300,13 @@ namespace GreenshotPlugin.Core {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/// <summary>
|
||||||
* Set the color at location x,y
|
/// Set the color at location x,y
|
||||||
* Before the first time this is called the Lock() should be called once!
|
/// Before the first time this is called the Lock() should be called once!
|
||||||
*/
|
/// </summary>
|
||||||
|
/// <param name="x"></param>
|
||||||
|
/// <param name="y"></param>
|
||||||
|
/// <param name="color"></param>
|
||||||
public void SetColorAt(int x, int y, Color color) {
|
public void SetColorAt(int x, int y, Color color) {
|
||||||
if(x>=0 && y>=0 && x<rect.Width && y<rect.Height) {
|
if(x>=0 && y>=0 && x<rect.Width && y<rect.Height) {
|
||||||
int offset = x*bytesPerPixel+y*stride;
|
int offset = x*bytesPerPixel+y*stride;
|
||||||
|
@ -302,10 +317,13 @@ namespace GreenshotPlugin.Core {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/// <summary>
|
||||||
* Retrieve the color at location x,y to a byte[]
|
/// Retrieve the color at location x,y to a byte[]
|
||||||
* Before the first time this is called the Lock() should be called once!
|
/// Before the first time this is called the Lock() should be called once!
|
||||||
*/
|
/// </summary>
|
||||||
|
/// <param name="x"></param>
|
||||||
|
/// <param name="y"></param>
|
||||||
|
/// <param name="color"></param>
|
||||||
public void GetUncheckedColorIn(int x, int y, byte[] color) {
|
public void GetUncheckedColorIn(int x, int y, byte[] color) {
|
||||||
int offset = x * bytesPerPixel + y * stride;
|
int offset = x * bytesPerPixel + y * stride;
|
||||||
color[0] = (aIndex == -1) ? (byte)255 : (byte)pointer[aIndex + offset];
|
color[0] = (aIndex == -1) ? (byte)255 : (byte)pointer[aIndex + offset];
|
||||||
|
@ -314,11 +332,14 @@ namespace GreenshotPlugin.Core {
|
||||||
color[3] = pointer[bIndex + offset];
|
color[3] = pointer[bIndex + offset];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/// <summary>
|
||||||
* Retrieve the color at location x,y to a byte[]
|
/// Retrieve the color at location x,y to a byte[]
|
||||||
* Before the first time this is called the Lock() should be called once!
|
/// Before the first time this is called the Lock() should be called once!
|
||||||
*/
|
/// </summary>
|
||||||
public void GetColorIn(int x, int y, byte[] color) {
|
/// <param name="x"></param>
|
||||||
|
/// <param name="y"></param>
|
||||||
|
/// <param name="color"></param>
|
||||||
|
public void GetColorAt(int x, int y, byte[] color) {
|
||||||
if (x >= 0 && y >= 0 && x < rect.Width && y < rect.Height) {
|
if (x >= 0 && y >= 0 && x < rect.Width && y < rect.Height) {
|
||||||
int offset = x * bytesPerPixel + y * stride;
|
int offset = x * bytesPerPixel + y * stride;
|
||||||
color[0] = (aIndex == -1) ? (byte)255 : (byte)pointer[aIndex + offset];
|
color[0] = (aIndex == -1) ? (byte)255 : (byte)pointer[aIndex + offset];
|
||||||
|
@ -333,11 +354,14 @@ namespace GreenshotPlugin.Core {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/// <summary>
|
||||||
* Set the color at location x,y as an array
|
/// Set the color at location x,y as an array
|
||||||
* Before the first time this is called the Lock() should be called once!
|
/// Before the first time this is called the Lock() should be called once!
|
||||||
*/
|
/// </summary>
|
||||||
public void SetColorArrayAt(int x, int y, byte[] colors) {
|
/// <param name="x"></param>
|
||||||
|
/// <param name="y"></param>
|
||||||
|
/// <param name="colors"></param>
|
||||||
|
public void SetColorAt(int x, int y, byte[] colors) {
|
||||||
if(x>=0 && y>=0 && x<rect.Width && y<rect.Height) {
|
if(x>=0 && y>=0 && x<rect.Width && y<rect.Height) {
|
||||||
int offset = x*bytesPerPixel+y*stride;
|
int offset = x*bytesPerPixel+y*stride;
|
||||||
if(aIndex!=-1) pointer[aIndex+offset] = (byte)colors[0];
|
if(aIndex!=-1) pointer[aIndex+offset] = (byte)colors[0];
|
||||||
|
@ -346,20 +370,10 @@ namespace GreenshotPlugin.Core {
|
||||||
pointer[bIndex+offset] = (byte)colors[3];
|
pointer[bIndex+offset] = (byte)colors[3];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* Set the color at location x,y as an array
|
/// <summary>
|
||||||
* Before the first time this is called the Lock() should be called once!
|
/// Set some internal values for accessing the bitmap according to the PixelFormat
|
||||||
*/
|
/// </summary>
|
||||||
public void SetUncheckedColorArrayAt(int x, int y, byte[] colors) {
|
|
||||||
int offset = x * bytesPerPixel + y * stride;
|
|
||||||
if (aIndex != -1) pointer[aIndex + offset] = (byte)colors[0];
|
|
||||||
pointer[rIndex + offset] = (byte)colors[1];
|
|
||||||
pointer[gIndex + offset] = (byte)colors[2];
|
|
||||||
pointer[bIndex + offset] = (byte)colors[3];
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Set some internal values for accessing the bitmap according to the PixelFormat
|
|
||||||
*/
|
|
||||||
private void PrepareForPixelFormat() {
|
private void PrepareForPixelFormat() {
|
||||||
// aIndex is only set if the pixel format supports "A".
|
// aIndex is only set if the pixel format supports "A".
|
||||||
aIndex = -1;
|
aIndex = -1;
|
||||||
|
|
|
@ -29,20 +29,79 @@ namespace GreenshotPlugin.Core {
|
||||||
/// The interface for the FastBitmap
|
/// The interface for the FastBitmap
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IFastBitmap : IDisposable {
|
public interface IFastBitmap : IDisposable {
|
||||||
|
/// <summary>
|
||||||
|
/// Get the color at x,y
|
||||||
|
/// The returned Color object depends on the underlying pixel format
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="x">int x</param>
|
||||||
|
/// <param name="y">int y</param>
|
||||||
|
/// <returns>Color</returns>
|
||||||
Color GetColorAt(int x, int y);
|
Color GetColorAt(int x, int y);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set the color at the specified location
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="x">int x</param>
|
||||||
|
/// <param name="y">int y</param>
|
||||||
|
/// <param name="color">Color</param>
|
||||||
void SetColorAt(int x, int y, Color color);
|
void SetColorAt(int x, int y, Color color);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the color at x,y
|
||||||
|
/// The returned byte[] color depends on the underlying pixel format
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="x">int x</param>
|
||||||
|
/// <param name="y">int y</par
|
||||||
|
void GetColorAt(int x, int y, byte[] color);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set the color at the specified location
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="x">int x</param>
|
||||||
|
/// <param name="y">int y</param>
|
||||||
|
/// <param name="color">byte[] color</param>
|
||||||
|
void SetColorAt(int x, int y, byte[] color);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Lock the bitmap
|
||||||
|
/// </summary>
|
||||||
void Lock();
|
void Lock();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Unlock the bitmap
|
||||||
|
/// </summary>
|
||||||
void Unlock();
|
void Unlock();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Unlock the bitmap and get the underlying bitmap in one call
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
Bitmap UnlockAndReturnBitmap();
|
Bitmap UnlockAndReturnBitmap();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Size of the underlying image
|
||||||
|
/// </summary>
|
||||||
Size Size {
|
Size Size {
|
||||||
get;
|
get;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Height of the underlying image
|
||||||
|
/// </summary>
|
||||||
int Height {
|
int Height {
|
||||||
get;
|
get;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Width of the underlying image
|
||||||
|
/// </summary>
|
||||||
int Width {
|
int Width {
|
||||||
get;
|
get;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Does the underlying image need to be disposed
|
||||||
|
/// </summary>
|
||||||
bool NeedsDispose {
|
bool NeedsDispose {
|
||||||
get;
|
get;
|
||||||
set;
|
set;
|
||||||
|
@ -55,6 +114,10 @@ namespace GreenshotPlugin.Core {
|
||||||
public unsafe abstract class FastBitmap : IFastBitmap {
|
public unsafe abstract class FastBitmap : IFastBitmap {
|
||||||
private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(FastBitmap));
|
private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(FastBitmap));
|
||||||
|
|
||||||
|
protected const int AINDEX = 3;
|
||||||
|
protected const int RINDEX = 2;
|
||||||
|
protected const int GINDEX = 1;
|
||||||
|
protected const int BINDEX = 0;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// If this is set to true, the bitmap will be disposed when disposing the IFastBitmap
|
/// If this is set to true, the bitmap will be disposed when disposing the IFastBitmap
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -86,6 +149,7 @@ namespace GreenshotPlugin.Core {
|
||||||
case PixelFormat.Format32bppRgb:
|
case PixelFormat.Format32bppRgb:
|
||||||
return new Fast32RGBBitmap(source);
|
return new Fast32RGBBitmap(source);
|
||||||
case PixelFormat.Format32bppArgb:
|
case PixelFormat.Format32bppArgb:
|
||||||
|
case PixelFormat.Format32bppPArgb:
|
||||||
return new Fast32ARGBBitmap(source);
|
return new Fast32ARGBBitmap(source);
|
||||||
default:
|
default:
|
||||||
throw new NotSupportedException(string.Format("Not supported Pixelformat {0}", source.PixelFormat));
|
throw new NotSupportedException(string.Format("Not supported Pixelformat {0}", source.PixelFormat));
|
||||||
|
@ -97,7 +161,7 @@ namespace GreenshotPlugin.Core {
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="source">Bitmap to access</param>
|
/// <param name="source">Bitmap to access</param>
|
||||||
/// <returns>IFastBitmap</returns>
|
/// <returns>IFastBitmap</returns>
|
||||||
public static IFastBitmap CreateDestinationFor(Bitmap source, PixelFormat pixelFormat) {
|
public static IFastBitmap CreateCloneOf(Image source, PixelFormat pixelFormat) {
|
||||||
Bitmap destination = ImageHelper.CloneArea(source, Rectangle.Empty, pixelFormat);
|
Bitmap destination = ImageHelper.CloneArea(source, Rectangle.Empty, pixelFormat);
|
||||||
IFastBitmap fastBitmap = Create(destination);
|
IFastBitmap fastBitmap = Create(destination);
|
||||||
((FastBitmap)fastBitmap).NeedsDispose = true;
|
((FastBitmap)fastBitmap).NeedsDispose = true;
|
||||||
|
@ -119,8 +183,13 @@ namespace GreenshotPlugin.Core {
|
||||||
return fastBitmap;
|
return fastBitmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constructor which stores the image and locks it when called
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="bitmap"></param>
|
||||||
protected FastBitmap(Bitmap bitmap) {
|
protected FastBitmap(Bitmap bitmap) {
|
||||||
this.bitmap = bitmap;
|
this.bitmap = bitmap;
|
||||||
|
Lock();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -272,8 +341,13 @@ namespace GreenshotPlugin.Core {
|
||||||
|
|
||||||
public abstract Color GetColorAt(int x, int y);
|
public abstract Color GetColorAt(int x, int y);
|
||||||
public abstract void SetColorAt(int x, int y, Color color);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This is the implementation of the FastBitmat for the 8BPP pixelformat
|
||||||
|
/// </summary>
|
||||||
public unsafe class FastChunkyBitmap : FastBitmap {
|
public unsafe class FastChunkyBitmap : FastBitmap {
|
||||||
// Used for indexed images
|
// Used for indexed images
|
||||||
private Color[] colorEntries;
|
private Color[] colorEntries;
|
||||||
|
@ -295,6 +369,26 @@ namespace GreenshotPlugin.Core {
|
||||||
return colorEntries[colorIndex];
|
return colorEntries[colorIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the color from the specified location into the specified array
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="x"></param>
|
||||||
|
/// <param name="y"></param>
|
||||||
|
/// <param name="color">byte[4] as reference</param>
|
||||||
|
public override void GetColorAt(int x, int y, byte[] color) {
|
||||||
|
throw new NotImplementedException("No performance gain!");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set the color at the specified location from the specified array
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="x"></param>
|
||||||
|
/// <param name="y"></param>
|
||||||
|
/// <param name="color">byte[4] as reference</param>
|
||||||
|
public override void SetColorAt(int x, int y, byte[] color) {
|
||||||
|
throw new NotImplementedException("No performance gain!");
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get the color-index from the specified location
|
/// Get the color-index from the specified location
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -361,7 +455,7 @@ namespace GreenshotPlugin.Core {
|
||||||
/// <returns>Color</returns>
|
/// <returns>Color</returns>
|
||||||
public override Color GetColorAt(int x, int y) {
|
public override Color GetColorAt(int x, int y) {
|
||||||
int offset = (x * 3) + (y * stride);
|
int offset = (x * 3) + (y * stride);
|
||||||
return Color.FromArgb(255, pointer[2 + offset], pointer[1 + offset], pointer[offset]);
|
return Color.FromArgb(255, pointer[RINDEX + offset], pointer[GINDEX + offset], pointer[BINDEX + offset]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -373,10 +467,38 @@ namespace GreenshotPlugin.Core {
|
||||||
/// <param name="color"></param>
|
/// <param name="color"></param>
|
||||||
public override void SetColorAt(int x, int y, Color color) {
|
public override void SetColorAt(int x, int y, Color color) {
|
||||||
int offset = (x * 3) + (y * stride);
|
int offset = (x * 3) + (y * stride);
|
||||||
pointer[2 + offset] = color.R;
|
pointer[RINDEX + offset] = color.R;
|
||||||
pointer[1 + offset] = color.G;
|
pointer[GINDEX + offset] = color.G;
|
||||||
pointer[offset] = color.B;
|
pointer[BINDEX + offset] = color.B;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the color from the specified location into the specified array
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="x"></param>
|
||||||
|
/// <param name="y"></param>
|
||||||
|
/// <param name="color">byte[4] as reference (a,r,g,b)</param>
|
||||||
|
public override void GetColorAt(int x, int y, byte[] color) {
|
||||||
|
int offset = (x * 3) + (y * stride);
|
||||||
|
color[0] = 255;
|
||||||
|
color[1] = pointer[RINDEX + offset];
|
||||||
|
color[2] = pointer[GINDEX + offset];
|
||||||
|
color[3] = pointer[BINDEX + offset];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set the color at the specified location from the specified array
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="x"></param>
|
||||||
|
/// <param name="y"></param>
|
||||||
|
/// <param name="color">byte[4] as reference (a,r,g,b)</param>
|
||||||
|
public override void SetColorAt(int x, int y, byte[] color) {
|
||||||
|
int offset = (x * 3) + (y * stride);
|
||||||
|
pointer[RINDEX + offset] = color[1];
|
||||||
|
pointer[GINDEX + offset] = color[2];
|
||||||
|
pointer[BINDEX + offset] = color[3];
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -396,7 +518,7 @@ namespace GreenshotPlugin.Core {
|
||||||
/// <returns>Color</returns>
|
/// <returns>Color</returns>
|
||||||
public override Color GetColorAt(int x, int y) {
|
public override Color GetColorAt(int x, int y) {
|
||||||
int offset = (x * 4) + (y * stride);
|
int offset = (x * 4) + (y * stride);
|
||||||
return Color.FromArgb(255, pointer[2 + offset], pointer[1 + offset], pointer[offset]);
|
return Color.FromArgb(255, pointer[RINDEX + offset], pointer[GINDEX + offset], pointer[BINDEX + offset]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -408,9 +530,36 @@ namespace GreenshotPlugin.Core {
|
||||||
/// <param name="color"></param>
|
/// <param name="color"></param>
|
||||||
public override void SetColorAt(int x, int y, Color color) {
|
public override void SetColorAt(int x, int y, Color color) {
|
||||||
int offset = (x * 4) + (y * stride);
|
int offset = (x * 4) + (y * stride);
|
||||||
pointer[2 + offset] = color.R;
|
pointer[RINDEX + offset] = color.R;
|
||||||
pointer[1 + offset] = color.G;
|
pointer[GINDEX + offset] = color.G;
|
||||||
pointer[offset] = color.B;
|
pointer[BINDEX + offset] = color.B;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the color from the specified location into the specified array
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="x"></param>
|
||||||
|
/// <param name="y"></param>
|
||||||
|
/// <param name="color">byte[4] as reference (a,r,g,b)</param>
|
||||||
|
public override void GetColorAt(int x, int y, byte[] color) {
|
||||||
|
int offset = (x * 4) + (y * stride);
|
||||||
|
color[0] = 255;
|
||||||
|
color[1] = pointer[RINDEX + offset];
|
||||||
|
color[2] = pointer[GINDEX + offset];
|
||||||
|
color[3] = pointer[BINDEX + offset];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set the color at the specified location from the specified array
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="x"></param>
|
||||||
|
/// <param name="y"></param>
|
||||||
|
/// <param name="color">byte[4] as reference (a,r,g,b)</param>
|
||||||
|
public override void SetColorAt(int x, int y, byte[] color) {
|
||||||
|
int offset = (x * 4) + (y * stride);
|
||||||
|
pointer[RINDEX + offset] = color[1]; // R
|
||||||
|
pointer[GINDEX + offset] = color[2];
|
||||||
|
pointer[BINDEX + offset] = color[3];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -434,7 +583,7 @@ namespace GreenshotPlugin.Core {
|
||||||
/// <returns>Color</returns>
|
/// <returns>Color</returns>
|
||||||
public override Color GetColorAt(int x, int y) {
|
public override Color GetColorAt(int x, int y) {
|
||||||
int offset = (x * 4) + (y * stride);
|
int offset = (x * 4) + (y * stride);
|
||||||
return Color.FromArgb(pointer[3 + offset], pointer[2 + offset], pointer[1 + offset], pointer[offset]);
|
return Color.FromArgb(pointer[AINDEX + offset], pointer[RINDEX + offset], pointer[GINDEX + offset], pointer[BINDEX + offset]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -446,10 +595,38 @@ namespace GreenshotPlugin.Core {
|
||||||
/// <param name="color"></param>
|
/// <param name="color"></param>
|
||||||
public override void SetColorAt(int x, int y, Color color) {
|
public override void SetColorAt(int x, int y, Color color) {
|
||||||
int offset = (x * 4) + (y * stride);
|
int offset = (x * 4) + (y * stride);
|
||||||
pointer[3 + offset] = color.A;
|
pointer[AINDEX + offset] = color.A;
|
||||||
pointer[2 + offset] = color.R;
|
pointer[RINDEX + offset] = color.R;
|
||||||
pointer[1 + offset] = color.G;
|
pointer[GINDEX + offset] = color.G;
|
||||||
pointer[offset] = color.B;
|
pointer[BINDEX + offset] = color.B;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the color from the specified location into the specified array
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="x"></param>
|
||||||
|
/// <param name="y"></param>
|
||||||
|
/// <param name="color">byte[4] as reference (a,r,g,b)</param>
|
||||||
|
public override void GetColorAt(int x, int y, byte[] color) {
|
||||||
|
int offset = (x * 4) + (y * stride);
|
||||||
|
color[0] = pointer[AINDEX + offset];
|
||||||
|
color[1] = pointer[RINDEX + offset];
|
||||||
|
color[2] = pointer[GINDEX + offset];
|
||||||
|
color[3] = pointer[BINDEX + offset];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set the color at the specified location from the specified array
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="x"></param>
|
||||||
|
/// <param name="y"></param>
|
||||||
|
/// <param name="color">byte[4] as reference (a,r,g,b)</param>
|
||||||
|
public override void SetColorAt(int x, int y, byte[] color) {
|
||||||
|
int offset = (x * 4) + (y * stride);
|
||||||
|
pointer[AINDEX + offset] = color[0];
|
||||||
|
pointer[RINDEX + offset] = color[1]; // R
|
||||||
|
pointer[GINDEX + offset] = color[2];
|
||||||
|
pointer[BINDEX + offset] = color[3];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -459,12 +636,12 @@ namespace GreenshotPlugin.Core {
|
||||||
/// <param name="x">X coordinate</param>
|
/// <param name="x">X coordinate</param>
|
||||||
/// <param name="y">Y Coordinate</param>
|
/// <param name="y">Y Coordinate</param>
|
||||||
/// <returns>Color</returns>
|
/// <returns>Color</returns>
|
||||||
public Color GetColorAtWithoutAlpha(int x, int y) {
|
public Color GetBlendedColorAt(int x, int y) {
|
||||||
int offset = (x * 4) + (y * stride);
|
int offset = (x * 4) + (y * stride);
|
||||||
int a = pointer[3 + offset];
|
int a = pointer[AINDEX + offset];
|
||||||
int red = pointer[2 + offset];
|
int red = pointer[RINDEX + offset];
|
||||||
int green = pointer[1 + offset];
|
int green = pointer[GINDEX + offset];
|
||||||
int blue = pointer[offset];
|
int blue = pointer[BINDEX + offset];
|
||||||
|
|
||||||
if (a < 255) {
|
if (a < 255) {
|
||||||
// As the request is to get without alpha, we blend.
|
// As the request is to get without alpha, we blend.
|
||||||
|
|
|
@ -487,10 +487,12 @@ namespace GreenshotPlugin.Core {
|
||||||
byte[] settingColor = new byte[4];
|
byte[] settingColor = new byte[4];
|
||||||
byte[] readingColor = new byte[4];
|
byte[] readingColor = new byte[4];
|
||||||
|
|
||||||
using (BitmapBuffer bbbDest = new BitmapBuffer(sourceBitmap, applyRect, true)) {
|
using (BitmapBuffer dst = new BitmapBuffer(sourceBitmap, applyRect, true)) {
|
||||||
bbbDest.Lock();
|
//using (IFastBitmap dst = FastBitmap.CreateEmpty(sourceBitmap.Size, sourceBitmap.PixelFormat, Color.Empty)) {
|
||||||
using (BitmapBuffer bbbSrc = new BitmapBuffer(sourceBitmap, applyRect, false)) {
|
dst.Lock();
|
||||||
bbbSrc.Lock();
|
using (BitmapBuffer src = new BitmapBuffer(sourceBitmap, applyRect, false)) {
|
||||||
|
//using (IFastBitmap src = FastBitmap.Create(sourceBitmap)) {
|
||||||
|
src.Lock();
|
||||||
Random rand = new Random();
|
Random rand = new Random();
|
||||||
unchecked {
|
unchecked {
|
||||||
int r = blurRadius;
|
int r = blurRadius;
|
||||||
|
@ -519,12 +521,12 @@ namespace GreenshotPlugin.Core {
|
||||||
gSums[wx] = 0;
|
gSums[wx] = 0;
|
||||||
bSums[wx] = 0;
|
bSums[wx] = 0;
|
||||||
|
|
||||||
if (srcX >= 0 && srcX < bbbDest.Width) {
|
if (srcX >= 0 && srcX < src.Width) {
|
||||||
for (int wy = 0; wy < wlen; ++wy) {
|
for (int wy = 0; wy < wlen; ++wy) {
|
||||||
int srcY = y + wy - r;
|
int srcY = y + wy - r;
|
||||||
|
|
||||||
if (srcY >= 0 && srcY < bbbDest.Height) {
|
if (srcY >= 0 && srcY < src.Height) {
|
||||||
bbbSrc.GetColorIn(srcX, srcY, readingColor);
|
src.GetColorAt(srcX, srcY, readingColor);
|
||||||
int wp = w[wy];
|
int wp = w[wy];
|
||||||
|
|
||||||
waSums[wx] += wp;
|
waSums[wx] += wp;
|
||||||
|
@ -553,13 +555,13 @@ namespace GreenshotPlugin.Core {
|
||||||
|
|
||||||
if (parentBounds.Contains(applyRect.Left, applyRect.Top + y) ^ invert) {
|
if (parentBounds.Contains(applyRect.Left, applyRect.Top + y) ^ invert) {
|
||||||
if (waSum == 0 || wcSum == 0) {
|
if (waSum == 0 || wcSum == 0) {
|
||||||
bbbDest.SetUncheckedColorArrayAt(0, y, nullColor);
|
dst.SetColorAt(0, y, nullColor);
|
||||||
} else {
|
} else {
|
||||||
settingColor[0] = (byte)(aSum / waSum);
|
settingColor[0] = (byte)(aSum / waSum);
|
||||||
settingColor[1] = (byte)(rSum / wcSum);
|
settingColor[1] = (byte)(rSum / wcSum);
|
||||||
settingColor[2] = (byte)(gSum / wcSum);
|
settingColor[2] = (byte)(gSum / wcSum);
|
||||||
settingColor[3] = (byte)(bSum / wcSum);
|
settingColor[3] = (byte)(bSum / wcSum);
|
||||||
bbbDest.SetUncheckedColorArrayAt(0, y, settingColor);
|
dst.SetColorAt(0, y, settingColor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -609,7 +611,7 @@ namespace GreenshotPlugin.Core {
|
||||||
if ((useExportQuality || rand.NextDouble() < previewQuality) && srcY >= 0 && srcY < applyRect.Height) {
|
if ((useExportQuality || rand.NextDouble() < previewQuality) && srcY >= 0 && srcY < applyRect.Height) {
|
||||||
int wp = w[wy];
|
int wp = w[wy];
|
||||||
waSums[wx] += wp;
|
waSums[wx] += wp;
|
||||||
bbbSrc.GetColorIn(srcX, srcY, readingColor);
|
src.GetColorAt(srcX, srcY, readingColor);
|
||||||
wp *= readingColor[0] + (readingColor[0] >> 7);
|
wp *= readingColor[0] + (readingColor[0] >> 7);
|
||||||
wcSums[wx] += wp;
|
wcSums[wx] += wp;
|
||||||
wp >>= 8;
|
wp >>= 8;
|
||||||
|
@ -633,21 +635,20 @@ namespace GreenshotPlugin.Core {
|
||||||
wcSum >>= 8;
|
wcSum >>= 8;
|
||||||
if (parentBounds.Contains(applyRect.Left + x, applyRect.Top + y) ^ invert) {
|
if (parentBounds.Contains(applyRect.Left + x, applyRect.Top + y) ^ invert) {
|
||||||
if (waSum == 0 || wcSum == 0) {
|
if (waSum == 0 || wcSum == 0) {
|
||||||
bbbDest.SetUncheckedColorArrayAt(x, y, nullColor);
|
dst.SetColorAt(x, y, nullColor);
|
||||||
} else {
|
} else {
|
||||||
settingColor[0] = (byte)(aSum / waSum);
|
settingColor[0] = (byte)(aSum / waSum);
|
||||||
settingColor[1] = (byte)(rSum / wcSum);
|
settingColor[1] = (byte)(rSum / wcSum);
|
||||||
settingColor[2] = (byte)(gSum / wcSum);
|
settingColor[2] = (byte)(gSum / wcSum);
|
||||||
settingColor[3] = (byte)(bSum / wcSum);
|
settingColor[3] = (byte)(bSum / wcSum);
|
||||||
bbbDest.SetUncheckedColorArrayAt(x, y, settingColor);
|
dst.SetColorAt(x, y, settingColor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bbbDest.Unlock();
|
return dst.UnlockAndReturnBitmap();
|
||||||
return bbbDest.Bitmap;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -659,17 +660,15 @@ namespace GreenshotPlugin.Core {
|
||||||
/// <returns>Bitmap</returns>
|
/// <returns>Bitmap</returns>
|
||||||
public static Bitmap BoxBlur(Bitmap sourceBitmap, int range) {
|
public static Bitmap BoxBlur(Bitmap sourceBitmap, int range) {
|
||||||
if ((range & 1) == 0) {
|
if ((range & 1) == 0) {
|
||||||
throw new InvalidOperationException("Range must be odd!");
|
range++;
|
||||||
|
//throw new InvalidOperationException("Range must be odd!");
|
||||||
}
|
}
|
||||||
using (BitmapBuffer bbbDest = new BitmapBuffer(sourceBitmap, true)) {
|
using (IFastBitmap bbbDest = FastBitmap.CreateCloneOf(sourceBitmap, PixelFormat.Format32bppArgb)) {
|
||||||
bbbDest.Lock();
|
BoxBlurHorizontal(bbbDest, range);
|
||||||
using (BitmapBuffer bbbSrc = new BitmapBuffer(sourceBitmap, false)) {
|
|
||||||
bbbSrc.Lock();
|
|
||||||
BoxBlurHorizontal(bbbSrc, bbbDest, range);
|
|
||||||
}
|
|
||||||
BoxBlurVertical(bbbDest, range);
|
BoxBlurVertical(bbbDest, range);
|
||||||
bbbDest.Unlock();
|
BoxBlurHorizontal(bbbDest, range + 1);
|
||||||
return bbbDest.Bitmap;
|
BoxBlurVertical(bbbDest, range + 1);
|
||||||
|
return bbbDest.UnlockAndReturnBitmap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -679,11 +678,11 @@ namespace GreenshotPlugin.Core {
|
||||||
/// <param name="bbbSrc">Source BitmapBuffer</param>
|
/// <param name="bbbSrc">Source BitmapBuffer</param>
|
||||||
/// <param name="bbbDest">Target BitmapBuffer</param>
|
/// <param name="bbbDest">Target BitmapBuffer</param>
|
||||||
/// <param name="range">Range must be odd!</param>
|
/// <param name="range">Range must be odd!</param>
|
||||||
private static void BoxBlurHorizontal(BitmapBuffer bbbSrc, BitmapBuffer bbbDest, int range) {
|
private static void BoxBlurHorizontal(IFastBitmap bbbDest, int range) {
|
||||||
int w = bbbSrc.Width;
|
int w = bbbDest.Width;
|
||||||
int h = bbbSrc.Height;
|
int h = bbbDest.Height;
|
||||||
int halfRange = range / 2;
|
int halfRange = range / 2;
|
||||||
int[] newColors = new int[w];
|
Color[] newColors = new Color[w];
|
||||||
byte[] tmpColor = new byte[4];
|
byte[] tmpColor = new byte[4];
|
||||||
for (int y = 0; y < h; y++) {
|
for (int y = 0; y < h; y++) {
|
||||||
int hits = 0;
|
int hits = 0;
|
||||||
|
@ -694,7 +693,7 @@ namespace GreenshotPlugin.Core {
|
||||||
for (int x = -halfRange; x < w; x++) {
|
for (int x = -halfRange; x < w; x++) {
|
||||||
int oldPixel = x - halfRange - 1;
|
int oldPixel = x - halfRange - 1;
|
||||||
if (oldPixel >= 0) {
|
if (oldPixel >= 0) {
|
||||||
bbbSrc.GetUncheckedColorIn(oldPixel, y, tmpColor);
|
bbbDest.GetColorAt(oldPixel, y, tmpColor);
|
||||||
a -= tmpColor[0];
|
a -= tmpColor[0];
|
||||||
r -= tmpColor[1];
|
r -= tmpColor[1];
|
||||||
g -= tmpColor[2];
|
g -= tmpColor[2];
|
||||||
|
@ -704,7 +703,7 @@ namespace GreenshotPlugin.Core {
|
||||||
|
|
||||||
int newPixel = x + halfRange;
|
int newPixel = x + halfRange;
|
||||||
if (newPixel < w) {
|
if (newPixel < w) {
|
||||||
bbbSrc.GetUncheckedColorIn(newPixel, y, tmpColor);
|
bbbDest.GetColorAt(newPixel, y, tmpColor);
|
||||||
a += tmpColor[0];
|
a += tmpColor[0];
|
||||||
r += tmpColor[1];
|
r += tmpColor[1];
|
||||||
g += tmpColor[2];
|
g += tmpColor[2];
|
||||||
|
@ -713,11 +712,11 @@ namespace GreenshotPlugin.Core {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (x >= 0) {
|
if (x >= 0) {
|
||||||
newColors[x] = ((byte)(a / hits)) << 24 | ((byte)(r / hits) << 16) | ((byte)(g / hits) << 8 ) | ((byte)(b / hits));
|
newColors[x] = Color.FromArgb((byte)(a / hits), (byte)(r / hits), (byte)(g / hits), (byte)(b / hits));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int x = 0; x < w; x++) {
|
for (int x = 0; x < w; x++) {
|
||||||
bbbDest.SetARGB(x, y, newColors[x]);
|
bbbDest.SetColorAt(x, y, newColors[x]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -727,11 +726,11 @@ namespace GreenshotPlugin.Core {
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="bbbDest">BitmapBuffer which previously was created with BoxBlurHorizontal</param>
|
/// <param name="bbbDest">BitmapBuffer which previously was created with BoxBlurHorizontal</param>
|
||||||
/// <param name="range">Range must be odd!</param>
|
/// <param name="range">Range must be odd!</param>
|
||||||
private static void BoxBlurVertical(BitmapBuffer bbbDest, int range) {
|
private static void BoxBlurVertical(IFastBitmap bbbDest, int range) {
|
||||||
int w = bbbDest.Width;
|
int w = bbbDest.Width;
|
||||||
int h = bbbDest.Height;
|
int h = bbbDest.Height;
|
||||||
int halfRange = range / 2;
|
int halfRange = range / 2;
|
||||||
int[] newColors = new int[h];
|
Color[] newColors = new Color[h];
|
||||||
int oldPixelOffset = -(halfRange + 1) * w;
|
int oldPixelOffset = -(halfRange + 1) * w;
|
||||||
int newPixelOffset = (halfRange) * w;
|
int newPixelOffset = (halfRange) * w;
|
||||||
byte[] tmpColor = new byte[4];
|
byte[] tmpColor = new byte[4];
|
||||||
|
@ -745,7 +744,7 @@ namespace GreenshotPlugin.Core {
|
||||||
int oldPixel = y - halfRange - 1;
|
int oldPixel = y - halfRange - 1;
|
||||||
if (oldPixel >= 0) {
|
if (oldPixel >= 0) {
|
||||||
//int colorg = pixels[index + oldPixelOffset];
|
//int colorg = pixels[index + oldPixelOffset];
|
||||||
bbbDest.GetUncheckedColorIn(x, oldPixel, tmpColor);
|
bbbDest.GetColorAt(x, oldPixel, tmpColor);
|
||||||
a -= tmpColor[0];
|
a -= tmpColor[0];
|
||||||
r -= tmpColor[1];
|
r -= tmpColor[1];
|
||||||
g -= tmpColor[2];
|
g -= tmpColor[2];
|
||||||
|
@ -756,7 +755,7 @@ namespace GreenshotPlugin.Core {
|
||||||
int newPixel = y + halfRange;
|
int newPixel = y + halfRange;
|
||||||
if (newPixel < h) {
|
if (newPixel < h) {
|
||||||
//int colorg = pixels[index + newPixelOffset];
|
//int colorg = pixels[index + newPixelOffset];
|
||||||
bbbDest.GetUncheckedColorIn(x, newPixel, tmpColor);
|
bbbDest.GetColorAt(x, newPixel, tmpColor);
|
||||||
a += tmpColor[0];
|
a += tmpColor[0];
|
||||||
r += tmpColor[1];
|
r += tmpColor[1];
|
||||||
g += tmpColor[2];
|
g += tmpColor[2];
|
||||||
|
@ -765,121 +764,26 @@ namespace GreenshotPlugin.Core {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (y >= 0) {
|
if (y >= 0) {
|
||||||
newColors[y] = ((byte)(a / hits)) << 24 | ((byte)(r / hits) << 16) | ((byte)(g / hits) << 8) | ((byte)(b / hits));
|
newColors[y] = Color.FromArgb((byte)(a / hits), (byte)(r / hits), (byte)(g / hits), (byte)(b / hits));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int y = 0; y < h; y++) {
|
for (int y = 0; y < h; y++) {
|
||||||
bbbDest.SetARGB(x, y, newColors[y]);
|
bbbDest.SetColorAt(x, y, newColors[y]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Bitmap FastBlur(Bitmap sourceBitmap, int radius) {
|
|
||||||
if (radius < 1) return null;
|
|
||||||
|
|
||||||
var rct = new Rectangle(0, 0, sourceBitmap.Width, sourceBitmap.Height);
|
|
||||||
var dest = new int[rct.Width * rct.Height];
|
|
||||||
var source = new int[rct.Width * rct.Height];
|
|
||||||
var bits = sourceBitmap.LockBits(rct, ImageLockMode.ReadWrite, sourceBitmap.PixelFormat);
|
|
||||||
Marshal.Copy(bits.Scan0, source, 0, source.Length);
|
|
||||||
sourceBitmap.UnlockBits(bits);
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
int w = rct.Width;
|
/// This method fixes the problem that we can't apply a filter outside the target bitmap,
|
||||||
int h = rct.Height;
|
/// therefor the filtered-bitmap will be shifted if we try to draw it outside the target bitmap.
|
||||||
int wm = w - 1;
|
/// It will also account for the Invert flag.
|
||||||
int hm = h - 1;
|
/// </summary>
|
||||||
int wh = w * h;
|
/// <param name="applySize"></param>
|
||||||
int div = radius + radius + 1;
|
/// <param name="rect"></param>
|
||||||
var r = new int[wh];
|
/// <param name="invert"></param>
|
||||||
var g = new int[wh];
|
/// <returns></returns>
|
||||||
var b = new int[wh];
|
|
||||||
int rsum, gsum, bsum, x, y, i, p1, p2, yi;
|
|
||||||
var vmin = new int[max(w, h)];
|
|
||||||
var vmax = new int[max(w, h)];
|
|
||||||
|
|
||||||
var dv = new int[256 * div];
|
|
||||||
for (i = 0; i < 256 * div; i++) {
|
|
||||||
dv[i] = (i / div);
|
|
||||||
}
|
|
||||||
|
|
||||||
int yw = yi = 0;
|
|
||||||
|
|
||||||
for (y = 0; y < h; y++) { // blur horizontal
|
|
||||||
rsum = gsum = bsum = 0;
|
|
||||||
for (i = -radius; i <= radius; i++) {
|
|
||||||
int p = source[yi + min(wm, max(i, 0))];
|
|
||||||
rsum += (p & 0xff0000) >> 16;
|
|
||||||
gsum += (p & 0x00ff00) >> 8;
|
|
||||||
bsum += p & 0x0000ff;
|
|
||||||
}
|
|
||||||
for (x = 0; x < w; x++) {
|
|
||||||
|
|
||||||
r[yi] = dv[rsum];
|
|
||||||
g[yi] = dv[gsum];
|
|
||||||
b[yi] = dv[bsum];
|
|
||||||
|
|
||||||
if (y == 0) {
|
|
||||||
vmin[x] = min(x + radius + 1, wm);
|
|
||||||
vmax[x] = max(x - radius, 0);
|
|
||||||
}
|
|
||||||
p1 = source[yw + vmin[x]];
|
|
||||||
p2 = source[yw + vmax[x]];
|
|
||||||
|
|
||||||
rsum += ((p1 & 0xff0000) - (p2 & 0xff0000)) >> 16;
|
|
||||||
gsum += ((p1 & 0x00ff00) - (p2 & 0x00ff00)) >> 8;
|
|
||||||
bsum += (p1 & 0x0000ff) - (p2 & 0x0000ff);
|
|
||||||
yi++;
|
|
||||||
}
|
|
||||||
yw += w;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (x = 0; x < w; x++) { // blur vertical
|
|
||||||
rsum = gsum = bsum = 0;
|
|
||||||
int yp = -radius * w;
|
|
||||||
for (i = -radius; i <= radius; i++) {
|
|
||||||
yi = max(0, yp) + x;
|
|
||||||
rsum += r[yi];
|
|
||||||
gsum += g[yi];
|
|
||||||
bsum += b[yi];
|
|
||||||
yp += w;
|
|
||||||
}
|
|
||||||
yi = x;
|
|
||||||
for (y = 0; y < h; y++) {
|
|
||||||
dest[yi] = unchecked((int)(0xff000000u | (uint)(dv[rsum] << 16) | (uint)(dv[gsum] << 8) | (uint)dv[bsum]));
|
|
||||||
if (x == 0) {
|
|
||||||
vmin[y] = min(y + radius + 1, hm) * w;
|
|
||||||
vmax[y] = max(y - radius, 0) * w;
|
|
||||||
}
|
|
||||||
p1 = x + vmin[y];
|
|
||||||
p2 = x + vmax[y];
|
|
||||||
|
|
||||||
rsum += r[p1] - r[p2];
|
|
||||||
gsum += g[p1] - g[p2];
|
|
||||||
bsum += b[p1] - b[p2];
|
|
||||||
|
|
||||||
yi += w;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// copy back to image
|
|
||||||
Bitmap newImage = CreateEmptyLike(sourceBitmap, Color.Empty);
|
|
||||||
var bits2 = newImage.LockBits(rct, ImageLockMode.ReadWrite, newImage.PixelFormat);
|
|
||||||
Marshal.Copy(dest, 0, bits2.Scan0, dest.Length);
|
|
||||||
newImage.UnlockBits(bits);
|
|
||||||
return newImage;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int min(int a, int b) { return Math.Min(a, b); }
|
|
||||||
private static int max(int a, int b) { return Math.Max(a, b); }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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) {
|
public static Rectangle CreateIntersectRectangle(Size applySize, Rectangle rect, bool invert) {
|
||||||
Rectangle myRect;
|
Rectangle myRect;
|
||||||
if (invert) {
|
if (invert) {
|
||||||
|
@ -927,10 +831,16 @@ namespace GreenshotPlugin.Core {
|
||||||
graphics.DrawImage(sourceBitmap, shadowRectangle, 0, 0, sourceBitmap.Width, sourceBitmap.Height, GraphicsUnit.Pixel, ia);
|
graphics.DrawImage(sourceBitmap, shadowRectangle, 0, 0, sourceBitmap.Width, sourceBitmap.Height, GraphicsUnit.Pixel, ia);
|
||||||
}
|
}
|
||||||
// blur "shadow", apply to whole new image
|
// blur "shadow", apply to whole new image
|
||||||
Rectangle newImageRectangle = new Rectangle(0, 0, tmpImage.Width, tmpImage.Height);
|
|
||||||
//using (Bitmap blurImage = FastBlur(newImage, shadowSize-1)) {
|
//using (Bitmap blurImage = FastBlur(newImage, shadowSize-1)) {
|
||||||
|
|
||||||
|
// Gaussian
|
||||||
|
Rectangle newImageRectangle = new Rectangle(0, 0, tmpImage.Width, tmpImage.Height);
|
||||||
returnImage = CreateBlur(tmpImage, newImageRectangle, true, shadowSize, 1d, false, newImageRectangle);
|
returnImage = CreateBlur(tmpImage, newImageRectangle, true, shadowSize, 1d, false, newImageRectangle);
|
||||||
|
|
||||||
|
// Box
|
||||||
//returnImage = BoxBlur(tmpImage, shadowSize);
|
//returnImage = BoxBlur(tmpImage, shadowSize);
|
||||||
|
|
||||||
|
//returnImage = FastBlur(tmpImage, shadowSize - 1);
|
||||||
}
|
}
|
||||||
if (returnImage != null) {
|
if (returnImage != null) {
|
||||||
using (Graphics graphics = Graphics.FromImage(returnImage)) {
|
using (Graphics graphics = Graphics.FromImage(returnImage)) {
|
||||||
|
@ -976,18 +886,17 @@ namespace GreenshotPlugin.Core {
|
||||||
/// <param name="sourceImage">Bitmap to create a b/w off</param>
|
/// <param name="sourceImage">Bitmap to create a b/w off</param>
|
||||||
/// <returns>b/w bitmap</returns>
|
/// <returns>b/w bitmap</returns>
|
||||||
public static Bitmap CreateMonochrome(Image sourceImage) {
|
public static Bitmap CreateMonochrome(Image sourceImage) {
|
||||||
using (BitmapBuffer bb = new BitmapBuffer(sourceImage, true)) {
|
using (IFastBitmap fastBitmap = FastBitmap.CreateCloneOf(sourceImage, sourceImage.PixelFormat)) {
|
||||||
bb.Lock();
|
fastBitmap.Lock();
|
||||||
for (int y = 0; y < bb.Height; y++) {
|
for (int y = 0; y < fastBitmap.Height; y++) {
|
||||||
for (int x = 0; x < bb.Width; x++) {
|
for (int x = 0; x < fastBitmap.Width; x++) {
|
||||||
Color color = bb.GetColorAt(x, y);
|
Color color = fastBitmap.GetColorAt(x, y);
|
||||||
int colorBrightness = (color.R+color.G+color.B > 382) ? 255 : 0;
|
int colorBrightness = (color.R + color.G + color.B > 382) ? 255 : 0;
|
||||||
Color monoColor = Color.FromArgb(color.A, colorBrightness, colorBrightness, colorBrightness);
|
Color monoColor = Color.FromArgb(color.A, colorBrightness, colorBrightness, colorBrightness);
|
||||||
bb.SetColorAt(x, y, monoColor);
|
fastBitmap.SetColorAt(x, y, monoColor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bb.Unlock();
|
return fastBitmap.UnlockAndReturnBitmap();
|
||||||
return bb.Bitmap;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue