Re: Рисование части изображения WPF
От: vit_as Россия  
Дата: 11.12.11 19:18
Оценка:
Здравствуйте, Shiho, Вы писали:

S>Имеется большое изображение и маленькое окно, позволяющее видеть только часть изображения.

S>Нужно в этом окне уметь рисовать необходимую часть. Также необходима возможность перемещать окно, соответственно видимая часть изображения изменяется.

S>Как это реализовать с помощью Windows Presentation Foundation?


Можно реализовать свой контрол для отображения больших картинок

    public class ImageDataViewer:Control
    {
        Image m_Image;
        Canvas m_Canvas;
        ScrollViewer m_ScrollViewer;
        ImageData m_Source;
        WriteableBitmap m_wb;
        static ImageDataViewer()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(ImageDataViewer), new FrameworkPropertyMetadata(typeof(ImageDataViewer)));
        }
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            m_Image = this.Template.FindName("PART_Image",this) as Image;
            m_Canvas = this.Template.FindName("PART_Canvas", this) as Canvas;
            m_ScrollViewer = this.Template.FindName("PART_ScrollViewer",this) as ScrollViewer;
            m_ScrollViewer.ScrollChanged += new ScrollChangedEventHandler(m_ScrollViewer_ScrollChanged);
        }

        void m_ScrollViewer_ScrollChanged(object sender, ScrollChangedEventArgs e)
        {
            Canvas.SetLeft(m_Image, e.HorizontalOffset);
            Canvas.SetTop(m_Image, e.VerticalOffset);
            m_Image.Width = e.ViewportWidth;
            m_Image.Height = e.ViewportHeight;
            updateSource();
        }
        public ImageData Source
        {
            get { return m_Source; }
            set 
            { 
                m_Source = value;
                updateSource();
            }
        }
        private void updateSource()
        {
            if (m_ScrollViewer == null)
                return;
            if (m_Source == null)
                return;
            m_Canvas.Width = m_Source.Width;
            m_Canvas.Height = m_Source.Height;
            int w = (int)m_ScrollViewer.ViewportWidth;
            int h = (int)m_ScrollViewer.ViewportHeight;
            int x0 = (int)m_ScrollViewer.HorizontalOffset;
            int y0 = (int)m_ScrollViewer.VerticalOffset;
            if (m_wb == null || m_wb.PixelWidth != w || m_wb.PixelHeight !=h)
            {
                m_wb = new WriteableBitmap(w, h, 96, 96, m_Source.Format, null);
                m_Image.Source = m_wb;
            }
            m_wb.Lock();
            IntPtr ptr = m_wb.BackBuffer;
            int stride = m_wb.BackBufferStride;
            int ch = stride/m_wb.PixelWidth;
            int srcStride = m_Source.Stride;
            for (int y = 0; y < h; y++)
            {
                Marshal.Copy(m_Source.Pixels, x0 * ch + srcStride * (y + y0), ptr, stride);
                ptr += stride ;
            }
            m_wb.AddDirtyRect(new Int32Rect(0, 0, w, h));
            m_wb.Unlock();
        }
    }

Для контрола определяем шаблон по умолчанию
<Style TargetType="{x:Type local:ImageDataViewer}">
        <Setter Property="Template" >
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:ImageDataViewer}">
                    <ScrollViewer Name="PART_ScrollViewer" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
                        <Canvas Name="PART_Canvas">
                            <Image Name="PART_Image"></Image>
                        </Canvas>
                    </ScrollViewer>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>


Картинку можно подсовывать как из памяти так и с диска или с любого другого Stream'a. Приведу простой пример реализации:


public class ImageData
    {
        public int Width;
        public int Height;
        public int BitsPerPixel;
        public byte[] Pixels;
        public PixelFormat Format;
        public int Stride
        {
            get{return ((((Width) * (BitsPerPixel) +31) & ~31) >> 3);}
        }
        ImageData(int width, int height, int bpp)
        {
            Width = width;
            Height = height;
            BitsPerPixel = bpp;
            Pixels = new byte[Stride * Height];
        }
        public static ImageData Load(string path)
        {
            BitmapImage img = new BitmapImage(new Uri(path));
            ImageData image = new ImageData(img.PixelWidth, img.PixelHeight, img.Format.BitsPerPixel);
            img.CopyPixels(image.Pixels, image.Stride, 0);
            image.Format = img.Format;
            return image;
        }
}

Остается только разместить в окне контрол ImageDataViewer и назначить ему свойство Source.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.