【问题标题】:custom drawing portion of image .net 4.5图像 .net 4.5 的自定义绘图部分
【发布时间】:2012-11-30 23:01:56
【问题描述】:

我在屏幕上自定义绘制了两个放大图像,一个并排。他们每个人都占据了屏幕的一半。

我之前在 .net 3.5(我认为)中通过覆盖 OnPaint() 完成了它:

    //using System.Drawing

    /// <summary>
    /// Custom drawing
    /// </summary>
    /// <param name="e"></param>
    protected override void OnPaint(PaintEventArgs e)
    {
        e.Graphics.DrawImage(Image, DestRectangle, SrcRectangle, GraphicsUnit);
    }

DrawImage方法的描述:“在指定位置以指定大小绘制指定Image的指定部分。” (MSDN)

我正在尝试使用 .net 4.5 来实现相同的目标。我正在覆盖 OnRender 并使用 DrawingContext 对象来执行我的绘图。基本上这是我的循环:

    //using System.Windows.Media;

    /// <summary>
    /// Overide the OnRender to have access to a lower level of drawing.
    /// </summary>
    /// <param name="drawingContext"></param>
    protected override void OnRender(DrawingContext drawingContext)
    {
        drawingContext.DrawImage(BitmapImage_Left, Window_LeftHalf);
        drawingContext.DrawImage(BitmapImage_Right, Window_RightHalf);
    }

如果我想显示拉伸的图片,它工作得很好。我想要的是显示(在 Window_LeftHalf 和 Window_RightHalf 中)图片的一部分(如放大)。基本上是 graphics.DrawImage(见上图)所做的,但使用的是 DrawingContext 对象。

我曾尝试查看 MSDN,但找不到任何有趣的内容。也许创建一个稍后由 DrawingContext 使用的缓冲区?我几乎可以肯定需要一个中间对象来保存放大的图像。有什么想法吗?

更新:我使用鼠标浏览图像,所以性能很重要。例如:

    /// <summary>
    /// Handles the mouse move events.
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private static void MouseMoveEventHandler(RoutedEventArgs e)
    {
        // The size of the crop is always the same
        // but the portion of the picture different.
        crop.X += mouseDelta.X;
        crop.Y += mouseDelta.Y;
    }

【问题讨论】:

    标签: c# .net-3.5 drawing .net-4.5 system.windows.media


    【解决方案1】:

    看看CroppedBitmap 类。就像您过去可以使用 e.Graphics.DrawImage() 一样,CroppedBitmap 允许您仅指定您感兴趣的图像部分。

    这是一个例子:

    protected override void OnRender(System.Windows.Media.DrawingContext dc)
    {
        int halfWidth = (int)this.Width / 2;
        int height = (int)this.Height;
        BitmapImage leftImage = new BitmapImage(new Uri(@"C:\Users\Public\Pictures\Sample Pictures\Chrysanthemum.jpg"));
        BitmapImage rightImage = new BitmapImage(new Uri(@"C:\Users\Public\Pictures\Sample Pictures\Desert.jpg"));
        CroppedBitmap leftImageCropped = new CroppedBitmap(leftImage, new Int32Rect(0, 0, halfWidth, height));
        CroppedBitmap rightImageCropped = new CroppedBitmap(rightImage, new Int32Rect(0, 0, halfWidth, height));
        dc.DrawImage(leftImageCropped, new System.Windows.Rect(0, 0, leftImageCropped.Width, height));
        dc.DrawImage(rightImageCropped, new System.Windows.Rect(halfWidth, 0, halfWidth, height));
    }
    

    【讨论】:

    • 嘿 cokeman19,感谢您的回复。是的!我还没有尝试过,但它看起来就像我想要的东西。唯一的区别是,每次我需要图像的新部分时,我都需要创建/修改 CroppedBitmap 对象,其中e.Graphics.DrawImage() 将始终使用相同的位图。无论如何,谢谢,我会用它。我会将我的帖子更新为更具体的问题。
    【解决方案2】:

    编辑 2ImageBrush.Viewbox。 Viewbox 是一个Rect,尺寸为 [0.0...1.0],可让您控制原来的 SourceRect。我对此进行了测试,效果很好。我做了什么:

    在我的窗口中:

        protected ImageBrush imgBrush = new ImageBrush(new ImageSource(new Uri("image.png")));
        protected Rect vBox = new Rect(0, 0, 1, 1);
        protected Point lastPosition = new Point(0, 0);
    

    我的容器是一个名为 tgtRect 的 WPF 矩形,其 Rect.FillimgBrush。缩放和滚动方法如下:

        protected void tgtRect_MouseWheel(object sender, MouseWheelEventArgs e)
        {
            // Zoom in when Delta is positive, Zoom out when negative
            double exp = -e.Delta / Math.Abs(e.Delta);
            double val = Math.Pow(1.1, exp);
            vBox.Scale(val, val);
            imgBrush.Viewbox = vBox;
        }
    
        void tgtRect_MouseMove(object sender, MouseEventArgs e)
        {
            Point thisPosition = e.GetPosition(tgtRect);
            if (e.RightButton == MouseButtonState.Pressed)
            {
                double w = tgtRect.ActualWidth;
                double h = tgtRect.ActualHeight;
                Vector offset = lastPosition - thisPosition;
                offset.X /= w;
                offset.Y /= h;
                vBox.Offset(offset);
                imgBrush.Viewbox = vBox;
            }
            lastPosition = thisPosition;
        }
    

    对于您的实施:

        protected override void OnRender(DrawingContext drawingContext)
        {
            drawingContext.DrawRectangle(imgBrush, null, DesRect);
        }
    

    您可能需要为每个要绘制的矩形维护一个单独的 imgBrush。我在 WPF 窗口中尝试了上面的代码(不是 OnRender 覆盖),只有一个矩形,其Rectangle.Fill 是这个ImageBrush,性能非常好。如果您有任何问题,我认为我们可以解决,但我认为 ImageBrush 最终会成为正确的实现。这是一个非常有趣的项目!谢谢你的提问。

    结束编辑 2

    您需要将Rect 对象“Window_LeftHalf”和“Window_RightHalf”定义为您希望渲染图像的实际大小。例如,如果您缩放 200%,则 Rect.WidthRect.Height 属性需要是原始 ImageSource 的 2 倍。

    编辑

    旧方法是:

    protected override void OnPaint(PaintEventArgs e)
    {
        e.Graphics.DrawImage(Image, DestRectangle, SrcRectangle, GraphicsUnit);
    }
    

    使用 'BitmapImage.SourceRect` :

    protected override void OnRender(DrawingContext drawingContext)
    {
        BitmapImage_Left.SourceRect = SrcRectangleLeft;
        drawingContext.DrawImage(BitmapImage_Left, Window_LeftHalf);
        BitmapImage_Right.SourceRect = SrcRectangleRight;
        drawingContext.DrawImage(BitmapImage_Right, Window_RightHalf);
    }
    

    您的鼠标功能可以更改 SourceRect。例如:

    private static void MouseMoveEventHandler(RoutedEventArgs e)
    {
        // The size of the crop is always the same
        // but the portion of the picture different.
        SrcRectangleLeft = new Int32Rect(SrcRectangleLeft.X + mouseDelta.X, 
            SrcRectangleLeft.Y + mouseDelta.Y,
            SrcRectangleLeft.Width, SrcRectangleLeft.Height);
    }
    

    不确定性能如何,但应该比每次更新都将位图的一部分映射到新对象上要好。

    希望这对您有所帮助。

    【讨论】:

    • 嘿新手,感谢您的回复。我以前试过。如果我这样做,图像将重叠。即使我将它们显示在正确的位置,Window_Half 也不会显示图像的*特定部分(缩放)。
    • 如果您不重新定位目标矩形,那将是有意义的。我正在重新阅读这篇文章并想象窗口的每一半的并排滚动窗口。对吗?
    • 是的,并排,固定“窗口”。但内容总是在变化。所以如果我显示 200% 我只能有一个固定的内容(在 x 轴上)。
    • 好的。我想我可能有另一种解决方案。如果您的 BitmapImage_Left 和 BitmapImage_Right 确实是 BitmapImage 对象,您可以根据位置和缩放设置它们的 BitmapImage.SourceRect 属性。我会用一个例子来编辑原始答案。
    • 如果 SourceRect 是要考虑的图像区域,那么我认为这就是答案。我不知道我是怎么完全错过的。我还没有检查过,但如果它不起作用,我肯定会回到这里。谢谢!
    猜你喜欢
    • 1970-01-01
    • 2018-08-12
    • 1970-01-01
    • 2023-03-19
    • 1970-01-01
    • 1970-01-01
    • 2011-12-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多