Introduction 

WPF에서 파일로부터 불러온 이미지의 픽셀데이터에 접근하고자 할 경우 아래와 같이 CopyPixels를 통해 이미지에 포함된 픽셀 값들을 복사하는 방법을 사용합니다. CopyPixels는 이름에서도 알 수 있듯이 이미지에 있는 픽셀데이터를 복사하는데요, 이 때문에 데이터의 용도가 단순한 읽기 전용이거나 업데이트를 위한 용도일 경우에는 불필요한 메모리와 퍼포먼스를 요구하게 되므로 효율적이지 못합니다.

MSDN에서는 픽셀데이터에 접근하기 위한 또다른 방법으로 WriteableBitmap을 이야기하는데 WriteableBitmap 또한 내부적으로는 CopyPixels를 사용하기 때문에 큰 효율은 얻을 수 없습니다.)

이번시간에는 WPF내부적으로 사용되고 있는 Image Framework인 WIC(Windows Image Component)에 직접 Access하여 보다 효과적으로 픽셀데이터에 접근하는 방법에 대해 소개합니다. 아래 동영상은 WIC를 이용했을 때와 CopyPixels를 이용했을 때의 비교영상입니다.

위 테스트에서 사용된 코드는 첨부파일을 다운로드 하시면 확인 하실 수 있습니다.

Windows Image Component

앞서 말씀드린 것과 같이 WPF에서는 내부적으로 WIC를 이용해 이미지를 관리합니다. 즉 Native Code로 작성된 WIC API를 Managed Code로 Wrapping하여 제공하는건데요. 이때 Native Code에서 생성된 이미지 데이터를 Managed Code에서 무분별하게 Access할 경우 발생할 수 있는 메모리 관련 이슈들을 사전에 방지하고자 직접적인 Access를 허용하지 않고 Copy 관련 메서드만 제공하는것으로 보입니다.

※ .Net Reflector등의 툴로 BitmapSource객체를 열어보시면 아래와같이 내부적으로 WIC 이미지를 가지고 있는것을 확인 하실 수 있습니다.

_wicSource라는 이름으로 WIC객체가 저장되어 있는것을 확인하실 수 있습니다. wicSource는 Internal로 정의되어있기 때문에 Reflection을 통해 WIC객체 포인터에 Access하고 WIC API를 이용해 Native Code상에서 생성된 이미지 데이터에 접근하시면됩니다.

WIC에 대한 자세한 내용은 여기(http://msdn.microsoft.com/ko-kr/library/windows/desktop/ee719654.aspx)서 확인 할 수 있습니다.

Create WICBitmapBuffer

WIC를 이용해 픽셀 데이터를 접근하기 위해 필요한 API들과 Native객체 생성과 파괴를 관리 할 수 있도록 임의의 WICBitmapBuffer를 아래와 같이 사용하면 더 쉽게 사용할 수 있습니다.

위 코드를 사용할 때에는 아래와 같이 사용합니다. WICBitmapBuffer.Create 메서드에 BitmapSource객체를 넣고 Buffer에 접근하시면 됩니다.

이상으로 이번 포스팅을 마치며 영상에서 사용된 전체 소스코드는 아래에서 다운로드 받으시면됩니다. 기타 질문이나 문의사항은 댓글이나 이메일 주시면 답변드리도록 하겠습니다. 감사합니다.

WIT.WPF.BitmapExtensionExample.zip

 

신고

Introduction

WPF를 이용해 Application을 개발 할 때 기본 Window모양이 아닌 임의의 디자인의 Window로 구현해야 하는 경우가 있습니다. 이때 아래 그림과 같이 WindowStyle 속성과 AllowsTransparency 속성을 이용해 기본 Frame을 나타나지 않도록 구현 할 수 있는데요.

WindowStyle을 None으로 설정할 경우 기본 제목 표시줄을 사라지지만 윈도우의 테두리에 크기를 변경할 때 사용하는 테두리가 남아 있는데요. 이를 제거하기 위해서 AllowsTransparency 속성을 True 지정하면 이 테두리가 사라지게 됩니다. 그런데, 한가지 문제점은 AllowsTransparency 속성이 True일 경우에는 기본적으로 마우스를 이용해 크기조절이 불가능하기 때문에 크기조절 부분을 직접 구현해줘야 하는 단점이 있습니다.

이번시간에는 위와 같은 상황에서 간단하게 크기를 조절하거나 창을 움직일 수 있도록 하는 WindowResizer를 소개합니다. 개인적으로 만들어 사용하던 코드인데 마침 정리 할 기회가 되어 공유합니다. 아래 동영상은 샘플로 사용된 코드의 시연 영상입니다.

How to use WindowResizer

WindowResizer를 사용하기 위해서는 아래와 같이 XAML에 WindowResizer의 네임스페이스를 추가하고, 리사이즈 영역으로 사용할 객체에 WindowResizer.Direction 속성을 Left, Right, Top, TopLeft, TopRight, Bottom, BottomLeft, BottomRight, Drag중 하나로 지정하면 됩니다.


그리고 C#코드에서 WindowResizer를 적용하고자 할경우 아래와 같이 사용하실 수 있습니다.

이상이며  아래는 WindowResizer의 샘플 프로젝트와 전체 소스코드파일입니다. 기타 궁금하신점이나 문의사항은 이메일이나 댓글로 남겨주시면 답변드리도록 하겠습니다.

WIT.WPF.Samples.WindowResizerExample.zip

신고

 

Introduction 

WPF에서 Geometry를 이용해 도형을 그릴때 테두리를 그리기 위해 아래와 같이 Stroke를 이용해 도형을 그립니다.

그런데 Stroke를 이용해 테두리를 그릴때 Stroke가 하나가 아니고 두개 이상을 그려야 하는 경우 문제가 발생합니다. 정 N각형의 경우 간한히 크기가 작은 도형을 한번 더 그려서 Stroke를 두개 이상 생성하는게 가능하지만, 임의의 모양의 도형일 경우에는 아래 그림과 같이 단순히 크기 조절만으로는 Stroke와 같은 효과를 낼 수 가 없습니다.

정 N각 형이 아닐 경우 직접 Path Data의 위치를 수정하거나 다시 그려야 하는데 간단한 모양일 경우에는 한두번정도 해보겠지만, 모양이 복잡해질 수록 정확도는 떨어지고 시간도 오래걸리게 됩니다. 이번시간에는 입력된 Geometry에서 특정 거리만큼 들어간(Padding) 모양을 자동으로 생성하는 방법에 대해 소개합니다. 아래는 이번시간에 구현하게될 샘플 동영상입니다.

 

Geometry Padding Extension 

이와 같은 내용은 폴리곤 버퍼링(Polygon Buffering) 이라고 하여 주로 GIS분야에서 자주 사용되는 기술이지만 GUI분야에서도 충분이 으용될 수 있습니다. 기본적인 원리는 도형의 매 포인트마다 도형의 방향으로 N거리만큼 떨어뜨린 점들을 조합하여 도형을 완성하는 방식입니다. (http://www.cgal.org/Manual/3.2/doc_html/cgal_manual/Straight_skeleton_2/Chapter_main.html)

뭔가 어려워 보이지만 WPF에서는 GetWidenedPathGeometry를 통해 입력된 Geometry에 Stroke가 생성된 Geometry를 간단하게 생성할 수 있기 때문에 쉽게 처리 할 수 있습니다.

한가지 확인해야하는 부분은 GetWidenedPathGeometry를 통해 Geometry를 생성 할 경우 Stroke가 안쪽과 바깥쪽으로 적용된 도형이 생성되기 때문에 CombinedGeometry를 통해 다듬어 주는 과정이 필요합니다. 위 코드에서는 이와 같은 방식으로 Padding값이 적용된 Inner, Center, Outer Stroke 도형을 생성할 수 있습니다.

아래는 이번시간에 사용된 전체 소스코드이며 질문은 댓글이나 메일 주시면 답변 드리도록 하겠습니다. 감사합니다.

WIT.WPF.Samples.GeometryPadding.zip

 

신고

Introduction

일반적으로 Image Viewer 등과 같이 화면에 출력해야할 내용이 화면크기보다 클 경우 ScrollViewer를 이용해 내용을 스크롤할 수 있도록 구현을 하는데요, 이번시간에는 화면을 스크롤하기 위해서 스크롤바를 조작하지 않고 간단한 마우스조작으로 컨텐츠를 직접 드래그하는 방식으로 View를 조절하고 확대 축소할 수 있는 기능을 구현해보았습니다. 아래는 이번시간에 구현한 결과물 영상입니다.

Create ZoomAndPanning Behavior

Zoom 또는 Panning의 경우 자주 사용될 수 있는 기능이기 때문에 재사용을 용이하게 하기 위해서 Behavior의 형태로 작성했습니다. ZoomAndPanning Behavior의 기본적인 구성은 와래와 같습니다.

ScrollViewer의 기본적인 마우스 이벤트와 ScrollChanged이벤트를 수신하고 각 이벤트마다 적적할 처리를 진행 해줬습니다. 그리고 추가적으로 최대 확대배율이나 최소 확대배율, Zoom And Panning 단축키등을 통해 다양한 조작환경을 제공 할 수 있도록 구현됬습니다.

소스코드자체가 어려운 내용들은 아니기 때문에 이번시간에는 별도의 코드 설명은 생략하겠습니다. 아래는 이번시간에 사용한 전체소스코드 파일이며 VisualStudio 2010에서 작업되었습니다. 기타 질문이나 문의사항은 이메일이나 댓글남겨주시면 답변드리겠습니다. 감사합니다.

WIT.WPF.Sample.ZoomAndPanningBehaviorExample.zip

신고

Introduction

ListBox나 Listview와 같이 목록형으로 데이터를 출력하는 컨트롤에서 많은 양의 데이터를 출력할경우, 스크롤 바를 조작할때 스크롤 속도가 매우 느려지는 현상을 발생합니다. 속도가 느려지는 가장큰 원인은 스크롤하는 도중에 매번 화면에 출력될 View가 업데이트되면서 퍼포먼스에 영향을 주게 되는것인데, 이를 해결하기 위한 간단한 방법으로 ScrollViewer의 IsDeferredScrollingEnabled 속성을 이용해 스크롤이 모두 끝났을때 View를 갱신하는 방법이 있습니다.

하지만 IsDeferredScrollingEnabled을 사용 할 경우 스크롤 동작이 완료될때까지 뷰가 갱신되지 않기때문에 디테일한 탐색이 불가능하기 때문에 오히려 더 불편한 상황이 발생 할 수도 있습니다. 이번시간에는 IsDeferredScrollingEnabled를 사용하여 스크롤할 때 View 전체가 갱신되지는 않지만 Thumb가 위치 한 데이터를 미리보기 형태로 제공함으로서 효과적인 탐색이 가능하도록 하는 방법에 대해 소개합니다. 아래는 이번시간에 구현할 결과물 영상입니다.

Create Scrolling Preview Helper

위 동영상과 같은 내용을 구현하기 위해 가장 먼저 확인 해 봐야 할 것이 DefferedScrolling을 이용했을 때 ScrollBar의 변경상태를 확인하는 방법입니다. ScrollViewer에서 기본적으로 제공되는 ScrollChanged는 DefferedScrolling을 이용할 경우 마지막에만 이벤트가 호출되기 때문에 정확한 위치를 계산할 수 없습니다.

WPF에서는 DefferedScrolling을 제어할 수 있도록 ScrollBar에 DeferScrollToVerticalOffsetCommand를 제공하고 있습니다. 이 Command는 ScrollViewer가 DefferedScrolling를 사용해 스크롤을 조작할 때 호출되는 Command로 CommandParameter를 통해 현재 Thumb의 위치를 가져올 수 있습니다.

ScrollViewer를 사용하는 Selector 컨트롤에서 미리보기가 가능하도록 하기 위해서 아래와 같이 Attached Dependency Property를 정의하고 ScrollViewer에 CommandBinding을 추가해줍니다.

속성값을 DataTemplate으로 받는 이유는 사용자가 임의로 미리보기로 출력될 데이터의 모양을 수정할 수 있도록 하기 위해서입니다. 그리고 아래와 같이 Command가 발생했을때의 처리를 해줍니다.


마지막으로 Thumb의 위치를 통해 계산된 Item Index에 해당하는 아이템을 Thumb옆에 Popup으로 출력하면 완성 할 수 있습니다.


아래는 이번시간에 구현한 전체 소스코드이며 궁금하신점이나 문의사항은 이메일이나 댓글로 남겨주시면 답변드리도록 하겠습니다. 아래소스코드는 VisualStudio2010버전에서 제작되었습니다.

신고