mirror of
https://github.com/greenshot/greenshot
synced 2025-08-14 02:37:03 -07:00
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:
parent
46758d238c
commit
dede5cf292
16 changed files with 275 additions and 161 deletions
|
@ -80,7 +80,7 @@ namespace GreenshotPlugin.Core {
|
|||
if (image != null && image is Bitmap && ((image.Width * image.Height) > 0)) {
|
||||
cropRectangle.Intersect(new Rectangle(0,0, image.Width, image.Height));
|
||||
if (cropRectangle.Width != 0 || cropRectangle.Height != 0) {
|
||||
returnImage = (image as Bitmap).Clone(cropRectangle, image.PixelFormat);
|
||||
returnImage = CloneArea(image, cropRectangle, PixelFormat.DontCare);
|
||||
image.Dispose();
|
||||
image = returnImage;
|
||||
return true;
|
||||
|
@ -90,6 +90,12 @@ namespace GreenshotPlugin.Core {
|
|||
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) {
|
||||
Rectangle cropRectangle = Rectangle.Empty;
|
||||
Color referenceColor = buffer.GetColorAtWithoutAlpha(colorPoint.X,colorPoint.Y);
|
||||
|
@ -163,6 +169,11 @@ namespace GreenshotPlugin.Core {
|
|||
return cropRectangle;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Load an image from file
|
||||
/// </summary>
|
||||
/// <param name="filename"></param>
|
||||
/// <returns></returns>
|
||||
public static Bitmap LoadBitmap(string filename) {
|
||||
if (string.IsNullOrEmpty(filename)) {
|
||||
return null;
|
||||
|
@ -179,7 +190,7 @@ namespace GreenshotPlugin.Core {
|
|||
try {
|
||||
using (Image tmpImage = ExtractVistaIcon(imageFileStream)) {
|
||||
if (tmpImage != null) {
|
||||
fileBitmap = CloneImageToBitmap(tmpImage);
|
||||
fileBitmap = Clone(tmpImage);
|
||||
}
|
||||
}
|
||||
} catch (Exception vistaIconException) {
|
||||
|
@ -192,7 +203,7 @@ namespace GreenshotPlugin.Core {
|
|||
// We create a copy of the bitmap, so everything else can be disposed
|
||||
using (Icon tmpIcon = new Icon(imageFileStream, new Size(1024,1024))) {
|
||||
using (Image tmpImage = tmpIcon.ToBitmap()) {
|
||||
fileBitmap = ImageHelper.CloneImageToBitmap(tmpImage);
|
||||
fileBitmap = Clone(tmpImage);
|
||||
}
|
||||
}
|
||||
} catch (Exception iconException) {
|
||||
|
@ -204,45 +215,13 @@ namespace GreenshotPlugin.Core {
|
|||
// We create a copy of the bitmap, so everything else can be disposed
|
||||
imageFileStream.Position = 0;
|
||||
using (Image tmpImage = Image.FromStream(imageFileStream, true, true)) {
|
||||
fileBitmap = ImageHelper.CloneImageToBitmap(tmpImage);
|
||||
fileBitmap = Clone(tmpImage);
|
||||
}
|
||||
}
|
||||
}
|
||||
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
|
||||
*/
|
||||
|
@ -414,9 +393,9 @@ namespace GreenshotPlugin.Core {
|
|||
nullColor = Color.Transparent;
|
||||
}
|
||||
|
||||
using (BitmapBuffer bbbDest = new BitmapBuffer(sourceBitmap, applyRect)) {
|
||||
using (BitmapBuffer bbbDest = new BitmapBuffer(sourceBitmap, applyRect, true)) {
|
||||
bbbDest.Lock();
|
||||
using (BitmapBuffer bbbSrc = new BitmapBuffer(sourceBitmap, applyRect)) {
|
||||
using (BitmapBuffer bbbSrc = new BitmapBuffer(sourceBitmap, applyRect, false)) {
|
||||
bbbSrc.Lock();
|
||||
Random rand = new Random();
|
||||
|
||||
|
@ -426,25 +405,25 @@ namespace GreenshotPlugin.Core {
|
|||
long[] waSums = new long[wlen];
|
||||
long[] wcSums = new long[wlen];
|
||||
long[] aSums = new long[wlen];
|
||||
long[] bSums = new long[wlen];
|
||||
long[] gSums = 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) {
|
||||
long waSum = 0;
|
||||
long wcSum = 0;
|
||||
long aSum = 0;
|
||||
long bSum = 0;
|
||||
long gSum = 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;
|
||||
bSums[wx] = 0;
|
||||
gSums[wx] = 0;
|
||||
rSums[wx] = 0;
|
||||
gSums[wx] = 0;
|
||||
bSums[wx] = 0;
|
||||
|
||||
if (srcX >= 0 && srcX < bbbDest.Width) {
|
||||
for (int wy = 0; wy < wlen; ++wy) {
|
||||
|
@ -460,9 +439,9 @@ namespace GreenshotPlugin.Core {
|
|||
wp >>= 8;
|
||||
|
||||
aSums[wx] += wp * colors[0];
|
||||
bSums[wx] += wp * colors[3];
|
||||
gSums[wx] += wp * colors[2];
|
||||
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];
|
||||
wcSum += wwx * wcSums[wx];
|
||||
aSum += wwx * aSums[wx];
|
||||
bSum += wwx * bSums[wx];
|
||||
gSum += wwx * gSums[wx];
|
||||
rSum += wwx * rSums[wx];
|
||||
gSum += wwx * gSums[wx];
|
||||
bSum += wwx * bSums[wx];
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
} else {
|
||||
int alpha = (int)(aSum / waSum);
|
||||
int blue = (int)(bSum / wcSum);
|
||||
int green = (int)(gSum / wcSum);
|
||||
int red = (int)(rSum / wcSum);
|
||||
if (parentBounds.Contains(applyRect.Left, applyRect.Top + y) ^ invert) {
|
||||
} else {
|
||||
int alpha = (int)(aSum / waSum);
|
||||
int red = (int)(rSum / wcSum);
|
||||
int green = (int)(gSum / wcSum);
|
||||
int blue = (int)(bSum / wcSum);
|
||||
bbbDest.SetColorAt(0, y, Color.FromArgb(alpha, red, green, blue));
|
||||
}
|
||||
}
|
||||
|
@ -497,17 +474,17 @@ namespace GreenshotPlugin.Core {
|
|||
waSums[i] = waSums[i + 1];
|
||||
wcSums[i] = wcSums[i + 1];
|
||||
aSums[i] = aSums[i + 1];
|
||||
bSums[i] = bSums[i + 1];
|
||||
gSums[i] = gSums[i + 1];
|
||||
rSums[i] = rSums[i + 1];
|
||||
gSums[i] = gSums[i + 1];
|
||||
bSums[i] = bSums[i + 1];
|
||||
}
|
||||
|
||||
waSum = 0;
|
||||
wcSum = 0;
|
||||
aSum = 0;
|
||||
bSum = 0;
|
||||
gSum = 0;
|
||||
rSum = 0;
|
||||
gSum = 0;
|
||||
bSum = 0;
|
||||
|
||||
int wx;
|
||||
for (wx = 0; wx < wlen - 1; ++wx) {
|
||||
|
@ -515,9 +492,9 @@ namespace GreenshotPlugin.Core {
|
|||
waSum += wwx * waSums[wx];
|
||||
wcSum += wwx * wcSums[wx];
|
||||
aSum += wwx * aSums[wx];
|
||||
bSum += wwx * bSums[wx];
|
||||
gSum += wwx * gSums[wx];
|
||||
rSum += wwx * rSums[wx];
|
||||
gSum += wwx * gSums[wx];
|
||||
bSum += wwx * bSums[wx];
|
||||
}
|
||||
|
||||
wx = wlen - 1;
|
||||
|
@ -525,9 +502,9 @@ namespace GreenshotPlugin.Core {
|
|||
waSums[wx] = 0;
|
||||
wcSums[wx] = 0;
|
||||
aSums[wx] = 0;
|
||||
bSums[wx] = 0;
|
||||
gSums[wx] = 0;
|
||||
rSums[wx] = 0;
|
||||
gSums[wx] = 0;
|
||||
bSums[wx] = 0;
|
||||
|
||||
int srcX = x + wx - r;
|
||||
|
||||
|
@ -545,9 +522,9 @@ namespace GreenshotPlugin.Core {
|
|||
wp >>= 8;
|
||||
|
||||
aSums[wx] += wp * (long)colors[0];
|
||||
bSums[wx] += wp * (long)colors[3];
|
||||
gSums[wx] += wp * (long)colors[2];
|
||||
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];
|
||||
wcSum += (long)wr * wcSums[wx];
|
||||
aSum += (long)wr * aSums[wx];
|
||||
bSum += (long)wr * bSums[wx];
|
||||
gSum += (long)wr * gSums[wx];
|
||||
rSum += (long)wr * rSums[wx];
|
||||
gSum += (long)wr * gSums[wx];
|
||||
bSum += (long)wr * bSums[wx];
|
||||
}
|
||||
|
||||
wcSum >>= 8;
|
||||
|
||||
if (waSum == 0 || wcSum == 0) {
|
||||
if (parentBounds.Contains(applyRect.Left + x, applyRect.Top + y) ^ invert) {
|
||||
if (parentBounds.Contains(applyRect.Left, applyRect.Top + y) ^ invert) {
|
||||
if (waSum == 0 || wcSum == 0) {
|
||||
bbbDest.SetColorAt(x, y, nullColor);
|
||||
}
|
||||
} else {
|
||||
int alpha = (int)(aSum / waSum);
|
||||
int blue = (int)(bSum / wcSum);
|
||||
int green = (int)(gSum / wcSum);
|
||||
int red = (int)(rSum / wcSum);
|
||||
if (parentBounds.Contains(applyRect.Left + x, applyRect.Top + y) ^ invert) {
|
||||
} else {
|
||||
int alpha = (int)(aSum / waSum);
|
||||
int red = (int)(rSum / wcSum);
|
||||
int green = (int)(gSum / wcSum);
|
||||
int blue = (int)(bSum / wcSum);
|
||||
bbbDest.SetColorAt(x, y, Color.FromArgb(alpha, red, green, blue));
|
||||
}
|
||||
}
|
||||
|
@ -731,5 +705,103 @@ namespace GreenshotPlugin.Core {
|
|||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue