첨부 실행 코드는 나눔고딕코딩 폰트를 사용합니다.
본 블로그는 광고를 포함하고 있습니다.
광고 클릭에서 발생하는 수익금은 모두 블로그 콘텐츠 향상을 위해 쓰여집니다.

728x90
반응형
728x170

TestProject.zip
0.02MB

▶ CustomCompositionBrush.cs

using Microsoft.Graphics.Canvas;
using Microsoft.Graphics.Canvas.Effects;
using System;
using Windows.UI.Composition;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Media;
using Windows.Storage.Streams;

namespace TestProject
{
    /// <summary>
    /// 커스텀 혼합 브러시
    /// </summary>
    public class CustomCompositionBrush : XamlCompositionBrushBase
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Dependency Property
        ////////////////////////////////////////////////////////////////////////////////////////// Static
        //////////////////////////////////////////////////////////////////////////////// Public

        #region 불선명도 양 속성 - BlurAmountProperty

        /// <summary>
        /// 불선명도 양 속성
        /// </summary>
        public static readonly DependencyProperty BlurAmountProperty = DependencyProperty.Register
        (
            "BlurAmount",
            typeof(double),
            typeof(CustomCompositionBrush),
            new PropertyMetadata
            (
                0.0,
                BlurAmountPropertyChangedCallback
            )
        );

        #endregion
        #region 대비 양 속성 - ContrastAmountProperty

        /// <summary>
        /// 대비 양 속성
        /// </summary>
        public static readonly DependencyProperty ContrastAmountProperty = DependencyProperty.Register
        (
            "ContrastAmount",
            typeof(double),
            typeof(CustomCompositionBrush),
            new PropertyMetadata
            (
                0.0,
                new PropertyChangedCallback(ContrastAmountPropertyChangedCallback)
            )
        );

        #endregion
        #region 채도 양 속성 - SaturationAmountProperty

        /// <summary>
        /// 채도 양 속성
        /// </summary>
        public static readonly DependencyProperty SaturationAmountProperty = DependencyProperty.Register
        (
            "SaturationAmount",
            typeof(double),
            typeof(CustomCompositionBrush),
            new PropertyMetadata
            (
                1.0,
                new PropertyChangedCallback(SaturationAmountPropertyChangedCallback)
            )
        );

        #endregion
        #region 노출 양 속성 - ExposureAmountProperty

        /// <summary>
        /// 노출 양 속성
        /// </summary>
        public static readonly DependencyProperty ExposureAmountProperty = DependencyProperty.Register
        (
            "ExposureAmount",
            typeof(double),
            typeof(CustomCompositionBrush),
            new PropertyMetadata
            (
                0.0,
                new PropertyChangedCallback(ExposureAmountPropertyChangedCallback)
            )
        );

        #endregion
        #region 색조 양 속성 - TintAmountProperty

        /// <summary>
        /// 색조 양 속성
        /// </summary>
        public static readonly DependencyProperty TintAmountProperty = DependencyProperty.Register
        (
            "TintAmount",
            typeof(double),
            typeof(CustomCompositionBrush),
            new PropertyMetadata
            (
                0.0,
                new PropertyChangedCallback(TintAmountPropertyChangedCallback)
            )
        );

        #endregion
        #region 온도 양 속성 - TemperatureAmountProperty

        /// <summary>
        /// 온도 양 속성
        /// </summary>
        public static readonly DependencyProperty TemperatureAmountProperty = DependencyProperty.Register
        (
            "TemperatureAmount",
            typeof(double),
            typeof(CustomCompositionBrush),
            new PropertyMetadata
            (
                0.0,
                new PropertyChangedCallback(TemperatureAmountPropertyChangedCallback)
            )
        );

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        /// <summary>
        /// 이미지 로딩 여부
        /// </summary>
        private bool isImageLoading = false;

        /// <summary>
        /// 로드된 이미지 표면
        /// </summary>
        private LoadedImageSurface loadedImageSurface;

        /// <summary>
        /// 혼합 효과 브러시
        /// </summary>
        private CompositionEffectBrush compositionEffectBrush;

        /// <summary>
        /// 대비 효과
        /// </summary>
        private ContrastEffect contrastEffect;

        /// <summary>
        /// 노출 효과
        /// </summary>
        private ExposureEffect exposureEffect;

        /// <summary>
        /// 온도/색조 효과
        /// </summary>
        private TemperatureAndTintEffect temperatureAndTintEffect;

        /// <summary>
        /// 가우스안 불선명 효과
        /// </summary>
        private GaussianBlurEffect gaussianBlurEffect;

        /// <summary>
        /// 채도 효과
        /// </summary>
        private SaturationEffect saturationEffect;

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Property
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 이미지 - Image

        /// <summary>
        /// 이미지
        /// </summary>
        public ICanvasImage Image
        {
            get
            {
                this.contrastEffect.Contrast              = (float)ContrastAmount;
                this.exposureEffect.Exposure              = (float)ExposureAmount;
                this.temperatureAndTintEffect.Tint        = (float)TintAmount;
                this.temperatureAndTintEffect.Temperature = (float)TemperatureAmount;
                this.saturationEffect.Saturation          = (float)SaturationAmount;
                this.gaussianBlurEffect.BlurAmount        = (float)BlurAmount;

                return this.gaussianBlurEffect;
            }
        }

        #endregion

        #region 불선명도 양 - BlurAmount

        /// <summary>
        /// 불선명도 양
        /// </summary>
        public double BlurAmount
        {
            get
            {
                return (double)GetValue(BlurAmountProperty);
            }
            set
            {
                SetValue(BlurAmountProperty, value);
            }
        }

        #endregion
        #region 대비 양 - ContrastAmount

        /// <summary>
        /// 대비 양
        /// </summary>
        public double ContrastAmount
        {
            get
            {
                return (double)GetValue(ContrastAmountProperty);
            }
            set
            {
                SetValue(ContrastAmountProperty, value);
            }
        }

        #endregion
        #region 채도 양 - SaturationAmount

        /// <summary>
        /// 채도 양
        /// </summary>
        public double SaturationAmount
        {
            get
            {
                return (double)GetValue(SaturationAmountProperty);
            }
            set
            {
                SetValue(SaturationAmountProperty, value);
            }
        }

        #endregion
        #region 노출 양 - ExposureAmount

        /// <summary>
        /// 노출 양
        /// </summary>
        public double ExposureAmount
        {
            get
            {
                return (double)GetValue(ExposureAmountProperty);
            }
            set
            {
                SetValue(ExposureAmountProperty, value);
            }
        }

        #endregion
        #region 색조 양 - TintAmount

        /// <summary>
        /// 색조 양
        /// </summary>
        public double TintAmount
        {
            get
            {
                return (double)GetValue(TintAmountProperty);
            }
            set
            {
                SetValue(TintAmountProperty, value);
            }
        }

        #endregion
        #region 온도 양 - TemperatureAmount

        /// <summary>
        /// 온도 양
        /// </summary>
        public double TemperatureAmount
        {
            get
            {
                return (double)GetValue(TemperatureAmountProperty);
            }
            set
            {
                SetValue(TemperatureAmountProperty, value);
            }
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - CustomCompositionBrush()

        /// <summary>
        /// 생성자
        /// </summary>
        public CustomCompositionBrush()
        {
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Static
        //////////////////////////////////////////////////////////////////////////////// Private

        #region 불선명도 양 속성 변경시 콜백 처리하기 - BlurAmountPropertyChangedCallback(d, e)

        /// <summary>
        /// 불선명도 양 속성 변경시 콜백 처리하기
        /// </summary>
        /// <param name="d">의존 객체</param>
        /// <param name="e">이벤트 인자</param>
        private static void BlurAmountPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            CustomCompositionBrush brush = d as CustomCompositionBrush;

            brush.CompositionBrush?.Properties.InsertScalar("Blur.BlurAmount", (float)(double)e.NewValue);
        }

        #endregion
        #region 대비 양 속성 변경시 콜백 처리하기 - ContrastAmountPropertyChangedCallback(d, e)

        /// <summary>
        /// 대비 양 속성 변경시 콜백 처리하기
        /// </summary>
        /// <param name="d">의존 객체</param>
        /// <param name="e">이벤트 인자</param>
        private static void ContrastAmountPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            CustomCompositionBrush brush = d as CustomCompositionBrush;

            brush.CompositionBrush?.Properties.InsertScalar("ContrastEffect.Contrast", (float)(double)e.NewValue);
        }

        #endregion
        #region 채도 양 속성 변경시 콜백 처리하기 - SaturationAmountPropertyChangedCallback(d, e)

        /// <summary>
        /// 채도 양 속성 변경시 콜백 처리하기
        /// </summary>
        /// <param name="d">의존 객체</param>
        /// <param name="e">이벤트 인자</param>
        private static void SaturationAmountPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            CustomCompositionBrush brush = d as CustomCompositionBrush;

            brush.CompositionBrush?.Properties.InsertScalar("SaturationEffect.Saturation", (float)(double)e.NewValue);
        }

        #endregion
        #region 노출 양 속성 변경시 콜백 처리하기 - ExposureAmountPropertyChangedCallback(d, e)

        /// <summary>
        /// 노출 양 속성 변경시 콜백 처리하기
        /// </summary>
        /// <param name="d">의존 객체</param>
        /// <param name="e">이벤트 인자</param>
        private static void ExposureAmountPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            CustomCompositionBrush brush = d as CustomCompositionBrush;

            brush.CompositionBrush?.Properties.InsertScalar("ExposureEffect.Exposure", (float)(double)e.NewValue);
        }

        #endregion
        #region 색조 양 속성 변경시 콜백 처리하기 - TintAmountPropertyChangedCallback(d, e)

        /// <summary>
        /// 색조 양 속성 변경시 콜백 처리하기
        /// </summary>
        /// <param name="d">의존 객체</param>
        /// <param name="e">이벤트 인자</param>
        private static void TintAmountPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            CustomCompositionBrush brush = d as CustomCompositionBrush;

            brush.CompositionBrush?.Properties.InsertScalar("TemperatureAndTintEffect.Tint", (float)(double)e.NewValue);
        }

        #endregion
        #region 온도 양 속성 변경시 콜백 처리하기 - TemperatureAmountPropertyChangedCallback(d, e)

        /// <summary>
        /// 온도 양 속성 변경시 콜백 처리하기
        /// </summary>
        /// <param name="d">의존 객체</param>
        /// <param name="e">이벤트 인자</param>
        private static void TemperatureAmountPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            CustomCompositionBrush brush = d as CustomCompositionBrush;

            brush.CompositionBrush?.Properties.InsertScalar("TemperatureAndTintEffect.Temperature", (float)(double)e.NewValue);
        }

        #endregion

        ////////////////////////////////////////////////////////////////////////////////////////// Instance
        //////////////////////////////////////////////////////////////////////////////// Public

        #region 소스 설정하기 - SetSource(source)

        /// <summary>
        /// 소스 설정하기
        /// </summary>
        /// <param name="source">소스</param>
        public void SetSource(ICanvasImage source)
        {
            this.saturationEffect.Source = source;
        }

        #endregion
        #region 이미지 로드하기 - LoadImage(filePath)

        /// <summary>
        /// 이미지 로드하기
        /// </summary>
        /// <param name="filePath">파일 경로</param>
        public void LoadImage(string filePath)
        {
            Compositor compositor = Window.Current.Compositor;

            this.loadedImageSurface = LoadedImageSurface.StartLoadFromUri(new Uri(filePath));

            this.loadedImageSurface.LoadCompleted += loadedImageSurface_LoadedCompleted;
        }

        #endregion
        #region 이미지 로드하기 - LoadImage(stream)

        /// <summary>
        /// 이미지 로드하기
        /// </summary>
        /// <param name="stream">스트림</param>
        public void LoadImage(IRandomAccessStream stream)
        {
            if(stream != null && this.isImageLoading == false)
            {
                Compositor compositor = Window.Current.Compositor;

                this.isImageLoading = true;

                this.loadedImageSurface = LoadedImageSurface.StartLoadFromStream(stream);       

                this.loadedImageSurface.LoadCompleted += loadedImageSurface_LoadedCompleted;
            }
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////// Protected

        #region 연결 취소시 처리하기 - OnDisconnected()

        /// <summary>
        /// 연결 취소시 처리하기
        /// </summary>
        protected override void OnDisconnected()
        {
            if(this.loadedImageSurface != null)
            {
                this.loadedImageSurface.Dispose();

                this.loadedImageSurface = null;
            }

            if(CompositionBrush != null)
            {
                CompositionBrush.Dispose();

                CompositionBrush = null;
            }
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////// Private

        #region 로드된 이미지 표면 로드 완료시 처리하기 - loadedImageSurface_LoadedCompleted(sender, e)

        /// <summary>
        /// 로드된 이미지 표면 로드 완료시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void loadedImageSurface_LoadedCompleted(LoadedImageSurface sender, LoadedImageSourceLoadCompletedEventArgs e)
        {
            this.isImageLoading = false;

            if(e.Status == LoadedImageSourceLoadStatus.Success)
            {
                Compositor compositor = Window.Current.Compositor;

                CompositionSurfaceBrush brush = compositor.CreateSurfaceBrush(this.loadedImageSurface);

                brush.Stretch = CompositionStretch.UniformToFill;

                this.saturationEffect = new SaturationEffect()
                {
                    Name       = "SaturationEffect",
                    Saturation = (float)SaturationAmount,
                    Source     = new CompositionEffectSourceParameter("image")
                };

                this.contrastEffect = new ContrastEffect()
                {
                    Name     = "ContrastEffect",
                    Contrast = (float)ContrastAmount,
                    Source   = this.saturationEffect
                };

                this.exposureEffect = new ExposureEffect()
                {
                    Name     = "ExposureEffect",
                    Source   = this.contrastEffect,
                    Exposure = (float)ExposureAmount,
                };

                this.temperatureAndTintEffect = new TemperatureAndTintEffect()
                {
                    Name        = "TemperatureAndTintEffect",
                    Source      = this.exposureEffect,
                    Temperature = (float)TemperatureAmount,
                    Tint        = (float)TintAmount
                };

                this.gaussianBlurEffect = new GaussianBlurEffect()
                {
                    Name       = "Blur",
                    Source     = this.temperatureAndTintEffect,
                    BlurAmount = (float)BlurAmount,
                    BorderMode = EffectBorderMode.Hard,
                };

                CompositionEffectFactory factory = compositor.CreateEffectFactory
                (
                    this.gaussianBlurEffect,
                    new[]
                    {
                        "SaturationEffect.Saturation",
                        "ExposureEffect.Exposure",
                        "Blur.BlurAmount",
                        "TemperatureAndTintEffect.Temperature",
                        "TemperatureAndTintEffect.Tint",
                        "ContrastEffect.Contrast"
                    }
                );

                this.compositionEffectBrush = factory.CreateBrush();

                this.compositionEffectBrush.SetSourceParameter("image", brush);

                CompositionBrush = this.compositionEffectBrush;
            }
            else
            {
                LoadImage("ms-appx:///Assets/StoreLogo.png");
            }
        }

        #endregion
    }
}

 

728x90

 

▶ MainPage.xaml

<Page x:Class="TestProject.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:TestProject"
    RequestedTheme="Dark"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
    FontFamily="나눔고딕코딩"
    FontSize="16">
    <Grid>
        <StackPanel
            HorizontalAlignment="Center"
            VerticalAlignment="Center">
            <Rectangle
                Width="200"
                Height="200">
                <Rectangle.Fill>
                    <local:CustomCompositionBrush x:Name="customCompositionBrush"
                        BlurAmount="0"
                        ContrastAmount="0"
                        SaturationAmount="0"
                        ExposureAmount="0"
                        TintAmount="0"
                        TemperatureAmount="0" />
                </Rectangle.Fill>
            </Rectangle>
            <Slider Header="불선명도"
                Width="500"
                Minimum="0"
                Maximum="5"
                StepFrequency="0.1"
                TickFrequency="0.1"
                Value="{x:Bind customCompositionBrush.BlurAmount, Mode=TwoWay}" />
            <Slider Header="대비"
                Margin="0 10 0 0"
                Width="500"
                Minimum="-1"
                Maximum="1"
                StepFrequency="0.1"
                TickFrequency="0.1"
                Value="{x:Bind customCompositionBrush.ContrastAmount, Mode=TwoWay}" />
            <Slider Header="채도"
                Margin="0 10 0 0"
                Width="500"
                Minimum="-2"
                Maximum="2"
                StepFrequency="0.1"
                TickFrequency="0.1"
                Value="{x:Bind customCompositionBrush.SaturationAmount, Mode=TwoWay}" />
            <Slider Header="노출"
                Margin="0 10 0 0"
                Width="500"
                Minimum="-2"
                Maximum="2"
                StepFrequency="0.1"
                TickFrequency="0.1"
                Value="{x:Bind customCompositionBrush.ExposureAmount, Mode=TwoWay}" />
            <Slider Header="색조"
                Margin="0 10 0 0"
                Width="500"
                Minimum="-1"
                Maximum="1"
                StepFrequency="0.1"
                TickFrequency="0.1"
                Value="{x:Bind customCompositionBrush.TintAmount, Mode=TwoWay}" />
            <Slider Header="온도"
                Margin="0 10 0 0"
                Width="500"
                Minimum="-1"
                Maximum="1"
                StepFrequency="0.1"
                TickFrequency="0.1"
                Value="{x:Bind customCompositionBrush.TemperatureAmount, Mode=TwoWay}" />
        </StackPanel>
    </Grid>
</Page>

 

300x250

 

▶ MainPage.xaml.cs

using System;
using Windows.ApplicationModel;
using Windows.Storage;
using Windows.Storage.Streams;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;

namespace TestProject
{
    /// <summary>
    /// 메인 페이지
    /// </summary>
    public sealed partial class MainPage : Page
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - MainPage()

        /// <summary>
        /// 생성자
        /// </summary>
        public MainPage()
        {
            InitializeComponent();
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Protected
        //////////////////////////////////////////////////////////////////////////////// Function

        #region 탐색되는 경우 처리하기 - OnNavigatedTo(e)

        /// <summary>
        /// 탐색되는 경우 처리하기
        /// </summary>
        /// <param name="e">이벤트 인자</param>
        protected override async void OnNavigatedTo(NavigationEventArgs e)
        {
            StorageFolder packageStorageFolder = Package.Current.InstalledLocation;

            StorageFolder assetsStorageFolder = await packageStorageFolder.GetFolderAsync("Assets");

            StorageFile storageFile = await assetsStorageFolder.GetFileAsync("Square150x150Logo.scale-200.png");

            using(IRandomAccessStream stream = await storageFile.OpenReadAsync())
            {
                this.customCompositionBrush.LoadImage(stream);
            }
        }

        #endregion
    }
}
728x90
반응형
그리드형
Posted by 사용자 icodebroker
TAG , , , , ,

댓글을 달아 주세요