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,
|
* Greenshot - a free and open source screenshot tool
|
||||||
/// which was released under MIT license.
|
* Copyright (C) 2007-2013 Thomas Braun, Jens Klingen, Robin Krom
|
||||||
/// http://www.getpaint.net
|
*
|
||||||
/// Some of this code has been adapted for integration with Greenshot.
|
* For more information see: http://getgreenshot.org/
|
||||||
/// See Paint.NET copyright notice below.
|
* The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/
|
||||||
/// </summary>
|
*
|
||||||
|
* 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
|
||||||
// Paint.NET //
|
* the Free Software Foundation, either version 1 of the License, or
|
||||||
// Copyright (C) Rick Brewster, Tom Jackson, and past contributors. //
|
* (at your option) any later version.
|
||||||
// Portions Copyright (C) Microsoft Corporation. All Rights Reserved. //
|
*
|
||||||
// See src/Resources/Files/License.txt for full licensing and attribution //
|
* This program is distributed in the hope that it will be useful,
|
||||||
// details. //
|
* 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;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using Greenshot.Drawing.Fields;
|
using Greenshot.Drawing.Fields;
|
||||||
using Greenshot.Plugin.Drawing;
|
using Greenshot.Plugin.Drawing;
|
||||||
using GreenshotPlugin.Core;
|
using GreenshotPlugin.Core;
|
||||||
using System.Drawing.Imaging;
|
using System.Drawing.Imaging;
|
||||||
|
using GreenshotPlugin.UnmanagedHelpers;
|
||||||
|
using System.Drawing.Drawing2D;
|
||||||
|
|
||||||
namespace Greenshot.Drawing.Filters {
|
namespace Greenshot.Drawing.Filters {
|
||||||
[Serializable()]
|
[Serializable()]
|
||||||
public class BlurFilter : AbstractFilter {
|
public class BlurFilter : AbstractFilter {
|
||||||
|
private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(BlurFilter));
|
||||||
|
|
||||||
public double previewQuality;
|
public double previewQuality;
|
||||||
public double PreviewQuality {
|
public double PreviewQuality {
|
||||||
get { return previewQuality; }
|
get { return previewQuality; }
|
||||||
|
@ -40,11 +47,20 @@ namespace Greenshot.Drawing.Filters {
|
||||||
int blurRadius = GetFieldValueAsInt(FieldType.BLUR_RADIUS);
|
int blurRadius = GetFieldValueAsInt(FieldType.BLUR_RADIUS);
|
||||||
double previewQuality = GetFieldValueAsDouble(FieldType.PREVIEW_QUALITY);
|
double previewQuality = GetFieldValueAsDouble(FieldType.PREVIEW_QUALITY);
|
||||||
Rectangle applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert);
|
Rectangle applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert);
|
||||||
using (Bitmap blurImage = ImageHelper.CreateBlur(applyBitmap, applyRect, renderMode == RenderMode.EXPORT, blurRadius, previewQuality, Invert, parent.Bounds)) {
|
GraphicsState state = graphics.Save();
|
||||||
if (blurImage != null) {
|
if (Invert) {
|
||||||
graphics.DrawImageUnscaled(blurImage, applyRect.Location);
|
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;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ using Greenshot.Drawing.Fields;
|
||||||
using Greenshot.Plugin.Drawing;
|
using Greenshot.Plugin.Drawing;
|
||||||
using GreenshotPlugin.Core;
|
using GreenshotPlugin.Core;
|
||||||
using System.Drawing.Imaging;
|
using System.Drawing.Imaging;
|
||||||
|
using System.Drawing.Drawing2D;
|
||||||
|
|
||||||
namespace Greenshot.Drawing.Filters {
|
namespace Greenshot.Drawing.Filters {
|
||||||
[Serializable()]
|
[Serializable()]
|
||||||
|
@ -48,24 +49,14 @@ namespace Greenshot.Drawing.Filters {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
using (IFastBitmap fastBitmap = FastBitmap.CreateCloneOf(applyBitmap, applyRect)) {
|
GraphicsState state = graphics.Save();
|
||||||
double brightness = GetFieldValueAsDouble(FieldType.BRIGHTNESS);
|
if (Invert) {
|
||||||
for (int y = 0; y < fastBitmap.Height; y++) {
|
graphics.SetClip(applyRect);
|
||||||
for (int x = 0; x < fastBitmap.Width; x++) {
|
graphics.ExcludeClip(rect);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
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 System.Drawing;
|
||||||
using GreenshotPlugin.Core;
|
using GreenshotPlugin.Core;
|
||||||
using Greenshot.Plugin.Drawing;
|
using Greenshot.Plugin.Drawing;
|
||||||
|
using System.Drawing.Drawing2D;
|
||||||
|
using System.Drawing.Imaging;
|
||||||
|
|
||||||
namespace Greenshot.Drawing.Filters {
|
namespace Greenshot.Drawing.Filters {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -39,20 +41,23 @@ namespace Greenshot.Drawing.Filters {
|
||||||
// nothing to do
|
// nothing to do
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
GraphicsState state = graphics.Save();
|
||||||
using (IFastBitmap fastBitmap = FastBitmap.CreateCloneOf(applyBitmap, applyRect)) {
|
if (Invert) {
|
||||||
for (int y = 0; y < fastBitmap.Height; y++) {
|
graphics.SetClip(applyRect);
|
||||||
for (int x = 0; x < fastBitmap.Width; x++) {
|
graphics.ExcludeClip(rect);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
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 Greenshot.Plugin.Drawing;
|
||||||
using GreenshotPlugin.Core;
|
using GreenshotPlugin.Core;
|
||||||
using System.Drawing.Imaging;
|
using System.Drawing.Imaging;
|
||||||
|
using System.Drawing.Drawing2D;
|
||||||
|
|
||||||
namespace Greenshot.Drawing.Filters {
|
namespace Greenshot.Drawing.Filters {
|
||||||
[Serializable()]
|
[Serializable()]
|
||||||
|
@ -46,20 +47,23 @@ namespace Greenshot.Drawing.Filters {
|
||||||
// nothing to do
|
// nothing to do
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
GraphicsState state = graphics.Save();
|
||||||
|
if (Invert) {
|
||||||
|
graphics.SetClip(applyRect);
|
||||||
|
graphics.ExcludeClip(rect);
|
||||||
|
}
|
||||||
using (IFastBitmap fastBitmap = FastBitmap.CreateCloneOf(applyBitmap, applyRect)) {
|
using (IFastBitmap fastBitmap = FastBitmap.CreateCloneOf(applyBitmap, applyRect)) {
|
||||||
Color highlightColor = GetFieldValueAsColor(FieldType.FILL_COLOR);
|
Color highlightColor = GetFieldValueAsColor(FieldType.FILL_COLOR);
|
||||||
for (int y = 0; y < fastBitmap.Height; y++) {
|
for (int y = fastBitmap.Top; y < fastBitmap.Bottom; y++) {
|
||||||
for (int x = 0; x < fastBitmap.Width; x++) {
|
for (int x = fastBitmap.Left; x < fastBitmap.Right; x++) {
|
||||||
if (parent.Contains(applyRect.Left + x, applyRect.Top + y) ^ Invert) {
|
Color color = fastBitmap.GetColorAt(x, y);
|
||||||
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));
|
||||||
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.SetColorAt(x, y, color);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fastBitmap.DrawTo(graphics, applyRect.Location);
|
fastBitmap.DrawTo(graphics, applyRect.Location);
|
||||||
}
|
}
|
||||||
|
graphics.Restore(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ using Greenshot.Drawing.Fields;
|
||||||
using Greenshot.Plugin.Drawing;
|
using Greenshot.Plugin.Drawing;
|
||||||
using GreenshotPlugin.Core;
|
using GreenshotPlugin.Core;
|
||||||
using System.Drawing.Imaging;
|
using System.Drawing.Imaging;
|
||||||
|
using System.Drawing.Drawing2D;
|
||||||
|
|
||||||
namespace Greenshot.Drawing.Filters {
|
namespace Greenshot.Drawing.Filters {
|
||||||
[Serializable]
|
[Serializable]
|
||||||
|
@ -40,24 +41,22 @@ namespace Greenshot.Drawing.Filters {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int magnificationFactor = GetFieldValueAsInt(FieldType.MAGNIFICATION_FACTOR);
|
int magnificationFactor = GetFieldValueAsInt(FieldType.MAGNIFICATION_FACTOR);
|
||||||
|
GraphicsState state = graphics.Save();
|
||||||
using (IFastBitmap destFastBitmap = FastBitmap.CreateCloneOf(applyBitmap, applyRect)) {
|
if (Invert) {
|
||||||
int halfWidth = destFastBitmap.Size.Width / 2;
|
graphics.SetClip(applyRect);
|
||||||
int halfHeight = destFastBitmap.Size.Height / 2;
|
graphics.ExcludeClip(rect);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
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) {
|
if (rect.Height < pixelSize) {
|
||||||
pixelSize = rect.Height;
|
pixelSize = rect.Height;
|
||||||
}
|
}
|
||||||
|
using (IFastBitmap dest = FastBitmap.CreateCloneOf(applyBitmap, rect)) {
|
||||||
using (BitmapBuffer bbbDest = new BitmapBuffer(applyBitmap, rect)) {
|
using (IFastBitmap src = FastBitmap.Create(applyBitmap, rect)) {
|
||||||
bbbDest.Lock();
|
|
||||||
using (BitmapBuffer bbbSrc = new BitmapBuffer(applyBitmap, rect, false)) {
|
|
||||||
bbbSrc.Lock();
|
|
||||||
List<Color> colors = new List<Color>();
|
List<Color> colors = new List<Color>();
|
||||||
int halbPixelSize = pixelSize / 2;
|
int halbPixelSize = pixelSize / 2;
|
||||||
for (int y = -halbPixelSize; y < bbbSrc.Height + halbPixelSize; y = y + pixelSize) {
|
for (int y = src.Top - halbPixelSize; y < src.Bottom + halbPixelSize; y = y + pixelSize) {
|
||||||
for (int x = -halbPixelSize; x <= bbbSrc.Width + halbPixelSize; x = x + pixelSize) {
|
for (int x = src.Left - halbPixelSize; x <= src.Right + halbPixelSize; x = x + pixelSize) {
|
||||||
colors.Clear();
|
colors.Clear();
|
||||||
for (int yy = y; yy < y + pixelSize; yy++) {
|
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++) {
|
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);
|
Color currentAvgColor = Colors.Mix(colors);
|
||||||
for (int yy = y; yy <= y + pixelSize; yy++) {
|
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++) {
|
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>
|
/// <summary>
|
||||||
/// Height of the underlying image
|
/// Height of the image area that this fastbitmap covers
|
||||||
/// </summary>
|
/// </summary>
|
||||||
int Height {
|
int Height {
|
||||||
get;
|
get;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Width of the underlying image
|
/// Width of the image area that this fastbitmap covers
|
||||||
/// </summary>
|
/// </summary>
|
||||||
int Width {
|
int Width {
|
||||||
get;
|
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>
|
/// <summary>
|
||||||
/// Does the underlying image need to be disposed
|
/// Does the underlying image need to be disposed
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -136,6 +164,108 @@ namespace GreenshotPlugin.Core {
|
||||||
/// <param name="y"></param>
|
/// <param name="y"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
bool Contains(int x, int y);
|
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>
|
/// <summary>
|
||||||
|
@ -152,7 +282,7 @@ namespace GreenshotPlugin.Core {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The base class for the fast bitmap implementation
|
/// The base class for the fast bitmap implementation
|
||||||
/// </summary>
|
/// </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));
|
private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(FastBitmap));
|
||||||
|
|
||||||
protected const int PIXELFORMAT_INDEX_A = 3;
|
protected const int PIXELFORMAT_INDEX_A = 3;
|
||||||
|
@ -174,6 +304,16 @@ namespace GreenshotPlugin.Core {
|
||||||
set;
|
set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Rectangle Clip {
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool InvertClip {
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The bitmap for which the FastBitmap is creating access
|
/// The bitmap for which the FastBitmap is creating access
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -187,6 +327,11 @@ namespace GreenshotPlugin.Core {
|
||||||
public static IFastBitmap Create(Bitmap source) {
|
public static IFastBitmap Create(Bitmap source) {
|
||||||
return Create(source, Rectangle.Empty);
|
return Create(source, Rectangle.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetResolution(float horizontal, float vertical) {
|
||||||
|
bitmap.SetResolution(horizontal, vertical);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Factory for creating a FastBitmap depending on the pixelformat of the source
|
/// 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
|
/// The supplied rectangle specifies the area for which the FastBitmap does its thing
|
||||||
|
@ -247,8 +392,10 @@ namespace GreenshotPlugin.Core {
|
||||||
/// <returns>IFastBitmap</returns>
|
/// <returns>IFastBitmap</returns>
|
||||||
public static IFastBitmap CreateCloneOf(Image source, PixelFormat pixelFormat, Rectangle area) {
|
public static IFastBitmap CreateCloneOf(Image source, PixelFormat pixelFormat, Rectangle area) {
|
||||||
Bitmap destination = ImageHelper.CloneArea(source, area, pixelFormat);
|
Bitmap destination = ImageHelper.CloneArea(source, area, pixelFormat);
|
||||||
IFastBitmap fastBitmap = Create(destination);
|
FastBitmap fastBitmap = Create(destination) as FastBitmap;
|
||||||
((FastBitmap)fastBitmap).NeedsDispose = true;
|
fastBitmap.NeedsDispose = true;
|
||||||
|
fastBitmap.Left = area.Left;
|
||||||
|
fastBitmap.Top = area.Top;
|
||||||
return fastBitmap;
|
return fastBitmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,6 +426,13 @@ namespace GreenshotPlugin.Core {
|
||||||
} else {
|
} else {
|
||||||
this.area = bitmapArea;
|
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();
|
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>
|
/// <summary>
|
||||||
/// Returns the underlying bitmap, unlocks it and prevents that it will be disposed
|
/// Returns the underlying bitmap, unlocks it and prevents that it will be disposed
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Bitmap UnlockAndReturnBitmap() {
|
public Bitmap UnlockAndReturnBitmap() {
|
||||||
if (bitsLocked) {
|
if (bitsLocked) {
|
||||||
LOG.Warn("Unlocking the bitmap");
|
|
||||||
Unlock();
|
Unlock();
|
||||||
}
|
}
|
||||||
NeedsDispose = false;
|
NeedsDispose = false;
|
||||||
|
@ -401,7 +622,7 @@ namespace GreenshotPlugin.Core {
|
||||||
/// <param name="graphics"></param>
|
/// <param name="graphics"></param>
|
||||||
/// <param name="destination"></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, new Rectangle(destination, area.Size));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -410,38 +631,15 @@ namespace GreenshotPlugin.Core {
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="graphics"></param>
|
/// <param name="graphics"></param>
|
||||||
/// <param name="destinationRect"></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>
|
/// <param name="destination"></param>
|
||||||
private void DrawTo(Graphics graphics, Rectangle? destinationRect, Point? destination) {
|
public void DrawTo(Graphics graphics, Rectangle destinationRect) {
|
||||||
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
|
// Make sure this.bitmap is unlocked, if it was locked
|
||||||
bool isLocked = bitsLocked;
|
bool isLocked = bitsLocked;
|
||||||
if (isLocked) {
|
if (isLocked) {
|
||||||
Unlock();
|
Unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (destinationRect.HasValue) {
|
graphics.DrawImage(this.bitmap, destinationRect, area, GraphicsUnit.Pixel);
|
||||||
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>
|
/// <summary>
|
||||||
|
@ -451,13 +649,75 @@ namespace GreenshotPlugin.Core {
|
||||||
/// <param name="y"></param>
|
/// <param name="y"></param>
|
||||||
/// <returns>true if x & y are inside the FastBitmap</returns>
|
/// <returns>true if x & y are inside the FastBitmap</returns>
|
||||||
public bool Contains(int x, int y) {
|
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 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 GetColorAt(int x, int y, byte[] color);
|
||||||
public abstract void SetColorAt(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>
|
/// <summary>
|
||||||
|
@ -771,6 +1031,5 @@ namespace GreenshotPlugin.Core {
|
||||||
}
|
}
|
||||||
return Color.FromArgb(255, red, green, blue);
|
return Color.FromArgb(255, red, green, blue);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -175,8 +175,6 @@ namespace GreenshotPlugin.Core {
|
||||||
// Bottom Right
|
// Bottom Right
|
||||||
checkPoints.Add(new Point(image.Width - 1, image.Height - 1));
|
checkPoints.Add(new Point(image.Width - 1, image.Height - 1));
|
||||||
using (IFastBitmap fastBitmap = FastBitmap.Create((Bitmap)image)) {
|
using (IFastBitmap fastBitmap = FastBitmap.Create((Bitmap)image)) {
|
||||||
fastBitmap.Lock();
|
|
||||||
|
|
||||||
// find biggest area
|
// find biggest area
|
||||||
foreach(Point checkPoint in checkPoints) {
|
foreach(Point checkPoint in checkPoints) {
|
||||||
currentRectangle = FindAutoCropRectangle(fastBitmap, checkPoint, cropDifference);
|
currentRectangle = FindAutoCropRectangle(fastBitmap, checkPoint, cropDifference);
|
||||||
|
@ -461,197 +459,6 @@ namespace GreenshotPlugin.Core {
|
||||||
return weights;
|
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>
|
/// <summary>
|
||||||
/// Apply BoxBlur to the destinationBitmap
|
/// Apply BoxBlur to the destinationBitmap
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -674,6 +481,9 @@ namespace GreenshotPlugin.Core {
|
||||||
if ((range & 1) == 0) {
|
if ((range & 1) == 0) {
|
||||||
range++;
|
range++;
|
||||||
}
|
}
|
||||||
|
if (range <= 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
// Box blurs are frequently used to approximate a Gaussian blur.
|
// 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.
|
// 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.
|
// 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) {
|
if (targetFastBitmap.hasAlphaChannel) {
|
||||||
throw new NotSupportedException("BoxBlurHorizontal should NOT be called for bitmaps with alpha channel");
|
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;
|
int halfRange = range / 2;
|
||||||
Color[] newColors = new Color[w];
|
Color[] newColors = new Color[targetFastBitmap.Width];
|
||||||
byte[] tmpColor = new byte[3];
|
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 hits = 0;
|
||||||
int r = 0;
|
int r = 0;
|
||||||
int g = 0;
|
int g = 0;
|
||||||
int b = 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;
|
int oldPixel = x - halfRange - 1;
|
||||||
if (oldPixel >= 0) {
|
if (oldPixel >= targetFastBitmap.Left) {
|
||||||
targetFastBitmap.GetColorAt(oldPixel, y, tmpColor);
|
targetFastBitmap.GetColorAt(oldPixel, y, tmpColor);
|
||||||
r -= tmpColor[FastBitmap.COLOR_INDEX_R];
|
r -= tmpColor[FastBitmap.COLOR_INDEX_R];
|
||||||
g -= tmpColor[FastBitmap.COLOR_INDEX_G];
|
g -= tmpColor[FastBitmap.COLOR_INDEX_G];
|
||||||
|
@ -721,7 +529,7 @@ namespace GreenshotPlugin.Core {
|
||||||
}
|
}
|
||||||
|
|
||||||
int newPixel = x + halfRange;
|
int newPixel = x + halfRange;
|
||||||
if (newPixel < w) {
|
if (newPixel < targetFastBitmap.Right) {
|
||||||
targetFastBitmap.GetColorAt(newPixel, y, tmpColor);
|
targetFastBitmap.GetColorAt(newPixel, y, tmpColor);
|
||||||
r += tmpColor[FastBitmap.COLOR_INDEX_R];
|
r += tmpColor[FastBitmap.COLOR_INDEX_R];
|
||||||
g += tmpColor[FastBitmap.COLOR_INDEX_G];
|
g += tmpColor[FastBitmap.COLOR_INDEX_G];
|
||||||
|
@ -729,12 +537,12 @@ namespace GreenshotPlugin.Core {
|
||||||
hits++;
|
hits++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (x >= 0) {
|
if (x >= targetFastBitmap.Left) {
|
||||||
newColors[x] = Color.FromArgb(255, (byte)(r / hits), (byte)(g / hits), (byte)(b / hits));
|
newColors[x - targetFastBitmap.Left] = Color.FromArgb(255, (byte)(r / hits), (byte)(g / hits), (byte)(b / hits));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int x = 0; x < w; x++) {
|
for (int x = targetFastBitmap.Left; x < targetFastBitmap.Right; x++) {
|
||||||
targetFastBitmap.SetColorAt(x, y, newColors[x]);
|
targetFastBitmap.SetColorAt(x, y, newColors[x - targetFastBitmap.Left]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -748,20 +556,18 @@ namespace GreenshotPlugin.Core {
|
||||||
if (!targetFastBitmap.hasAlphaChannel) {
|
if (!targetFastBitmap.hasAlphaChannel) {
|
||||||
throw new NotSupportedException("BoxBlurHorizontalAlpha should be called for bitmaps with alpha channel");
|
throw new NotSupportedException("BoxBlurHorizontalAlpha should be called for bitmaps with alpha channel");
|
||||||
}
|
}
|
||||||
int w = targetFastBitmap.Width;
|
|
||||||
int h = targetFastBitmap.Height;
|
|
||||||
int halfRange = range / 2;
|
int halfRange = range / 2;
|
||||||
Color[] newColors = new Color[w];
|
Color[] newColors = new Color[targetFastBitmap.Width];
|
||||||
byte[] tmpColor = new byte[4];
|
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 hits = 0;
|
||||||
int a = 0;
|
int a = 0;
|
||||||
int r = 0;
|
int r = 0;
|
||||||
int g = 0;
|
int g = 0;
|
||||||
int b = 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;
|
int oldPixel = x - halfRange - 1;
|
||||||
if (oldPixel >= 0) {
|
if (oldPixel >= targetFastBitmap.Left) {
|
||||||
targetFastBitmap.GetColorAt(oldPixel, y, tmpColor);
|
targetFastBitmap.GetColorAt(oldPixel, y, tmpColor);
|
||||||
a -= tmpColor[FastBitmap.COLOR_INDEX_A];
|
a -= tmpColor[FastBitmap.COLOR_INDEX_A];
|
||||||
r -= tmpColor[FastBitmap.COLOR_INDEX_R];
|
r -= tmpColor[FastBitmap.COLOR_INDEX_R];
|
||||||
|
@ -771,7 +577,7 @@ namespace GreenshotPlugin.Core {
|
||||||
}
|
}
|
||||||
|
|
||||||
int newPixel = x + halfRange;
|
int newPixel = x + halfRange;
|
||||||
if (newPixel < w) {
|
if (newPixel < targetFastBitmap.Right) {
|
||||||
targetFastBitmap.GetColorAt(newPixel, y, tmpColor);
|
targetFastBitmap.GetColorAt(newPixel, y, tmpColor);
|
||||||
a += tmpColor[FastBitmap.COLOR_INDEX_A];
|
a += tmpColor[FastBitmap.COLOR_INDEX_A];
|
||||||
r += tmpColor[FastBitmap.COLOR_INDEX_R];
|
r += tmpColor[FastBitmap.COLOR_INDEX_R];
|
||||||
|
@ -780,12 +586,12 @@ namespace GreenshotPlugin.Core {
|
||||||
hits++;
|
hits++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (x >= 0) {
|
if (x >= targetFastBitmap.Left) {
|
||||||
newColors[x] = Color.FromArgb((byte)(a / hits), (byte)(r / hits), (byte)(g / hits), (byte)(b / hits));
|
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++) {
|
for (int x = targetFastBitmap.Left; x < targetFastBitmap.Right; x++) {
|
||||||
targetFastBitmap.SetColorAt(x, y, newColors[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");
|
throw new NotSupportedException("BoxBlurVertical should NOT be called for bitmaps with alpha channel");
|
||||||
}
|
}
|
||||||
int w = targetFastBitmap.Width;
|
int w = targetFastBitmap.Width;
|
||||||
int h = targetFastBitmap.Height;
|
|
||||||
int halfRange = range / 2;
|
int halfRange = range / 2;
|
||||||
Color[] newColors = new Color[h];
|
Color[] newColors = new Color[targetFastBitmap.Height];
|
||||||
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];
|
||||||
for (int x = 0; x < w; x++) {
|
for (int x = targetFastBitmap.Left; x < targetFastBitmap.Right; x++) {
|
||||||
int hits = 0;
|
int hits = 0;
|
||||||
int r = 0;
|
int r = 0;
|
||||||
int g = 0;
|
int g = 0;
|
||||||
int b = 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;
|
int oldPixel = y - halfRange - 1;
|
||||||
if (oldPixel >= 0) {
|
if (oldPixel >= targetFastBitmap.Top) {
|
||||||
targetFastBitmap.GetColorAt(x, oldPixel, tmpColor);
|
targetFastBitmap.GetColorAt(x, oldPixel, tmpColor);
|
||||||
r -= tmpColor[FastBitmap.COLOR_INDEX_R];
|
r -= tmpColor[FastBitmap.COLOR_INDEX_R];
|
||||||
g -= tmpColor[FastBitmap.COLOR_INDEX_G];
|
g -= tmpColor[FastBitmap.COLOR_INDEX_G];
|
||||||
|
@ -822,7 +627,7 @@ namespace GreenshotPlugin.Core {
|
||||||
}
|
}
|
||||||
|
|
||||||
int newPixel = y + halfRange;
|
int newPixel = y + halfRange;
|
||||||
if (newPixel < h) {
|
if (newPixel < targetFastBitmap.Bottom) {
|
||||||
targetFastBitmap.GetColorAt(x, newPixel, tmpColor);
|
targetFastBitmap.GetColorAt(x, newPixel, tmpColor);
|
||||||
r += tmpColor[FastBitmap.COLOR_INDEX_R];
|
r += tmpColor[FastBitmap.COLOR_INDEX_R];
|
||||||
g += tmpColor[FastBitmap.COLOR_INDEX_G];
|
g += tmpColor[FastBitmap.COLOR_INDEX_G];
|
||||||
|
@ -830,13 +635,13 @@ namespace GreenshotPlugin.Core {
|
||||||
hits++;
|
hits++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (y >= 0) {
|
if (y >= targetFastBitmap.Top) {
|
||||||
newColors[y] = Color.FromArgb(255, (byte)(r / hits), (byte)(g / hits), (byte)(b / hits));
|
newColors[y - targetFastBitmap.Top] = Color.FromArgb(255, (byte)(r / hits), (byte)(g / hits), (byte)(b / hits));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int y = 0; y < h; y++) {
|
for (int y = targetFastBitmap.Top; y < targetFastBitmap.Bottom; y++) {
|
||||||
targetFastBitmap.SetColorAt(x, y, newColors[y]);
|
targetFastBitmap.SetColorAt(x, y, newColors[y - targetFastBitmap.Top]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -852,22 +657,20 @@ namespace GreenshotPlugin.Core {
|
||||||
}
|
}
|
||||||
|
|
||||||
int w = targetFastBitmap.Width;
|
int w = targetFastBitmap.Width;
|
||||||
int h = targetFastBitmap.Height;
|
|
||||||
int halfRange = range / 2;
|
int halfRange = range / 2;
|
||||||
Color[] newColors = new Color[h];
|
Color[] newColors = new Color[targetFastBitmap.Height];
|
||||||
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];
|
||||||
for (int x = 0; x < w; x++) {
|
for (int x = targetFastBitmap.Left; x < targetFastBitmap.Right; x++) {
|
||||||
int hits = 0;
|
int hits = 0;
|
||||||
int a = 0;
|
int a = 0;
|
||||||
int r = 0;
|
int r = 0;
|
||||||
int g = 0;
|
int g = 0;
|
||||||
int b = 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;
|
int oldPixel = y - halfRange - 1;
|
||||||
if (oldPixel >= 0) {
|
if (oldPixel >= targetFastBitmap.Top) {
|
||||||
//int colorg = pixels[index + oldPixelOffset];
|
|
||||||
targetFastBitmap.GetColorAt(x, oldPixel, tmpColor);
|
targetFastBitmap.GetColorAt(x, oldPixel, tmpColor);
|
||||||
a -= tmpColor[FastBitmap.COLOR_INDEX_A];
|
a -= tmpColor[FastBitmap.COLOR_INDEX_A];
|
||||||
r -= tmpColor[FastBitmap.COLOR_INDEX_R];
|
r -= tmpColor[FastBitmap.COLOR_INDEX_R];
|
||||||
|
@ -877,7 +680,7 @@ namespace GreenshotPlugin.Core {
|
||||||
}
|
}
|
||||||
|
|
||||||
int newPixel = y + halfRange;
|
int newPixel = y + halfRange;
|
||||||
if (newPixel < h) {
|
if (newPixel < targetFastBitmap.Bottom) {
|
||||||
//int colorg = pixels[index + newPixelOffset];
|
//int colorg = pixels[index + newPixelOffset];
|
||||||
targetFastBitmap.GetColorAt(x, newPixel, tmpColor);
|
targetFastBitmap.GetColorAt(x, newPixel, tmpColor);
|
||||||
a += tmpColor[FastBitmap.COLOR_INDEX_A];
|
a += tmpColor[FastBitmap.COLOR_INDEX_A];
|
||||||
|
@ -887,13 +690,13 @@ namespace GreenshotPlugin.Core {
|
||||||
hits++;
|
hits++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (y >= 0) {
|
if (y >= targetFastBitmap.Top) {
|
||||||
newColors[y] = Color.FromArgb((byte)(a / hits), (byte)(r / hits), (byte)(g / hits), (byte)(b / hits));
|
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++) {
|
for (int y = targetFastBitmap.Top; y < targetFastBitmap.Bottom; y++) {
|
||||||
targetFastBitmap.SetColorAt(x, y, newColors[y]);
|
targetFastBitmap.SetColorAt(x, y, newColors[y - targetFastBitmap.Top]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1068,7 +871,6 @@ namespace GreenshotPlugin.Core {
|
||||||
/// <returns>b/w bitmap</returns>
|
/// <returns>b/w bitmap</returns>
|
||||||
public static Bitmap CreateMonochrome(Image sourceImage, byte threshold) {
|
public static Bitmap CreateMonochrome(Image sourceImage, byte threshold) {
|
||||||
using (IFastBitmap fastBitmap = FastBitmap.CreateCloneOf(sourceImage, sourceImage.PixelFormat)) {
|
using (IFastBitmap fastBitmap = FastBitmap.CreateCloneOf(sourceImage, sourceImage.PixelFormat)) {
|
||||||
fastBitmap.Lock();
|
|
||||||
for (int y = 0; y < fastBitmap.Height; y++) {
|
for (int y = 0; y < fastBitmap.Height; y++) {
|
||||||
for (int x = 0; x < fastBitmap.Width; x++) {
|
for (int x = 0; x < fastBitmap.Width; x++) {
|
||||||
Color color = fastBitmap.GetColorAt(x, y);
|
Color color = fastBitmap.GetColorAt(x, y);
|
||||||
|
@ -1122,15 +924,13 @@ namespace GreenshotPlugin.Core {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adjust the brightness, contract or gamma of an image.
|
/// Create ImageAttributes to modify
|
||||||
/// Use the value "1.0f" for no changes.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="sourceImage">Original bitmap</param>
|
/// <param name="brightness"></param>
|
||||||
/// <returns>Bitmap with grayscale</returns>
|
/// <param name="contrast"></param>
|
||||||
public static Image Adjust(Image sourceImage, float brightness, float contrast, float gamma) {
|
/// <param name="gamma"></param>
|
||||||
//create a blank bitmap the same size as original
|
/// <returns>ImageAttributes</returns>
|
||||||
// If using 8bpp than the following exception comes: A Graphics object cannot be created from an image that has an indexed pixel format.
|
public static ImageAttributes CreateAdjustAttributes(float brightness, float contrast, float gamma) {
|
||||||
Bitmap newBitmap = CreateEmpty(sourceImage.Width, sourceImage.Height, PixelFormat.Format24bppRgb, Color.Empty, sourceImage.HorizontalResolution, sourceImage.VerticalResolution);
|
|
||||||
float adjustedBrightness = brightness - 1.0f;
|
float adjustedBrightness = brightness - 1.0f;
|
||||||
ColorMatrix applyColorMatrix = new ColorMatrix(
|
ColorMatrix applyColorMatrix = new ColorMatrix(
|
||||||
new float[][] {
|
new float[][] {
|
||||||
|
@ -1146,8 +946,19 @@ namespace GreenshotPlugin.Core {
|
||||||
attributes.ClearColorMatrix();
|
attributes.ClearColorMatrix();
|
||||||
attributes.SetColorMatrix(applyColorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
|
attributes.SetColorMatrix(applyColorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
|
||||||
attributes.SetGamma(gamma, 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;
|
return newBitmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1407,8 +1218,7 @@ namespace GreenshotPlugin.Core {
|
||||||
if (!includeAlpha) {
|
if (!includeAlpha) {
|
||||||
toCount = toCount & 0xffffff;
|
toCount = toCount & 0xffffff;
|
||||||
}
|
}
|
||||||
using (BitmapBuffer bb = new BitmapBuffer(sourceImage, false)) {
|
using (IFastBitmap bb = FastBitmap.Create((Bitmap)sourceImage)) {
|
||||||
bb.Lock();
|
|
||||||
for (int y = 0; y < bb.Height; y++) {
|
for (int y = 0; y < bb.Height; y++) {
|
||||||
for (int x = 0; x < bb.Width; x++) {
|
for (int x = 0; x < bb.Width; x++) {
|
||||||
int bitmapcolor = bb.GetColorAt(x, y).ToArgb();
|
int bitmapcolor = bb.GetColorAt(x, y).ToArgb();
|
||||||
|
@ -1420,7 +1230,6 @@ namespace GreenshotPlugin.Core {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bb.Unlock();
|
|
||||||
return colors;
|
return colors;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -332,21 +332,19 @@ namespace GreenshotPlugin.Core {
|
||||||
|
|
||||||
LOG.Info("Starting bitmap reconstruction...");
|
LOG.Info("Starting bitmap reconstruction...");
|
||||||
|
|
||||||
using (FastChunkyBitmap bbbDest = FastBitmap.Create(resultBitmap) as FastChunkyBitmap) {
|
using (FastChunkyBitmap dest = FastBitmap.Create(resultBitmap) as FastChunkyBitmap) {
|
||||||
bbbDest.Lock();
|
using (IFastBitmap src = FastBitmap.Create(sourceBitmap)) {
|
||||||
using (IFastBitmap bbbSrc = FastBitmap.Create(sourceBitmap)) {
|
IFastBitmapWithBlend srcBlend = src as IFastBitmapWithBlend;
|
||||||
IFastBitmapWithBlend bbbSrcBlend = bbbSrc as IFastBitmapWithBlend;
|
|
||||||
bbbSrc.Lock();
|
|
||||||
Dictionary<Color, byte> lookup = new Dictionary<Color, byte>();
|
Dictionary<Color, byte> lookup = new Dictionary<Color, byte>();
|
||||||
byte bestMatch;
|
byte bestMatch;
|
||||||
for (int y = 0; y < bbbSrc.Height; y++) {
|
for (int y = 0; y < src.Height; y++) {
|
||||||
for (int x = 0; x < bbbSrc.Width; x++) {
|
for (int x = 0; x < src.Width; x++) {
|
||||||
Color color;
|
Color color;
|
||||||
if (bbbSrcBlend != null) {
|
if (srcBlend != null) {
|
||||||
// WithoutAlpha, this makes it possible to ignore the alpha
|
// WithoutAlpha, this makes it possible to ignore the alpha
|
||||||
color = bbbSrcBlend.GetBlendedColorAt(x, y);
|
color = srcBlend.GetBlendedColorAt(x, y);
|
||||||
} else {
|
} else {
|
||||||
color = bbbSrc.GetColorAt(x, y);
|
color = src.GetColorAt(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if we already matched the color
|
// Check if we already matched the color
|
||||||
|
@ -354,7 +352,7 @@ namespace GreenshotPlugin.Core {
|
||||||
// If not we need to find the best match
|
// If not we need to find the best match
|
||||||
|
|
||||||
// First get initial match
|
// First get initial match
|
||||||
bestMatch = bbbDest.GetColorIndexAt(x, y);
|
bestMatch = dest.GetColorIndexAt(x, y);
|
||||||
bestMatch = tag[bestMatch];
|
bestMatch = tag[bestMatch];
|
||||||
|
|
||||||
Int32 bestDistance = 100000000;
|
Int32 bestDistance = 100000000;
|
||||||
|
@ -384,7 +382,7 @@ namespace GreenshotPlugin.Core {
|
||||||
blues[bestMatch] += color.B;
|
blues[bestMatch] += color.B;
|
||||||
sums[bestMatch]++;
|
sums[bestMatch]++;
|
||||||
|
|
||||||
bbbDest.SetColorIndexAt(x, y, bestMatch);
|
dest.SetColorIndexAt(x, y, bestMatch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1117,14 +1117,13 @@ namespace GreenshotPlugin.Core {
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="image">The bitmap to remove the corners from.</param>
|
/// <param name="image">The bitmap to remove the corners from.</param>
|
||||||
private void RemoveCorners(Bitmap image) {
|
private void RemoveCorners(Bitmap image) {
|
||||||
using (BitmapBuffer buffer = new BitmapBuffer((Bitmap)image, false)) {
|
using (IFastBitmap fastBitmap = FastBitmap.Create(image)) {
|
||||||
buffer.Lock();
|
|
||||||
for (int y = 0; y < conf.WindowCornerCutShape.Count; y++) {
|
for (int y = 0; y < conf.WindowCornerCutShape.Count; y++) {
|
||||||
for (int x = 0; x < conf.WindowCornerCutShape[y]; x++) {
|
for (int x = 0; x < conf.WindowCornerCutShape[y]; x++) {
|
||||||
buffer.SetColorAt(x, y, Color.Transparent);
|
fastBitmap.SetColorAt(x, y, Color.Transparent);
|
||||||
buffer.SetColorAt(image.Width-1-x, y, Color.Transparent);
|
fastBitmap.SetColorAt(image.Width-1-x, y, Color.Transparent);
|
||||||
buffer.SetColorAt(image.Width-1-x, image.Height-1-y, Color.Transparent);
|
fastBitmap.SetColorAt(image.Width-1-x, image.Height-1-y, Color.Transparent);
|
||||||
buffer.SetColorAt(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>
|
/// <param name="whiteBitmap">Bitmap with the black image</param>
|
||||||
/// <returns>Bitmap with transparency</returns>
|
/// <returns>Bitmap with transparency</returns>
|
||||||
private Bitmap ApplyTransparency(Bitmap blackBitmap, Bitmap whiteBitmap) {
|
private Bitmap ApplyTransparency(Bitmap blackBitmap, Bitmap whiteBitmap) {
|
||||||
Bitmap returnBitmap = new Bitmap(blackBitmap.Width, blackBitmap.Height, PixelFormat.Format32bppArgb);
|
using (IFastBitmap targetBuffer = FastBitmap.CreateEmpty(blackBitmap.Size, PixelFormat.Format32bppArgb, Color.Transparent)) {
|
||||||
returnBitmap.SetResolution(blackBitmap.HorizontalResolution, blackBitmap.VerticalResolution);
|
targetBuffer.SetResolution(blackBitmap.HorizontalResolution, blackBitmap.VerticalResolution);
|
||||||
using (BitmapBuffer blackBuffer = new BitmapBuffer(blackBitmap, false)) {
|
using (IFastBitmap blackBuffer = FastBitmap.Create(blackBitmap)) {
|
||||||
blackBuffer.Lock();
|
using (IFastBitmap whiteBuffer = FastBitmap.Create(whiteBitmap)) {
|
||||||
using (BitmapBuffer whiteBuffer = new BitmapBuffer(whiteBitmap, false)) {
|
for (int y = 0; y < blackBuffer.Height; y++) {
|
||||||
whiteBuffer.Lock();
|
for (int x = 0; x < blackBuffer.Width; x++) {
|
||||||
using (BitmapBuffer targetBuffer = new BitmapBuffer(returnBitmap, false)) {
|
Color c0 = blackBuffer.GetColorAt(x, y);
|
||||||
targetBuffer.Lock();
|
Color c1 = whiteBuffer.GetColorAt(x, y);
|
||||||
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
|
// Calculate alpha as double in range 0-1
|
||||||
double alpha = (c0.R - c1.R + 255) / 255d;
|
double alpha = (c0.R - c1.R + 255) / 255d;
|
||||||
if (alpha == 1) {
|
if (alpha == 1) {
|
||||||
// Alpha == 1 means no change!
|
// Alpha == 1 means no change!
|
||||||
targetBuffer.SetColorAt(x, y, c0);
|
targetBuffer.SetColorAt(x, y, c0);
|
||||||
} else if (alpha == 0) {
|
} else if (alpha == 0) {
|
||||||
// Complete transparency, use transparent pixel
|
// Complete transparency, use transparent pixel
|
||||||
targetBuffer.SetColorAt(x, y, Color.Transparent);
|
targetBuffer.SetColorAt(x, y, Color.Transparent);
|
||||||
|
@ -1168,14 +1163,14 @@ namespace GreenshotPlugin.Core {
|
||||||
byte originalBlue = (byte)Math.Min(255, c0.B / alpha);
|
byte originalBlue = (byte)Math.Min(255, c0.B / alpha);
|
||||||
Color originalColor = Color.FromArgb(originalAlpha, originalRed, originalGreen, originalBlue);
|
Color originalColor = Color.FromArgb(originalAlpha, originalRed, originalGreen, originalBlue);
|
||||||
//Color originalColor = Color.FromArgb(originalAlpha, originalRed, c0.G, c0.B);
|
//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>
|
/// <summary>
|
||||||
|
|
|
@ -146,7 +146,6 @@
|
||||||
<Compile Include="Core\AccessibleHelper.cs" />
|
<Compile Include="Core\AccessibleHelper.cs" />
|
||||||
<Compile Include="Core\AnimationHelpers.cs" />
|
<Compile Include="Core\AnimationHelpers.cs" />
|
||||||
<Compile Include="Core\BinaryStructHelper.cs" />
|
<Compile Include="Core\BinaryStructHelper.cs" />
|
||||||
<Compile Include="Core\BitmapBuffer.cs" />
|
|
||||||
<Compile Include="Core\Cache.cs" />
|
<Compile Include="Core\Cache.cs" />
|
||||||
<Compile Include="Core\ClipboardHelper.cs" />
|
<Compile Include="Core\ClipboardHelper.cs" />
|
||||||
<Compile Include="Core\CoreConfiguration.cs" />
|
<Compile Include="Core\CoreConfiguration.cs" />
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue