NGMsoftware

NGMsoftware
로그인 회원가입
  • 매뉴얼
  • 학습
  • 매뉴얼

    학습


    C# C# .NET Core 매크로 프로그램 만들기. (이미지 캡쳐 컨트롤과 돋보기 컨트롤 만들기)

    페이지 정보

    본문

    안녕하세요. 엔지엠소프트웨어입니다. 이번에 알아볼 내용은 이미지 캡쳐 컨트롤과 돋보기 컨트롤입니다. 사실 매크로 프로그램에서 이 기능은 크게 필요하진 않습니다. 다양한 캡쳐 프로그램들이 존재하고, 돋보기 기능뿐만 아니라 편집 기능도 다수 보유하고 있으니까요. 그렇더라도 기본적인 캡쳐 기능을 제공해야 하고, 이미지 편집기에서는 이미지 마스크나 투명 처리 또는 이미지 흑백과 같은 필터를 어느정도 제공해야 합니다. 단순한 이미지만 비교할건 아니니까요^^

     

    이미지 필터 처리에 대해서 업무 자동화 매크로 프로그램이 제공하지 않으면 여러가지 문제가 발생할 수 있습니다. 찾을 이미지만 편집해서는 의미가 없기 때문입니다. 비교 대상 이미지(윈도우 또는 프로그램 창 화면)도 동일한 필터가 설정되어야 합니다. 단순히 예를 들어서, 그림판으로 이미지를 흑백으로 만들었다고 생각 해보세요. 이 때 윈도우 캡쳐 화면도 흑백으로 처리해야 동일하게 비교가 됩니다. 그렇지 않으면 다른 이미지로 인식할거예요. 오늘은 일단 이미지 캡쳐하는 방법에 대해서만 알아보고, 다음에 필터 처리에 대해서 좀 더 깊이있게 알아보도록 하겠습니다.

     

    Ai 프로젝트에 ScreenManager가 있습니다. 여기에 ScreenCapture 컨트롤과 ZoomControl 컨트롤을 만들었습니다.

    muCXxSs.png

     

     

    ZoomControl만 해도 생각보다 다양한 기능들이 포함되어 있고, 여러가지 정보들을 표시 해줍니다. 전부 윈도우 컨트롤이다보니 정보를 표시하기 위해서는 Paint 이벤트에 코드를 추가해야 합니다. 그리고, 창 크기를 변경할 때마다 새롭게 사이즈를 적용해서 그려주도록 처리해야 합니다.

            protected override void OnPaint(PaintEventArgs e)
            {
                Rectangle rc = new Rectangle(this.ClientSize.Width - cGrip, this.ClientSize.Height - cGrip, cGrip, cGrip);
                e.Graphics.FillRectangle(Brushes.SkyBlue, rc);
            }

     

    추가로 창을 이동할 때 윈도우 메세지도 처리해야 합니다. 아래 코드는 창 드래그를 직접 구현할 때 필요한 코드입니다.

            protected override void WndProc(ref Message m)
            {
                if (m.Msg == 0x84)
                {
                    Point pos = new Point(m.LParam.ToInt32());
                    pos = this.PointToClient(pos);
                    if (pos.X >= this.ClientSize.Width - cGrip && pos.Y >= this.ClientSize.Height - cGrip)
                    {
                        m.Result = (IntPtr)17;
                        return;
                    }
                }
                base.WndProc(ref m);
            }

     

    돋보기 컨트롤은 Scale Factor가 트랙바 형식으로 만들어져 있습니다. 트랙바를 이동할 때마다 Paint에서 캡쳐 화면의 이미지를 가져와서 리사이징하는 방식입니다. 이외에 더 좋은 아이디어가 있다면 좋겠지만... 제가 처음 만들 당시에는 이 방법밖에 떠오르질 않더라고요^^; NuGet에서 서치해봐도 쓸만한걸 못찾았습니다.

    9Kg96gV.png

     

     

    Show Information 체크 박스는 사용자가 드래그한 영역의 크기와 이미지 정보들을 표시 해줍니다. 픽셀 서치의 경우에는 픽셀 색상을 보여줍니다. 세밀하게 이미지 캡쳐 작업을 한다면 Show Information 체크 박스를 해제하면 됩니다. 그리고, 창 크기도 자유롭게 변경 가능합니다. 기능적인 부분은 NGM 6과 동일하기 때문에 NGM 6 에디터를 설치하고, 이미지 조건 액션의 캡쳐에서 확인 해보세요.

     

    ScreenCapture 컨트롤은 실제로 윈도우 화면을 캡쳐한 후 사용자가 영역을 드래그해서 저장하는 기능입니다. SaveSelection 함수가 실제로 이미지를 저장할 때 사용하는 메소드입니다.

            /// <summary>
            /// 캡쳐한 스크린 영역을 저장합니다.
            /// </summary>
            /// <param name="continuity">연속해서 캡쳐하려면 이 값을 True로 설정하세요.</param>
            public void SaveSelection(bool continuity = false, bool newCapture = false)

     

    이미지 저장은 NGM 6과 다르게 png, jpg, gif와 같은 일반적인 이미지만 저장할 수 있습니다. ngi 포멧을 사용하는 이미지는 더이상 사용하지 않을 예정입니다. 참고로, 스크립트도 확장자가 기본으로 .ngs로 되어 있지만, 실제로 제품을 출시할 때는 다른 확장자로 변경될수도 있습니다. 하지만, 다음 버전에서는 스크립트 확장자를 사용자가 직접 변경할 수 있도록 되어 있어서 자유도는 더 높다고 할 수 있습니다.

                saveFileDialog.Filter = Ai.Definition.ImageFilter;
                saveFileDialog.InitialDirectory = initDirectory;
                saveFileDialog.FileName = string.IsNullOrEmpty(this.ImagePath) ? Ai.Definition.NewImageName : this.ImagePath;

     

    옵션에서 스크립트 확장자를 사용자가 변경 가능합니다. 출력창의 내용도 사용자가 변경할 수 있습니다.

    qcFYwrw.png

     

     

    단축키 부분을 만들 때 캡쳐 관련 단축키도 사용자가 설졍할 수 있도록 개선할 예정입니다. 이 요구사항도 몇차례 있었지만, 내부적으로 사용하는 단축키가 너무 많아서 반영하지 못했습니다. 기능적으로 문제가 되는게 아니라서 현재 제공되는 단축키와 마우스로 처리해도 충분합니다. 다음 버전은 구조적인 부분이 변경되어 좀 더 자유롭게 단축키를 설정할 수 있도록 만들 생각입니다. 아무튼, 잠깐 내용이 벗어났는데요. 단축키 설정은 아래와 같습니다. 엔지엠 6과 동일합니다. 아직까지는요^^

    if (e.KeyCode == Keys.Escape)
    {
        this.InstanceRef.Show();
        this.InstanceRef.Activate();
        this.Close();
    }
    else if (e.KeyCode == Keys.F1 || e.KeyCode == Keys.F2)
    {
        if (RectangleDrawn)
            SaveSelection();
    }
    else if (e.KeyCode == Keys.F3)
    {
        if (RectangleDrawn)
            SaveSelection(true, false);
    }
    else if (e.KeyCode == Keys.F4)
    {
        if (RectangleDrawn)
            SaveSelection(true, true);
    }
    else if (e.KeyCode == Keys.F7)
        this.zoom.Location = new Point(0, 0);

     

    ESC는 캡쳐 모드를 취소하는거고, F1과 F2는 캡쳐할 영역을 이미지로 저장하는 단축키입니다. 영역을 더블 클릭해도 저장할 수 있습니다. F3은 연속으로 캡쳐할 수 있는 단축키입니다. F3과 F4가 동일한데요. 다른점이 하나 있습니다. F3은 처음 캡쳐한 화면을 계속 재사용하기 때문에 한 화면에서 여러개를 캡쳐할 때 유용합니다. F4는 화면은 멈춰 있지만, 캡쳐가 완료되면 연속해서 캡쳐할 때 현재 화면으로 다시 캡쳐됩니다. 쉽게 말해서 F3은 정지 상태에서 여러개를 캡쳐할 때 사용하고, F4는 실시간으로 연속 캡쳐할 때 사용하는 단축키입니다.

     

    참고로, 듀얼 모니터 또는 트리플 모니터와 같이 멀티 모니터를 사용하다가 모니터가 하나로 줄어드는 경우 돋보기 컨트롤이 화면 밖으로 사라지는 경우가 있습니다. 이 때 돋보기를 다시 처음 위치로 되돌리려면 F7을 누르세요. 돋보기는 사용자가 드래그하거나 사이즈를 변경할 수 있습니다. 이런 변경 값들은 실시간으로 저장되고, 다시 실행될 때 상태가 복구됩니다. 그렇기 때문에 창이 밖으로 벗어났을 때 초기 위치로 되돌릴 수 있어야 합니다.

     

    이외에도 방향키를 이용해서 영역을 미세하게 조정할 수 있습니다. 아래 내용을 보면 알겠지만, 방향키로 이동할 수 있고, Shift와 Alt키를 조합해서 크기 조정도 가능합니다.

    if (e.Shift && e.KeyCode == Keys.Up)
    {
      if (RectangleDrawn)
      {
        if (RectangleHeight == 0)
          return;
    
        RectangleHeight = RectangleHeight - (e.Alt ? 10 : 1);
        this.SelectionRectangle = new Rectangle(CurrentTopLeft, new Size(RectangleWidth, RectangleHeight));
        zoom.UpdateZoomedImage(new MouseEventArgs(MouseButtons.None, 0, MousePosition.X, MousePosition.Y, 0));
      }
    }

     

    훨씬 더 복잡하게 코딩되어 있지만, 디테일한 구현들은 필요 없을수도 있는 기능들입니다. 부수적으로 편의 기능이기 때문에 아이디어만 있으면 기본 뼈대에 붙여서 충분히 개발할 수 있을겁니다. 현재 엔지엠 매크로도 그렇지만, 다음 버전의 매크로 프로그램도 속성창의 속성에서 출발합니다. UITypeEditor를 상속 받아서 타입 에디터를 만들어주세요.

    public class CaptureEditor : UITypeEditor

     

    타입 에디터를 어떤 형식으로 표시할지 설정 해줍니다.

            public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext? context)
            {
                if (context == null || context.Instance == null)
                    return base.GetEditStyle(context);
    
                return UITypeEditorEditStyle.Modal;
            }

     

    프로퍼티를 만들어서 값을 넘겨줘야 하기 때문에 EditValue 를 재정의 해줍니다.

            public override object? EditValue(ITypeDescriptorContext? context, IServiceProvider provider, object? value)
            {
                IWindowsFormsEditorService? editorService;
    
                if (context == null || context.Instance == null || provider == null)
                    return value;

     

    핵심 코드는 아래와 같습니다. 캡쳐 컨트롤을 만들고, 캡쳐가 완료되었는지 확인합니다. 그리고, context의 PropertyDescriptor에 값을 넘겨주세요. 이렇게하면 넘겨 받은 데이터는 프로퍼티 그리드에 바인딩되어 있는 모델의 속성으로 값이 넘어오게 됩니다. 이 부분까지는 자동입니다.

                    var capture = new Ai.Api.ScreenManager.ScreenCapture((Ai.Interface.IEditor)mainView, option.UseMultiMonitor, option.CaptureMode);
                    capture.InstanceRef = mainView;
                    capture.Property = context;
                    capture.ShowDialog();
    
                    if (capture.IsSaved)
                        context.PropertyDescriptor?.SetValue(context.Instance, capture.ImagePath);

     

    캡쳐 방법은 아래와 같습니다. 아래는 엔지엠 6인데요. 현재 만들고 있는 엔지엠 7(가칭)도 동일합니다. 다만, 이미지 저장 방식만 달라졌을 뿐입니다.

    btEQBYP.gif

     

     

    캡쳐 영역은 모서리에서 드래그로 키우거나 줄일 수 있습니다. 물론, 이동도 가능합니다.

    8HFp7Pb.gif

     

     

    돋보기를 이용하면 좀 더 디테일하게 이미지를 캡쳐할 수 있습니다.

    ubOrGGx.gif

     

     

    위에서 간단하게 이미지 캡쳐 컨트롤과 돋보기 컨트롤에 대해 알아봤는데요. 내용이 너무 복잡해서 디테일하게 작성하지는 못했습니다. 코딩을 같이 하는건 아니고, 설계나 디자인을 참고하기 위해서 작성하다보니 많은 내용이 누락되는거 같네요. 기존에 여러가지 문제점들을 제거하고 새롭게 만드는 과정입니다. 스레드에 자유롭고, 윈도우 리소스를 최소한으로 사용하기 위한 여러가지 기술들이 새롭게 적용되었습니다. 아마도, 다음에는 좀 더 쾌적한 환경에서 작업할 수 있을겁니다^^

     

    개발자에게 후원하기

    MGtdv7r.png

     

    추천, 구독, 홍보 꼭~ 부탁드립니다.

    여러분의 후원이 빠른 귀농을 가능하게 해줍니다~ 답답한 도시를 벗어나 귀농하고 싶은 개발자~

    감사합니다~

    • 네이버 공유하기
    • 페이스북 공유하기
    • 트위터 공유하기
    • 카카오스토리 공유하기
    추천0 비추천0

    댓글목록

    등록된 댓글이 없습니다.