C# 当图像宽度超过40000时,渲染图像失败
我正在尝试创建一个类似于Adobe Premiere的时间刻度,如下所示: 但是,我必须降到0.01秒的增量 我的时间线控件看起来像: 更新: 我使用了@Sten Petrov建议,并使用了C# 当图像宽度超过40000时,渲染图像失败,c#,wpf,image,bitmap,png,C#,Wpf,Image,Bitmap,Png,我正在尝试创建一个类似于Adobe Premiere的时间刻度,如下所示: 但是,我必须降到0.01秒的增量 我的时间线控件看起来像: 更新: 我使用了@Sten Petrov建议,并使用了可视化画笔 但是现在我被困在如何实现标签的问题上 我的新代码(包含可以更改的控件): 下面是创建DrawingVisual的 private List<DrawingVisual> generateHeaderVisualChunks(int width, int chunkSize, Time
可视化画笔
但是现在我被困在如何实现标签的问题上
我的新代码(包含可以更改的控件):
下面是创建DrawingVisual的
private List<DrawingVisual> generateHeaderVisualChunks(int width, int chunkSize, TimelineViewModel.ViewLevel level)
{
var ret = new List<DrawingVisual>();
var currentTime = new TimeSpan(0, 0, 0, 0, 0);
var timeStep = new TimeSpan(0, 0, 0, 0, (int)level);
var currentLine = 0;
const double DistanceBetweenLines = 5;
const int TenthOfSecondLine = 10;
const int SecondLine = 100;
int iterations = (width / chunkSize);
int remainder = width % chunkSize; //not doing anything with yet
var grayBrush = new SolidColorBrush(Color.FromRgb(192, 192, 192));
var grayPen = new Pen(grayBrush, 2);
var whitePen = new Pen(Brushes.Purple, 2);
grayBrush.Freeze();
grayPen.Freeze();
whitePen.Freeze();
for (int i = 0; i < iterations; i++)
{
var visual = new DrawingVisual();
using (var dc = visual.RenderOpen())
{
double currentX = 0;
if (i > 0)
{
currentLine--;
currentTime -= timeStep;
}
while (currentX <= chunkSize)
{
if (((currentLine % SecondLine) == 0) && currentLine != 0)
{
dc.DrawLine(whitePen, new Point(currentX, 30), new Point(currentX, 15));
FormattedText text = null;
double tempX = currentX;
switch (level)
{
case TimelineViewModel.ViewLevel.Level1:
text = new FormattedText(
currentTime.ToString(@"hh\:mm\:ss\.fff"),
CultureInfo.CurrentCulture,
FlowDirection.LeftToRight,
new Typeface("Tahoma"),
8,
grayBrush);
break;
}
dc.DrawText(text, new Point((tempX - 22), 0));
}
else if ((((currentLine % TenthOfSecondLine) == 0) && currentLine != 0)
&& (currentLine % SecondLine) != 0)
{
dc.DrawLine(grayPen, new Point(currentX, 30), new Point(currentX, 20));
FormattedText text = null;
switch (level)
{
case TimelineViewModel.ViewLevel.Level1:
text = new FormattedText(
string.Format(".{0}", currentTime.Milliseconds),
CultureInfo.CurrentCulture,
FlowDirection.LeftToRight,
new Typeface("Tahoma"),
8,
grayBrush);
break;
}
dc.DrawText(text, new Point((currentX - 8), 8));
}
else
{
dc.DrawLine(grayPen, new Point(currentX, 30), new Point(currentX, 25));
}
currentX += DistanceBetweenLines;
currentLine++;
currentTime += timeStep;
}
}
ret.Add(visual);
}
return ret;
}
我的所有png片段都在各自的文件中正确呈现。
我的时间轴被正确渲染,直到我超过1:20,然后事情就破裂了
见:
就像图像被弄脏了一样。
有人知道这是怎么回事吗
谢谢我在等有一天我的客厅会有一台水平分辨率的电视,这需要像你这样的方法
放弃你刚才演示的这整段代码,它永远不会变得可用和可维护,你只能设法从中挤出一段
然后了解,有很多教程,它可以重复您的视觉模板,不需要PNG,并且在屏幕分辨率改变时(高达40001px宽)可以更好地扩展
对于出现在标记上方的数字,有一百万种不同的方法,其中一些方法可以与上面提到的可视笔刷组合,例如表示时间线单位(两个较大标记之间的空间)的用户控件。现在,将其中几个放置在网格中(stackpanel、canvas…如您所愿),并(动态地)调整它们的偏移量和标签-突然之间,您可以在屏幕上用10个控件表示无限时间线。“我的假设错了吗?”是的。“嗯,它不够轻。”为什么不够轻?也许您应该考虑虚拟化,只绘制可见的内容,而不是所有内容。不知道你以前是怎么做的,我们无法修复它。但是图像这件事绝对不是轻量级的。我以前使用过一个VisualHost
,我会使用generateHeadServiceSualChunks,但不会对它进行分块。它不够亮,因为VisualHost
会导致我的视频跳过。我的ScrollViewer
将当前视频位置保持在ScrollViewer
的中心位置,因此ScrollViewer
每10毫秒滚动一次。我注意到在GenerateHeadServicesHunk中,您的笔、画笔和字体应该在函数之外创建,可能是静态的,不需要通过创建新的GC来给GC施加压力,它们不会改变。我还想知道你是否可以在你的视觉中生成一个比可见的更大的图像,允许scrollviewer移动它,在接近尾声时检测,然后重新生成。换句话说,把它分成更大的块,这样你就不会经常做繁重的工作。即使是Jumbotron也有40000像素的宽度吗?你为什么要在每个像素中压缩这么多信息?猜猜Pieter的意思是,不管你的时间轴分辨率如何,平均屏幕最多只能显示2000个像素。您需要生成可见部分,而不是整个时间线。
public void RenderHeaderPicture()
{
const int ChunkSize = 5000;
var bitmapFrames = new List<BitmapFrame>();
// generates X number of DrawingVisual's based on ChunkSize
List<DrawingVisual> visuals = generateHeaderVisualChunks(
AppViewModel.TimelineViewModel.HeaderWidth, ChunkSize, TimelineViewModel.ViewLevel.Level1);
for (var i = 0; i < visuals.Count; i++)
{
var renderTargetBitmap = new RenderTargetBitmap(ChunkSize, 30, 96, 96, PixelFormats.Pbgra32);
renderTargetBitmap.Render(visuals[i]);
//test to make sure image good
saveHeaderSegmentAsPng(string.Format("headerSeg{0}.png", i), renderTargetBitmap);
bitmapFrames.Add(BitmapFrame.Create(renderTargetBitmap));
}
// put the frames back together now
var drawingVisual = new DrawingVisual();
using (var drawingContext = drawingVisual.RenderOpen())
{
for (int i = 0; i < bitmapFrames.Count; i++)
{
drawingContext.DrawImage(bitmapFrames[i], new Rect(i * ChunkSize, 0, bitmapFrames[i].PixelWidth, 30));
}
drawingContext.Close();
}
var newBmp = new RenderTargetBitmap(AppViewModel.TimelineViewModel.HeaderWidth, 30, 96, 96, PixelFormats.Pbgra32);
newBmp.Render(drawingVisual);
AppViewModel.TimelineViewModel.HeaderImageSource = newBmp;
}
private List<DrawingVisual> generateHeaderVisualChunks(int width, int chunkSize, TimelineViewModel.ViewLevel level)
{
var ret = new List<DrawingVisual>();
var currentTime = new TimeSpan(0, 0, 0, 0, 0);
var timeStep = new TimeSpan(0, 0, 0, 0, (int)level);
var currentLine = 0;
const double DistanceBetweenLines = 5;
const int TenthOfSecondLine = 10;
const int SecondLine = 100;
int iterations = (width / chunkSize);
int remainder = width % chunkSize; //not doing anything with yet
var grayBrush = new SolidColorBrush(Color.FromRgb(192, 192, 192));
var grayPen = new Pen(grayBrush, 2);
var whitePen = new Pen(Brushes.Purple, 2);
grayBrush.Freeze();
grayPen.Freeze();
whitePen.Freeze();
for (int i = 0; i < iterations; i++)
{
var visual = new DrawingVisual();
using (var dc = visual.RenderOpen())
{
double currentX = 0;
if (i > 0)
{
currentLine--;
currentTime -= timeStep;
}
while (currentX <= chunkSize)
{
if (((currentLine % SecondLine) == 0) && currentLine != 0)
{
dc.DrawLine(whitePen, new Point(currentX, 30), new Point(currentX, 15));
FormattedText text = null;
double tempX = currentX;
switch (level)
{
case TimelineViewModel.ViewLevel.Level1:
text = new FormattedText(
currentTime.ToString(@"hh\:mm\:ss\.fff"),
CultureInfo.CurrentCulture,
FlowDirection.LeftToRight,
new Typeface("Tahoma"),
8,
grayBrush);
break;
}
dc.DrawText(text, new Point((tempX - 22), 0));
}
else if ((((currentLine % TenthOfSecondLine) == 0) && currentLine != 0)
&& (currentLine % SecondLine) != 0)
{
dc.DrawLine(grayPen, new Point(currentX, 30), new Point(currentX, 20));
FormattedText text = null;
switch (level)
{
case TimelineViewModel.ViewLevel.Level1:
text = new FormattedText(
string.Format(".{0}", currentTime.Milliseconds),
CultureInfo.CurrentCulture,
FlowDirection.LeftToRight,
new Typeface("Tahoma"),
8,
grayBrush);
break;
}
dc.DrawText(text, new Point((currentX - 8), 8));
}
else
{
dc.DrawLine(grayPen, new Point(currentX, 30), new Point(currentX, 25));
}
currentX += DistanceBetweenLines;
currentLine++;
currentTime += timeStep;
}
}
ret.Add(visual);
}
return ret;
}
private static void saveHeaderSegmentAsPng(string fileName, RenderTargetBitmap renderTargetBitmap)
{
var pngBitmapEncoder = new PngBitmapEncoder();
pngBitmapEncoder.Frames.Add(BitmapFrame.Create(renderTargetBitmap));
using (var fileStream = new FileStream(fileName, FileMode.Create))
{
pngBitmapEncoder.Save(fileStream);
fileStream.Flush();
fileStream.Close();
}
}