Fixed and optimized some drawing routines, still didn't find a solution for shadowing when target format has transparency.

git-svn-id: http://svn.code.sf.net/p/greenshot/code/trunk@1648 7dccd23d-a4a3-4e1f-8c07-b4c1b4018ab4
This commit is contained in:
RKrom 2012-02-10 11:55:21 +00:00
parent 46758d238c
commit dede5cf292
16 changed files with 275 additions and 161 deletions

View file

@ -44,12 +44,15 @@ namespace Greenshot.Drawing {
AddField(GetType(), FieldType.ARROWHEADS, Greenshot.Drawing.ArrowContainer.ArrowHeadCombination.END_POINT); AddField(GetType(), FieldType.ARROWHEADS, Greenshot.Drawing.ArrowContainer.ArrowHeadCombination.END_POINT);
} }
public override void Draw(Graphics g, RenderMode rm) { public override void Draw(Graphics graphics, RenderMode rm) {
int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS);
bool shadow = GetFieldValueAsBool(FieldType.SHADOW); bool shadow = GetFieldValueAsBool(FieldType.SHADOW);
if (lineThickness > 0 ) { if (lineThickness > 0 ) {
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR);
ArrowHeadCombination heads = (ArrowHeadCombination)GetFieldValue(FieldType.ARROWHEADS); ArrowHeadCombination heads = (ArrowHeadCombination)GetFieldValue(FieldType.ARROWHEADS);
if (shadow) { if (shadow) {
@ -63,7 +66,7 @@ namespace Greenshot.Drawing {
shadowCapPen.Width = lineThickness; shadowCapPen.Width = lineThickness;
SetArrowHeads(heads, shadowCapPen); SetArrowHeads(heads, shadowCapPen);
g.DrawLine(shadowCapPen, graphics.DrawLine(shadowCapPen,
this.Left + currentStep, this.Left + currentStep,
this.Top + currentStep, this.Top + currentStep,
this.Left + currentStep + this.Width, this.Left + currentStep + this.Width,
@ -80,7 +83,7 @@ namespace Greenshot.Drawing {
if ( pen.Width > 0 ) { if ( pen.Width > 0 ) {
SetArrowHeads(heads, pen); SetArrowHeads(heads, pen);
g.DrawLine(pen, this.Left, this.Top, this.Left + this.Width, this.Top + this.Height); graphics.DrawLine(pen, this.Left, this.Top, this.Left + this.Width, this.Top + this.Height);
} }
} }
} }

View file

@ -28,6 +28,7 @@ using Greenshot.Drawing.Fields;
using Greenshot.Helpers; using Greenshot.Helpers;
using Greenshot.Plugin.Drawing; using Greenshot.Plugin.Drawing;
using GreenshotPlugin.Core; using GreenshotPlugin.Core;
using System.Drawing.Drawing2D;
namespace Greenshot.Drawing { namespace Greenshot.Drawing {
/// <summary> /// <summary>
@ -54,7 +55,7 @@ namespace Greenshot.Drawing {
if (bitmap != null) { if (bitmap != null) {
bitmap.Dispose(); bitmap.Dispose();
} }
bitmap = (Bitmap)value.Clone(); bitmap = ImageHelper.Clone(value);
Width = value.Width; Width = value.Width;
Height = value.Height; Height = value.Height;
} }
@ -103,6 +104,11 @@ namespace Greenshot.Drawing {
public override void Draw(Graphics graphics, RenderMode rm) { public override void Draw(Graphics graphics, RenderMode rm) {
if (bitmap != null) { if (bitmap != null) {
bool shadow = GetFieldValueAsBool(FieldType.SHADOW); bool shadow = GetFieldValueAsBool(FieldType.SHADOW);
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
if (shadow) { if (shadow) {
ImageAttributes ia = new ImageAttributes(); ImageAttributes ia = new ImageAttributes();
ColorMatrix cm = new ColorMatrix(); ColorMatrix cm = new ColorMatrix();
@ -111,7 +117,7 @@ namespace Greenshot.Drawing {
cm.Matrix22 = 0; cm.Matrix22 = 0;
cm.Matrix33 = 0.25f; cm.Matrix33 = 0.25f;
ia.SetColorMatrix(cm); ia.SetColorMatrix(cm);
graphics.DrawImage(bitmap, new Rectangle(Bounds.Left+2, Bounds.Top+2, Bounds.Width, Bounds.Height), 0, 0, bitmap.Width, bitmap.Height, GraphicsUnit.Pixel, ia); graphics.DrawImage(bitmap, new Rectangle(Bounds.Left + 2, Bounds.Top + 2, Bounds.Width, Bounds.Height), 0, 0, bitmap.Width, bitmap.Height, GraphicsUnit.Pixel, ia);
} }
graphics.DrawImage(bitmap, Bounds); graphics.DrawImage(bitmap, Bounds);
} }

View file

@ -24,6 +24,7 @@ using System.IO;
using System.Windows.Forms; using System.Windows.Forms;
using Greenshot.Plugin.Drawing; using Greenshot.Plugin.Drawing;
using System.Drawing.Drawing2D;
namespace Greenshot.Drawing { namespace Greenshot.Drawing {
/// <summary> /// <summary>
@ -98,6 +99,10 @@ namespace Greenshot.Drawing {
public override void Draw(Graphics graphics, RenderMode rm) { public override void Draw(Graphics graphics, RenderMode rm) {
if (cursor != null) { if (cursor != null) {
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.InterpolationMode = InterpolationMode.NearestNeighbor;
graphics.CompositingQuality = CompositingQuality.Default;
graphics.PixelOffsetMode = PixelOffsetMode.None;
cursor.DrawStretched(graphics, Bounds); cursor.DrawStretched(graphics, Bounds);
} }
} }

View file

@ -408,7 +408,7 @@ namespace Greenshot.Drawing {
public virtual void DrawContent(Graphics graphics, Bitmap bmp, RenderMode renderMode, Rectangle clipRectangle) { public virtual void DrawContent(Graphics graphics, Bitmap bmp, RenderMode renderMode, Rectangle clipRectangle) {
if (Children.Count > 0) { if (Children.Count > 0) {
if(Status != EditStatus.IDLE) { if (Status != EditStatus.IDLE) {
DrawSelectionBorder(graphics, Bounds); DrawSelectionBorder(graphics, Bounds);
} else { } else {
if (clipRectangle.Width != 0 && clipRectangle.Height != 0) { if (clipRectangle.Width != 0 && clipRectangle.Height != 0) {

View file

@ -40,7 +40,10 @@ namespace Greenshot.Drawing {
} }
public override void Draw(Graphics graphics, RenderMode renderMode) { public override void Draw(Graphics graphics, RenderMode renderMode) {
graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS);
Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR);

View file

@ -174,7 +174,9 @@ namespace Greenshot.Drawing {
/// <param name="graphics"></param> /// <param name="graphics"></param>
/// <param name="renderMode"></param> /// <param name="renderMode"></param>
public override void Draw(Graphics graphics, RenderMode renderMode) { public override void Draw(Graphics graphics, RenderMode renderMode) {
graphics.SmoothingMode = SmoothingMode.AntiAlias; graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS);

View file

@ -24,6 +24,7 @@ using System.IO;
using System.Windows.Forms; using System.Windows.Forms;
using Greenshot.Plugin.Drawing; using Greenshot.Plugin.Drawing;
using System.Drawing.Drawing2D;
namespace Greenshot.Drawing { namespace Greenshot.Drawing {
/// <summary> /// <summary>
@ -97,6 +98,10 @@ namespace Greenshot.Drawing {
public override void Draw(Graphics graphics, RenderMode rm) { public override void Draw(Graphics graphics, RenderMode rm) {
if (icon != null) { if (icon != null) {
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.InterpolationMode = InterpolationMode.NearestNeighbor;
graphics.CompositingQuality = CompositingQuality.Default;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphics.DrawIcon(icon, Bounds); graphics.DrawIcon(icon, Bounds);
} }
} }

View file

@ -56,9 +56,11 @@ namespace Greenshot.Drawing {
} }
public override void Draw(Graphics graphics, RenderMode rm) { public override void Draw(Graphics graphics, RenderMode rm) {
graphics.SmoothingMode = SmoothingMode.AntiAlias; graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS);
Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR);
bool shadow = GetFieldValueAsBool(FieldType.SHADOW); bool shadow = GetFieldValueAsBool(FieldType.SHADOW);

View file

@ -24,6 +24,7 @@ using System.Drawing.Imaging;
using System.IO; using System.IO;
using Greenshot.Plugin.Drawing; using Greenshot.Plugin.Drawing;
using System.Drawing.Drawing2D;
namespace Greenshot.Drawing { namespace Greenshot.Drawing {
/// <summary> /// <summary>
@ -111,6 +112,10 @@ namespace Greenshot.Drawing {
public override void Draw(Graphics graphics, RenderMode rm) { public override void Draw(Graphics graphics, RenderMode rm) {
if (metafile != null) { if (metafile != null) {
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphics.DrawImage(metafile, Bounds); graphics.DrawImage(metafile, Bounds);
} }
} }

View file

@ -41,7 +41,12 @@ namespace Greenshot.Drawing {
} }
public override void Draw(Graphics g, RenderMode rm) { public override void Draw(Graphics graphics, RenderMode rm) {
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS);
Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR);
Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR); Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR);
@ -61,7 +66,7 @@ namespace Greenshot.Drawing {
this.Top + currentStep, this.Top + currentStep,
this.Width, this.Width,
this.Height); this.Height);
g.DrawRectangle(shadowPen, shadowRect); graphics.DrawRectangle(shadowPen, shadowRect);
currentStep++; currentStep++;
alpha = alpha - (basealpha / steps); alpha = alpha - (basealpha / steps);
} }
@ -72,14 +77,14 @@ namespace Greenshot.Drawing {
if (!Color.Transparent.Equals(fillColor)) { if (!Color.Transparent.Equals(fillColor)) {
using (Brush brush = new SolidBrush(fillColor)) { using (Brush brush = new SolidBrush(fillColor)) {
g.FillRectangle(brush, rect); graphics.FillRectangle(brush, rect);
} }
} }
if (lineThickness > 0) { if (lineThickness > 0) {
using (Pen pen = new Pen(lineColor)) { using (Pen pen = new Pen(lineColor)) {
pen.Width = lineThickness; pen.Width = lineThickness;
g.DrawRectangle(pen, rect); graphics.DrawRectangle(pen, rect);
} }
} }
} }

View file

@ -576,6 +576,9 @@ namespace Greenshot.Drawing {
MakeUndoable(new SurfaceBackgroundChangeMemento(this, offset), false); MakeUndoable(new SurfaceBackgroundChangeMemento(this, offset), false);
SetImage(newImage, false); SetImage(newImage, false);
Invalidate(); Invalidate();
if (SurfaceSizeChanged != null && !imageRectangle.Equals(new Rectangle(Point.Empty, newImage.Size))) {
SurfaceSizeChanged(this);
}
} }
} }
@ -604,8 +607,9 @@ namespace Greenshot.Drawing {
public bool ApplyCrop(Rectangle cropRectangle) { public bool ApplyCrop(Rectangle cropRectangle) {
if (isCropPossible(ref cropRectangle)) { if (isCropPossible(ref cropRectangle)) {
Rectangle imageRectangle = new Rectangle(Point.Empty, Image.Size);
// we should not forget to Dispose the images!! // we should not forget to Dispose the images!!
Bitmap tmpImage = ((Bitmap)Image).Clone(cropRectangle, Image.PixelFormat); Bitmap tmpImage = ImageHelper.CloneArea(Image, cropRectangle, PixelFormat.DontCare);
tmpImage.SetResolution(Image.HorizontalResolution, Image.VerticalResolution); tmpImage.SetResolution(Image.HorizontalResolution, Image.VerticalResolution);
Point offset = new Point(-cropRectangle.Left, -cropRectangle.Top); Point offset = new Point(-cropRectangle.Left, -cropRectangle.Top);
@ -614,7 +618,7 @@ namespace Greenshot.Drawing {
SetImage(tmpImage, false); SetImage(tmpImage, false);
elements.MoveBy(offset.X, offset.Y); elements.MoveBy(offset.X, offset.Y);
if (SurfaceSizeChanged != null) { if (SurfaceSizeChanged != null && !imageRectangle.Equals(new Rectangle(Point.Empty, tmpImage.Size))) {
SurfaceSizeChanged(this); SurfaceSizeChanged(this);
} }
Invalidate(); Invalidate();
@ -799,14 +803,15 @@ namespace Greenshot.Drawing {
private Image GetImage(RenderMode renderMode) { private Image GetImage(RenderMode renderMode) {
// Generate a copy of the original image with a dpi equal to the default... // Generate a copy of the original image with a dpi equal to the default...
Bitmap clone = ImageHelper.CloneImageToBitmap(Image); Bitmap clone = ImageHelper.Clone(Image);
// otherwise we would have a problem drawing the image to the surface... :( // otherwise we would have a problem drawing the image to the surface... :(
using (Graphics graphics = Graphics.FromImage(clone)) { using (Graphics graphics = Graphics.FromImage(clone)) {
graphics.SmoothingMode = SmoothingMode.HighQuality; // Do not set the following, the containers need to decide themselves
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; //graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.CompositingQuality = CompositingQuality.HighQuality; //graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; //graphics.CompositingQuality = CompositingQuality.HighQuality;
elements.Draw(graphics, (Bitmap)clone, renderMode, new Rectangle(Point.Empty, clone.Size)); //graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
elements.Draw(graphics, clone, renderMode, new Rectangle(Point.Empty, clone.Size));
} }
return clone; return clone;
} }
@ -841,10 +846,11 @@ namespace Greenshot.Drawing {
} }
// Elements might need the bitmap, so we copy the part we need // Elements might need the bitmap, so we copy the part we need
using (Graphics graphics = Graphics.FromImage(buffer)) { using (Graphics graphics = Graphics.FromImage(buffer)) {
graphics.SmoothingMode = SmoothingMode.HighQuality; // do not set the following, the containers need to decide this themselves!
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; //graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.CompositingQuality = CompositingQuality.HighQuality; //graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; //graphics.CompositingQuality = CompositingQuality.HighQuality;
//graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.DrawImage(Image, clipRectangle, clipRectangle, GraphicsUnit.Pixel); graphics.DrawImage(Image, clipRectangle, clipRectangle, GraphicsUnit.Pixel);
graphics.SetClip(targetGraphics); graphics.SetClip(targetGraphics);
elements.Draw(graphics, buffer, RenderMode.EDIT, clipRectangle); elements.Draw(graphics, buffer, RenderMode.EDIT, clipRectangle);
@ -852,7 +858,7 @@ namespace Greenshot.Drawing {
targetGraphics.DrawImage(buffer, clipRectangle, clipRectangle, GraphicsUnit.Pixel); targetGraphics.DrawImage(buffer, clipRectangle, clipRectangle, GraphicsUnit.Pixel);
} else { } else {
// Only "simple" elements need to be redrawn, as the image is already drawn before getting the event we don't need the next line: // Only "simple" elements need to be redrawn, as the image is already drawn before getting the event we don't need the next line:
//targetGraphics.DrawImage(Image, clipRectangle, clipRectangle, GraphicsUnit.Pixel); // targetGraphics.DrawImage(Image, clipRectangle, clipRectangle, GraphicsUnit.Pixel);
elements.Draw(targetGraphics, null, RenderMode.EDIT, clipRectangle); elements.Draw(targetGraphics, null, RenderMode.EDIT, clipRectangle);
} }
} }

View file

@ -28,6 +28,8 @@ using Greenshot.Drawing.Fields;
using Greenshot.Helpers; using Greenshot.Helpers;
using Greenshot.Plugin.Drawing; using Greenshot.Plugin.Drawing;
using Greenshot.Memento; using Greenshot.Memento;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
namespace Greenshot.Drawing { namespace Greenshot.Drawing {
/// <summary> /// <summary>
@ -264,13 +266,18 @@ namespace Greenshot.Drawing {
HideTextBox(); HideTextBox();
} }
public override void Draw(Graphics g, RenderMode rm) { public override void Draw(Graphics graphics, RenderMode rm) {
base.Draw(g, rm); base.Draw(graphics, rm);
UpdateFont(); UpdateFont();
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphics.TextRenderingHint = TextRenderingHint.SystemDefault;
Rectangle rect = GuiRectangle.GetGuiRectangle(this.Left, this.Top, this.Width, this.Height); Rectangle rect = GuiRectangle.GetGuiRectangle(this.Left, this.Top, this.Width, this.Height);
if (Selected && rm == RenderMode.EDIT) { if (Selected && rm == RenderMode.EDIT) {
DrawSelectionBorder(g, rect); DrawSelectionBorder(graphics, rect);
} }
if (text == null || text.Length == 0 ) { if (text == null || text.Length == 0 ) {
@ -295,7 +302,7 @@ namespace Greenshot.Drawing {
shadowRect.Inflate(-textOffset, -textOffset); shadowRect.Inflate(-textOffset, -textOffset);
} }
using (Brush fontBrush = new SolidBrush(Color.FromArgb(alpha, 100, 100, 100))) { using (Brush fontBrush = new SolidBrush(Color.FromArgb(alpha, 100, 100, 100))) {
g.DrawString(text, font, fontBrush, shadowRect); graphics.DrawString(text, font, fontBrush, shadowRect);
currentStep++; currentStep++;
alpha = alpha - basealpha / steps; alpha = alpha - basealpha / steps;
} }
@ -308,7 +315,7 @@ namespace Greenshot.Drawing {
fontRect.Inflate(-textOffset,-textOffset); fontRect.Inflate(-textOffset,-textOffset);
} }
using (Brush fontBrush = new SolidBrush(lineColor)) { using (Brush fontBrush = new SolidBrush(lineColor)) {
g.DrawString(text, font, fontBrush, fontRect); graphics.DrawString(text, font, fontBrush, fontRect);
} }
} }

View file

@ -129,7 +129,7 @@ namespace GreenshotNetworkImportPlugin {
// Convert byte[] to Image // Convert byte[] to Image
memoryStream.Write(imageBytes, 0, imageBytes.Length); memoryStream.Write(imageBytes, 0, imageBytes.Length);
using (Image image = Bitmap.FromStream(memoryStream, true)) { using (Image image = Bitmap.FromStream(memoryStream, true)) {
ICapture capture = host.GetCapture(ImageHelper.CloneImageToBitmap(image)); ICapture capture = host.GetCapture(ImageHelper.Clone(image));
capture.CaptureDetails.Title = title; capture.CaptureDetails.Title = title;
host.ImportCapture(capture); host.ImportCapture(capture);
} }

View file

@ -33,9 +33,7 @@ namespace GreenshotPlugin.Core {
private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(BitmapBuffer)); private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(BitmapBuffer));
private bool clone; private bool clone;
private Bitmap bitmap; private Bitmap bitmap;
public Bitmap Bitmap {
get {return bitmap;}
}
[NonSerialized] [NonSerialized]
private BitmapData bmData; private BitmapData bmData;
[NonSerialized] [NonSerialized]
@ -113,31 +111,18 @@ namespace GreenshotPlugin.Core {
if (sourceRect.Height <= 0 || sourceRect.Width <= 0) { if (sourceRect.Height <= 0 || sourceRect.Width <= 0) {
return; return;
} }
if (SupportsPixelFormat(sourceBmp)) { if (clone) {
if (clone) { this.bitmap = ImageHelper.CloneArea(sourceBmp, sourceRect, PixelFormat.DontCare);
// Create copy with supported format // Set "this" rect to location 0,0
this.bitmap = sourceBmp.Clone(sourceRect, sourceBmp.PixelFormat); // as the Cloned Bitmap is only the part we want to work with
} else { this.rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
this.bitmap = sourceBmp; } else if (!ImageHelper.SupportsPixelFormat(sourceBmp)) {
} throw new ArgumentException("Unsupported pixel format: " + sourceBmp.PixelFormat + " set clone to true!");
} else { } else {
// We can only clone, as we don't support the pixel format! this.bitmap = sourceBmp;
if (!clone) { this.rect = sourceRect;
throw new ArgumentException("Not supported pixel format: " + sourceBmp.PixelFormat);
}
// When sourceRect is the whole bitmap there is a GDI+ bug in Clone
// Clone will than return the same PixelFormat as the source
// a quick workaround is using new Bitmap which uses a default of Format32bppArgb
if (sourceRect.Equals(bitmapRect)) {
this.bitmap = new Bitmap(sourceBmp);
} else {
this.bitmap = sourceBmp.Clone(sourceRect, PixelFormat.Format32bppArgb);
}
} }
// 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);
} }
/** /**
@ -187,23 +172,29 @@ namespace GreenshotPlugin.Core {
* This is called when serializing the object * This is called when serializing the object
*/ */
public void GetObjectData(SerializationInfo info, StreamingContext ctxt) { public void GetObjectData(SerializationInfo info, StreamingContext ctxt) {
Unlock(); bool isLocked = bitsLocked;
if (isLocked) {
Unlock();
}
info.AddValue("bitmap", this.bitmap); info.AddValue("bitmap", this.bitmap);
if (isLocked) {
Lock();
}
} }
/** /**
* Lock the bitmap so we have direct access to the memory * Lock the bitmap so we have direct access to the memory
*/ */
public void Lock() { public void Lock() {
if(rect.Width > 0 && rect.Height > 0) { if(rect.Width > 0 && rect.Height > 0 && !bitsLocked) {
bmData = bitmap.LockBits(rect, ImageLockMode.ReadWrite, bitmap.PixelFormat); bmData = bitmap.LockBits(rect, ImageLockMode.ReadWrite, bitmap.PixelFormat);
bitsLocked = true; bitsLocked = true;
System.IntPtr Scan0 = bmData.Scan0; IntPtr Scan0 = bmData.Scan0;
pointer = (byte*)(void*)Scan0; pointer = (byte*)(void*)Scan0;
PrepareForPixelFormat(); PrepareForPixelFormat();
stride = bmData.Stride; stride = bmData.Stride;
} }
} }
@ -211,7 +202,7 @@ namespace GreenshotPlugin.Core {
* Unlock the System Memory * Unlock the System Memory
*/ */
private void Unlock() { private void Unlock() {
if(bitsLocked) { if (bitsLocked) {
bitmap.UnlockBits(bmData); bitmap.UnlockBits(bmData);
bitsLocked = false; bitsLocked = false;
} }
@ -242,14 +233,20 @@ namespace GreenshotPlugin.Core {
return; return;
} }
} }
// Make sure this.bitmap is unlocked // Make sure this.bitmap is unlocked, if it was locked
Unlock(); bool isLocked = bitsLocked;
if (isLocked) {
Unlock();
}
if (destinationRect.HasValue) { if (destinationRect.HasValue) {
graphics.DrawImage(this.bitmap, destinationRect.Value); graphics.DrawImage(this.bitmap, destinationRect.Value);
} else if (destination.HasValue) { } else if (destination.HasValue) {
graphics.DrawImage(this.bitmap, destination.Value); graphics.DrawImageUnscaled(this.bitmap, destination.Value);
}
// If it was locked, lock it again
if (isLocked) {
Lock();
} }
} }
@ -304,7 +301,7 @@ namespace GreenshotPlugin.Core {
int a = (aIndex==-1) ? 255 : (int)pointer[aIndex+offset]; int a = (aIndex==-1) ? 255 : (int)pointer[aIndex+offset];
return new int[]{a, pointer[rIndex+offset], pointer[gIndex+offset], pointer[bIndex+offset]}; return new int[]{a, pointer[rIndex+offset], pointer[gIndex+offset], pointer[bIndex+offset]};
} else { } else {
return new int[]{0,0,0,0}; return new int[]{255,255,255,255};
} }
} }
@ -322,15 +319,6 @@ namespace GreenshotPlugin.Core {
} }
} }
/**
* Checks if the supplied Bitmap has a PixelFormat we support
*/
private bool SupportsPixelFormat(Bitmap bitmap) {
return (bitmap.PixelFormat.Equals(PixelFormat.Format32bppArgb) ||
bitmap.PixelFormat.Equals(PixelFormat.Format32bppRgb) ||
bitmap.PixelFormat.Equals(PixelFormat.Format24bppRgb));
}
/** /**
* Set some internal values for accessing the bitmap according to the PixelFormat * Set some internal values for accessing the bitmap according to the PixelFormat
*/ */

View file

@ -80,7 +80,7 @@ namespace GreenshotPlugin.Core {
if (image != null && image is Bitmap && ((image.Width * image.Height) > 0)) { if (image != null && image is Bitmap && ((image.Width * image.Height) > 0)) {
cropRectangle.Intersect(new Rectangle(0,0, image.Width, image.Height)); cropRectangle.Intersect(new Rectangle(0,0, image.Width, image.Height));
if (cropRectangle.Width != 0 || cropRectangle.Height != 0) { if (cropRectangle.Width != 0 || cropRectangle.Height != 0) {
returnImage = (image as Bitmap).Clone(cropRectangle, image.PixelFormat); returnImage = CloneArea(image, cropRectangle, PixelFormat.DontCare);
image.Dispose(); image.Dispose();
image = returnImage; image = returnImage;
return true; return true;
@ -90,6 +90,12 @@ namespace GreenshotPlugin.Core {
return false; return false;
} }
/// <summary>
/// Helper method for the FindAutoCropRectangle
/// </summary>
/// <param name="buffer"></param>
/// <param name="colorPoint"></param>
/// <returns></returns>
private static Rectangle FindAutoCropRectangle(BitmapBuffer buffer, Point colorPoint) { private static Rectangle FindAutoCropRectangle(BitmapBuffer buffer, Point colorPoint) {
Rectangle cropRectangle = Rectangle.Empty; Rectangle cropRectangle = Rectangle.Empty;
Color referenceColor = buffer.GetColorAtWithoutAlpha(colorPoint.X,colorPoint.Y); Color referenceColor = buffer.GetColorAtWithoutAlpha(colorPoint.X,colorPoint.Y);
@ -163,6 +169,11 @@ namespace GreenshotPlugin.Core {
return cropRectangle; return cropRectangle;
} }
/// <summary>
/// Load an image from file
/// </summary>
/// <param name="filename"></param>
/// <returns></returns>
public static Bitmap LoadBitmap(string filename) { public static Bitmap LoadBitmap(string filename) {
if (string.IsNullOrEmpty(filename)) { if (string.IsNullOrEmpty(filename)) {
return null; return null;
@ -179,7 +190,7 @@ namespace GreenshotPlugin.Core {
try { try {
using (Image tmpImage = ExtractVistaIcon(imageFileStream)) { using (Image tmpImage = ExtractVistaIcon(imageFileStream)) {
if (tmpImage != null) { if (tmpImage != null) {
fileBitmap = CloneImageToBitmap(tmpImage); fileBitmap = Clone(tmpImage);
} }
} }
} catch (Exception vistaIconException) { } catch (Exception vistaIconException) {
@ -192,7 +203,7 @@ namespace GreenshotPlugin.Core {
// We create a copy of the bitmap, so everything else can be disposed // We create a copy of the bitmap, so everything else can be disposed
using (Icon tmpIcon = new Icon(imageFileStream, new Size(1024,1024))) { using (Icon tmpIcon = new Icon(imageFileStream, new Size(1024,1024))) {
using (Image tmpImage = tmpIcon.ToBitmap()) { using (Image tmpImage = tmpIcon.ToBitmap()) {
fileBitmap = ImageHelper.CloneImageToBitmap(tmpImage); fileBitmap = Clone(tmpImage);
} }
} }
} catch (Exception iconException) { } catch (Exception iconException) {
@ -204,45 +215,13 @@ namespace GreenshotPlugin.Core {
// We create a copy of the bitmap, so everything else can be disposed // We create a copy of the bitmap, so everything else can be disposed
imageFileStream.Position = 0; imageFileStream.Position = 0;
using (Image tmpImage = Image.FromStream(imageFileStream, true, true)) { using (Image tmpImage = Image.FromStream(imageFileStream, true, true)) {
fileBitmap = ImageHelper.CloneImageToBitmap(tmpImage); fileBitmap = Clone(tmpImage);
} }
} }
} }
return fileBitmap; return fileBitmap;
} }
/// <summary>
/// Clone the image to a bitmap
/// </summary>
/// <param name="srcImage">Image to clone</param>
/// <returns>Bitmap</returns>
public static Bitmap CloneImageToBitmap(Image srcImage) {
Bitmap returnImage;
int width = srcImage.Width;
int height = srcImage.Height;
float horizontalResolution = srcImage.HorizontalResolution;
float verticalResolution = srcImage.VerticalResolution;
PixelFormat pixelFormat = srcImage.PixelFormat;
if (srcImage is Metafile) {
pixelFormat = PixelFormat.Format32bppArgb;
}
// Make sure Greenshot supports the pixelformat, if not convert to one we support
if (!isSupported(pixelFormat)) {
pixelFormat = PixelFormat.Format24bppRgb;
}
returnImage = new Bitmap(width, height, pixelFormat);
returnImage.SetResolution(horizontalResolution, verticalResolution);
using (Graphics graphics = Graphics.FromImage(returnImage)) {
if (Image.IsAlphaPixelFormat(pixelFormat)) {
graphics.Clear(Color.Transparent);
} else {
graphics.Clear(Color.White);
}
graphics.DrawImageUnscaled(srcImage, 0, 0);
}
return returnImage;
}
/** /**
* Checks if we support the supplied PixelFormat * Checks if we support the supplied PixelFormat
*/ */
@ -414,9 +393,9 @@ namespace GreenshotPlugin.Core {
nullColor = Color.Transparent; nullColor = Color.Transparent;
} }
using (BitmapBuffer bbbDest = new BitmapBuffer(sourceBitmap, applyRect)) { using (BitmapBuffer bbbDest = new BitmapBuffer(sourceBitmap, applyRect, true)) {
bbbDest.Lock(); bbbDest.Lock();
using (BitmapBuffer bbbSrc = new BitmapBuffer(sourceBitmap, applyRect)) { using (BitmapBuffer bbbSrc = new BitmapBuffer(sourceBitmap, applyRect, false)) {
bbbSrc.Lock(); bbbSrc.Lock();
Random rand = new Random(); Random rand = new Random();
@ -426,25 +405,25 @@ namespace GreenshotPlugin.Core {
long[] waSums = new long[wlen]; long[] waSums = new long[wlen];
long[] wcSums = new long[wlen]; long[] wcSums = new long[wlen];
long[] aSums = new long[wlen]; long[] aSums = new long[wlen];
long[] bSums = new long[wlen];
long[] gSums = new long[wlen];
long[] rSums = new long[wlen]; long[] rSums = new long[wlen];
long[] gSums = new long[wlen];
long[] bSums = new long[wlen];
for (int y = 0; y < applyRect.Height; ++y) { for (int y = 0; y < applyRect.Height; ++y) {
long waSum = 0; long waSum = 0;
long wcSum = 0; long wcSum = 0;
long aSum = 0; long aSum = 0;
long bSum = 0;
long gSum = 0;
long rSum = 0; long rSum = 0;
long gSum = 0;
long bSum = 0;
for (int wx = 0; wx < wlen; ++wx) { for (int wx = 0; wx < wlen; ++wx) {
int srcX = wx - r; int srcX = wx - r;
waSums[wx] = 0; waSums[wx] = 0;
wcSums[wx] = 0; wcSums[wx] = 0;
aSums[wx] = 0; aSums[wx] = 0;
bSums[wx] = 0;
gSums[wx] = 0;
rSums[wx] = 0; rSums[wx] = 0;
gSums[wx] = 0;
bSums[wx] = 0;
if (srcX >= 0 && srcX < bbbDest.Width) { if (srcX >= 0 && srcX < bbbDest.Width) {
for (int wy = 0; wy < wlen; ++wy) { for (int wy = 0; wy < wlen; ++wy) {
@ -460,9 +439,9 @@ namespace GreenshotPlugin.Core {
wp >>= 8; wp >>= 8;
aSums[wx] += wp * colors[0]; aSums[wx] += wp * colors[0];
bSums[wx] += wp * colors[3];
gSums[wx] += wp * colors[2];
rSums[wx] += wp * colors[1]; rSums[wx] += wp * colors[1];
gSums[wx] += wp * colors[2];
bSums[wx] += wp * colors[3];
} }
} }
@ -470,24 +449,22 @@ namespace GreenshotPlugin.Core {
waSum += wwx * waSums[wx]; waSum += wwx * waSums[wx];
wcSum += wwx * wcSums[wx]; wcSum += wwx * wcSums[wx];
aSum += wwx * aSums[wx]; aSum += wwx * aSums[wx];
bSum += wwx * bSums[wx];
gSum += wwx * gSums[wx];
rSum += wwx * rSums[wx]; rSum += wwx * rSums[wx];
gSum += wwx * gSums[wx];
bSum += wwx * bSums[wx];
} }
} }
wcSum >>= 8; wcSum >>= 8;
if (waSum == 0 || wcSum == 0) { if (parentBounds.Contains(applyRect.Left, applyRect.Top + y) ^ invert) {
if (parentBounds.Contains(applyRect.Left, applyRect.Top + y) ^ invert) { if (waSum == 0 || wcSum == 0) {
bbbDest.SetColorAt(0, y, nullColor); bbbDest.SetColorAt(0, y, nullColor);
} } else {
} else { int alpha = (int)(aSum / waSum);
int alpha = (int)(aSum / waSum); int red = (int)(rSum / wcSum);
int blue = (int)(bSum / wcSum); int green = (int)(gSum / wcSum);
int green = (int)(gSum / wcSum); int blue = (int)(bSum / wcSum);
int red = (int)(rSum / wcSum);
if (parentBounds.Contains(applyRect.Left, applyRect.Top + y) ^ invert) {
bbbDest.SetColorAt(0, y, Color.FromArgb(alpha, red, green, blue)); bbbDest.SetColorAt(0, y, Color.FromArgb(alpha, red, green, blue));
} }
} }
@ -497,17 +474,17 @@ namespace GreenshotPlugin.Core {
waSums[i] = waSums[i + 1]; waSums[i] = waSums[i + 1];
wcSums[i] = wcSums[i + 1]; wcSums[i] = wcSums[i + 1];
aSums[i] = aSums[i + 1]; aSums[i] = aSums[i + 1];
bSums[i] = bSums[i + 1];
gSums[i] = gSums[i + 1];
rSums[i] = rSums[i + 1]; rSums[i] = rSums[i + 1];
gSums[i] = gSums[i + 1];
bSums[i] = bSums[i + 1];
} }
waSum = 0; waSum = 0;
wcSum = 0; wcSum = 0;
aSum = 0; aSum = 0;
bSum = 0;
gSum = 0;
rSum = 0; rSum = 0;
gSum = 0;
bSum = 0;
int wx; int wx;
for (wx = 0; wx < wlen - 1; ++wx) { for (wx = 0; wx < wlen - 1; ++wx) {
@ -515,9 +492,9 @@ namespace GreenshotPlugin.Core {
waSum += wwx * waSums[wx]; waSum += wwx * waSums[wx];
wcSum += wwx * wcSums[wx]; wcSum += wwx * wcSums[wx];
aSum += wwx * aSums[wx]; aSum += wwx * aSums[wx];
bSum += wwx * bSums[wx];
gSum += wwx * gSums[wx];
rSum += wwx * rSums[wx]; rSum += wwx * rSums[wx];
gSum += wwx * gSums[wx];
bSum += wwx * bSums[wx];
} }
wx = wlen - 1; wx = wlen - 1;
@ -525,9 +502,9 @@ namespace GreenshotPlugin.Core {
waSums[wx] = 0; waSums[wx] = 0;
wcSums[wx] = 0; wcSums[wx] = 0;
aSums[wx] = 0; aSums[wx] = 0;
bSums[wx] = 0;
gSums[wx] = 0;
rSums[wx] = 0; rSums[wx] = 0;
gSums[wx] = 0;
bSums[wx] = 0;
int srcX = x + wx - r; int srcX = x + wx - r;
@ -545,9 +522,9 @@ namespace GreenshotPlugin.Core {
wp >>= 8; wp >>= 8;
aSums[wx] += wp * (long)colors[0]; aSums[wx] += wp * (long)colors[0];
bSums[wx] += wp * (long)colors[3];
gSums[wx] += wp * (long)colors[2];
rSums[wx] += wp * (long)colors[1]; rSums[wx] += wp * (long)colors[1];
gSums[wx] += wp * (long)colors[2];
bSums[wx] += wp * (long)colors[3];
} }
} }
@ -555,23 +532,20 @@ namespace GreenshotPlugin.Core {
waSum += (long)wr * waSums[wx]; waSum += (long)wr * waSums[wx];
wcSum += (long)wr * wcSums[wx]; wcSum += (long)wr * wcSums[wx];
aSum += (long)wr * aSums[wx]; aSum += (long)wr * aSums[wx];
bSum += (long)wr * bSums[wx];
gSum += (long)wr * gSums[wx];
rSum += (long)wr * rSums[wx]; rSum += (long)wr * rSums[wx];
gSum += (long)wr * gSums[wx];
bSum += (long)wr * bSums[wx];
} }
wcSum >>= 8; wcSum >>= 8;
if (parentBounds.Contains(applyRect.Left, applyRect.Top + y) ^ invert) {
if (waSum == 0 || wcSum == 0) { if (waSum == 0 || wcSum == 0) {
if (parentBounds.Contains(applyRect.Left + x, applyRect.Top + y) ^ invert) {
bbbDest.SetColorAt(x, y, nullColor); bbbDest.SetColorAt(x, y, nullColor);
} } else {
} else { int alpha = (int)(aSum / waSum);
int alpha = (int)(aSum / waSum); int red = (int)(rSum / wcSum);
int blue = (int)(bSum / wcSum); int green = (int)(gSum / wcSum);
int green = (int)(gSum / wcSum); int blue = (int)(bSum / wcSum);
int red = (int)(rSum / wcSum);
if (parentBounds.Contains(applyRect.Left + x, applyRect.Top + y) ^ invert) {
bbbDest.SetColorAt(x, y, Color.FromArgb(alpha, red, green, blue)); bbbDest.SetColorAt(x, y, Color.FromArgb(alpha, red, green, blue));
} }
} }
@ -731,5 +705,103 @@ namespace GreenshotPlugin.Core {
return newBitmap; return newBitmap;
} }
/// <summary>
/// Checks if the supplied Bitmap has a PixelFormat we support
/// </summary>
/// <param name="bitmap">bitmap to check</param>
/// <returns>bool if we support it</returns>
public static bool SupportsPixelFormat(Bitmap bitmap) {
return SupportsPixelFormat(bitmap.PixelFormat);
}
/// <summary>
/// Checks if we support the pixel format
/// </summary>
/// <param name="pixelformat">PixelFormat to check</param>
/// <returns>bool if we support it</returns>
public static bool SupportsPixelFormat(PixelFormat pixelformat) {
return (pixelformat.Equals(PixelFormat.Format32bppArgb) ||
pixelformat.Equals(PixelFormat.Format32bppRgb) ||
pixelformat.Equals(PixelFormat.Format24bppRgb));
}
/// <summary>
/// Wrapper for just cloning which calls the CloneArea
/// </summary>
/// <param name="sourceBitmap">Image to clone</param>
/// <returns>Bitmap with clone image data</returns>
public static Bitmap Clone(Image sourceBitmap) {
return CloneArea(sourceBitmap, Rectangle.Empty, PixelFormat.DontCare);
}
/// <summary>
/// Clone an image, taking some rules into account:
/// 1) When sourceRect is the whole bitmap there is a GDI+ bug in Clone
/// Clone will than return the same PixelFormat as the source
/// a quick workaround is using new Bitmap which uses a default of Format32bppArgb
/// 2) When going from a transparent to a non transparent bitmap, we draw the background white!
/// </summary>
/// <param name="sourceBitmap">Source bitmap to clone</param>
/// <param name="sourceRect">Rectangle to copy from the source, use Rectangle.Empty for all</param>
/// <param name="targetFormat">Target Format, use PixelFormat.DontCare if you want the original (or a default if the source PixelFormat is not supported)</param>
/// <returns></returns>
public static Bitmap CloneArea(Image sourceBitmap, Rectangle sourceRect, PixelFormat targetFormat) {
Bitmap newImage = null;
Rectangle bitmapRect = new Rectangle(0, 0, sourceBitmap.Width, sourceBitmap.Height);
// Make sure the source is not Rectangle.Empty
if (Rectangle.Empty.Equals(sourceRect)) {
sourceRect = new Rectangle(0, 0, sourceBitmap.Width, sourceBitmap.Height);
}
// If no pixelformat is supplied
if (PixelFormat.DontCare == targetFormat || PixelFormat.Undefined == targetFormat) {
if (SupportsPixelFormat(sourceBitmap.PixelFormat)) {
targetFormat = sourceBitmap.PixelFormat;
} else if (Image.IsAlphaPixelFormat(sourceBitmap.PixelFormat)) {
targetFormat = PixelFormat.Format32bppArgb;
} else {
targetFormat = PixelFormat.Format24bppRgb;
}
}
// check the target format
if (!SupportsPixelFormat(targetFormat)) {
if (Image.IsAlphaPixelFormat(targetFormat)) {
targetFormat = PixelFormat.Format32bppArgb;
} else {
targetFormat = PixelFormat.Format24bppRgb;
}
}
bool destinationIsTransparent = Image.IsAlphaPixelFormat(targetFormat);
bool sourceIsTransparent = Image.IsAlphaPixelFormat(sourceBitmap.PixelFormat);
bool fromTransparentToNon = !destinationIsTransparent && sourceIsTransparent;
bool isBitmap = sourceBitmap is Bitmap;
bool isAreaEqual = sourceRect.Equals(bitmapRect);
if (isAreaEqual || fromTransparentToNon || !isBitmap) {
// Rule 1: if the areas are equal, always copy ourselves
newImage = new Bitmap(bitmapRect.Width, bitmapRect.Height, targetFormat);
using (Graphics graphics = Graphics.FromImage(newImage)) {
if (fromTransparentToNon) {
// Rule 2: Make sure the background color is white
graphics.Clear(Color.White);
}
// decide fastest copy method
if (isAreaEqual) {
graphics.DrawImageUnscaled(sourceBitmap, 0, 0);
} else {
graphics.DrawImage(sourceBitmap, 0, 0, sourceRect, GraphicsUnit.Pixel);
}
}
} else {
// Let GDI+ decide how to convert, need to test what is quicker...
newImage = (sourceBitmap as Bitmap).Clone(sourceRect, targetFormat);
}
// Make sure both images have the same resolution
newImage.SetResolution(sourceBitmap.HorizontalResolution, sourceBitmap.VerticalResolution);
return newImage;
}
} }
} }

View file

@ -209,7 +209,12 @@ namespace Greenshot.Interop {
private void Dispose(bool disposing) { private void Dispose(bool disposing) {
if (null != this._COMObject) { if (null != this._COMObject) {
if(Marshal.IsComObject(this._COMObject)) { if(Marshal.IsComObject(this._COMObject)) {
while( Marshal.ReleaseComObject(this._COMObject) > 0 ); try {
while (Marshal.ReleaseComObject(this._COMObject) > 0) ;
} catch (Exception ex) {
LOG.WarnFormat("Problem releasing {0}", _COMType);
LOG.Warn("Error: ", ex);
}
} }
this._COMObject = null; this._COMObject = null;