mirror of
https://github.com/ShareX/ShareX.git
synced 2024-10-01 09:47:22 +13:00
ImageHelpers refactoring
This commit is contained in:
parent
cefae849df
commit
14cde29c05
5 changed files with 335 additions and 350 deletions
|
@ -166,5 +166,43 @@ public static void SetHighQuality(this Graphics g)
|
||||||
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
|
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
|
||||||
g.SmoothingMode = SmoothingMode.HighQuality;
|
g.SmoothingMode = SmoothingMode.HighQuality;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void DrawTextWithOutline(this Graphics g, string text, PointF position, Font font, Color textColor, Color borderColor, int borderSize = 2)
|
||||||
|
{
|
||||||
|
SmoothingMode tempMode = g.SmoothingMode;
|
||||||
|
|
||||||
|
g.SmoothingMode = SmoothingMode.HighQuality;
|
||||||
|
|
||||||
|
using (GraphicsPath gp = new GraphicsPath())
|
||||||
|
{
|
||||||
|
using (StringFormat sf = new StringFormat())
|
||||||
|
{
|
||||||
|
gp.AddString(text, font.FontFamily, (int)font.Style, font.Size, position, sf);
|
||||||
|
}
|
||||||
|
|
||||||
|
using (Pen borderPen = new Pen(borderColor, borderSize) { LineJoin = LineJoin.Round })
|
||||||
|
{
|
||||||
|
g.DrawPath(borderPen, gp);
|
||||||
|
}
|
||||||
|
|
||||||
|
using (Brush textBrush = new SolidBrush(textColor))
|
||||||
|
{
|
||||||
|
g.FillPath(textBrush, gp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g.SmoothingMode = tempMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void DrawTextWithShadow(this Graphics g, string text, PointF position, Font font, Brush textBrush, Brush shadowBrush)
|
||||||
|
{
|
||||||
|
DrawTextWithShadow(g, text, position, font, textBrush, shadowBrush, new Point(1, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void DrawTextWithShadow(this Graphics g, string text, PointF position, Font font, Brush textBrush, Brush shadowBrush, Point shadowOffset)
|
||||||
|
{
|
||||||
|
g.DrawString(text, font, shadowBrush, position.X + shadowOffset.X, position.Y + shadowOffset.Y);
|
||||||
|
g.DrawString(text, font, textBrush, position.X, position.Y);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -200,10 +200,10 @@ public static Image ResizeImageLimit(Image img, int width, int height)
|
||||||
return ResizeImage(img, newWidth, newHeight);
|
return ResizeImage(img, newWidth, newHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Image ResizeImageLimit(Image img, int maxPixels)
|
public static Image ResizeImageLimit(Image img, int maxSize)
|
||||||
{
|
{
|
||||||
double ratio = (double)img.Width / img.Height;
|
double ratio = (double)img.Width / img.Height;
|
||||||
double x = Math.Sqrt(maxPixels / ratio);
|
double x = Math.Sqrt(maxSize / ratio);
|
||||||
|
|
||||||
int width, height;
|
int width, height;
|
||||||
if (ratio > 1)
|
if (ratio > 1)
|
||||||
|
@ -243,44 +243,7 @@ public static Bitmap CropBitmap(Bitmap bmp, Rectangle rect)
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Image DrawOutline(Image img, GraphicsPath gp)
|
/// <summary>Adds empty space around image.</summary>
|
||||||
{
|
|
||||||
if (img != null && gp != null)
|
|
||||||
{
|
|
||||||
Bitmap bmp = new Bitmap(img);
|
|
||||||
|
|
||||||
using (Graphics g = Graphics.FromImage(bmp))
|
|
||||||
{
|
|
||||||
g.SmoothingMode = SmoothingMode.HighQuality;
|
|
||||||
gp.WindingModeOutline();
|
|
||||||
g.DrawPath(Pens.Black, gp);
|
|
||||||
}
|
|
||||||
|
|
||||||
return bmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Bitmap AddSkew(Image img, int x, int y)
|
|
||||||
{
|
|
||||||
Bitmap result = img.CreateEmptyBitmap(Math.Abs(x), Math.Abs(y));
|
|
||||||
|
|
||||||
using (Graphics g = Graphics.FromImage(result))
|
|
||||||
using (img)
|
|
||||||
{
|
|
||||||
g.SetHighQuality();
|
|
||||||
int startX = -Math.Min(0, x);
|
|
||||||
int startY = -Math.Min(0, y);
|
|
||||||
int endX = Math.Max(0, x);
|
|
||||||
int endY = Math.Max(0, y);
|
|
||||||
Point[] destinationPoints = { new Point(startX, startY), new Point(startX + img.Width - 1, endY), new Point(endX, startY + img.Height - 1) };
|
|
||||||
g.DrawImage(img, destinationPoints);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Image AddCanvas(Image img, Padding margin)
|
public static Image AddCanvas(Image img, Padding margin)
|
||||||
{
|
{
|
||||||
Bitmap bmp = img.CreateEmptyBitmap(margin.Horizontal, margin.Vertical);
|
Bitmap bmp = img.CreateEmptyBitmap(margin.Horizontal, margin.Vertical);
|
||||||
|
@ -362,11 +325,31 @@ public static Image DrawReflection(Image img, int percentage, int maxAlpha, int
|
||||||
Bitmap result = new Bitmap(reflection.Width, img.Height + reflection.Height + offset);
|
Bitmap result = new Bitmap(reflection.Width, img.Height + reflection.Height + offset);
|
||||||
|
|
||||||
using (Graphics g = Graphics.FromImage(result))
|
using (Graphics g = Graphics.FromImage(result))
|
||||||
|
using (img)
|
||||||
|
using (reflection)
|
||||||
{
|
{
|
||||||
g.SetHighQuality();
|
g.SetHighQuality();
|
||||||
g.DrawImage(img, 0, 0, img.Width, img.Height);
|
g.DrawImage(img, 0, 0, img.Width, img.Height);
|
||||||
g.DrawImage(reflection, 0, img.Height + offset, reflection.Width, reflection.Height);
|
g.DrawImage(reflection, 0, img.Height + offset, reflection.Width, reflection.Height);
|
||||||
img.Dispose();
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Bitmap AddSkew(Image img, int x, int y)
|
||||||
|
{
|
||||||
|
Bitmap result = img.CreateEmptyBitmap(Math.Abs(x), Math.Abs(y));
|
||||||
|
|
||||||
|
using (Graphics g = Graphics.FromImage(result))
|
||||||
|
using (img)
|
||||||
|
{
|
||||||
|
g.SetHighQuality();
|
||||||
|
int startX = -Math.Min(0, x);
|
||||||
|
int startY = -Math.Min(0, y);
|
||||||
|
int endX = Math.Max(0, x);
|
||||||
|
int endY = Math.Max(0, y);
|
||||||
|
Point[] destinationPoints = { new Point(startX, startY), new Point(startX + img.Width - 1, endY), new Point(endX, startY + img.Height - 1) };
|
||||||
|
g.DrawImage(img, destinationPoints);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -560,44 +543,6 @@ public static Image CreateCheckers(int width, int height, Color color1, Color co
|
||||||
return bmp;
|
return bmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void DrawTextWithOutline(Graphics g, string text, PointF position, Font font, Color textColor, Color borderColor, int borderSize = 2)
|
|
||||||
{
|
|
||||||
SmoothingMode tempMode = g.SmoothingMode;
|
|
||||||
|
|
||||||
g.SmoothingMode = SmoothingMode.HighQuality;
|
|
||||||
|
|
||||||
using (GraphicsPath gp = new GraphicsPath())
|
|
||||||
{
|
|
||||||
using (StringFormat sf = new StringFormat())
|
|
||||||
{
|
|
||||||
gp.AddString(text, font.FontFamily, (int)font.Style, font.Size, position, sf);
|
|
||||||
}
|
|
||||||
|
|
||||||
using (Pen borderPen = new Pen(borderColor, borderSize) { LineJoin = LineJoin.Round })
|
|
||||||
{
|
|
||||||
g.DrawPath(borderPen, gp);
|
|
||||||
}
|
|
||||||
|
|
||||||
using (Brush textBrush = new SolidBrush(textColor))
|
|
||||||
{
|
|
||||||
g.FillPath(textBrush, gp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
g.SmoothingMode = tempMode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void DrawTextWithShadow(Graphics g, string text, PointF position, Font font, Brush textBrush, Brush shadowBrush)
|
|
||||||
{
|
|
||||||
DrawTextWithShadow(g, text, position, font, textBrush, shadowBrush, new Point(1, 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void DrawTextWithShadow(Graphics g, string text, PointF position, Font font, Brush textBrush, Brush shadowBrush, Point shadowOffset)
|
|
||||||
{
|
|
||||||
g.DrawString(text, font, shadowBrush, position.X + shadowOffset.X, position.Y + shadowOffset.Y);
|
|
||||||
g.DrawString(text, font, textBrush, position.X, position.Y);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool IsImagesEqual(Bitmap bmp1, Bitmap bmp2)
|
public static bool IsImagesEqual(Bitmap bmp1, Bitmap bmp2)
|
||||||
{
|
{
|
||||||
using (UnsafeBitmap unsafeBitmap1 = new UnsafeBitmap(bmp1))
|
using (UnsafeBitmap unsafeBitmap1 = new UnsafeBitmap(bmp1))
|
||||||
|
@ -629,7 +574,7 @@ public static bool AddMetadata(Image img, int id, string text)
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
DebugHelper.WriteException(e, "Reflection fail");
|
DebugHelper.WriteException(e, "Reflection failed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -638,6 +583,7 @@ public static bool AddMetadata(Image img, int id, string text)
|
||||||
public static void CopyMetadata(Image fromImage, Image toImage)
|
public static void CopyMetadata(Image fromImage, Image toImage)
|
||||||
{
|
{
|
||||||
PropertyItem[] propertyItems = fromImage.PropertyItems;
|
PropertyItem[] propertyItems = fromImage.PropertyItems;
|
||||||
|
|
||||||
foreach (PropertyItem pi in propertyItems)
|
foreach (PropertyItem pi in propertyItems)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -660,20 +606,20 @@ public static void CopyMetadata(Image fromImage, Image toImage)
|
||||||
/// Note that this method always returns a new Bitmap object, even if rotation is zero - in
|
/// Note that this method always returns a new Bitmap object, even if rotation is zero - in
|
||||||
/// which case the returned object is a clone of the input object.
|
/// which case the returned object is a clone of the input object.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="inputImage">input Image object, is not modified</param>
|
/// <param name="img">input Image object, is not modified</param>
|
||||||
/// <param name="angleDegrees">angle of rotation, in degrees</param>
|
/// <param name="angleDegrees">angle of rotation, in degrees</param>
|
||||||
/// <param name="upsize">see comments above</param>
|
/// <param name="upsize">see comments above</param>
|
||||||
/// <param name="clip">see comments above, not used if upsizeOk = true</param>
|
/// <param name="clip">see comments above, not used if upsizeOk = true</param>
|
||||||
/// <returns>new Bitmap object, may be larger than input image</returns>
|
/// <returns>new Bitmap object, may be larger than input image</returns>
|
||||||
public static Bitmap RotateImage(Image inputImage, float angleDegrees, bool upsize, bool clip)
|
public static Bitmap RotateImage(Image img, float angleDegrees, bool upsize, bool clip)
|
||||||
{
|
{
|
||||||
// Test for zero rotation and return a clone of the input image
|
// Test for zero rotation and return a clone of the input image
|
||||||
if (angleDegrees == 0f)
|
if (angleDegrees == 0f)
|
||||||
return (Bitmap)inputImage.Clone();
|
return (Bitmap)img.Clone();
|
||||||
|
|
||||||
// Set up old and new image dimensions, assuming upsizing not wanted and clipping OK
|
// Set up old and new image dimensions, assuming upsizing not wanted and clipping OK
|
||||||
int oldWidth = inputImage.Width;
|
int oldWidth = img.Width;
|
||||||
int oldHeight = inputImage.Height;
|
int oldHeight = img.Height;
|
||||||
int newWidth = oldWidth;
|
int newWidth = oldWidth;
|
||||||
int newHeight = oldHeight;
|
int newHeight = oldHeight;
|
||||||
float scaleFactor = 1f;
|
float scaleFactor = 1f;
|
||||||
|
@ -698,89 +644,43 @@ public static Bitmap RotateImage(Image inputImage, float angleDegrees, bool upsi
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the new bitmap object.
|
// Create the new bitmap object.
|
||||||
Bitmap newBitmap = new Bitmap(newWidth, newHeight, PixelFormat.Format32bppArgb);
|
Bitmap newBitmap = img.CreateEmptyBitmap();
|
||||||
newBitmap.SetResolution(inputImage.HorizontalResolution, inputImage.VerticalResolution);
|
|
||||||
|
|
||||||
// Create the Graphics object that does the work
|
// Create the Graphics object that does the work
|
||||||
using (Graphics graphicsObject = Graphics.FromImage(newBitmap))
|
using (Graphics g = Graphics.FromImage(newBitmap))
|
||||||
{
|
{
|
||||||
graphicsObject.InterpolationMode = InterpolationMode.HighQualityBicubic;
|
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
|
||||||
graphicsObject.PixelOffsetMode = PixelOffsetMode.HighQuality;
|
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
|
||||||
graphicsObject.SmoothingMode = SmoothingMode.HighQuality;
|
g.SmoothingMode = SmoothingMode.HighQuality;
|
||||||
|
|
||||||
// Set up the built-in transformation matrix to do the rotation and maybe scaling
|
// Set up the built-in transformation matrix to do the rotation and maybe scaling
|
||||||
graphicsObject.TranslateTransform(newWidth / 2f, newHeight / 2f);
|
g.TranslateTransform(newWidth / 2f, newHeight / 2f);
|
||||||
|
|
||||||
if (scaleFactor != 1f)
|
if (scaleFactor != 1f)
|
||||||
graphicsObject.ScaleTransform(scaleFactor, scaleFactor);
|
g.ScaleTransform(scaleFactor, scaleFactor);
|
||||||
|
|
||||||
graphicsObject.RotateTransform(angleDegrees);
|
g.RotateTransform(angleDegrees);
|
||||||
graphicsObject.TranslateTransform(-oldWidth / 2f, -oldHeight / 2f);
|
g.TranslateTransform(-oldWidth / 2f, -oldHeight / 2f);
|
||||||
|
|
||||||
// Draw the result
|
// Draw the result
|
||||||
graphicsObject.DrawImage(inputImage, 0, 0, inputImage.Width, inputImage.Height);
|
g.DrawImage(img, 0, 0, img.Width, img.Height);
|
||||||
}
|
}
|
||||||
|
|
||||||
return newBitmap;
|
return newBitmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Image AnnotateImage(Image img, string imgPath, bool allowSave, string configPath,
|
public static Bitmap AddShadow(Image img, float opacity, int size)
|
||||||
Action<Image> clipboardCopyRequested,
|
|
||||||
Action<Image> imageUploadRequested,
|
|
||||||
Action<Image, string> imageSaveRequested,
|
|
||||||
Func<Image, string, string> imageSaveAsRequested,
|
|
||||||
Action<Image> printImageRequested)
|
|
||||||
{
|
{
|
||||||
if (!IniConfig.isInitialized)
|
return AddShadow(img, opacity, size, 1, Color.Black, new Point(0, 0));
|
||||||
{
|
|
||||||
IniConfig.AllowSave = allowSave;
|
|
||||||
IniConfig.Init(configPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
using (Image cloneImage = img != null ? (Image)img.Clone() : LoadImage(imgPath))
|
|
||||||
using (ICapture capture = new Capture { Image = cloneImage })
|
|
||||||
using (Surface surface = new Surface(capture))
|
|
||||||
using (ImageEditorForm editor = new ImageEditorForm(surface, true))
|
|
||||||
{
|
|
||||||
editor.IsTaskWork = img != null;
|
|
||||||
editor.SetImagePath(imgPath);
|
|
||||||
editor.ClipboardCopyRequested += clipboardCopyRequested;
|
|
||||||
editor.ImageUploadRequested += imageUploadRequested;
|
|
||||||
editor.ImageSaveRequested += imageSaveRequested;
|
|
||||||
editor.ImageSaveAsRequested += imageSaveAsRequested;
|
|
||||||
editor.PrintImageRequested += printImageRequested;
|
|
||||||
|
|
||||||
DialogResult result = editor.ShowDialog();
|
|
||||||
|
|
||||||
if (result == DialogResult.OK && editor.IsTaskWork)
|
|
||||||
{
|
|
||||||
using (img)
|
|
||||||
{
|
|
||||||
return editor.GetImageForExport();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result == DialogResult.Abort)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return img;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Bitmap AddShadow(Image sourceImage, float opacity, int size)
|
public static Bitmap AddShadow(Image img, float opacity, int size, float darkness, Color color, Point offset)
|
||||||
{
|
|
||||||
return AddShadow(sourceImage, opacity, size, 1, Color.Black, new Point(0, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Bitmap AddShadow(Image sourceImage, float opacity, int size, float darkness, Color color, Point offset)
|
|
||||||
{
|
{
|
||||||
Image shadowImage = null;
|
Image shadowImage = null;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
shadowImage = sourceImage.CreateEmptyBitmap(size * 2, size * 2);
|
shadowImage = img.CreateEmptyBitmap(size * 2, size * 2);
|
||||||
|
|
||||||
ColorMatrix maskMatrix = new ColorMatrix();
|
ColorMatrix maskMatrix = new ColorMatrix();
|
||||||
maskMatrix.Matrix00 = 0;
|
maskMatrix.Matrix00 = 0;
|
||||||
|
@ -791,8 +691,8 @@ public static Bitmap AddShadow(Image sourceImage, float opacity, int size, float
|
||||||
maskMatrix.Matrix41 = ((float)color.G).Remap(0, 255, 0, 1);
|
maskMatrix.Matrix41 = ((float)color.G).Remap(0, 255, 0, 1);
|
||||||
maskMatrix.Matrix42 = ((float)color.B).Remap(0, 255, 0, 1);
|
maskMatrix.Matrix42 = ((float)color.B).Remap(0, 255, 0, 1);
|
||||||
|
|
||||||
Rectangle shadowRectangle = new Rectangle(size, size, sourceImage.Width, sourceImage.Height);
|
Rectangle shadowRectangle = new Rectangle(size, size, img.Width, img.Height);
|
||||||
maskMatrix.Apply(sourceImage, shadowImage, shadowRectangle);
|
maskMatrix.Apply(img, shadowImage, shadowRectangle);
|
||||||
|
|
||||||
if (size > 0)
|
if (size > 0)
|
||||||
{
|
{
|
||||||
|
@ -815,190 +715,18 @@ public static Bitmap AddShadow(Image sourceImage, float opacity, int size, float
|
||||||
{
|
{
|
||||||
g.SetHighQuality();
|
g.SetHighQuality();
|
||||||
g.DrawImage(shadowImage, Math.Max(0, offset.X), Math.Max(0, offset.Y), shadowImage.Width, shadowImage.Height);
|
g.DrawImage(shadowImage, Math.Max(0, offset.X), Math.Max(0, offset.Y), shadowImage.Width, shadowImage.Height);
|
||||||
g.DrawImage(sourceImage, Math.Max(size, -offset.X + size), Math.Max(size, -offset.Y + size), sourceImage.Width, sourceImage.Height);
|
g.DrawImage(img, Math.Max(size, -offset.X + size), Math.Max(size, -offset.Y + size), img.Width, img.Height);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
if (sourceImage != null) sourceImage.Dispose();
|
if (img != null) img.Dispose();
|
||||||
if (shadowImage != null) shadowImage.Dispose();
|
if (shadowImage != null) shadowImage.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Blur(Bitmap sourceImage, int radius)
|
|
||||||
{
|
|
||||||
if (GDIplus.IsBlurPossible(radius))
|
|
||||||
{
|
|
||||||
GDIplus.ApplyBlur(sourceImage, new Rectangle(0, 0, sourceImage.Width, sourceImage.Height), radius, false);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ImageHelper.ApplyBoxBlur(sourceImage, radius);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Bitmap Pixelate(Bitmap sourceImage, int pixelSize)
|
|
||||||
{
|
|
||||||
pixelSize = Math.Min(pixelSize, sourceImage.Width);
|
|
||||||
pixelSize = Math.Min(pixelSize, sourceImage.Height);
|
|
||||||
|
|
||||||
Bitmap result = sourceImage.CreateEmptyBitmap();
|
|
||||||
|
|
||||||
using (IFastBitmap src = FastBitmap.Create(sourceImage, new Rectangle(0, 0, sourceImage.Width, sourceImage.Height)))
|
|
||||||
using (IFastBitmap dest = FastBitmap.Create(result))
|
|
||||||
{
|
|
||||||
List<Color> colors = new List<Color>();
|
|
||||||
int halbPixelSize = pixelSize / 2;
|
|
||||||
for (int y = src.Top - halbPixelSize; y < src.Bottom + halbPixelSize; y = y + pixelSize)
|
|
||||||
{
|
|
||||||
for (int x = src.Left - halbPixelSize; x <= src.Right + halbPixelSize; x = x + pixelSize)
|
|
||||||
{
|
|
||||||
colors.Clear();
|
|
||||||
for (int yy = y; yy < y + pixelSize; yy++)
|
|
||||||
{
|
|
||||||
if (yy >= src.Top && yy < src.Bottom)
|
|
||||||
{
|
|
||||||
for (int xx = x; xx < x + pixelSize; xx++)
|
|
||||||
{
|
|
||||||
if (xx >= src.Left && xx < src.Right)
|
|
||||||
{
|
|
||||||
colors.Add(src.GetColorAt(xx, yy));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Color currentAvgColor = ColorHelpers.Mix(colors);
|
|
||||||
for (int yy = y; yy <= y + pixelSize; yy++)
|
|
||||||
{
|
|
||||||
if (yy >= src.Top && yy < src.Bottom)
|
|
||||||
{
|
|
||||||
for (int xx = x; xx <= x + pixelSize; xx++)
|
|
||||||
{
|
|
||||||
if (xx >= src.Left && xx < src.Right)
|
|
||||||
{
|
|
||||||
dest.SetColorAt(xx, yy, currentAvgColor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Image CreateTornEdge(Image sourceImage, int toothHeight, int horizontalToothRange, int verticalToothRange, AnchorStyles sides)
|
|
||||||
{
|
|
||||||
Image result = sourceImage.CreateEmptyBitmap();
|
|
||||||
|
|
||||||
using (GraphicsPath path = new GraphicsPath())
|
|
||||||
{
|
|
||||||
Random random = new Random();
|
|
||||||
int horizontalRegions = sourceImage.Width / horizontalToothRange;
|
|
||||||
int verticalRegions = sourceImage.Height / verticalToothRange;
|
|
||||||
|
|
||||||
Point previousEndingPoint = new Point(horizontalToothRange, random.Next(1, toothHeight));
|
|
||||||
Point newEndingPoint;
|
|
||||||
|
|
||||||
if (sides.HasFlag(AnchorStyles.Top))
|
|
||||||
{
|
|
||||||
for (int i = 0; i < horizontalRegions; i++)
|
|
||||||
{
|
|
||||||
int x = previousEndingPoint.X + horizontalToothRange;
|
|
||||||
int y = random.Next(1, toothHeight);
|
|
||||||
newEndingPoint = new Point(x, y);
|
|
||||||
path.AddLine(previousEndingPoint, newEndingPoint);
|
|
||||||
previousEndingPoint = newEndingPoint;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
previousEndingPoint = new Point(0, 0);
|
|
||||||
newEndingPoint = new Point(sourceImage.Width, 0);
|
|
||||||
path.AddLine(previousEndingPoint, newEndingPoint);
|
|
||||||
previousEndingPoint = newEndingPoint;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sides.HasFlag(AnchorStyles.Right))
|
|
||||||
{
|
|
||||||
for (int i = 0; i < verticalRegions; i++)
|
|
||||||
{
|
|
||||||
int x = sourceImage.Width - random.Next(1, toothHeight);
|
|
||||||
int y = previousEndingPoint.Y + verticalToothRange;
|
|
||||||
newEndingPoint = new Point(x, y);
|
|
||||||
path.AddLine(previousEndingPoint, newEndingPoint);
|
|
||||||
previousEndingPoint = newEndingPoint;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
previousEndingPoint = new Point(sourceImage.Width, 0);
|
|
||||||
newEndingPoint = new Point(sourceImage.Width, sourceImage.Height);
|
|
||||||
path.AddLine(previousEndingPoint, newEndingPoint);
|
|
||||||
previousEndingPoint = newEndingPoint;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sides.HasFlag(AnchorStyles.Bottom))
|
|
||||||
{
|
|
||||||
for (int i = 0; i < horizontalRegions; i++)
|
|
||||||
{
|
|
||||||
int x = previousEndingPoint.X - horizontalToothRange;
|
|
||||||
int y = sourceImage.Height - random.Next(1, toothHeight);
|
|
||||||
newEndingPoint = new Point(x, y);
|
|
||||||
path.AddLine(previousEndingPoint, newEndingPoint);
|
|
||||||
previousEndingPoint = newEndingPoint;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
previousEndingPoint = new Point(sourceImage.Width, sourceImage.Height);
|
|
||||||
newEndingPoint = new Point(0, sourceImage.Height);
|
|
||||||
path.AddLine(previousEndingPoint, newEndingPoint);
|
|
||||||
previousEndingPoint = newEndingPoint;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sides.HasFlag(AnchorStyles.Left))
|
|
||||||
{
|
|
||||||
for (int i = 0; i < verticalRegions; i++)
|
|
||||||
{
|
|
||||||
int x = random.Next(1, toothHeight);
|
|
||||||
int y = previousEndingPoint.Y - verticalToothRange;
|
|
||||||
newEndingPoint = new Point(x, y);
|
|
||||||
path.AddLine(previousEndingPoint, newEndingPoint);
|
|
||||||
previousEndingPoint = newEndingPoint;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
previousEndingPoint = new Point(0, sourceImage.Height);
|
|
||||||
newEndingPoint = new Point(0, 0);
|
|
||||||
path.AddLine(previousEndingPoint, newEndingPoint);
|
|
||||||
previousEndingPoint = newEndingPoint;
|
|
||||||
}
|
|
||||||
|
|
||||||
path.CloseFigure();
|
|
||||||
|
|
||||||
using (Graphics graphics = Graphics.FromImage(result))
|
|
||||||
{
|
|
||||||
graphics.SmoothingMode = SmoothingMode.HighQuality;
|
|
||||||
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
|
|
||||||
graphics.CompositingQuality = CompositingQuality.HighQuality;
|
|
||||||
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
|
|
||||||
|
|
||||||
// Draw the created figure with the original image by using a TextureBrush so we have anti-aliasing
|
|
||||||
using (Brush brush = new TextureBrush(sourceImage))
|
|
||||||
{
|
|
||||||
graphics.FillPath(brush, path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Bitmap Sharpen(Image image, double strength)
|
public static Bitmap Sharpen(Image image, double strength)
|
||||||
{
|
{
|
||||||
using (Bitmap bitmap = (Bitmap)image)
|
using (Bitmap bitmap = (Bitmap)image)
|
||||||
|
@ -1099,6 +827,39 @@ public static Bitmap Sharpen(Image image, double strength)
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void HighlightImage(Bitmap bmp)
|
||||||
|
{
|
||||||
|
HighlightImage(bmp, new Rectangle(0, 0, bmp.Width, bmp.Height));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void HighlightImage(Bitmap bmp, Color highlightColor)
|
||||||
|
{
|
||||||
|
HighlightImage(bmp, new Rectangle(0, 0, bmp.Width, bmp.Height), highlightColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void HighlightImage(Bitmap bmp, Rectangle rect)
|
||||||
|
{
|
||||||
|
HighlightImage(bmp, rect, Color.Yellow);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void HighlightImage(Bitmap bmp, Rectangle rect, Color highlightColor)
|
||||||
|
{
|
||||||
|
using (UnsafeBitmap unsafeBitmap = new UnsafeBitmap(bmp, true))
|
||||||
|
{
|
||||||
|
for (int y = rect.Y; y < rect.Height; y++)
|
||||||
|
{
|
||||||
|
for (int x = rect.X; x < rect.Width; x++)
|
||||||
|
{
|
||||||
|
ColorBgra color = unsafeBitmap.GetPixel(x, y);
|
||||||
|
color.Red = Math.Min(color.Red, highlightColor.R);
|
||||||
|
color.Green = Math.Min(color.Green, highlightColor.G);
|
||||||
|
color.Blue = Math.Min(color.Blue, highlightColor.B);
|
||||||
|
unsafeBitmap.SetPixel(x, y, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static string OpenImageFileDialog()
|
public static string OpenImageFileDialog()
|
||||||
{
|
{
|
||||||
string[] images = OpenImageFileDialog(false);
|
string[] images = OpenImageFileDialog(false);
|
||||||
|
@ -1302,37 +1063,225 @@ public static void DrawColorPickerIcon(Graphics g, Color color, Rectangle rect,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void HighlightImage(Bitmap bmp)
|
#region Greenshot methods
|
||||||
{
|
|
||||||
HighlightImage(bmp, new Rectangle(0, 0, bmp.Width, bmp.Height));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void HighlightImage(Bitmap bmp, Color highlightColor)
|
public static Image AnnotateImage(Image img, string imgPath, bool allowSave, string configPath,
|
||||||
|
Action<Image> clipboardCopyRequested,
|
||||||
|
Action<Image> imageUploadRequested,
|
||||||
|
Action<Image, string> imageSaveRequested,
|
||||||
|
Func<Image, string, string> imageSaveAsRequested,
|
||||||
|
Action<Image> printImageRequested)
|
||||||
{
|
{
|
||||||
HighlightImage(bmp, new Rectangle(0, 0, bmp.Width, bmp.Height), highlightColor);
|
if (!IniConfig.isInitialized)
|
||||||
}
|
|
||||||
|
|
||||||
public static void HighlightImage(Bitmap bmp, Rectangle rect)
|
|
||||||
{
|
|
||||||
HighlightImage(bmp, rect, Color.Yellow);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void HighlightImage(Bitmap bmp, Rectangle rect, Color highlightColor)
|
|
||||||
{
|
|
||||||
using (UnsafeBitmap unsafeBitmap = new UnsafeBitmap(bmp, true))
|
|
||||||
{
|
{
|
||||||
for (int y = rect.Y; y < rect.Height; y++)
|
IniConfig.AllowSave = allowSave;
|
||||||
|
IniConfig.Init(configPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
using (Image cloneImage = img != null ? (Image)img.Clone() : LoadImage(imgPath))
|
||||||
|
using (ICapture capture = new Capture { Image = cloneImage })
|
||||||
|
using (Surface surface = new Surface(capture))
|
||||||
|
using (ImageEditorForm editor = new ImageEditorForm(surface, true))
|
||||||
|
{
|
||||||
|
editor.IsTaskWork = img != null;
|
||||||
|
editor.SetImagePath(imgPath);
|
||||||
|
editor.ClipboardCopyRequested += clipboardCopyRequested;
|
||||||
|
editor.ImageUploadRequested += imageUploadRequested;
|
||||||
|
editor.ImageSaveRequested += imageSaveRequested;
|
||||||
|
editor.ImageSaveAsRequested += imageSaveAsRequested;
|
||||||
|
editor.PrintImageRequested += printImageRequested;
|
||||||
|
|
||||||
|
DialogResult result = editor.ShowDialog();
|
||||||
|
|
||||||
|
if (result == DialogResult.OK && editor.IsTaskWork)
|
||||||
{
|
{
|
||||||
for (int x = rect.X; x < rect.Width; x++)
|
using (img)
|
||||||
{
|
{
|
||||||
ColorBgra color = unsafeBitmap.GetPixel(x, y);
|
return editor.GetImageForExport();
|
||||||
color.Red = Math.Min(color.Red, highlightColor.R);
|
}
|
||||||
color.Green = Math.Min(color.Green, highlightColor.G);
|
}
|
||||||
color.Blue = Math.Min(color.Blue, highlightColor.B);
|
|
||||||
unsafeBitmap.SetPixel(x, y, color);
|
if (result == DialogResult.Abort)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return img;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Blur(Bitmap sourceImage, int radius)
|
||||||
|
{
|
||||||
|
if (GDIplus.IsBlurPossible(radius))
|
||||||
|
{
|
||||||
|
GDIplus.ApplyBlur(sourceImage, new Rectangle(0, 0, sourceImage.Width, sourceImage.Height), radius, false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ImageHelper.ApplyBoxBlur(sourceImage, radius);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Bitmap Pixelate(Bitmap sourceImage, int pixelSize)
|
||||||
|
{
|
||||||
|
pixelSize = Math.Min(pixelSize, sourceImage.Width);
|
||||||
|
pixelSize = Math.Min(pixelSize, sourceImage.Height);
|
||||||
|
|
||||||
|
Bitmap result = sourceImage.CreateEmptyBitmap();
|
||||||
|
|
||||||
|
using (IFastBitmap src = FastBitmap.Create(sourceImage, new Rectangle(0, 0, sourceImage.Width, sourceImage.Height)))
|
||||||
|
using (IFastBitmap dest = FastBitmap.Create(result))
|
||||||
|
{
|
||||||
|
List<Color> colors = new List<Color>();
|
||||||
|
int halbPixelSize = pixelSize / 2;
|
||||||
|
for (int y = src.Top - halbPixelSize; y < src.Bottom + halbPixelSize; y = y + pixelSize)
|
||||||
|
{
|
||||||
|
for (int x = src.Left - halbPixelSize; x <= src.Right + halbPixelSize; x = x + pixelSize)
|
||||||
|
{
|
||||||
|
colors.Clear();
|
||||||
|
for (int yy = y; yy < y + pixelSize; yy++)
|
||||||
|
{
|
||||||
|
if (yy >= src.Top && yy < src.Bottom)
|
||||||
|
{
|
||||||
|
for (int xx = x; xx < x + pixelSize; xx++)
|
||||||
|
{
|
||||||
|
if (xx >= src.Left && xx < src.Right)
|
||||||
|
{
|
||||||
|
colors.Add(src.GetColorAt(xx, yy));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Color currentAvgColor = ColorHelpers.Mix(colors);
|
||||||
|
for (int yy = y; yy <= y + pixelSize; yy++)
|
||||||
|
{
|
||||||
|
if (yy >= src.Top && yy < src.Bottom)
|
||||||
|
{
|
||||||
|
for (int xx = x; xx <= x + pixelSize; xx++)
|
||||||
|
{
|
||||||
|
if (xx >= src.Left && xx < src.Right)
|
||||||
|
{
|
||||||
|
dest.SetColorAt(xx, yy, currentAvgColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Image CreateTornEdge(Image sourceImage, int toothHeight, int horizontalToothRange, int verticalToothRange, AnchorStyles sides)
|
||||||
|
{
|
||||||
|
Image result = sourceImage.CreateEmptyBitmap();
|
||||||
|
|
||||||
|
using (GraphicsPath path = new GraphicsPath())
|
||||||
|
{
|
||||||
|
Random random = new Random();
|
||||||
|
int horizontalRegions = sourceImage.Width / horizontalToothRange;
|
||||||
|
int verticalRegions = sourceImage.Height / verticalToothRange;
|
||||||
|
|
||||||
|
Point previousEndingPoint = new Point(horizontalToothRange, random.Next(1, toothHeight));
|
||||||
|
Point newEndingPoint;
|
||||||
|
|
||||||
|
if (sides.HasFlag(AnchorStyles.Top))
|
||||||
|
{
|
||||||
|
for (int i = 0; i < horizontalRegions; i++)
|
||||||
|
{
|
||||||
|
int x = previousEndingPoint.X + horizontalToothRange;
|
||||||
|
int y = random.Next(1, toothHeight);
|
||||||
|
newEndingPoint = new Point(x, y);
|
||||||
|
path.AddLine(previousEndingPoint, newEndingPoint);
|
||||||
|
previousEndingPoint = newEndingPoint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
previousEndingPoint = new Point(0, 0);
|
||||||
|
newEndingPoint = new Point(sourceImage.Width, 0);
|
||||||
|
path.AddLine(previousEndingPoint, newEndingPoint);
|
||||||
|
previousEndingPoint = newEndingPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sides.HasFlag(AnchorStyles.Right))
|
||||||
|
{
|
||||||
|
for (int i = 0; i < verticalRegions; i++)
|
||||||
|
{
|
||||||
|
int x = sourceImage.Width - random.Next(1, toothHeight);
|
||||||
|
int y = previousEndingPoint.Y + verticalToothRange;
|
||||||
|
newEndingPoint = new Point(x, y);
|
||||||
|
path.AddLine(previousEndingPoint, newEndingPoint);
|
||||||
|
previousEndingPoint = newEndingPoint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
previousEndingPoint = new Point(sourceImage.Width, 0);
|
||||||
|
newEndingPoint = new Point(sourceImage.Width, sourceImage.Height);
|
||||||
|
path.AddLine(previousEndingPoint, newEndingPoint);
|
||||||
|
previousEndingPoint = newEndingPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sides.HasFlag(AnchorStyles.Bottom))
|
||||||
|
{
|
||||||
|
for (int i = 0; i < horizontalRegions; i++)
|
||||||
|
{
|
||||||
|
int x = previousEndingPoint.X - horizontalToothRange;
|
||||||
|
int y = sourceImage.Height - random.Next(1, toothHeight);
|
||||||
|
newEndingPoint = new Point(x, y);
|
||||||
|
path.AddLine(previousEndingPoint, newEndingPoint);
|
||||||
|
previousEndingPoint = newEndingPoint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
previousEndingPoint = new Point(sourceImage.Width, sourceImage.Height);
|
||||||
|
newEndingPoint = new Point(0, sourceImage.Height);
|
||||||
|
path.AddLine(previousEndingPoint, newEndingPoint);
|
||||||
|
previousEndingPoint = newEndingPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sides.HasFlag(AnchorStyles.Left))
|
||||||
|
{
|
||||||
|
for (int i = 0; i < verticalRegions; i++)
|
||||||
|
{
|
||||||
|
int x = random.Next(1, toothHeight);
|
||||||
|
int y = previousEndingPoint.Y - verticalToothRange;
|
||||||
|
newEndingPoint = new Point(x, y);
|
||||||
|
path.AddLine(previousEndingPoint, newEndingPoint);
|
||||||
|
previousEndingPoint = newEndingPoint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
previousEndingPoint = new Point(0, sourceImage.Height);
|
||||||
|
newEndingPoint = new Point(0, 0);
|
||||||
|
path.AddLine(previousEndingPoint, newEndingPoint);
|
||||||
|
previousEndingPoint = newEndingPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
path.CloseFigure();
|
||||||
|
|
||||||
|
using (Graphics graphics = Graphics.FromImage(result))
|
||||||
|
{
|
||||||
|
graphics.SmoothingMode = SmoothingMode.HighQuality;
|
||||||
|
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
|
||||||
|
graphics.CompositingQuality = CompositingQuality.HighQuality;
|
||||||
|
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
|
||||||
|
|
||||||
|
// Draw the created figure with the original image by using a TextureBrush so we have anti-aliasing
|
||||||
|
using (Brush brush = new TextureBrush(sourceImage))
|
||||||
|
{
|
||||||
|
graphics.FillPath(brush, path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Greenshot methods
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -281,8 +281,7 @@ private Image CombineScreenshots(List<VideoThumbnailInfo> thumbnails)
|
||||||
|
|
||||||
using (Font font = new Font("Arial", 10, FontStyle.Bold))
|
using (Font font = new Font("Arial", 10, FontStyle.Bold))
|
||||||
{
|
{
|
||||||
ImageHelpers.DrawTextWithShadow(g, thumbnails[i].Timestamp.ToString(),
|
g.DrawTextWithShadow(thumbnails[i].Timestamp.ToString(), new Point(offsetX + timestampOffset, offsetY + timestampOffset), font, Brushes.White, Brushes.Black);
|
||||||
new Point(offsetX + timestampOffset, offsetY + timestampOffset), font, Brushes.White, Brushes.Black);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -581,7 +581,7 @@ private void DrawFPS(Graphics g, int offset)
|
||||||
{
|
{
|
||||||
Rectangle screenBounds = CaptureHelpers.GetActiveScreenBounds0Based();
|
Rectangle screenBounds = CaptureHelpers.GetActiveScreenBounds0Based();
|
||||||
|
|
||||||
ImageHelpers.DrawTextWithShadow(g, FPS.ToString(), screenBounds.Location.Add(offset), infoFontBig, Brushes.White, Brushes.Black, new Point(0, 1));
|
g.DrawTextWithShadow(FPS.ToString(), screenBounds.Location.Add(offset), infoFontBig, Brushes.White, Brushes.Black, new Point(0, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawInfoText(Graphics g, string text, Rectangle rect, Font font, int padding)
|
private void DrawInfoText(Graphics g, string text, Rectangle rect, Font font, int padding)
|
||||||
|
@ -596,7 +596,7 @@ private void DrawInfoText(Graphics g, string text, Rectangle rect, Font font, in
|
||||||
g.DrawRectangleProper(innerBorderPen, rect.Offset(-1));
|
g.DrawRectangleProper(innerBorderPen, rect.Offset(-1));
|
||||||
g.DrawRectangleProper(outerBorderPen, rect);
|
g.DrawRectangleProper(outerBorderPen, rect);
|
||||||
|
|
||||||
ImageHelpers.DrawTextWithShadow(g, text, rect.Offset(-padding).Location, font, textBrush, textShadowBrush);
|
g.DrawTextWithShadow(text, rect.Offset(-padding).Location, font, textBrush, textShadowBrush);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawAreaText(Graphics g, string text, Rectangle area)
|
private void DrawAreaText(Graphics g, string text, Rectangle area)
|
||||||
|
|
|
@ -371,8 +371,7 @@ private void DrawInfoText(Graphics g, string text, Rectangle rect, int padding)
|
||||||
g.FillRectangle(textBackgroundBrush, rect.Offset(-2));
|
g.FillRectangle(textBackgroundBrush, rect.Offset(-2));
|
||||||
g.DrawRectangleProper(textBackgroundPenBlack, rect.Offset(-1));
|
g.DrawRectangleProper(textBackgroundPenBlack, rect.Offset(-1));
|
||||||
g.DrawRectangleProper(textBackgroundPenWhite, rect);
|
g.DrawRectangleProper(textBackgroundPenWhite, rect);
|
||||||
|
g.DrawTextWithShadow(text, rect.Offset(-padding).Location, infoFont, Brushes.White, Brushes.Black);
|
||||||
ImageHelpers.DrawTextWithShadow(g, text, rect.Offset(-padding).Location, infoFont, Brushes.White, Brushes.Black);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawTips(Graphics g, int offset, int padding)
|
private void DrawTips(Graphics g, int offset, int padding)
|
||||||
|
|
Loading…
Reference in a new issue