본문 바로가기

C#

[WPF] 이미지 블러링을 원천적으로 해결하




XAML 로 이미지를 위치 시킬경우 빌드 하면 가끔씩 이미지가 흐려 보이는 현상이 보일때가 있다. 

이것을 해결 하려 구글링 하면 SnapsToDevicePixels , RenderOptions , UseLayoutRounding 등등의 방법이 난무 하지만 잘 안먹힐때가 많이 있다.


또한 이러한 현상은 왠지 낯설지가 않다.

플래시 에서도 이러한 현상을 볼 수 있는데, 이유는 픽셀 시작점이 정수가 아니라 소수점으로 떨어 질 경우 정확한 필셀이 화면에 그려지지 않고 두 픽셀에 걸쳐서 색을 섞어 버리니 결국 흐려 보이는 것이다.


이러한 배경을 가지고 실제로 포지션을 구해보면, ...



Window window = Window.GetWindow(target);
Point actualTargetPoint = target.TransformToAncestor(window).Transform(new Point(0, 0));



(target 은 이미지 객체나 텍스쳐를 활용하는 UIElement 가 되겠다)

actualTargetPoint 의 X 나 Y 값이 정수가 아닌 소수점으로 떨어지는것을 볼 수 있다. 예를 들어 (123.32,342.5)

(참고로 WPF 는 double 형의 포지션 을 가진다.)


그래서 이것을 인위적으로 소수점 자리만큼 빼주어 정상 위치를 확보 할 수 있다.


간단히 말해 소수점이 발생하는 X Y 포인트를 가장 가까운 정수 자리로 Translation 해준다.

이것을 구현 하는 코드는 아래와 같다.




        public static void PixelSnapping(UIElement target)
        {
            Window window = Window.GetWindow(target);
            Point actualTargetPoint = target.TransformToAncestor(window).Transform(new Point(0, 0));
            int _vx = (int)actualTargetPoint.X;
            double result = actualTargetPoint.X - _vx;

            double push_x = GetPushValue(actualTargetPoint.X);
            double push_y = GetPushValue(actualTargetPoint.Y);

            target.RenderTransform = new TranslateTransform(push_x, push_y);
        }


        /*
         * 입력값이 가장 가까운 정수로 가기위한 소수점 값을 반환한다.
         * */
        public static double GetPushValue(double orignal_value)
        {
            double round_value = Math.Round(orignal_value);
            double pushPosition = 0;

            if (orignal_value < round_value)
            {
                pushPosition = (orignal_value - round_value) * -1;
            }
            else
            {
                pushPosition = round_value - orignal_value;
            }

            return pushPosition;
        }



활용은 간단히 객체를 넣어 주면 된다.

ImageUtil.PixelSnapping(_topLogo);



그러면 결과는 아래와 같다.








//comment : 2015.01.09

PixelSnapping 을 사용할 경우 비주얼 스튜디오의 XAML 디자인뷰 에서 에러가 날 수 있는데 이때는 try...catch 로 감싸 주면 된다.