부드러운 애니메이션, 높은 프레임 속도, 고성능 미디어 캡처 및 재생을 사용하여 UWP(유니버설 Windows 플랫폼) 앱을 만듭니다.
애니메이션을 매끄럽게 만들기
UWP 앱의 주요 측면은 원활한 상호 작용입니다. 여기에는 "손가락에 달라붙는" 터치 조작, 부드러운 전환 및 애니메이션, 입력 피드백을 제공하는 작은 동작이 포함됩니다. XAML 프레임워크에는 앱의 시각적 요소의 컴퍼지션 및 애니메이션 전용 컴퍼지션 스레드라는 스레드가 있습니다. 컴퍼지션 스레드는 UI 스레드(프레임워크 및 개발자 코드를 실행하는 스레드)와 별개이므로 앱은 복잡한 레이아웃 전달 또는 확장 계산에 관계없이 일관된 프레임 속도와 부드러운 애니메이션을 달성할 수 있습니다. 이 섹션에서는 컴퍼지션 스레드를 사용하여 앱의 애니메이션을 매끄럽게 유지하는 방법을 보여 줍니다. 애니메이션에 대한 자세한 내용은 애니메이션 개요를 참조하세요. 집중적인 계산을 수행하는 동안 앱의 응답성을 높이는 방법에 대한 자세한 내용은 UI 스레드 응답 유지를 참조하세요.
종속 애니메이션 대신 독립 애니메이션 사용
애니메이션 효과를 적용하는 속성의 변경 내용은 장면의 나머지 개체에 영향을 주지 않으므로 독립 애니메이션은 생성 시 처음부터 끝까지 계산할 수 있습니다. 따라서 독립 애니메이션은 UI 스레드 대신 컴퍼지션 스레드에서 실행할 수 있습니다. 이렇게 하면 컴퍼지션 스레드가 일관된 주기로 업데이트되므로 원활하게 유지됩니다.
이러한 모든 유형의 애니메이션은 독립적이어야 합니다.
키 프레임을 사용하는 개체 애니메이션
지속 시간 0의 애니메이션
Canvas.Left 및 Canvas.Top 속성에 애니메이션을 추가한다.
UIElement.Opacity 속성에 애니메이션 적용
SolidColorBrush.Color 하위 속성을 대상으로 지정할 때 Brush 형식의 속성에 대한 애니메이션
다음 UIElement의 속성에 애니메이션을 적용할 때, 이러한 반환 값 형식의 하위 속성을 목표로 합니다.
종속 애니메이션은 레이아웃에 영향을 주므로 UI 스레드에서 추가 입력 없이는 계산할 수 없습니다. 종속 애니메이션에는 Width 및 Height같은 속성에 대한 수정이 포함됩니다. 기본적으로 종속 애니메이션은 실행되지 않으며 앱 개발자의 옵트인이 필요합니다. 사용하도록 설정하면 UI 스레드가 차단 해제된 상태로 유지되는 경우 원활하게 실행되지만 프레임워크 또는 앱이 UI 스레드에서 다른 많은 작업을 수행하는 경우 더듬거리기 시작합니다.
XAML 프레임워크의 거의 모든 애니메이션은 기본적으로 독립적이지만 이 최적화를 사용하지 않도록 설정하기 위해 수행할 수 있는 몇 가지 작업이 있습니다. 특히 다음 시나리오에 주의하세요.
- 종속 애니메이션이 UI 스레드에서 실행되도록 EnableDependentAnimation 속성을 설정합니다. 이러한 애니메이션을 독립 버전으로 변환합니다. 예를 들어, 개체의 Width 및 Height 대신 ScaleTransform.ScaleX 및 ScaleTransform.ScaleY을(를) 애니메이션 처리합니다. 이미지 및 텍스트와 같은 개체의 크기를 조정하는 것을 두려워하지 마세요. 프레임워크는 ScaleTransform이(가) 애니메이션될 때에만 쌍선형 크기 조정을 적용합니다. 이미지/텍스트는 항상 명확하도록 최종 크기로 다시 래스터화됩니다.
- 프레임마다 업데이트를 수행하여 사실상 종속 애니메이션 기능을 발휘하기. 예를 들어 CompositonTarget.Rendering 이벤트의 처리기에서 변환을 적용합니다.
- CacheMode 속성이 BitmapCache설정된 요소에서 독립적으로 간주되는 애니메이션을 실행합니다. 각 프레임에 대해 캐시를 다시 래스터화해야 하기 때문에 종속된 것으로 간주됩니다.
WebView 또는 MediaPlayerElement에 애니메이션 효과 주지 않음
WebView 컨트롤 내의 웹 콘텐츠는 XAML 프레임워크에서 직접 렌더링되지 않으며 나머지 장면으로 구성하려면 추가 작업이 필요합니다. 이 추가 작업은 화면 주위의 컨트롤에 애니메이션을 적용할 때 추가되며 잠재적으로 동기화 문제가 발생할 수 있습니다(예: HTML 콘텐츠가 페이지의 나머지 XAML 콘텐츠와 동기화되어 이동하지 않을 수 있음). WebView 컨트롤에 애니메이션 효과를 주어야 하는 경우, 애니메이션 기간 동안 WebViewBrush로 교체합니다.
MediaPlayerElement 에 애니메이션 효과를 주는 것은에 있어서도 마찬가지로 나쁜 생각입니다. 성능 저하 외에도 재생 중인 비디오 콘텐츠의 찢어지거나 다른 아티팩트가 발생할 수 있습니다.
ko-KR: 참고 이 문서의 MediaPlayerElement 에 대한 권장 사항은 MediaElement도 적용됩니다. MediaPlayerElement 는 Windows 10 버전 1607에서만 사용할 수 있으므로 이전 버전의 Windows용 앱을 만드는 경우 MediaElement를 사용해야 합니다.
무한 애니메이션은 절제하여 사용하세요
대부분의 애니메이션은 지정된 시간 동안 실행되지만 Timeline.Duration 속성을 Forever로 설정하면 애니메이션이 무기한 실행될 수 있습니다. 무한 애니메이션은 지속적으로 CPU 리소스를 사용하고 CPU가 저전력 또는 유휴 상태로 전환되지 않도록 방지하여 더 빠르게 전원이 부족해지도록 하므로 무한 애니메이션 사용을 최소화하는 것이 좋습니다.
CompositionTarget.Rendering에 대한 처리기를 추가하는 것은 무한 애니메이션을 실행하는 것과 비슷합니다. 일반적으로 UI 스레드는 해야 할 일이 있을 때만 활성화되지만 이 이벤트에 대한 처리기를 추가하면 모든 프레임을 실행하게 됩니다. 수행할 작업이 없을 때 처리기를 제거하고 다시 필요할 때 다시 등록합니다.
애니메이션 라이브러리 사용
Windows.UI.Xaml.Media.Animation 네임스페이스에는 다른 Windows 애니메이션과 일치하는 모양과 느낌을 주는 고성능의 부드러운 애니메이션 라이브러리가 포함되어 있습니다. 관련 클래스의 이름에는 "Theme"이 있으며, 애니메이션 개요에서 설명되어 있습니다. 이 라이브러리는 앱의 첫 번째 보기에 애니메이션 효과를 주는 것과 상태 및 콘텐츠 전환 만들기와 같은 많은 일반적인 애니메이션 시나리오를 지원합니다. UWP UI의 성능과 일관성을 높이려면 가능하면 이 애니메이션 라이브러리를 사용하는 것이 좋습니다.
메모 애니메이션 라이브러리가 가능한 모든 속성에 애니메이션 효과를 주지는 않습니다. 애니메이션 라이브러리가 적용되지 않는 XAML 시나리오의 경우, 스토리보드 애니메이션에 대한 설명을 참조하세요 .
CompositeTransform3D의 속성을 독립적으로 애니메이션화하기
CompositeTransform3D 각 속성을 독립적으로 애니메이션할 수 있으므로, 필요한 애니메이션만 적용하세요. 예제 및 자세한 내용은 UIElement.Transform3D를 참조하세요. 변환에 애니메이션 효과를 주는 방법에 대한 자세한 내용은 스토리보드된 애니메이션 및 키 프레임 및 이징 함수 애니메이션참조하세요.
미디어 리소스 최적화
오디오, 비디오 및 이미지는 대부분의 앱에서 사용하는 매력적인 형태의 콘텐츠입니다. 미디어 캡처 속도가 증가하고 콘텐츠가 표준 정의에서 고화질로 이동함에 따라 이 콘텐츠를 저장, 디코딩 및 재생하는 데 필요한 리소스의 양이 증가합니다. XAML 프레임워크는 UWP 미디어 엔진에 추가된 최신 기능을 기반으로 하므로 앱은 이러한 향상된 기능을 무료로 사용할 수 있습니다. 여기에서는 UWP 앱에서 미디어를 최대한 활용할 수 있는 몇 가지 추가적인 방법을 설명합니다.
미디어 스트림 해제
미디어 파일은 앱이 일반적으로 사용하는 가장 일반적이고 비용이 많이 드는 리소스 중 일부입니다. 미디어 파일 리소스는 앱의 메모리 공간 크기를 크게 늘릴 수 있으므로 앱에서 미디어 파일 사용을 완료하는 즉시 미디어에 대한 핸들을 해제해야 합니다.
예를 들어, 앱이 RandomAccessStream 또는 IInputStream 객체를 사용하여 작업하는 경우, 앱이 객체 사용을 완료했을 때 반드시 close 메서드를 호출하여 해당 기본 객체를 해제해야 합니다.
가능한 경우 전체 화면 비디오 재생 표시
UWP 앱에서는 항상 MediaPlayerElement에서 IsFullWindow 속성을 사용하여 전체 창 렌더링을 활성화하거나 비활성화하세요. 이렇게 하면 미디어 재생 중에 시스템 수준의 최적화가 보장됩니다.
XAML 프레임워크는 렌더링되는 유일한 경우 비디오 콘텐츠의 표시를 최적화할 수 있으며, 이로 인해 전력이 적게 사용되고 프레임 속도가 더 높은 환경이 생성됩니다. 가장 효율적인 미디어 재생을 위해 MediaPlayerElement 의 크기를 화면의 너비와 높이로 설정하고 다른 XAML 요소를 표시하지 않습니다.
화면의 전체 너비와 높이를 차지하는 MediaPlayerElement에 XAML 요소를 오버레이해야 하는 정당한 이유가 있습니다. 예를 들어, 폐쇄 자막이나 일시적인 재생 컨트롤의 경우가 그렇습니다. 미디어 재생을 가장 효율적인 상태로 되돌릴 필요가 없는 경우 이러한 요소(집합 Visibility="Collapsed")를 숨겨야 합니다.
비활성화 및 전원 절약 표시
앱이 비디오를 재생하는 경우와 같이 사용자 작업이 더 이상 검색되지 않을 때 디스플레이가 비활성화되지 않도록 하려면 DisplayRequest.RequestActive를 호출할 수 있습니다.
전원 및 배터리 수명을 절약하려면 DisplayRequest.RequestRelease 를 호출하여 더 이상 필요하지 않은 즉시 디스플레이 요청을 해제해야 합니다.
표시 요청을 해제해야 하는 몇 가지 상황은 다음과 같습니다.
- 비디오 재생이 일시 중지됩니다(예: 제한된 대역폭으로 인한 사용자 작업, 버퍼링 또는 조정).
- 재생이 중지됩니다. 예를 들어 비디오 재생이 완료되거나 프레젠테이션이 끝났습니다.
- 재생 오류가 발생했습니다. 예를 들어 네트워크 연결 문제 또는 손상된 파일입니다.
포함된 비디오의 측면에 다른 요소 배치
종종 앱은 페이지 내에서 비디오가 재생되는 포함된 보기를 제공합니다. 이제 MediaPlayerElement가 페이지와 크기가 맞지 않고, 다른 XAML 개체들이 추가로 그려져 있어서 전체 화면 최적화가 손실되었습니다. MediaPlayerElement주위에 테두리를 그려 의도치 않게 이 모드로 전환해야 합니다.
포함된 모드인 경우 비디오 위에 XAML 요소를 그리지 마세요. 이 경우 프레임워크는 장면을 구성하기 위해 약간의 추가 작업을 수행해야 합니다. 전송 컨트롤을 비디오 위쪽이 아닌 포함된 미디어 요소 아래에 배치하는 것이 이 상황을 최적화하는 좋은 예입니다. 이 이미지에서 빨간색 막대는 전송 컨트롤 집합(재생, 일시 중지, 중지 등)을 나타냅니다.
전체 화면이 아닌 미디어 위에 이러한 컨트롤을 배치하지 마세요. 대신 미디어가 렌더링되는 영역 외부 어딘가에 전송 컨트롤을 배치합니다. 다음 이미지에서 컨트롤은 미디어 아래에 배치됩니다.
MediaPlayerElement
와 함께 사용
MediaPlayerElement의 원본 설정 지연
미디어 엔진은 비용이 많이 드는 개체이며 XAML 프레임워크는 dll 로드 및 큰 개체 만들기를 가능한 한 오래 지연합니다. MediaPlayerElement 원본이 Source 속성을 통해 설정된 후에 이 작업을 수행해야 합니다. 사용자가 미디어를 재생할 준비가 되면 이를 설정하면 MediaPlayerElement와 관련된 대부분의 비용이 가능한 한 오랫동안 지연됩니다.
MediaPlayerElement.PosterSource 설정
MediaPlayerElement.PosterSource
미디어 스크러빙 개선
스크러빙은 미디어 플랫폼이 실제로 반응하기 어려운 작업입니다. 일반적으로 사람들은 슬라이더의 값을 변경하여 이 작업을 수행합니다. 이를 최대한 효율적으로 만드는 방법에 대한 몇 가지 팁은 다음과 같습니다.
- 타이머가 MediaPlayerElement.MediaPlayer에서 위치를 쿼리하여, 그에 따라 슬라이더의 값을 업데이트합니다. 타이머에 적절한 업데이트 빈도를 사용해야 합니다. Position 속성은 재생 중에 250밀리초마다만 업데이트됩니다.
- 슬라이더의 단계 빈도 크기는 비디오 길이로 조정해야 합니다.
- 구독하여 사용자가 슬라이더의 엄지손가락을 끌 때마다 슬라이더에서 발생하는 PointerPressed, PointerMoved, PointerReleased 이벤트에 반응하게 하고, PlaybackRate 속성을 0으로 설정합니다.
- PointerReleased 이벤트 처리기에서 스크러빙하는 동안 엄지 손가락의 스냅을 최적화하기 위해 미디어 위치를 슬라이더 위치 값에 수동으로 설정합니다.
비디오 해상도를 디바이스 해상도에 맞추다
비디오 디코딩에는 많은 메모리와 GPU 주기가 필요하므로 표시되는 해상도에 가까운 비디오 형식을 선택합니다. 훨씬 더 작은 크기로 축소하려는 경우 리소스를 사용하여 1080 비디오를 디코딩할 필요가 없습니다. 대부분의 앱에는 다른 해상도로 인코딩된 동일한 비디오가 없습니다. 그러나 사용 가능한 경우 표시되는 해상도에 가까운 인코딩을 사용합니다.
권장 형식 선택
미디어 형식 선택은 중요한 주제일 수 있으며 비즈니스 의사 결정에 따라 결정되는 경우가 많습니다. UWP 성능 관점에서 H.264 비디오를 기본 비디오 형식으로, AAC 및 MP3를 기본 오디오 형식으로 사용하는 것이 좋습니다. 로컬 파일 재생의 경우 MP4는 비디오 콘텐츠에 대한 기본 설정 파일 컨테이너입니다. H.264 디코딩은 최신 그래픽 하드웨어를 통해 가속화됩니다. 또한 VC-1 디코딩을 위한 하드웨어 가속은 광범위하게 제공되지만, 시장에 출시된 대다수의 그래픽 하드웨어에서는 가속이 전체 하드웨어 오프로드(즉, VLD 모드)가 아닌 부분적인 가속 수준(IDCT 수준)으로 제한됩니다.
비디오 콘텐츠 생성 프로세스를 완전히 제어할 수 있는 경우 압축 효율성과 GOP 구조 간의 균형을 유지하는 방법을 알아내야 합니다. B 프레임을 사용하는 상대적으로 작은 GOP 크기는 탐색 또는 트릭 모드에서 성능을 높일 수 있습니다.
예를 들어 게임에서 짧고 대기 시간이 짧은 오디오 효과를 사용할 때는 PCM 데이터가 압축되지 않은 WAV 파일을 사용하여 압축된 오디오 형식에서 발생하는 처리 오버헤드를 줄일 수 있습니다.
이미지 리소스 최적화
적절한 크기로 이미지 크기 조정
이미지는 매우 높은 해상도로 캡처되므로 이미지 데이터를 디코딩할 때 더 많은 CPU를 사용하는 앱과 디스크에서 로드된 후 더 많은 메모리를 사용할 수 있습니다. 그러나 고해상도 이미지를 메모리에 디코딩하고 저장하여 네이티브 크기보다 작게 표시하는 것은 의미가 없습니다. 대신 DecodePixelWidth 및 DecodePixelHeight 속성을 사용하여 화면에 그릴 정확한 크기로 이미지 버전을 만듭니다.
이러지 마:
<Image Source="ms-appx:///Assets/highresCar.jpg"
Width="300" Height="200"/> <!-- BAD CODE DO NOT USE.-->
대신 다음을 수행합니다.
<Image>
<Image.Source>
<BitmapImage UriSource="ms-appx:///Assets/highresCar.jpg"
DecodePixelWidth="300" DecodePixelHeight="200"/>
</Image.Source>
</Image>
DecodePixelWidth 및 DecodePixelHeight 단위는 기본적으로 물리적 픽셀입니다.
DecodePixelType 속성을 사용하여 이 동작을 변경할 수 있습니다. DecodePixelType을(를) 논리으로 설정하면, 디코딩 크기가 다른 XAML 콘텐츠와 마찬가지로 시스템의 현재 배율 인수를 자동으로 고려하여 조정됩니다. 따라서 일반적으로 DecodePixelWidth
DecodePixelWidth/Height가 이미지보다 명시적으로 더 크게 설정되면 앱은 픽셀당 최대 4바이트의 추가 메모리를 불필요하게 사용하게 되므로 큰 이미지의 경우 비용이 빠르게 듭니다. 또한 이미지는 이중 선형 배율을 사용하여 축소되므로 큰 배율 인수에 대해 흐리게 표시될 수 있습니다.
DecodePixelWidth/DecodePixelHeight가 화면에 표시될 이미지보다 더 작게 설정된 경우, 이미지가 확장되어 픽셀화되어 보일 수 있습니다.
적절한 디코딩 크기를 미리 확정할 수 없는 경우 XAML의 자동 적정 크기 디코딩 기능을 활용해야 합니다. 명시적인 DecodePixelWidth/DecodePixelHeight가 지정되지 않은 경우, XAML은 적절한 크기로 이미지를 디코딩하기 위해 최선의 노력을 기울입니다.
이미지 콘텐츠의 크기를 미리 알고 있는 경우 명시적 디코딩 크기를 설정해야 합니다. 제공된 디코드 크기가 다른 XAML 요소 크기를 기준으로 하는 경우, DecodePixelType를 Logical와 함께 설정해야 합니다. 예를 들어 Image.Width 및 Image.Height를 사용하여 콘텐츠 크기를 명시적으로 설정하는 경우 DecodePixelType을 DecodePixelType.Logical으로 설정하여 이미지 컨트롤과 동일한 논리 픽셀 차원을 사용한 다음 BitmapImage.DecodePixelWidth 및/또는 BitmapImage.DecodePixelHeight를 명시적으로 사용하여 이미지 크기를 제어하여 잠재적으로 큰 메모리 절약을 달성할 수 있습니다.
디코딩된 콘텐츠의 크기를 결정할 때 Image.Stretch를 고려해야 합니다.
적당한 크기의 디코딩
명시적 디코딩 크기를 설정하지 않은 경우 XAML은 포함된 페이지의 초기 레이아웃에 따라 화면에 표시되는 정확한 크기로 이미지를 디코딩하여 메모리를 저장하기 위해 최선의 노력을 기울입니다. 가능하면 이 기능을 사용하는 방식으로 애플리케이션을 작성하는 것이 좋습니다. 다음 조건이 충족되면 이 기능을 사용할 수 없습니다.
- BitmapImage는 SetSourceAsync 또는 UriSource를 사용하여 콘텐츠를 설정한 후 라이브 XAML 트리에 연결됩니다.
- 이미지는 SetSource와 같은 동기 디코딩을 사용하여 디코딩됩니다.
- 호스트 이미지 요소, 브러시 또는 부모 요소에서 Opacity 를 0으로 설정하거나 Visibility를 Collapsed 로 설정하여 이미지를 숨깁니다.
- 이미지 컨트롤 또는 브러시는 StretchNone사용합니다.
- 이미지는 NineGrid으로 사용됩니다.
-
CacheMode="BitmapCache"은 이미지 요소 또는 어떤 부모 요소에 설정됩니다. - 이미지 브러시는 비정형일 수 있습니다(예: 도형이나 텍스트에 적용할 때처럼).
위의 시나리오에서 명시적 디코딩 크기를 설정하는 것이 메모리 절약을 위한 유일한 방법입니다.
원본을 설정하기 전에 항상 BitmapImage를 라이브 트리에 연결시켜야 합니다. 이미지 요소 또는 브러시가 마크업에 지정될 때마다 이 자동으로 적용됩니다. 아래의 "라이브 트리 예제" 제목 아래에 예제가 제공됩니다. 항상 SetSource 를 사용하지 말고 스트림 원본을 설정할 때 SetSourceAsync 를 대신 사용해야 합니다. 또한 이미지 콘텐츠를 숨기는 것(불투명도를 0으로 설정하거나 가시성을 축소하는 방식)이 ImageOpened 이벤트가 발생할 때까지 기다리는 동안에 좋은 생각이 아닙니다. 이렇게 하는 것은 판단에 따른 선택입니다. 이렇게 하면 자동으로 크기를 조정한 디코딩의 이점을 누릴 수 없게 됩니다. 앱이 이미지 콘텐츠를 처음에 숨겨야 하는 경우 가능한 경우 디코딩 크기도 명시적으로 설정해야 합니다.
실시간 트리 예시
예제 1 (양호) - 마크업에 지정된 URI(Uniform Resource Identifier)입니다.
<Image x:Name="myImage" UriSource="Assets/cool-image.png"/>
코드 비하인드에 지정된 URI의 예제 2 마크업입니다.
<Image x:Name="myImage"/>
예제 2 코드 비하인드(양호)—UriSource를 설정하기 전에 BitmapImage를 트리에 연결합니다.
var bitmapImage = new BitmapImage();
myImage.Source = bitmapImage;
bitmapImage.UriSource = new URI("ms-appx:///Assets/cool-image.png", UriKind.RelativeOrAbsolute);
예제 2 코드 숨김 (잘못된 사례) - 트리에 연결하기 전에 BitmapImage의 UriSource를 설정하는 경우.
var bitmapImage = new BitmapImage();
bitmapImage.UriSource = new URI("ms-appx:///Assets/cool-image.png", UriKind.RelativeOrAbsolute);
myImage.Source = bitmapImage;
캐싱 최적화
캐싱 최적화는 UriSource 를 사용하여 앱 패키지 또는 웹에서 콘텐츠를 로드하는 이미지에 적용됩니다. URI는 기본 콘텐츠를 고유하게 식별하는 데 사용되며 내부적으로 XAML 프레임워크는 콘텐츠를 여러 번 다운로드하거나 디코딩하지 않습니다. 대신 캐시된 소프트웨어 또는 하드웨어 리소스를 사용하여 콘텐츠를 여러 번 표시합니다.
이 최적화의 예외는 이미지가 다른 해상도로 여러 번 표시되는 경우입니다(명시적으로 또는 자동 오른쪽 크기 디코딩을 통해 지정할 수 있습니다). 각 캐시 항목은 이미지의 해상도도 저장하며, XAML이 필요한 해상도와 일치하는 원본 URI가 있는 이미지를 찾을 수 없는 경우 해당 크기의 새 버전을 디코딩합니다. 그러나 인코딩된 이미지 데이터를 다시 다운로드하지는 않습니다.
따라서 앱 패키지에서 이미지를 로드할 때 UriSource 사용을 수용하고 필요하지 않은 경우 파일 스트림 및 SetSourceAsync 를 사용하지 않도록 해야 합니다.
가상화된 패널의 이미지(예: ListView)
앱이 명시적으로 제거했거나 현대적인 가상화 패널에 있어 보기에서 벗어나 스크롤될 때 암시적으로 제거된 이미지는 트리에서 삭제됩니다. 이 경우 XAML은 더 이상 필요하지 않은 이미지의 하드웨어 리소스를 해제하여 메모리 사용을 최적화합니다. 메모리는 즉시 해제되지 않고, 이미지 요소가 트리에서 사라진 후 1초 후에 발생하는 프레임 업데이트 시 해제됩니다.
따라서 최신 가상화된 패널을 사용하여 이미지 콘텐츠 목록을 호스트해야 합니다.
소프트웨어로 래스터화된 이미지
이미지가 직사각형이 아닌 브러시나 NineGrid에 사용될 때, 이미지는 크기를 전혀 조정하지 않는 소프트웨어 래스터화 경로를 사용하게 됩니다. 또한 소프트웨어 및 하드웨어 메모리 모두에 이미지의 복사본을 저장해야 합니다. 예를 들어 이미지가 타원에 대한 브러시로 사용되는 경우 잠재적으로 큰 전체 이미지가 내부적으로 두 번 저장됩니다. NineGrid 또는 직사각형이 아닌 브러시를 사용하는 경우, 앱은 이미지를 대략 렌더링될 크기로 미리 조정해야 합니다.
백그라운드 스레드에서 이미지 로딩
XAML에는 소프트웨어 메모리에 중간 표면을 요구하지 않고도 이미지의 내용을 하드웨어 메모리의 표면으로 비동기적으로 디코딩할 수 있는 내부 최적화 기능이 있습니다. 이렇게 하면 최대 메모리 사용량 및 렌더링 대기 시간이 줄어듭니다. 다음 조건이 충족되면 이 기능을 사용할 수 없습니다.
- 이미지는 NineGrid으로 사용됩니다.
-
CacheMode="BitmapCache"은 이미지 요소 또는 어떤 부모 요소에 설정됩니다. - 이미지 브러시는 비정형일 수 있습니다(예: 도형이나 텍스트에 적용할 때처럼).
소프트웨어 비트맵 소스 (SoftwareBitmapSource)
SoftwareBitmapSource 클래스는 BitmapDecoder, 카메라 API 및 XAML과 같은 여러 WinRT 네임스페이스 간에 상호 운용 가능한 압축되지 않은 이미지를 교환합니다. 이 클래스는 일반적으로 WriteableBitmap와 관련하여 필요할 수 있는 추가 복사본을 없애며, 이를 통해 최대 메모리 사용량 및 소스에서 화면까지의 지연 시간을 줄이는 데 도움이 됩니다.
원본 정보를 제공하는 SoftwareBitmap는 사용자 지정 IWICBitmap를 사용하여 구성할 수 있으며, 이를 통해 앱이 필요에 맞게 메모리를 다시 매핑할 수 있는 다시 로드 가능한 백업 저장소를 제공합니다. 고급 C++ 사용 사례입니다.
앱은 이미지를 생성하고 사용하는 다른 WinRT API와 상호 운용할 수 있도록 SoftwareBitmap 및 SoftwareBitmapSource를 사용해야 합니다. 앱은 압축되지 않은 이미지 데이터를 로드할 때 WriteableBitmap를 사용하는 대신 SoftwareBitmapSource 를 사용해야 합니다.
썸네일에 GetThumbnailAsync 사용
이미지 크기를 조정하는 한 가지 사용 사례는 썸네일을 만드는 것입니다. DecodePixelWidth 및 DecodePixelHeight를 사용하여 작은 버전의 이미지를 제공할 수 있지만 UWP는 미리 보기를 검색하는 데 훨씬 더 효율적인 API를 제공합니다. GetThumbnailAsync 는 파일 시스템이 이미 캐시된 이미지에 대한 썸네일을 제공합니다. 이미지를 열거나 디코딩할 필요가 없으므로 XAML API보다 성능이 훨씬 향상됩니다.
FileOpenPicker picker = new FileOpenPicker();
picker.FileTypeFilter.Add(".bmp");
picker.FileTypeFilter.Add(".jpg");
picker.FileTypeFilter.Add(".jpeg");
picker.FileTypeFilter.Add(".png");
picker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
StorageFile file = await picker.PickSingleFileAsync();
StorageItemThumbnail fileThumbnail = await file.GetThumbnailAsync(ThumbnailMode.SingleItem, 64);
BitmapImage bmp = new BitmapImage();
bmp.SetSource(fileThumbnail);
Image img = new Image();
img.Source = bmp;
Dim picker As New FileOpenPicker()
picker.FileTypeFilter.Add(".bmp")
picker.FileTypeFilter.Add(".jpg")
picker.FileTypeFilter.Add(".jpeg")
picker.FileTypeFilter.Add(".png")
picker.SuggestedStartLocation = PickerLocationId.PicturesLibrary
Dim file As StorageFile = Await picker.PickSingleFileAsync()
Dim fileThumbnail As StorageItemThumbnail = Await file.GetThumbnailAsync(ThumbnailMode.SingleItem, 64)
Dim bmp As New BitmapImage()
bmp.SetSource(fileThumbnail)
Dim img As New Image()
img.Source = bmp
이미지를 한 번 디코딩
이미지가 두 번 이상 디코딩되지 않도록 하려면 메모리 스트림을 사용하는 대신 Uri에서 Image.Source 속성을 할당합니다. XAML 프레임워크는 여러 위치에서 동일한 URI를 하나의 디코딩된 이미지와 연결할 수 있지만 동일한 데이터를 포함하고 각 메모리 스트림에 대해 다른 디코딩된 이미지를 만드는 여러 메모리 스트림에 대해서는 동일한 작업을 수행할 수 없습니다.