【问题标题】:Highlight effect like snipping tool像截图工具一样的高亮效果
【发布时间】:2014-03-20 15:45:29
【问题描述】:

我正在创建一个类似于 windows 7 截图工具的新截图工具。

但是我不能让高亮效果发挥同样的作用。

例如,截图工具高亮的工作原理如下:(高亮在白色背景上非常亮,看起来没有透明度

我的截图工具高亮如下:

我确定使用的颜色相同 (255,255,0),alpha 通道为 110。如果我降低透明度,那么它只会覆盖下面的文本。

我的截图是在白色的顶部应用透明度,而 windows 截图工具似乎可以更好地融合它。

我在这里做错了什么?

我用于高亮注释的代码是:

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
        }
    }

更新::

好的,我做了一些改变,我也喜欢手绘的想法,但我这样做的主要原因是有漂亮整洁的亮点等。

我现在遇到的问题是,当我释放鼠标按钮时,矩形被绘制为黑色,如下图所示。快到了!

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);
    }
}

新的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
    }
}

【问题讨论】:

    标签: c# winforms graphics


    【解决方案1】:

    您不能为此使用 Alpha 通道,因为这会使黄色褪色。

    我认为你必须回到老学校并为此使用 WIN32 API:

    [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>();
    

    这是我的高亮功能:

    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);
    }
    

    我的测试代码:

    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);
    }
    

    结果:

    要直接在图像上而不是控件的 Graphic 对象上绘图,需要更多的 API 调用:

    [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;
    

    这是修改后的代码:

    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);
      }
    }
    

    【讨论】:

    • 哇,谢谢,看起来它会工作的!我会尽快进行一些更改并回复您
    • 嗨,我说得更远了,但现在还有几个问题,我喜欢你的手绘想法,所以添加了一个形状枚举来手绘或矩形。我已经添加了问题的更新。你介意和我再看看吗?我可以发送整个源代码,但我使用的是 devexpress 组件,所以不确定你是否拥有它们?
    • @WraithNath 我更新了帖子以在位图上绘图。
    • 太棒了!让它在徒手和矩形模式下工作。感谢您对这个的坚持:)。如果你能推荐一些阅读,我不介意学习更多的 dgi 绘图?
    • @LarsTech 你能PM我吗?我知道这是一个旧线程,但我想问一下您发布的代码。
    猜你喜欢
    • 1970-01-01
    • 2013-12-19
    • 2014-11-16
    • 1970-01-01
    • 2011-03-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多