스크린샷 프로그램 구조 관련해서 질문 드립니다

제 목적은 windowsForm 을 사용하여 window 10 캡처 도구 같은 스크린샷 프로그램을 만들려고 합니다.

일단 제가 생각한 프로그램 구성입니다.

  1. 스크린샷 버튼을 누르면 전체화면 으로 한번 찍고 사진을 맨 위에 띄움
  2. 전체적으로 화면이 밝아짐
  3. drag해서 영역을 만듬 영역 안쪽은 원래 색상으로 돌아오게 해서 구분감을 준다
  4. 상자 영역 캡처

3번 부분이 막혔습니다. 개인적으로 생각했던 방법은

  1. 픽셀 단위로 제어해서 밝기를 제어한다.
  2. 밝은 사진과 원래 사진을 각각 찍어서 drag를 하면 원래 사진을 보여준다

로 생각하고 작업하고 있으나 둘 다 마땅치 않아서 혹시 다른 방법이 있을까 하고 질문 드립니다.

  • 추가적으로 window 10 캡처 도구 의 drag캡처 방식이 어떻게 되어있는지 도 질문 드립니다.

감사합니당

2 Likes

먼저 Windows 10 캡쳐 도구의 Drag 캡쳐 방식이 어떻게 되어있는지는 모르겠습니다.

Windows Forms의 GDI+를 이용해서 달성하는 가장 쉬운 방법은 아마도 진행하신 것 처럼 전체 화면을 비트맵으로 저장한 후, 드래깅 하는 영역을 Alpha 값을 적절히 줘서 반투명으로 가득한 박스를 그리는 방법인것 같습니다. 드래깅 중에는 저장한 비트맵을 이용해 영역을 복구해주면, 원하는 결과가 나올 것 같네요.

이 때 갱신되어야 할 영역만 복구하는게 핵심이 될 것 같습니다. 이렇게 구현한다면 상당히 빠른 속도로 영역지정 효과를 만들 수 있을 것입니다.

2 Likes

선택영역을 Control로 구현하는것도 괜찮은 전략 같네요. 그러니까 전체 캡쳐한 것을 스타일 없는 폼의 배경으로 그리고 컨트롤로 선택영역을 처리한다면 쉽게 구현이 될 것 같습니다. 도움이 되게 간단히 샘플 만들어 볼께요

2 Likes

대략 이런 느낌으로…

image

    public partial class Form1 : Form
    {
        private Image capture;
        //private Selector selector;
        private bool isDrag;
        private Rectangle selectRect;
        private Brush darkBrush = new SolidBrush(Color.FromArgb(150, Color.Black));

        public Form1()
        {
            InitializeComponent();

            capture = (Bitmap)Image.FromFile(@"Images\capture.png");
        }

        protected override void OnMouseDown(MouseEventArgs e)
        {
            if (isDrag == false)
            {
                Invalidate(selectRect);
                Refresh();
                selectRect.Location = e.Location;
                selectRect.Size = new Size(0, 0);

                isDrag = true;
            }
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            if (isDrag == true)
            {
                //selector.Size = new Size(e.X - selector.Location.X, e.Y - selector.Location.Y);

                Invalidate(selectRect);
                selectRect.Size = new Size(e.X - selectRect.Location.X, e.Y - selectRect.Location.Y);
                Invalidate(selectRect);
            }
        }

        protected override void OnMouseUp(MouseEventArgs e)
        {
            if (isDrag == true)
            {
                Refresh();
                isDrag = false;
            }
        }

        protected override void OnPaintBackground(PaintEventArgs e)
        {
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            var g = e.Graphics;

            g.DrawImage(capture, 0, 0);
            g.FillRectangle(darkBrush, ClientRectangle);

            if (isDrag == true)
            {
                g.DrawImage(capture, selectRect.X, selectRect.Y, selectRect, GraphicsUnit.Pixel);
                g.DrawRectangle(Pens.White, selectRect.X, selectRect.Y, selectRect.Width - 1, selectRect.Height - 1);
            }
        }
    }
2 Likes

Resion을 이용하면 성능을 좀 더 개선할 수 있어요

2 Likes

소스코드에서 Refresh() 가 아닌 Update() 입니다.

2 Likes

아래와 같이 바꾸면 드래깅 속도가 빨라집니다.

※ 참고로 FormDoubleBuffered = true 로 해야 깜빡임 없이 빠르게 표현됩니다.
※ 최종적으로 OnMouseMoveInvalidate영역을 selectRect가 아닌 변화된 가로, 세로의 딱 그 영역만 두번 Invalidate하면 더 빨라지겠죠.

        protected override void OnPaint(PaintEventArgs e)
        {
            var g = e.Graphics;

            g.DrawImage(capture, 0, 0);
            
            if (isDrag == true)
            {
                g.DrawRectangle(Pens.White, selectRect.X, selectRect.Y, selectRect.Width - 1, selectRect.Height - 1);
                g.ExcludeClip(selectRect);
            }
            
            g.FillRectangle(darkBrush, ClientRectangle);

            //if (isDrag == true)
            //{
            //    g.DrawImage(capture, selectRect.X, selectRect.Y, selectRect, GraphicsUnit.Pixel);
            //    g.DrawRectangle(Pens.White, selectRect.X, selectRect.Y, selectRect.Width - 1, selectRect.Height - 1);
            //}
        }
2 Likes

너무 성의 있게 답변해 주셔서 감사드립니다!!!
한번 적용 해보겠습니다!!! ( :heart:_​:heart: )

2 Likes

네 성의있게 질문해주셔서 거기에 맞는 ^^ 답변드렸습니다. 앞으로 많은 활동 부탁드리고요. 유용한 정보 있으시면 많이 올려주세요.

4 Likes

@Arkingco 환영합니다!

@dimohy 저도 WPF에서 적용해보고 싶은 기능이었는데 감사합니다 :smile: