Здравствуйте, 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.