You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WPF绘制旋转视频画面无法填充目标矩形的问题

问题:WPF视频旋转后无法完全填充目标Rect

我编写了一段在WPF中从视频绘制画面并进行旋转的代码,期望旋转后的画面能够完全填充目标rect,但旋转后画面仅垂直拉伸,未实现水平方向的拉伸;未旋转时画面可正常进行垂直和水平拉伸填充。请问该如何解决?

代码示例

int rotation = image.RotationAngle;

MediaPlayer mediaPlayer = new MediaPlayer();
var drawingVisual = new DrawingVisual();
Stopwatch sw = new Stopwatch();
mediaPlayer.ScrubbingEnabled = true;
mediaPlayer.Open(new Uri(image.Key));
mediaPlayer.MediaFailed += (sender, e) => OnMediaFailed(sender, e, dc, image, ref rect);
sw.Start();
while (!(mediaPlayer.NaturalVideoWidth > 0 && !image.IsVideoProcessingError))
{
    if (sw.ElapsedMilliseconds > 3000)
    {
        image.IsVideoProcessingError = true;
        break;
    }
    System.Threading.Thread.Sleep(100);
}

var duration = mediaPlayer.NaturalDuration.TimeSpan.Ticks;
mediaPlayer.Position = new TimeSpan(Convert.ToInt64(duration / 5));

var renderTargetBitmap = new RenderTargetBitmap(mediaPlayer.NaturalVideoWidth, mediaPlayer.NaturalVideoHeight, 96, 96, PixelFormats.Default);

using (var drawingContext = drawingVisual.RenderOpen())
{
    var rotateTransform = new RotateTransform(rotation, mediaPlayer.NaturalVideoWidth / 2, mediaPlayer.NaturalVideoHeight / 2);
    drawingContext.PushTransform(rotateTransform);
    drawingContext.DrawVideo(mediaPlayer, new Rect(0, 0, mediaPlayer.NaturalVideoWidth, mediaPlayer.NaturalVideoHeight));
}

renderTargetBitmap.Render(drawingVisual);

var pixels = new uint[mediaPlayer.NaturalVideoWidth * mediaPlayer.NaturalVideoHeight];

renderTargetBitmap.CopyPixels(pixels, mediaPlayer.NaturalVideoWidth * 4, 0);

im.Image = renderTargetBitmap;

mediaPlayer.Close();
mediaPlayer = null;

_dc.DrawImage(im.Image, rect);

解决方案

问题核心是旋转后未考虑画面外接矩形的尺寸变化,直接用原始视频宽高渲染会裁剪有效内容,导致拉伸时无法填满目标区域。调整步骤如下:

  1. 计算旋转后的实际外接尺寸
    根据旋转角度计算视频旋转后的实际宽高(非直角旋转用三角函数,直角旋转直接交换宽高):

    double radians = rotation * Math.PI / 180;
    double rotatedWidth = Math.Abs(mediaPlayer.NaturalVideoWidth * Math.Cos(radians)) + Math.Abs(mediaPlayer.NaturalVideoHeight * Math.Sin(radians));
    double rotatedHeight = Math.Abs(mediaPlayer.NaturalVideoHeight * Math.Cos(radians)) + Math.Abs(mediaPlayer.NaturalVideoWidth * Math.Sin(radians));
    
  2. 创建匹配尺寸的RenderTargetBitmap
    将渲染位图的宽高改为旋转后的计算值:

    var renderTargetBitmap = new RenderTargetBitmap((int)Math.Ceiling(rotatedWidth), (int)Math.Ceiling(rotatedHeight), 96, 96, PixelFormats.Default);
    
  3. 调整绘制时的变换与位置
    以旋转后的画布中心为旋转点,同时平移视频让其居中显示在新画布上:

    using (var drawingContext = drawingVisual.RenderOpen())
    {
        var centerX = rotatedWidth / 2;
        var centerY = rotatedHeight / 2;
        var rotateTransform = new RotateTransform(rotation, centerX, centerY);
        // 平移让原始视频居中到旋转后的画布
        double translateX = centerX - mediaPlayer.NaturalVideoWidth / 2;
        double translateY = centerY - mediaPlayer.NaturalVideoHeight / 2;
        var translateTransform = new TranslateTransform(translateX, translateY);
        
        drawingContext.PushTransform(rotateTransform);
        drawingContext.PushTransform(translateTransform);
        
        drawingContext.DrawVideo(mediaPlayer, new Rect(0, 0, mediaPlayer.NaturalVideoWidth, mediaPlayer.NaturalVideoHeight));
        
        drawingContext.Pop();
        drawingContext.Pop();
    }
    
  4. 按比例填充目标Rect
    绘制到目标区域时,计算合适的缩放比例,确保画面按比例填充(可选择填充或包含模式):

    // 填充模式:按最大比例拉伸,超出部分裁剪
    double scaleX = rect.Width / rotatedWidth;
    double scaleY = rect.Height / rotatedHeight;
    double scale = Math.Max(scaleX, scaleY);
    
    double drawWidth = rotatedWidth * scale;
    double drawHeight = rotatedHeight * scale;
    double offsetX = rect.X + (rect.Width - drawWidth) / 2;
    double offsetY = rect.Y + (rect.Height - drawHeight) / 2;
    
    _dc.DrawImage(im.Image, new Rect(offsetX, offsetY, drawWidth, drawHeight));
    

调整后,旋转后的画面就能完整填充目标rect,不会出现方向拉伸不均的问题。

内容的提问来源于stack exchange,提问作者stef

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 23:52:09