выбор пикселя для PanZoomImage - PullRequest
       7

выбор пикселя для PanZoomImage

1 голос
/ 20 февраля 2012

Я новичок в WPF и пытаюсь написать кликабельный элемент управления масштабированием. У меня уже есть изображение с зум-панорамированием, которое, кажется, работает:

<Border Name="border" ClipToBounds="True">
    <Canvas>
        <Image Name ="image"> 
               Source="{Binding Path=Source}"
               MouseLeftButtonDown="image_MouseLeftButtonDown"
               MouseLeftButtonUp="image_MouseLeftButtonUp"
               MouseMove="image_MouseMove"
               MouseWheel="image_MouseWheel">
        </Image>
    </Canvas>
</Border>

Для событий мыши и колеса я использовал этот пост: http://www.codeproject.com/Articles/168176/Zooming-and-panning-in-WPF-with-fixed-focus

Я пишу интерактивный элемент управления, наследуя его от ZoomPanImage и добавляя событие для LeftMouseUp.

public class ClickableImage : PanZoomImage
{
    public event Action<Point> Click;

    //...
    protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
    {
        base.OnMouseLeftButtonUp(e);
         // ... all sorts of checks to distinguish click from mouse move
        if (Click != null)
        {
           Click(ControlToImage(mouseUpCoordinates));
        }
    }

    protected Point ControlToImage(Point controlPixel)
    {
        //this is where i am stuck...       
    }
}

Моя проблема в том, что я не могу рассчитать правильные координаты изображения с учетом контрольных координат. Мне нужно принять во внимание, что изображение можно увеличивать и панорамировать, а размер самого окна можно изменять.

Я пытался использовать преобразование рендеринга. Когда я масштабирую и панорамирую изображение, я обновляю преобразование. И когда я пытаюсь преобразовать контрольные координаты в координаты изображения, я использую обратное преобразование:

Point imagePixel = image.RenderTransform.Inverse.Transform(controlPixel);

Но это не сработало. Одна из проблем заключается в том, что преобразование начинается с идентичности, тогда как на самом деле изображение растягивается равномерно до размера элемента управления.

Спасибо, Dina

1 Ответ

1 голос
/ 10 июля 2013

Вот как я это решил. Как предложил Клеменс, я установил режим растягивания изображения на none.

<Image Name="image" RenderOptions.BitmapScalingMode="NearestNeighbor" Stretch="None" 
                   Source="{Binding Path=Source}"
                   MouseLeftButtonDown="image_MouseLeftButtonDown"
                   MouseLeftButtonUp="image_MouseLeftButtonUp"
                   MouseMove="image_MouseMove"
                   MouseWheel="image_MouseWheel"
                   Loaded="image_Loaded">
                    <Image.ContextMenu>
                        <ContextMenu>
                            <MenuItem Header="Fit to window" Click="FitToWindow_MenuItem_Click"></MenuItem>
                        </ContextMenu>
                    </Image.ContextMenu>
                </Image>

Это означает, что когда изображение загружается в окно, вы можете видеть только его часть - в зависимости от размера окна. Это плохо, но важно то, что преобразование является тождественным, и теперь вы можете вручную установить его так, чтобы изображение полностью отображалось в окне.

private void FitViewToWindow()
{
    if (Source == null)
        throw new InvalidOperationException("Source not set");

    BitmapSource bitmapSource = Source as BitmapSource;
    if (bitmapSource == null)
        throw new InvalidOperationException("Unsupported Image Source Type");

    if (border.ActualWidth <= 0 || border.ActualHeight <= 0)
       return;

    double scaleX = border.ActualWidth / bitmapSource.PixelWidth;
    double scaleY = border.ActualHeight / bitmapSource.PixelHeight;
    double scale = Math.Min(scaleX, scaleY);

    Matrix m = Matrix.Identity;
    m.ScaleAtPrepend(scale, scale, 0, 0);

    double centerX = (border.ActualWidth - bitmapSource.PixelWidth * scale) / 2;
    double centerY = (border.ActualHeight - bitmapSource.PixelHeight * scale) / 2;
    m.Translate(centerX, centerY);

    image.RenderTransform = new MatrixTransform(m);
}

Эта функция должна вызываться при загрузке изображения и при изменении источника изображения. Что касается изменения размера окна - пока вы отслеживаете преобразование, вы сможете правильно преобразовывать системы координат. Например, вот что я делаю для изменения размера окна:

protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
{
    base.OnRenderSizeChanged(sizeInfo);

    //center the image in the new size

    if (sizeInfo.PreviousSize.Width <= 0 || sizeInfo.PreviousSize.Height <= 0)
        return;

    Matrix m = image.RenderTransform.Value;

    double offsetX = (sizeInfo.NewSize.Width - sizeInfo.PreviousSize.Width) / 2;
    double offsetY = (sizeInfo.NewSize.Height - sizeInfo.PreviousSize.Height) / 2;

    m.Translate(offsetX, offsetY);
    image.RenderTransform = new MatrixTransform(m);
}
...