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);
解决方案
问题核心是旋转后未考虑画面外接矩形的尺寸变化,直接用原始视频宽高渲染会裁剪有效内容,导致拉伸时无法填满目标区域。调整步骤如下:
计算旋转后的实际外接尺寸
根据旋转角度计算视频旋转后的实际宽高(非直角旋转用三角函数,直角旋转直接交换宽高):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));创建匹配尺寸的RenderTargetBitmap
将渲染位图的宽高改为旋转后的计算值:var renderTargetBitmap = new RenderTargetBitmap((int)Math.Ceiling(rotatedWidth), (int)Math.Ceiling(rotatedHeight), 96, 96, PixelFormats.Default);调整绘制时的变换与位置
以旋转后的画布中心为旋转点,同时平移视频让其居中显示在新画布上: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(); }按比例填充目标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
相关产品推荐
相关产品推荐

