Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Highlight effect like snipping tool

Im creating a new snipping tool similar to the windows 7 snipping tool.

however I cant get the highlight effect working the same.

for example, the snipping tool highlight works as follows: (The highlight is very bright on a white background, it looks like it has no transparency

enter image description here

and my snipping tool highlight looks as follows:

enter image description here

Im sure the color used is the same (255,255,0) with an alpha channel of 110. if i decrease the transparency then it just overwrites the text below.

my snip is applying the transparency over the top of the white, where as the windows snipping tool seems to blend it all better.

What am i doing wrong here?

the code I am using for my highlight annotation is:

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

    namespace Sicon.Snipper.Annotations
    {
        /// <summary>
        /// Highlight Annotation
        /// </summary>
        public class HighlightAnnotation : BaseAnnotation
        {
            #region Members

            protected Rectangle _selection = Rectangle.Empty;
            protected const int _transparancyAlpha = 110;
            private Brush _brush;

            #endregion Members

            #region Properties

            /// <summary>
            /// Gets or Sets the Brush
            /// </summary>
            protected Brush Brush
            {
                get { return _brush; }
                set { _brush = value; }
            }

            /// <summary>
            /// Gets the Selection
            /// </summary>
            public Rectangle Selection
            {
                get { return _selection; }
                protected set { _selection = value; }
            }

            #endregion Properties

            #region Constructors

            /// <summary>
            /// Constructor
            /// </summary>
            /// <param name="imageRef">Reference to the image</param>
            public HighlightAnnotation(Image imageRef, Control host)
                : base(imageRef, Pens.Yellow, host)
            {
                this.Brush = new SolidBrush(
                                Color.FromArgb(
                                _transparancyAlpha,
                                this.Pen.Color));
            }

            #endregion Constructors

            #region Methods

            /// <summary>
            /// Handles on Mouse down
            /// </summary>
            /// <param name="e">args</param>
            public override void OnMouseDown(MouseEventArgs e)
            {
                if (base.Enabled)
                {
                    // Start the snip on mouse down
                    if (e.Button != MouseButtons.Left) return;
                    _startPoint = e.Location;
                    _selection = new Rectangle(e.Location, new Size(0, 0));
                }
            }

            /// <summary>
            /// Handles Mouse Move
            /// </summary>
            /// <param name="e">args</param>
            public override void OnMouseMove(MouseEventArgs e)
            {
                if (base.Enabled)
                {
                    // Modify the selection on mouse move
                    if (e.Button != MouseButtons.Left) return;
                    int x1 = Math.Min(e.X, _startPoint.X);
                    int y1 = Math.Min(e.Y, _startPoint.Y);
                    int x2 = Math.Max(e.X, _startPoint.X);
                    int y2 = Math.Max(e.Y, _startPoint.Y);
                    _selection = new Rectangle(x1, y1, x2 - x1, y2 - y1);
                }
            }

            /// <summary>
            /// Handles on mouse up
            /// </summary>
            /// <param name="e">args</param>
            public override void OnMouseUp(MouseEventArgs e)
            {
                if (base.Enabled)
                {
                    if (_selection.Width <= 0 || _selection.Height <= 0) return;

                    using (Graphics g = Graphics.FromImage(this.ImageRef))
                    {
                        Rectangle dest = new Rectangle(
                            TranslateCenterImageMousePosition(_startPoint),
                            _selection.Size);

                        g.FillRectangle(
                            this.Brush,
                            dest);

                    }

                    this.Enabled = false;
                }
            }

            /// <summary>
            /// Hanles on paint
            /// </summary>
            /// <param name="g">graphics</param>
            public override void OnPaint(System.Drawing.Graphics g)
            {
                if (base.Enabled)
                    g.FillRectangle(this.Brush, _selection);
            }

            #endregion Methods
        }
    }

UPDATE::

Ok, I have made a few changes, I like the idea of freehand drawing too, but the main reason im making this is to have nice tidy highlights etc.

The issue I have now is that when i release the mouse button the rectangle gets drawn in black as image below. its almost there!

GDI32.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;

namespace Sicon.Snipper.Tools
{
    public static class GDI32
    {
        [DllImport("gdi32.dll")]
        public static extern int SetROP2(IntPtr hdc, int fnDrawMode);

        [DllImport("gdi32.dll")]
        public static extern IntPtr CreatePen(int fnPenStyle, int nWidth, uint crColor);

        [DllImport("gdi32.dll")]
        public static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj);

        [DllImport("gdi32.dll")]
        public static extern bool DeleteObject(IntPtr hObject);

        [DllImport("gdi32.dll")]
        public static extern bool MoveToEx(IntPtr hdc, int X, int Y, IntPtr lpPoint);

        [DllImport("gdi32.dll")]
        public static extern bool LineTo(IntPtr hdc, int nXEnd, int nYEnd);

        [DllImport("gdi32.dll")]
        public static extern bool Rectangle(IntPtr hdc, int nLeftRect, int nTopRect, int nRightRect, int nBottomRect);
    }
}

New Hightlight Annotation.cs

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Sicon.Snipper.Enums;
using Sicon.Snipper.Tools;

namespace Sicon.Snipper.Annotations
{
    /// <summary>
    /// Highlight Annotation
    /// </summary>
    public class HighlightAnnotation : BaseAnnotation
    {
        #region Members

        protected Rectangle _selection = Rectangle.Empty;
        protected const int _transparancyAlpha = 110;
        private ShapeEnum _shape = ShapeEnum.Rectangle;
        List<Point> points = new List<Point>();
        private const int PS_SOLID = 0;
        private const int R2_MASKPEN = 9;
        private const int R2_COPYPEN = 13;

        #endregion Members

        #region Properties

        /// <summary>
        /// Gets or Sets the Shape
        /// </summary>
        public ShapeEnum Shape
        {
            get { return _shape; }
            set { _shape = value; }
        }

        /// <summary>
        /// Gets the Selection
        /// </summary>
        public Rectangle Selection
        {
            get { return _selection; }
            protected set { _selection = value; }
        }

        #endregion Properties

        #region Constructors

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="imageRef">Reference to the image</param>
        public HighlightAnnotation(Image imageRef, Control host, ShapeEnum shape)
            : base(imageRef, new Pen(Color.Yellow, 16), host)
        {
            _shape = shape;
        }

        #endregion Constructors

        #region Methods

        /// <summary>
        /// Handles on Mouse down
        /// </summary>
        /// <param name="e">args</param>
        public override void OnMouseDown(MouseEventArgs e)
        {
            if (base.Enabled)
            {
                // Start the snip on mouse down
                if (e.Button != MouseButtons.Left) return;

                _startPoint = e.Location;
                _selection = new Rectangle(e.Location, new Size(0, 0));
            }
        }

        /// <summary>
        /// Handles Mouse Move
        /// </summary>
        /// <param name="e">args</param>
        public override void OnMouseMove(MouseEventArgs e)
        {
            if (base.Enabled)
            {
                // Modify the selection on mouse move
                if (e.Button != MouseButtons.Left) return;

                //Add freehand points
                points.Add(new Point(e.X, e.Y));

                //Update selection rectangele
                int x1 = Math.Min(e.X, _startPoint.X);
                int y1 = Math.Min(e.Y, _startPoint.Y);
                int x2 = Math.Max(e.X, _startPoint.X);
                int y2 = Math.Max(e.Y, _startPoint.Y);
                _selection = new Rectangle(x1, y1, x2 - x1, y2 - y1);
            }
        }

        /// <summary>
        /// Handles on mouse up
        /// </summary>
        /// <param name="e">args</param>
        public override void OnMouseUp(MouseEventArgs e)
        {
            if (base.Enabled)
            {
                if (_selection.Width <= 0 || _selection.Height <= 0) return;

                using (Graphics g = Graphics.FromImage(this.ImageRef))
                {
                    switch (this.Shape)
                    {
                        case ShapeEnum.Freehand:

                            DrawHighlight(g, points.ToArray());

                            break;

                        case ShapeEnum.Rectangle:

                            Rectangle dest = new Rectangle(
                                TranslateCenterImageMousePosition(_startPoint),
                                _selection.Size);

                            DrawRectange(g);

                            break;

                        default: return;
                    }
                }

                this.Enabled = false;
            }
        }

        /// <summary>
        /// Hanles on paint
        /// </summary>
        /// <param name="g">graphics</param>
        public override void OnPaint(System.Drawing.Graphics g)
        {
            if (base.Enabled)
            {
                switch (this.Shape)
                {
                    case ShapeEnum.Freehand:

                        DrawHighlight(g, points.ToArray());

                        break;

                    case ShapeEnum.Rectangle:

                        DrawRectange(g);

                        break;

                    default: return;
                }
            }
        }

        /// <summary>
        /// Draws a highlight
        /// </summary>
        /// <param name="g">graphics</param>
        /// <param name="usePoints">points to draw</param>
        private void DrawHighlight(Graphics g, Point[] usePoints)
        {
            int useColor = System.Drawing.ColorTranslator.ToWin32(base.Pen.Color);
            IntPtr pen = GDI32.CreatePen(PS_SOLID, (int)base.Pen.Width, (uint)useColor);
            IntPtr hDC = g.GetHdc();
            IntPtr xDC = GDI32.SelectObject(hDC, pen);
            GDI32.SetROP2(hDC, R2_MASKPEN);
            for (int i = 1; i <= usePoints.Length - 1; i++)
            {
                Point p1 = usePoints[i - 1];
                Point p2 = usePoints[i];
                GDI32.MoveToEx(hDC, p1.X, p1.Y, IntPtr.Zero);
                GDI32.LineTo(hDC, p2.X, p2.Y);
            }
            GDI32.SetROP2(hDC, R2_COPYPEN);
            GDI32.SelectObject(hDC, xDC);
            GDI32.DeleteObject(pen);
            g.ReleaseHdc(hDC);
        }

        /// <summary>
        /// Draws a rectangle
        /// </summary>
        /// <param name="g">Graphics</param>
        private void DrawRectange(Graphics g)
        {
            Rectangle dest = new Rectangle(
                                TranslateCenterImageMousePosition(_startPoint),
                                _selection.Size);

            int useColor = System.Drawing.ColorTranslator.ToWin32(base.Pen.Color);
            IntPtr pen = GDI32.CreatePen(PS_SOLID, (int)base.Pen.Width, (uint)useColor);
            IntPtr hDC = g.GetHdc();
            IntPtr xDC = GDI32.SelectObject(hDC, pen);
            GDI32.SetROP2(hDC, R2_MASKPEN);
            GDI32.Rectangle(hDC, dest.Left, dest.Top, dest.Right, dest.Bottom);
            GDI32.SetROP2(hDC, R2_COPYPEN);
            GDI32.SelectObject(hDC, xDC);
            GDI32.DeleteObject(pen);
            g.ReleaseHdc(hDC);
        }

        #endregion Methods
    }
}

enter image description here

like image 838
WraithNath Avatar asked Mar 20 '14 15:03

WraithNath


People also ask

Is there an app like Snipping Tool for Windows?

Fortunately for you, there are numerous apps like Snipping Tool available with a variety of special features and services. You can find a snipping tool for Windows with cloud storage, image editing tools, screen recording capabilities, and integrations with other productivity and messaging apps.

Is there a way to post a snip tool?

There was no posting option for the snipping tool so I posted the closest possible. I don't think I need to click the snip tool icon to open Paint to get a straight highlight line? I grab a screen shot with the snip tool.

What are the disadvantages of Windows Snipping Tool and Snip&Sketch?

One of the biggest drawbacks with both Windows Snipping Tool and Snip & Sketch is their lack of cloud storage capabilities. If you take several screenshots every day, then your desktop screen can fill up rather quickly with files.

What is the difference between Microsoft Snipping Tool and screenpresso?

The Microsoft Snipping Tool is free to download and so is Screenpresso. That’s where the similarities end. Screenpresso is a snipping tool alternative for Windows 10 and earlier that can record audio/video like ScreenRec and export screenshots in different formats like Lightshot.


1 Answers

You can't use an alpha channel for that since that would fade the yellow color.

I think you have to go old school and use the WIN32 API for this:

[DllImport("gdi32.dll")]
static extern int SetROP2(IntPtr hdc, int fnDrawMode);

[DllImport("gdi32.dll")]
static extern IntPtr CreatePen(int fnPenStyle, int nWidth, uint crColor);

[DllImport("gdi32.dll")]
static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj);

[DllImport("gdi32.dll")]
static extern bool DeleteObject(IntPtr hObject);

[DllImport("gdi32.dll")]
static extern bool MoveToEx(IntPtr hdc, int X, int Y, IntPtr lpPoint);

[DllImport("gdi32.dll")]
static extern bool LineTo(IntPtr hdc, int nXEnd, int nYEnd);

private const int PS_SOLID = 0;
private const int R2_MASKPEN = 9;
private const int R2_COPYPEN = 13;

Bitmap bmp = (Bitmap)Image.FromFile(@"c:\....png");
List<Point> points = new List<Point>();

Here is my Highlight function:

private void DrawHighlight(Graphics g, Point[] usePoints,
                           int brushSize, Color brushColor) {
  int useColor = System.Drawing.ColorTranslator.ToWin32(brushColor);
  IntPtr pen = CreatePen(PS_SOLID, brushSize, (uint)useColor);
  IntPtr hDC = g.GetHdc();
  IntPtr xDC = SelectObject(hDC, pen);
  SetROP2(hDC, R2_MASKPEN);
  for (int i = 1; i <= usePoints.Length - 1; i++) {
    Point p1 = usePoints[i - 1];
    Point p2 = usePoints[i];
    MoveToEx(hDC, p1.X, p1.Y, IntPtr.Zero);
    LineTo(hDC, p2.X, p2.Y);
  }
  SetROP2(hDC, R2_COPYPEN);
  SelectObject(hDC, xDC);
  DeleteObject(pen);
  g.ReleaseHdc(hDC);
}

My testing code:

protected override void OnMouseMove(MouseEventArgs e) {
  base.OnMouseMove(e);
  if (e.Button == MouseButtons.Left) {
    points.Add(new Point(e.X, e.Y));
    this.Invalidate();
  }
}

protected override void OnPaint(PaintEventArgs e) {
  base.OnPaint(e);
  e.Graphics.Clear(Color.White);
  e.Graphics.DrawImage(bmp, Point.Empty);
  DrawHighlight(e.Graphics, points.ToArray(), 16, Color.Yellow);
}

The result:

enter image description here

To draw directly on an image instead of control's Graphic object would require a few more API calls:

[DllImport("gdi32.dll")]
public static extern bool BitBlt(IntPtr hdcDst, int x1, int y1, int cx, int cy,
                                 IntPtr hdcSrc, int x2, int y2, int rop);

[DllImport("gdi32.dll")]
static extern IntPtr CreateCompatibleDC(IntPtr hdc);

[DllImport("gdi32.dll")]
static extern bool DeleteDC(IntPtr hdc);

private const int SRCCOPY = 0x00CC0020;

This is the modified code:

private void DrawHighlight(Point[] usePoints, int brushSize, Color brushColor) {
  using (Graphics gBMP = Graphics.FromImage(bmp)) {
    IntPtr hBMP = bmp.GetHbitmap();
    IntPtr bDC = gBMP.GetHdc();
    IntPtr mDC = CreateCompatibleDC(bDC);
    IntPtr oDC = SelectObject(mDC, hBMP);

    int useColor = System.Drawing.ColorTranslator.ToWin32(brushColor);
    IntPtr pen = CreatePen(PS_SOLID, brushSize, (uint)useColor);
    IntPtr xDC = SelectObject(mDC, pen);

    SetROP2(mDC, R2_MASKPEN);
    for (int i = 1; i <= usePoints.Length - 1; i++) {
      Point p1 = usePoints[i - 1];
      Point p2 = usePoints[i];
      MoveToEx(mDC, p1.X, p1.Y, IntPtr.Zero);
      LineTo(mDC, p2.X, p2.Y);
    }
    SetROP2(mDC, R2_COPYPEN);

    BitBlt(bDC, 0, 0, bmp.Width, bmp.Height, mDC, 0, 0, SRCCOPY);
    SelectObject(mDC, xDC);
    DeleteObject(pen);
    gBMP.ReleaseHdc(bDC);
    SelectObject(mDC, oDC);
    DeleteDC(mDC);
    DeleteObject(hBMP);
  }
}
like image 84
LarsTech Avatar answered Sep 18 '22 17:09

LarsTech