'RenderTargetBitmap'에 해당되는 글 2건

  1. 2010.05.08 [ WPF ] 이미지 그림판 2
  2. 2010.01.29 [WPF] Object Capture
Window/WPF2010. 5. 8. 18:13

이미지를 불러와 간단한 꾸미기를 하고 저장하는 예제에 대해 포스팅하겠습니다.

예전 해당 영역을 이미지로 저장하는 포스팅의 내용을 약간 수정한 내용입니다.

 

간략적으로,

InkCanvas를 사용해 그림을 그리고 DrawingVisualDrawingContext를 통해

RenderTargetBitmap으로 변환 후 이를 BitmapEncoder를 사용해 해당 포맷에 맞게 저장합니다.

 

InkCanvas를 이미지로 변환 후 저장하기 때문에

꾸미기 용도에 맞게 자식 객체로 여러가지를 포함시킨 후 저장하셔도 되겠죠.^^

 

이제, 소스를 통해 하나씩 알아보겠습니다.

 

1. 이미지를 InkCanvas의 Background로 지정합니다.

// 이미지 불러오기

private void btn_Open(object sender, RoutedEventArgs e)

{

    OpenFileDialog openDialog = new OpenFileDialog();

 

    if (openDialog.ShowDialog() == true)

    {

        if (File.Exists(openDialog.FileName))

        {

            BitmapImage bitmapImage = new BitmapImage(new Uri(openDialog.FileName,

                UriKind.RelativeOrAbsolute));

 

            // InkCanvas의 배경으로 지정

            inkCanvas.Background = new ImageBrush(bitmapImage);

        }

    }

}

 

2. 해당 객체(InkCanvas)를 비트맵으로 변환합니다.

 // 해당 객체를 이미지로 변환

private static RenderTargetBitmap ConverterBitmapImage(FrameworkElement element)

{

    DrawingVisual drawingVisual = new DrawingVisual();

    DrawingContext drawingContext = drawingVisual.RenderOpen();

 

    // 해당 객체의 그래픽요소로 사각형의 그림을 그립니다.

    drawingContext.DrawRectangle(new VisualBrush(element), null,

        new Rect(new Point(0, 0), new Point(element.ActualWidth, element.ActualHeight)));

 

    drawingContext.Close();

 

    // 비트맵으로 변환합니다.

    RenderTargetBitmap target =

        new RenderTargetBitmap((int)element.ActualWidth, (int)element.ActualHeight,

        96, 96, System.Windows.Media.PixelFormats.Pbgra32);

 

    target.Render(drawingVisual);

    return target;

}

 

3. 변환된 이미지를 해당 포맷에 맞게 저장합니다.

 // 해당 이미지 저장

private static void ImageSave(BitmapSource source)

{

    SaveFileDialog saveDialog = new SaveFileDialog();

 

    // 이미지 포맷들

    saveDialog.Filter = "PNG|*.png|JPG|*.jpg|GIF|*.gif|BMP|*.bmp";

    saveDialog.AddExtension = true;

 

    if (saveDialog.ShowDialog() == true)

    {

        BitmapEncoder encoder =  null;

        // 파일 생성

        FileStream stream = new FileStream(saveDialog.FileName, FileMode.Create, FileAccess.Write);

 

        // 파일 포맷

        string upper = saveDialog.SafeFileName.ToUpper();

        char[] format = upper.ToCharArray(saveDialog.SafeFileName.Length - 3, 3);

        upper = new string(format);

 

        // 해당 포맷에 맞게 인코더 생성

        switch (upper.ToString())

        {

            case "PNG":

                encoder = new PngBitmapEncoder();

                break;

 

            case "JPG":

                encoder = new JpegBitmapEncoder();

                break;

 

            case "GIF":

                encoder = new GifBitmapEncoder();

                break;

 

            case "BMP":

                encoder = new BmpBitmapEncoder();

                break;

        }

        // 인코더 프레임에 이미지 추가

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

        // 파일에 저장

        encoder.Save(stream);

        stream.Close();

    }

}

 

 

결과 화면은 다음과 같습니다.

 

1. 이미지를 불러옵니다.

        

 

2. 간단히 꾸미기를 하고 저장합니다.

      

 

3. 저장된 이미지

 

'Window > WPF' 카테고리의 다른 글

[ WPF ] 윈도우 이벤트  (4) 2010.07.11
[ WPF ] OpenCV로 캠 화면 띄우기  (3) 2010.06.20
[ WPF ] UI 쓰레드 변경하기  (0) 2010.05.04
[ WPF ] WPF in Flash  (0) 2010.04.29
[ WPF ] 클래스 구조  (0) 2010.04.27
Posted by 열ㅇl
Window/WPF2010. 1. 29. 03:21
윈도우 창에 있는 모든 객체들은 그래픽적 요소를 가지고 있기 때문에

VisualBrush를 통해 브러쉬 요소로 사용할 수 가 있습니다.

 

이를 사용하여 윈도우 창에 있는 객체를 선택하거나 선택영역을 지정하여

해당 포맷에 맞는 이미지로 저장하는 간단한 예제를 만들어 보았습니다.

 

예제를 위해 눈사람 이라고 만들었는데 영 이상하네요. ㅎㅎ

 

객체 선택 : 마우스를 커서가 위치한 객체에 다음과 같이 빨간 테두리가 생깁니다.

                 Background 해제 시 객체만을 이미지로 저장합니다.

                 Background 체크 시 객체 영역을 이미지로 저장합니다.

                 저장 : 마우스 왼쪽 버튼

 

 

선택 영역 지정 : Cut 체크박스를 체크 한 후 마우스 왼쪽 버튼을 누른 채 이동하여 사각형을 만듭니다.

                         사각형을 드래그하여 이미지로 저장할 영역을 설정합니다.

                         저장 : 마우스 오른쪽 버튼

 

저장된 결과입니다.

 

예제는 부모 요소가 Canvas임을 고려하여 만들었습니다.

 

객체를 이미지로 변경하는 소스부분입니다.

DrawingVisual 객체로 객체 브러쉬로 사각형 그림을 그린 뒤 RenderTargetBitmap을 사용하여 Bitmap으로 변환합니다.

DrawRectangle의 Rect 첫번째 인자는 브러쉬로 칠할 시작 위치입니다.

 

   30 public static RenderTargetBitmap ConverterBitmapImage(FrameworkElement element)

   31 {

   32     DrawingVisual drawingVisual = new DrawingVisual();

   33     DrawinContext drawingContext = drawingVisual.RenderOpen();

   34 

   35     // 해당 객체의 그래픽요소로 사각형의 그림을 그립니다.

   36     drawingContext.DrawRectangle(new VisualBrush(element), null,

   37         new Rect(new Point(0, 0), new Point(element.ActualWidth, element.ActualHeight)));

   38     drawingContext.Close();

   39 

   40     // 비트맵으로 변환합니다.

   41     RenderTargetBitmap target =

   42         new RenderTargetBitmap((int)element.ActualWidth, (int)element.ActualHeight,

   43         96, 96, System.Windows.Media.PixelFormats.Pbgra32);

   44 

   45     target.Render(drawingVisual);

   46     return target;

   47 }

 

 

선택영역을 이미지로 변환하는 부분입니다.

CopyPixels 함수에서 부모 Canvas 이미지에서 해당 영역 만큼 픽셀을 복사해 와 비트맵 소스로 변환합니다.

   104 public static BitmapSource CutAreaToImage(int x, int y, int width, int height)

  105 {

             .

             .   // 예외 처리 부분

             .

  126 

  127     byte[] pixels = CopyPixels(x, y, width, height);

  128 

  129     int stride = (width * backround.Format.BitsPerPixel + 7) / 8;

  130 

  131    return BitmapSource.Create(width, height, 96, 96, PixelFormats.Pbgra32, null, pixels, stride);

  132 }

 

 

CopyPixels은 단지 CopyPixels 함수로 픽셀을 복사합니다.

    82 public static byte[] CopyPixels(int x, int y, int width, int height)

   83 {

   84     byte[] pixels = new byte[width * height * 4];

   85     int stride = (width * backround.Format.BitsPerPixel + 7) / 8;

   86 

   87     // Canvas 이미지에서 객체 역역만큼 픽셀로 복사

   88     canvasImage.CopyPixels(new Int32Rect(x, y, width, height), pixels, stride, 0);

   89 

   90     return pixels;

   91 }

 

 

다음은 객체 영역을 계산하는 부분입니다.

객체 이미지 픽셀과 Canvas영역에서 객체 영역만큼 잘라온 픽셀을 통해 계산해 보았는데

수정이 필요한 부분이네요. -_-;; 아니면 다른 방식으로 객체 영역만을 가져와야 하겠습니다.

하나의 픽셀은 4가지의 값을 (B,G,R,A) 가지고 있기 때문에 객체 브러쉬를 통해 비트맵으로 변환하게 되면 객체가 아닌

부분은 알파값이 제로이기 때문에 이를 사용해 봤지만 에러가 좀 있네요. ㅎㅎ

  142 private static void PixelTransform(byte[] pixels, byte[] element_pixels, int length)

  143 {

  144    for(int i=3; i<length; i+=4)

  145    {

  146        if (element_pixels[i] == 0)

  147        {

  148            pixels[i] = 0;

  149        }

  150        else

  151        {

  152            if (pixels[i] > element_pixels[i])

  153            {

  154                pixels[i] = element_pixels[i];

  155                pixels[i - 1] = element_pixels[i - 1];

  156                pixels[i - 2] = element_pixels[i - 2];

  157                pixels[i - 3] = element_pixels[i - 3];

  158            }

  159        }

  160    }

  161 }

 

Save함수는 포맷에 맞게 인코딩 후 저장합니다.

   169 public static void Save(BitmapSource source, bool png)

  170 {

  171     SaveFileDialog dlg = new SaveFileDialog();

  172 

  173     dlg.Filter = "PNG|*.png|JPG|*.jpg|GIF|*.gif|BMP|*.bmp";

  174     dlg.AddExtension = true;

  175 

  176     if (dlg.ShowDialog() == true)

  177     {

  178         FileStream stream = new FileStream(dlg.FileName, FileMode.Create, FileAccess.Write);

  179         BitmapEncoder encoder = new PngBitmapEncoder();

  180 

  181         dlg.FileName.ToCharArray(dlg.FileName.Length - 3, 3);

  182 

  183         string upper = dlg.FileName.ToUpper();

  184         char[] format = upper.ToCharArray(dlg.FileName.Length - 3, 3);

  185         upper = new string(format);

  186 

  187         if (!png)

  188         {

  189             switch (upper.ToString())

  190             {

  191                 case "JPG":

  192                     encoder = new JpegBitmapEncoder();

  193                     break;

  194 

  195                 case "GIF":

  196                     encoder = new GifBitmapEncoder();

  197                     break;

  198 

  199                 case "BMP":

  200                     encoder = new BmpBitmapEncoder();

  201                     break;

  202             }

  203         }

  204 

  205         encoder.Frames.Add(BitmapFrame.Create(source));

  206 

  207         encoder.Save(stream);

  208         stream.Close();

  209     }

  210 }

 

'Window > WPF' 카테고리의 다른 글

[ WPF ] TextBox Select All Text  (0) 2010.02.11
[ WPF ] Window 사이즈 변경 시 컨트롤 크기 변경하기  (3) 2010.02.08
[WPF] 시계 만들기  (0) 2010.01.26
[WPF] Image Pixel  (0) 2010.01.24
[WPF] Drag, Scale, Rotate  (1) 2010.01.24
Posted by 열ㅇl