mirror of
https://github.com/greenshot/greenshot
synced 2025-07-15 01:23:47 -07:00
Optimizing: Replaced BitmapBuffer with FastBitmap, also changed some filters to use more GDI "hardware" instead of home-made pixel processing. Only on Windows 8 the blur is "slow", when radius < 20.
git-svn-id: http://svn.code.sf.net/p/greenshot/code/trunk@2531 7dccd23d-a4a3-4e1f-8c07-b4c1b4018ab4
This commit is contained in:
parent
ea20ead07e
commit
5018f67ff7
12 changed files with 481 additions and 814 deletions
|
@ -1,30 +1,37 @@
|
|||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
/// <summary>
|
||||
|
@ -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);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Color> colors = new List<Color>();
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace GreenshotPlugin.Core {
|
||||
/// <summary>
|
||||
/// 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
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the bitmap, you will always need to dispose the returned bitmap!!
|
||||
/// Only works, and makes sense, if cloned and not locked!
|
||||
/// </summary>
|
||||
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;}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a BitmapBuffer from a Bitmap
|
||||
/// </summary>
|
||||
/// <param name="sourceBmp">Bitmap</param>
|
||||
public BitmapBuffer(Image sourceBmp) : this(sourceBmp, Rectangle.Empty) {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a BitmapBuffer from a Bitmap a flag if we need a clone
|
||||
/// </summary>
|
||||
/// <param name="sourceBmp">Bitmap</param>
|
||||
/// <param name="clone">bool specifying if the bitmap needs to be cloned</param>
|
||||
public BitmapBuffer(Image sourceBmp, bool clone) : this(sourceBmp, Rectangle.Empty, clone) {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a BitmapBuffer from a Bitmap and a Rectangle specifying what part from the Bitmap to take.
|
||||
/// </summary>
|
||||
/// <param name="sourceBmp">Bitmap</param>
|
||||
/// <param name="applyRect">Rectangle</param>
|
||||
public BitmapBuffer(Image sourceBmp, Rectangle applyRect) : this(sourceBmp, applyRect, true) {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a BitmapBuffer from a Bitmap, a Rectangle specifying what part from the Bitmap to take and a flag if we need a clone
|
||||
/// </summary>
|
||||
/// <param name="sourceImage">Image, will be cloned if it's not a bitmap!!!</param>
|
||||
/// <param name="applyRect">Rectangle</param>
|
||||
/// <param name="clone">bool specifying if the bitmap needs to be cloned</param>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unlock the System Memory
|
||||
/// </summary>
|
||||
public void Unlock() {
|
||||
if (bitsLocked) {
|
||||
bitmap.UnlockBits(bmData);
|
||||
bitsLocked = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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) {
|
||||
DrawTo(graphics, null, destination);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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!!
|
||||
/// </summary>
|
||||
/// <param name="graphics"></param>
|
||||
/// <param name="destinationRect"></param>
|
||||
public void DrawTo(Graphics graphics, Rectangle destinationRect) {
|
||||
DrawTo(graphics, destinationRect, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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) {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use only when 32-bit bitmap!
|
||||
/// </summary>
|
||||
/// <param name="x">x</param>
|
||||
/// <param name="y">y</param>
|
||||
/// <param name="argb">argb value</param>
|
||||
public void SetARGB(int x, int y, int argb) {
|
||||
int offset = (y * (stride>>2)) + x;
|
||||
intPointer[offset] = argb;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve the color at location x,y
|
||||
/// Before the first time this is called the Lock() should be called once!
|
||||
/// </summary>
|
||||
/// <param name="x">X coordinate</param>
|
||||
/// <param name="y">Y Coordinate</param>
|
||||
/// <returns>Color</returns>
|
||||
public Color GetColorAt(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) ? 255 : (int)pointer[aIndex+offset];
|
||||
return Color.FromArgb(a, pointer[rIndex+offset], pointer[gIndex+offset], pointer[bIndex+offset]);
|
||||
} else {
|
||||
return Color.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the color at location x,y
|
||||
/// 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) {
|
||||
if(x>=0 && y>=0 && x<rect.Width && y<rect.Height) {
|
||||
int offset = x*bytesPerPixel+y*stride;
|
||||
if(aIndex!=-1) pointer[aIndex+offset] = color.A;
|
||||
pointer[rIndex+offset] = color.R;
|
||||
pointer[gIndex+offset] = color.G;
|
||||
pointer[bIndex+offset] = color.B;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve the color at location x,y to a byte[]
|
||||
/// 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) {
|
||||
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];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve the color at location x,y to a byte[]
|
||||
/// 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 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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the color at location x,y as an array
|
||||
/// Before the first time this is called the Lock() should be called once!
|
||||
/// </summary>
|
||||
/// <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) {
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set some internal values for accessing the bitmap according to the PixelFormat
|
||||
/// </summary>
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -86,19 +86,47 @@ namespace GreenshotPlugin.Core {
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Height of the underlying image
|
||||
/// Height of the image area that this fastbitmap covers
|
||||
/// </summary>
|
||||
int Height {
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Width of the underlying image
|
||||
/// Width of the image area that this fastbitmap covers
|
||||
/// </summary>
|
||||
int Width {
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Top of the image area that this fastbitmap covers
|
||||
/// </summary>
|
||||
int Top {
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Left of the image area that this fastbitmap covers
|
||||
/// </summary>
|
||||
int Left {
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Right of the image area that this fastbitmap covers
|
||||
/// </summary>
|
||||
int Right {
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bottom of the image area that this fastbitmap covers
|
||||
/// </summary>
|
||||
int Bottom {
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Does the underlying image need to be disposed
|
||||
/// </summary>
|
||||
|
@ -136,6 +164,108 @@ namespace GreenshotPlugin.Core {
|
|||
/// <param name="y"></param>
|
||||
/// <returns></returns>
|
||||
bool Contains(int x, int y);
|
||||
|
||||
/// <summary>
|
||||
/// Set the bitmap resolution
|
||||
/// </summary>
|
||||
/// <param name="horizontal"></param>
|
||||
/// <param name="vertical"></param>
|
||||
void SetResolution(float horizontal, float vertical);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This interface can be used for when offsetting is needed
|
||||
/// </summary>
|
||||
public interface IFastBitmapWithOffset : IFastBitmap {
|
||||
/// <summary>
|
||||
/// Return true if the coordinates are inside the FastBitmap
|
||||
/// </summary>
|
||||
/// <param name="x"></param>
|
||||
/// <param name="y"></param>
|
||||
/// <returns></returns>
|
||||
bool Contains(int x, int y);
|
||||
|
||||
/// <summary>
|
||||
/// Set the color at the specified location, using offsetting so the original coordinates can be used
|
||||
/// </summary>
|
||||
/// <param name="x">int x</param>
|
||||
/// <param name="y">int y</param>
|
||||
/// <param name="color">Color color</param>
|
||||
new void SetColorAt(int x, int y, Color color);
|
||||
|
||||
/// <summary>
|
||||
/// Set the color at the specified location, using offsetting so the original coordinates can be used
|
||||
/// </summary>
|
||||
/// <param name="x">int x</param>
|
||||
/// <param name="y">int y</param>
|
||||
/// <param name="color">byte[] color</param>
|
||||
new void SetColorAt(int x, int y, byte[] color);
|
||||
|
||||
/// <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>
|
||||
new Color GetColorAt(int x, int y);
|
||||
|
||||
/// <summary>
|
||||
/// 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
|
||||
/// </summary>
|
||||
/// <param name="x">int x</param>
|
||||
/// <param name="y">int y</par
|
||||
new void GetColorAt(int x, int y, byte[] color);
|
||||
|
||||
new int Left {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
new int Top {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This interface can be used for when clipping is needed
|
||||
/// </summary>
|
||||
public interface IFastBitmapWithClip : IFastBitmap {
|
||||
Rectangle Clip {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
bool InvertClip {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the color at the specified location, this doesn't do anything if the location is excluded due to clipping
|
||||
/// </summary>
|
||||
/// <param name="x">int x</param>
|
||||
/// <param name="y">int y</param>
|
||||
/// <param name="color">Color color</param>
|
||||
new void SetColorAt(int x, int y, Color color);
|
||||
|
||||
/// <summary>
|
||||
/// Set the color at the specified location, this doesn't do anything if the location is excluded due to clipping
|
||||
/// </summary>
|
||||
/// <param name="x">int x</param>
|
||||
/// <param name="y">int y</param>
|
||||
/// <param name="color">byte[] color</param>
|
||||
new void SetColorAt(int x, int y, byte[] color);
|
||||
|
||||
/// <summary>
|
||||
/// Return true if the coordinates are inside the FastBitmap and not clipped
|
||||
/// </summary>
|
||||
/// <param name="x"></param>
|
||||
/// <param name="y"></param>
|
||||
/// <returns></returns>
|
||||
new bool Contains(int x, int y);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -152,7 +282,7 @@ namespace GreenshotPlugin.Core {
|
|||
/// <summary>
|
||||
/// The base class for the fast bitmap implementation
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The bitmap for which the FastBitmap is creating access
|
||||
/// </summary>
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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 {
|
|||
/// <returns>IFastBitmap</returns>
|
||||
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;
|
||||
/// <summary>
|
||||
/// Return the left of the fastbitmap, this is also used as an offset
|
||||
/// </summary>
|
||||
public int Left {
|
||||
get {
|
||||
return 0;
|
||||
}
|
||||
set {
|
||||
left = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the left of the fastbitmap, this is also used as an offset
|
||||
/// </summary>
|
||||
int IFastBitmapWithOffset.Left {
|
||||
get {
|
||||
return left;
|
||||
}
|
||||
set {
|
||||
left = value;
|
||||
}
|
||||
}
|
||||
|
||||
private int top;
|
||||
/// <summary>
|
||||
/// Return the top of the fastbitmap, this is also used as an offset
|
||||
/// </summary>
|
||||
public int Top {
|
||||
get {
|
||||
return 0;
|
||||
}
|
||||
set {
|
||||
top = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the top of the fastbitmap, this is also used as an offset
|
||||
/// </summary>
|
||||
int IFastBitmapWithOffset.Top {
|
||||
get {
|
||||
return top;
|
||||
}
|
||||
set {
|
||||
top = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the right of the fastbitmap
|
||||
/// </summary>
|
||||
public int Right {
|
||||
get {
|
||||
return Left + Width;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the bottom of the fastbitmap
|
||||
/// </summary>
|
||||
public int Bottom {
|
||||
get {
|
||||
return Top + Height;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the underlying bitmap, unlocks it and prevents that it will be disposed
|
||||
/// </summary>
|
||||
public Bitmap UnlockAndReturnBitmap() {
|
||||
if (bitsLocked) {
|
||||
LOG.Warn("Unlocking the bitmap");
|
||||
Unlock();
|
||||
}
|
||||
NeedsDispose = false;
|
||||
|
@ -401,7 +622,7 @@ namespace GreenshotPlugin.Core {
|
|||
/// <param name="graphics"></param>
|
||||
/// <param name="destination"></param>
|
||||
public void DrawTo(Graphics graphics, Point destination) {
|
||||
DrawTo(graphics, null, destination);
|
||||
DrawTo(graphics, new Rectangle(destination, area.Size));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -410,38 +631,15 @@ namespace GreenshotPlugin.Core {
|
|||
/// </summary>
|
||||
/// <param name="graphics"></param>
|
||||
/// <param name="destinationRect"></param>
|
||||
public void DrawTo(Graphics graphics, Rectangle destinationRect) {
|
||||
DrawTo(graphics, destinationRect, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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) {
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -451,13 +649,75 @@ namespace GreenshotPlugin.Core {
|
|||
/// <param name="y"></param>
|
||||
/// <returns>true if x & y are inside the FastBitmap</returns>
|
||||
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
|
||||
/// <summary>
|
||||
/// returns true if x & y are inside the FastBitmap
|
||||
/// </summary>
|
||||
/// <param name="x"></param>
|
||||
/// <param name="y"></param>
|
||||
/// <returns>true if x & y are inside the FastBitmap</returns>
|
||||
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
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -771,6 +1031,5 @@ namespace GreenshotPlugin.Core {
|
|||
}
|
||||
return Color.FromArgb(255, red, green, blue);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new bitmap with the sourceBitmap blurred
|
||||
/// </summary>
|
||||
/// <param name="sourceBitmap">Source to blur</param>
|
||||
/// <param name="applyRect">Area to blur</param>
|
||||
/// <param name="useExportQuality">Use best quality</param>
|
||||
/// <param name="blurRadius">Radius of the blur</param>
|
||||
/// <param name="previewQuality">Quality, use 1d for normal anything less skipps calculations</param>
|
||||
/// <param name="invert">true if the blur needs to occur outside of the area</param>
|
||||
/// <param name="parentBounds">Rectangle limiting the area when using invert</param>
|
||||
public static 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();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Apply BoxBlur to the destinationBitmap
|
||||
/// </summary>
|
||||
|
@ -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 {
|
|||
/// <returns>b/w bitmap</returns>
|
||||
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 {
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adjust the brightness, contract or gamma of an image.
|
||||
/// Use the value "1.0f" for no changes.
|
||||
/// Create ImageAttributes to modify
|
||||
/// </summary>
|
||||
/// <param name="sourceImage">Original bitmap</param>
|
||||
/// <returns>Bitmap with grayscale</returns>
|
||||
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);
|
||||
/// <param name="brightness"></param>
|
||||
/// <param name="contrast"></param>
|
||||
/// <param name="gamma"></param>
|
||||
/// <returns>ImageAttributes</returns>
|
||||
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;
|
||||
}
|
||||
/// <summary>
|
||||
/// Adjust the brightness, contract or gamma of an image.
|
||||
/// Use the value "1.0f" for no changes.
|
||||
/// </summary>
|
||||
/// <param name="sourceImage">Original bitmap</param>
|
||||
/// <returns>Bitmap with grayscale</returns>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Color, byte> lookup = new Dictionary<Color, byte>();
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1117,14 +1117,13 @@ namespace GreenshotPlugin.Core {
|
|||
/// </summary>
|
||||
/// <param name="image">The bitmap to remove the corners from.</param>
|
||||
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 {
|
|||
/// <param name="whiteBitmap">Bitmap with the black image</param>
|
||||
/// <returns>Bitmap with transparency</returns>
|
||||
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<blackBuffer.Height;y++) {
|
||||
for(int x=0; x<blackBuffer.Width;x++) {
|
||||
Color c0 = blackBuffer.GetColorAt(x,y);
|
||||
Color c1 = whiteBuffer.GetColorAt(x,y);
|
||||
using (IFastBitmap targetBuffer = FastBitmap.CreateEmpty(blackBitmap.Size, PixelFormat.Format32bppArgb, Color.Transparent)) {
|
||||
targetBuffer.SetResolution(blackBitmap.HorizontalResolution, blackBitmap.VerticalResolution);
|
||||
using (IFastBitmap blackBuffer = FastBitmap.Create(blackBitmap)) {
|
||||
using (IFastBitmap whiteBuffer = FastBitmap.Create(whiteBitmap)) {
|
||||
for (int y = 0; y < blackBuffer.Height; y++) {
|
||||
for (int x = 0; x < blackBuffer.Width; x++) {
|
||||
Color c0 = blackBuffer.GetColorAt(x, y);
|
||||
Color c1 = whiteBuffer.GetColorAt(x, y);
|
||||
// Calculate alpha as double in range 0-1
|
||||
double alpha = (c0.R - c1.R + 255) / 255d;
|
||||
if (alpha == 1) {
|
||||
// Alpha == 1 means no change!
|
||||
targetBuffer.SetColorAt(x, y, c0);
|
||||
targetBuffer.SetColorAt(x, y, c0);
|
||||
} else if (alpha == 0) {
|
||||
// Complete transparency, use transparent pixel
|
||||
targetBuffer.SetColorAt(x, y, Color.Transparent);
|
||||
|
@ -1168,14 +1163,14 @@ namespace GreenshotPlugin.Core {
|
|||
byte originalBlue = (byte)Math.Min(255, c0.B / alpha);
|
||||
Color originalColor = Color.FromArgb(originalAlpha, originalRed, originalGreen, originalBlue);
|
||||
//Color originalColor = Color.FromArgb(originalAlpha, originalRed, c0.G, c0.B);
|
||||
targetBuffer.SetColorAt(x, y, originalColor);
|
||||
targetBuffer.SetColorAt(x, y, originalColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return targetBuffer.UnlockAndReturnBitmap();
|
||||
}
|
||||
return returnBitmap;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -146,7 +146,6 @@
|
|||
<Compile Include="Core\AccessibleHelper.cs" />
|
||||
<Compile Include="Core\AnimationHelpers.cs" />
|
||||
<Compile Include="Core\BinaryStructHelper.cs" />
|
||||
<Compile Include="Core\BitmapBuffer.cs" />
|
||||
<Compile Include="Core\Cache.cs" />
|
||||
<Compile Include="Core\ClipboardHelper.cs" />
|
||||
<Compile Include="Core\CoreConfiguration.cs" />
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue