MSDN : http://msdn2.microsoft.com/en-us/library/ms748873.aspx

Imaging Overview

이 토픽은 Microsoft WPF 이미징 컴포넌트의 소개를 제공합니다. WPF 이미징은 개발자가 이미지를 화면에 표시하고 변형하고 포맷을 지정할 수 있게 합니다.

이 토픽은 다음 섹션을 담습니다.
WPF 이미징 컴포넌트

WPF 이미징은 Microsoft Windows내에서의 이미징 능력에 상당한 향상을 제공합니다. 비트맵을 보여주거나 커먼 컨트롤에 이미지를 사용하는 것 같은 이미징 능력은 이전엔 Microsoft Windows Graphics Device Interface(GDI)나 Microsoft Windows GDI+ 라이브러리에 의존했습니다. 이 API는 이미징 기능의 기반을 제공했지만 코덱 확장성이나 고선명 이미지 지원과 같은 기능이 부족했습니다. WPF 이미징은 GDI와 GDI+의 단점을 극복하기 위해 디자인 되었고, 애플리케이션에 이미지를 표시하고 사용하기 위한 새로운 API 세트를 제공합니다.

WPF 이미징 API에 접근 방법은 매니지드(managed) 컴포넌트와 언매니지드(unmanaged) 컴포넌트의 두 가지 방법이 있습니다. 언매니지드 컴포넌트는 다음 기능을 제공합니다.
  • 새롭거나 소유권 있는 이미지 포맷을 위한 확장성있는 모델
  • 비트맵(BMP), Joint Photographics Experts Group(JPEG), Portable Network Graphics(PNG), Tagged Image File Format(TIFF), Microsoft Windows Media Photo, Graphics Interchange Format(GIF) 및 icon(.ico)를 포함하는 네이티브 이미지 상에서의 향상된 성능과 보안
  • 채널당 32비트까지의 고 비트 이미지 데이터 보존
  • 손실 없는 이미지 배율 조절(scaling), 자르기(cropping) 및 회전
  • 단순화된 색상 관리
  • 파일 내에 있는 소유권 메타데이터 지원
매니지드 컴포넌트는 사용자 인터페이스(UI), 애니메이션 및 그래픽 같은 다른 WPF 기능과 이미지의 매끄러운(seamless) 통합을 제공하기 위해 언매니지드 인프라스트럭쳐를 이용합니다. 매니지드 컴포넌트는 또한 WPF 애플리케이션에서 자동화된 새 이미지 포맷의 인식을 가능케 하는 WPF 이미징 코덱 확장 모델의 혜택을 받습니다.

매니지드 WPF 이미징 API의 대부분은 System.Windows.Media.Imaging 네임스페이스에 존재하지만 ImageBrushImageDrawing과 같은 몇 가지 중요한 타입은 System.Windows.Media 네임스페이스에 존재하며 ImageSystem.Windows.Controls 네임스페이스에 존재합니다.

WPF 이미징 포맷

코덱은 특정한 미디어 포맷을 디코드하거나 인코드합니다. WPF 이미징은 BMP, JPEG, PNG, TIFF, Windows Media Photo, GIF 및 ICON 이미지 포맷을 위한 코덱을 포함합니다. 각 코덱은 애플리케이션이 디코드하고, ICON을 제외한 각각의 이미지 포맷을 인코드할 수 있게 합니다.

BitmapSource는 이미지의 디코딩과 인코딩에 사용되는 중요한 클래스입니다. 이것은 WPF 이미징 파이프라인의 기본 빌딩 블럭이며 어떤 크기와 해상도에서 픽셀의 단일한 불변의 세트를 나타냅니다. BitmapSource는 다중 프레임 이미지의 개별적인 프레임이 될 수 있고 또는 BitmapSource상의 변형 동작의 결과가 될 수도 있습니다. BitmapSourceBitmapFrame과 같은 WPF 이미징에서 사용되는 많은 주요 클래스의 부모가 됩니다.

BitmapFrame은 이미지 포맷의 실제 비트맵 데이터를 저장합니다. 많은 이미지 포맷이 단지 하나의 BitmapFrame만을 지원하지만 GIF나 TIFF와 같은 포맷은 한 이미지에서 다중 프레임을 지원합니다. 프레임은 디코더에게 입력 데이터로 사용되고 인코더에게 이미지 파일을 생성하도록 전달됩니다.

다음 예제는 BitmapSource로부터 BitmapFrame을 생성하고 TIFF 이미지에 추가하는 방법을 보여줍니다.

C#
BitmapSource image5 = BitmapSource.Create(

    width,

    height,

    96,

    96,

    PixelFormats.Indexed1,

    BitmapPalettes.WebPalette,

    pixels,

    stride);


FileStream stream5 = new FileStream("palette.tif", FileMode.Create);

TiffBitmapEncoder encoder5 = new TiffBitmapEncoder();

encoder5.Frames.Add(BitmapFrame.Create(image5));

encoder5.Save(stream5);


이미지 포맷 디코딩
이미지 디코딩은 시스템이 사용할 수 있도는 이미지 데이터로 이미지 포맷을 번역하는 것입니다. 번역된 이미지 데이터는 화면 표시, 처리 또는 다른 포맷으로 인코드될 수 있습니다. 디코더 섹션은 이미지 포맷에 기반합니다. 코덱 섹션은 디코더가 지정되지 않으면 자동으로 지정됩니다. Displaying Images in WPF의 예제 섹션은 자동 디코딩을 시연합니다. 사용자 정의 포맷 디코더는 언매니지드 WPF 이미징 인터페이스를 사용하여 개발되고 자동으로 디코더 섹션에 포함되어 시스템에 등록됩니다. 이것은 사용자 정의 포맷이 WPF 애플리케이션에서 자동으로 표시될 수 있도록 합니다.

다음 예제는 BMP 포맷 이미지를 디코드하기 위한 비트맵 디코더의 사용을 보여줍니다.(※역주: C++코드는 생략합니다.)

C#
// Open a Uri and decode a BMP image

Uri myUri = new Uri("tulipfarm.bmp", UriKind.RelativeOrAbsolute);

BmpBitmapDecoder decoder2 = new BmpBitmapDecoder(myUri, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);

BitmapSource bitmapSource2 = decoder2.Frames[0];


// Draw the Image

Image myImage2 = new Image();

myImage2.Source = bitmapSource2;

myImage2.Stretch = Stretch.None;

myImage2.Margin = new Thickness(20);


이미지 포맷 인코딩
이미지 인코딩은 이미지 데이터를 특정 이미지 포맷으로 번역하는 것입니다. 인코드된 이미지 데이터로는 새 이미지 파일을 생성할 수 있습니다. WPF 이미징은 위에서 기술한 이미지 포맷 각각을 위한 인코더를 제공합니다.

다음 예제는 새로 생성한 비트맵 이미지를 저장하는 인코더의 사용을 보여줍니다.

C#

FileStream stream = new FileStream("new.bmp", FileMode.Create);

BmpBitmapEncoder encoder = new BmpBitmapEncoder();

TextBlock myTextBlock = new TextBlock();

myTextBlock.Text = "Codec Author is: " + encoder.CodecInfo.Author.ToString();

encoder.Frames.Add(BitmapFrame.Create(image));

encoder.Save(stream);


WPF에서 이미지 표시하기

BitmapImage는 XAML 로딩을 위해 최적화된 특수한 BitmapSource이고 Image 컨트롤의 Source로 이미지를 표시하는 쉬운 방법입니다.

이미지 컨트롤 사용하기
Image는 프레임워크 엘리먼트이고 애플리케이션에서 이미지를 표시하는 주된 수단입니다. XAML에서 Image는 어트리뷰트 문법 또는 프로퍼티 문법의 두 가지 방법으로 사용될 수 있습니다. 다음 예제는 어트리뷰트 문법과 프로퍼티 태그 문법을 모두 사용하여 이미지를 200 픽셀 너비로 그리는 방법을 보여줍니다. 어트리뷰트 문법과 프로퍼티 문법의 더 자세한 정보는 Dependency Properties Overview를 참고하십시오.

XAML

<!-- 간단한 이미지 렌더링. 그러나 이 방법으로 렌더링하는 것은 애플리케이션 메모리의 사용량에는 좋지 않습니다. 같은 결과를 더 적은 메모리로 생성하는 아래쪽 마크업을 참고하십시오. -->

<Image Width="200"

Source="C:\Documents and Settings\All Users\Documents\My Pictures\Sample Pictures\Water Lilies.jpg"/>


<Image Width="200">

  <Image.Source>

    <!-- 상당한 애플리케이션 메모리를 아끼기 위해 이미지 소스의 BitmapImage의 DecodePixelWidth나 DecodePixelHeight값을 원하는 높이와 너비로 설정하십시오. 그렇게 하지 않으면 애플리케이션은 이미지를 화면에 표시될 크기가 아닌 그것의 보통 크기로 렌더링 될 것이라고 생각하고 캐슁할 것입니다. -->

    <!-- Note: 원래 비율을 보호하기 위해 DecodePixelHeight이나 DecodePixelWidth중 하나만을 설정하십시오. -->

    <BitmapImage DecodePixelWidth="200" 

    UriSource="C:\Documents and Settings\All Users\Documents\My Pictures\Sample Pictures\Water Lilies.jpg" />

  </Image.Source>

</Image>


다음 예제는 코드를 사용하여 이미지를 200픽셀 너비로 그리는 방법을 보여줍니다.

노트:
BitmapImage는 다중 속성에서 초기화 최적화를 위해 ISupportInitilize 인터페이스를 구현합니다. 속성 변경은 오직 객체 초기화 중에만 발생할 수 있습니다. 초기화가 시작되었음을 알리는 신호로 BeginInit을 호출하고 초기화가 완료되었음을 알리는 신호로 EndInit을 호출합니다. 일단 초기화되면 속성 변경은 무시됩니다.


C#
// 이미지 엘리먼트 생성

Image myImage = new Image();

myImage.Width = 200;


// 소스 생성

BitmapImage myBitmapImage = new BitmapImage();


// BitmapImage.UriSource는 반드시 BeginInit/EndInit 블럭 내에 있어야 합니다.

myBitmapImage.BeginInit();

myBitmapImage.UriSource = new Uri(@"C:\Documents and Settings\All Users\Documents\My Pictures\Sample Pictures\Water Lilies.jpg");


myBitmapImage.DecodePixelWidth = 200;

myBitmapImage.EndInit();

// 이미지 소스 설정

myImage.Source = myBitmapImage;


이미지 회전, 변환(converting) 및 자르기(cropping)
WPF는 BitmapImage의 속성을 사용하거나 CroppedBitmap이나 FormatConvertedBitmap과 같은 추가적인 BitmapSource 객체를 사용하여 이미지를 변형 할 수 있습니다. 이 이미지 변형은 이미지를 배율 조절하거나 회전할 수 있고 이미지의 픽셀 포맷을 바꾸거나 이미지를 자를 수 있습니다.

이미지 회전은 BitmapImageRotation 속성을 사용하여 작동됩니다. 회전은 90도씩만 증가될 수 있습니다. 다음 예제에서 이미지는 90도 회전됩니다.

XAML
<Image Width="150" Margin="5" Grid.Column="0" Grid.Row="1">
  <Image.Source>
    <TransformedBitmap Source="/sampleImages/watermelon.jpg" >
      <TransformedBitmap.Transform>
        <RotateTransform Angle="90"/>
      </TransformedBitmap.Transform>
    </TransformedBitmap>
  </Image.Source>
</Image>


C#
// 이미지 엘리먼트 생성
Image rotated90 = new Image();
rotated90.Width = 150;

// 이미지 소스로써 사용할 TransformedBitmap 생성
TransformedBitmap tb = new TransformedBitmap();

// 소스로써 사용할 (비트맵이미지)소스 생성
BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.UriSource = new Uri(@"sampleImages/watermelon.jpg", UriKind.RelativeOrAbsolute);
bi.EndInit();

// 속성은 반드시 BeginInit과 EndInit 호출 사이에서 설정해야 합니다.
tb.BeginInit();
tb.Source = bi;
// 이미지 회전을 설정
RotateTransform transform = new RotateTransform(90);
tb.Transform = transform;
tb.EndInit();
// 이미지 소스를 설정
rotated90.Source = tb;

이미지를 그레이스케일과 같은 다른 픽셀 포맷으로 변환하는 것은 FormatConvertedBitmap을 사용합니다. 다음 예제에서 이미지는 Gray4로 변환됩니다.

XAML
<!-- Grayscale XAML Image -->
<Image Width="200" Grid.Column="0" Grid.Row="1">
   <Image.Source>
      <FormatConvertedBitmap Source="/sampleImages/rocks.jpg"  DestinationFormat="Gray4" />
   </Image.Source>
</Image>


C#
// 이미지 엘리먼트 생성
Image grayImage = new Image();
grayImage.Width = 200;
grayImage.Margin = new Thickness(5);

// XAML에서 정의된 리소스를 사용하여 소스 생성
FormatConvertedBitmap fcb = new FormatConvertedBitmap(
   (BitmapImage)this.Resources["masterImage"],PixelFormats.Gray4,null,0);
// 이미지 소스 설정
grayImage.Source = fcb;

이미지를 자르기 위해서 ImageClip 속성이나 CroppedBitmap을 사용할 수 있습니다. 일반적으로 단지 이미지의 일부분만 보여주고 싶다면 Clip이 사용됩니다. 만약 잘린 이미지를 인코드하고 저장할 필요가 있다면 CroppedBitmap이 사용됩니다. 다음 예제에서 이미지는 EllipseGeometry를 사용한 Clip 속성을 사용하여 잘립니다.

XAML
<!-- Cropping an Image using Clip -->
<Image Width="200" Grid.Column="0" Grid.Row="5" Margin="5"
   Source="/sampleImages/gecko.jpg">
  <Image.Clip>
    <EllipseGeometry Center="75,50" RadiusX="50" RadiusY="25" />
  </Image.Clip>
</Image>


C#
// 클리핑을 위한 이미지 생성
Image clipImage = new Image();
clipImage.Width = 200;
clipImage.Margin = new Thickness(5);
 
// 소스 생성 및 설정
BitmapImage bi = new BitmapImage();
// BitmapImage.UriSource는 반드시 BeginInit/EndInit 블럭 내에 있어야 합니다.
bi.BeginInit();
bi.UriSource = new Uri("pack://application:,,/sampleImages/gecko.jpg");
bi.EndInit();
clipImage.Source = bi;

// EllipseGeometry를 사용하여 클립
EllipseGeometry clipGeometry = new EllipseGeometry(new Point(75, 50), 50, 25);
clipImage.Clip = clipGeometry;

이미지 늘리기
Stretch 속성은 이미지가 컨테이너에 어떻게 늘려져서 채워질지를 제어합니다. Stretch 속성은 Stretch 열거값에서 정의된 다음 값을 받아들입니다.
  • None: 이미지는 출력 영역을 늘려져서 채우지 않습니다. 이미지가 출력 영역보다 클 경우 이미지는 출력 영역에 그려지고 맞지 않는 부분은 잘립니다.
  • Fill: 이미지는 출력 영역에 맞춰 배율이 조절됩니다. 이미지의 높이와 너비가 독립적으로 조절되기 때문에 이미지의 원래 비율은 보호되지 않을 것입니다. 이미지는 출력 컨테이너를 완전히 채우도록 정렬되어 비뚤어질 것입니다.
  • Uniform: 이미지는 출력 영역 내에 완전하게 맞춰서 배율 조절 됩니다. 이미지의 비율은 보호됩니다.
  • UnformFill: 이미지는 출력 영역을 이미지의 원래 배율을 보존하면서 완전하게 채워 배율 조절 됩니다.
※역주: 원문에는 여기에 각각의 Stretch를 다르게 설정한 예제 코드만 나와있습니다. 여기에서는 이 코드를 거의 그대로 사용한 수정된 코드 및 결과물을 대신 올립니다.

XAML
<Window x:Class="WindowsApplication1.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="WindowsApplication1" Height="500" Width="400">

  <DockPanel>


    <Border DockPanel.Dock="Top" Background="Black">

      <TextBlock Foreground="White" HorizontalAlignment="Stretch" FontSize="20">

        Stretching an Image

      </TextBlock>

    </Border>


    <Grid Name="simpleGrid"

      Margin="10"

      ShowGridLines="True"

      VerticalAlignment="Center"

      HorizontalAlignment="Center">

      <Grid.ColumnDefinitions>

        <ColumnDefinition Width="175" />

        <ColumnDefinition Width="175" />

      </Grid.ColumnDefinitions>

      <Grid.RowDefinitions>

        <RowDefinition Height="200"/>

        <RowDefinition Height="200"/>

      </Grid.RowDefinitions>

      <!-- Labels -->

      <TextBlock

        Grid.Column="0" Grid.Row="0">None</TextBlock>

      <TextBlock

        Grid.Column="1" Grid.Row="0">Uniform</TextBlock>

      <TextBlock

        Grid.Column="0" Grid.Row="1">UniformToFill</TextBlock>

      <TextBlock

        Grid.Column="1" Grid.Row="1">Fill</TextBlock>

      <Border Grid.Column="0" Grid.Row="0" BorderThickness="1" BorderBrush="Black">

        <!-- None: 이미지는 배율 조절되지 않습니다. 이미지가 출력 영역보다 크다면 이미지는 출력 영역의 크기로 잘릴 것입니다.-->

        <Image

          Source="sampleImages/만년삼.gif"

          Stretch="None" />

      </Border>

      <Border Grid.Column="1" Grid.Row="0" BorderThickness="1" BorderBrush="Black">

        <!-- Uniform: 출력 영역에 맞춰 배율 조절합니다. 비율은 보호됩니다.-->

        <Image

          Source="sampleImages/만년삼.gif"

          Stretch="Uniform" />

      </Border>

      <Border Grid.Column="0" Grid.Row="1" BorderThickness="1" BorderBrush="Black">

        <!-- UniformToFill: 출력 영역을 완전히 채우도록 배율 조절됩니다. 비율은 보호됩니다. 크기에 따라 잘릴 수 있습니다.-->

        <Image 

          Source="sampleImages/만년삼.gif"

        Stretch="UniformToFill" />

      </Border>

      <Border Grid.Column="1" Grid.Row="1" BorderThickness="1" BorderBrush="Black">

        <!-- Fill: 출력 영역을 완전히 채우도록 배율 조절됩니다. 비율은 보호되지 않을 것입니다.-->

        <Image

          Source="sampleImages/만년삼.gif"

          Stretch="Fill" />

      </Border>

    </Grid>

  </DockPanel>


</Window>




이미지로 페인팅하기
이미지는 또한 Brush로 페인팅하여 애플리케이션에서 표시될 수 있습니다. 브러쉬는 단순한 단일 컬러에서 복잡한 패턴의 세트와 이미지까지 어떤 것으로도 UI 객체를 칠할 수 있게 합니다. 이미지를 칠하려면 ImageBrush를 사용합니다. ImageBrush는 자신의 내용을 비트맵 이미지로 정의하는 TileBrush의 타입입니다. ImageBrushImageSource 속성에서 지정된 단일 이미지를 표시합니다. 이미지가 늘려지고 정렬되고 배열되는 방법을 제어할 수 있고 왜곡을 막고 패턴과 다른 효과를 제작하는 것을 가능케 합니다. 다음 그림은 ImageBrush로 얻을 수 있는 몇 가지 효과를 보여줍니다.

도형, 컨트롤, 텍스트 및 기타를 채울 수 있는 이미지 브러쉬


다음 예제는 버튼의 배경을 ImageBrush를 사용하여 이미지로 칠할 수 있는 방법을 보여줍니다.

XAML
<!-- 버튼의 배경 속성을 이미지 브러쉬로 설정합니다. 결과적으로 버튼은 배경에 이미지를 가지게 됩니다. -->

<Button Grid.Row="3" Grid.Column="2"

 Height="75" Width="100" Foreground="White" FontWeight="Bold"

 HorizontalAlignment="Left">

  A Button

  <Button.Background>

    <ImageBrush ImageSource="sampleImages\blueberries.jpg" />

  </Button.Background>

</Button>


ImageBrush와 칠하기에 대한 추가적인 정보는 Painting with Images, Drawings, and Visuals를 참고하십시오.

이미지 메타데이터

어떤 이미지 파일은 컨텐트나 파일의 특성을 기술하는 메타데이터를 포함합니다. 예를 들어 대부분의 디지털 카메라는 이미지 캡쳐에 사용된 카메라의 메이커와 모델에 관한 메타데이터를 포함하는 이미지를 생성합니다. 각 이미지 포맷은 메타데이터를 다르게 처리하지만 WPF 이미징은 지원되는 각 이미지 포맷을 위한 통합된 메타데이터 저장과 얻는 수단을 제공합니다.

메타데이터 접근은 BitmapSource 객체의 Metadata 속성을 통해 제공됩니다. Metadata는 이미지가 담고 있는 모든 메타데이터를 포함하는 BitmapMetadata 객체를 반환합니다. 이 데이터는 하나의 메타데이터 스키마 또는 다른 스키마의 조합일 수 있습니다. WPF 이미징은 다음의 메타데이터 스키마를 지원합니다. Exchangeable image file(Exif), tExt(PNG Textual Data), Image File Directory(IFD), International Press Telecommunications Council(IPTC) 및 Extensible Metadata Platform(XMP)

메타데이터 읽기 프로세스를 단순화하기 위해 BitmapMetadataAuthor, TitleCameraModel과 같이 쉽게 접근할 수 있는 몇 가지 명명된 속성을 제공합니다. 이들 명명된 속성의 대부분은 또한 메타데이터 기록에도 사용될 수 있습니다. 메타데이터 읽기를 위한 추가적인 지원은 메타데이터 쿼리 리더가 제공합니다. GetQuery 메소드는 "/app1/exif/"와 같은 문자열 쿼리를 제공함으로써 메타데이터 쿼리 리더를 받습니다. 다음 예제에서 GetQuery는 "/Text/Description" 위치에 저장된 텍스트를 얻기 위해 사용됩니다.

C#
// 텍스트 블럭에 비트맵 이미지의 메타데이터를 추가
TextBlock myTextBlock = new TextBlock();
myTextBlock.Text = "The Description metadata of this image is: " + pngInplace.GetQuery("/Text/Description").ToString();

메타데이터를 쓰기 위해 메타데이터 쿼리 라이터(writer)가 사용됩니다. SetQuery는 쿼리 라이터를 얻고 원하는 값을 설정합니다. 다음 예제에서 SetQuery는 "/Text/Description" 위치에 저장된 텍스트를 쓰기 위해 사용됩니다.

C#
Stream pngStream = new System.IO.FileStream("smiley.png", FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite);

PngBitmapDecoder pngDecoder = new PngBitmapDecoder(pngStream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);

BitmapFrame pngFrame = pngDecoder.Frames[0];

InPlaceBitmapMetadataWriter pngInplace = pngFrame.CreateInPlaceBitmapMetadataWriter();

if (pngInplace.TrySave() == true)

{ pngInplace.SetQuery("/Text/Description", "Have a nice day."); }

pngStream.Close();



코덱 확장성

WPF 이미징의 핵심 기능은 새로운 이미지 코덱을 위한 확장성 있는 모델입니다. 이 언매니지드 인터페이스는 코덱 개발자가 WPF와 코덱을 통합할 수 있게 하므로 새로운 이미지 포맷이 WPF 애플리케이션에서 자동으로 사용될 수 있습니다.

확장 API의 샘플은 Win32 Sample Codec을 참고하십시오. 이 샘플은 사용자 정의 이미지 포맷을 위한 디코더와 인코더를 만드는 방법을 제시합니다.

노트:
코덱은 그것을 인식하기 위해 반드시 시스템을 위한 디지털 사인이 되어 있어야 합니다.

See also

Reference
BitmapSource
BitmapImage
Image
BitmapMetadata

Other Resources
Win32 Sample Codec
Photo Store Demo
신고
Posted by gongdo


티스토리 툴바