我试图在Adobe Premiere中像这样创建时间比例尺: 但是,我必须下降到0.01秒的增量。当图像超过40,000宽时,渲染图像失败
我的时间轴控制的样子:
UPDATE: 我用@Sten彼得罗夫的建议,并使用了VisualBrush
。
但现在我被困在如何实现秒为Label
。
我的新代码(含控制可以改变):
<Window x:Class="WpfApplication3.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="680.839">
<Grid Background="Black">
<ScrollViewer VerticalScrollBarVisibility="Disabled" HorizontalScrollBarVisibility="Visible" >
<ScrollViewer.ContentTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<Grid SnapsToDevicePixels="False" UseLayoutRounding="True">
<Grid.Background>
<VisualBrush TileMode="Tile" Viewport="0,0,5,30" ViewportUnits="Absolute" Viewbox="0,0,5,30" ViewboxUnits="Absolute">
<VisualBrush.Visual>
<Line Stroke="Coral" StrokeThickness="2" X1="0" X2="0" Y1="25" Y2="30" UseLayoutRounding="True" />
</VisualBrush.Visual>
</VisualBrush>
</Grid.Background>
</Grid>
<Grid Margin="50,0,0,0" SnapsToDevicePixels="False" UseLayoutRounding="True">
<Grid.Background>
<VisualBrush TileMode="Tile" Viewport="0,0,50,30" ViewportUnits="Absolute" Viewbox="0,0,50,30" ViewboxUnits="Absolute">
<VisualBrush.Visual>
<Line Stroke="Red" StrokeThickness="2" X1="0" X2="0" Y1="20" Y2="30" UseLayoutRounding="True" />
</VisualBrush.Visual>
</VisualBrush>
</Grid.Background>
</Grid>
<Grid SnapsToDevicePixels="False" Height="30" UseLayoutRounding="True" >
<Grid.Background>
<VisualBrush TileMode="Tile" Viewport="0,0,500,30" ViewportUnits="Absolute" Viewbox="0,0,500,30" ViewboxUnits="Absolute">
<VisualBrush.Visual>
<Grid HorizontalAlignment="Left" Width="500" UseLayoutRounding="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="21*"/>
<ColumnDefinition Width="25*"/>
<ColumnDefinition Width="25*"/>
<ColumnDefinition Width="25*"/>
<ColumnDefinition Width="25*"/>
<ColumnDefinition Width="25*"/>
<ColumnDefinition Width="25*"/>
<ColumnDefinition Width="25*"/>
<ColumnDefinition Width="25*"/>
<ColumnDefinition Width="20*"/>
<ColumnDefinition Width="9*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="15"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<Label Grid.Row="0" FontFamily="Tahoma" FontSize="8" Padding="0" VerticalAlignment="Bottom" Grid.Column="1" Height="9" Content=".100" Foreground="White"/>
<Label Grid.Row="0" FontFamily="Tahoma" FontSize="8" Padding="0" VerticalAlignment="Bottom" Grid.Column="2" Height="9" Content=".200" Foreground="White"/>
<Label Grid.Row="0" FontFamily="Tahoma" FontSize="8" Padding="0" VerticalAlignment="Bottom" Grid.Column="3" Height="9" Content=".300" Foreground="White"/>
<Label Grid.Row="0" FontFamily="Tahoma" FontSize="8" Padding="0" VerticalAlignment="Bottom" Grid.Column="4" Height="9" Content=".400" Foreground="White"/>
<Label Grid.Row="0" FontFamily="Tahoma" FontSize="8" Padding="0" VerticalAlignment="Bottom" Grid.Column="5" Height="9" Content=".500" Foreground="White"/>
<Label Grid.Row="0" FontFamily="Tahoma" FontSize="8" Padding="0" VerticalAlignment="Bottom" Grid.Column="6" Height="9" Content=".600" Foreground="White"/>
<Label Grid.Row="0" FontFamily="Tahoma" FontSize="8" Padding="0" VerticalAlignment="Bottom" Grid.Column="7" Height="9" Content=".700" Foreground="White"/>
<Label Grid.Row="0" FontFamily="Tahoma" FontSize="8" Padding="0" VerticalAlignment="Bottom" Grid.Column="8" Height="9" Content=".800" Foreground="White"/>
<Label Grid.Row="0" FontFamily="Tahoma" FontSize="8" Padding="0" VerticalAlignment="Bottom" Grid.Column="9" Height="9" Content=".900" Foreground="White"/>
</Grid>
</VisualBrush.Visual>
</VisualBrush>
</Grid.Background>
</Grid>
<Grid SnapsToDevicePixels="False" Height="30" UseLayoutRounding="True" Margin="500,0,0,0" >
<Grid.Background>
<VisualBrush TileMode="Tile" Viewport="0,0,500,30" ViewportUnits="Absolute" Viewbox="0,0,500,30" ViewboxUnits="Absolute">
<VisualBrush.Visual>
<Line Stroke="Blue" StrokeThickness="2" X1="0" X2="0" Y1="10" Y2="30" UseLayoutRounding="True" />
</VisualBrush.Visual>
</VisualBrush>
</Grid.Background>
</Grid>
<Grid SnapsToDevicePixels="False" Height="30" UseLayoutRounding="True" Margin="491,0,0,0" >
<Grid.RowDefinitions>
<RowDefinition Height="7"/>
<RowDefinition Height="23"/>
</Grid.RowDefinitions>
<!--Need something here-->
<Label Grid.Row="0" FontFamily="Tahoma" FontSize="8" Padding="0" VerticalAlignment="Bottom" Grid.Column="0" Height="9" Content="00:00" Foreground="White"/>
</Grid>
</Grid>
</DataTemplate>
</ScrollViewer.ContentTemplate>
</ScrollViewer>
</Grid>
/UPDATE
我去每行0.01秒,所以10分钟的时间线我期待绘制60000行+ 6000个标签。在Canvas
10000's+ UI elements, bind or draw?
本来我是画线直接:
我问了一个问题,之前在这之前。 然后我去使用VisualHost
,因为它应该是较轻的重量。
那么它不够轻。
我有一个MediaElement
播放视频和时间轴滚动与视频位置同步。 A ScrollViewer
包装我的时间轴,并且每10ms做.ScrollToHorizontalOffset
。
如果我的时间轴结束了3分钟的视频快门。 我认为这是因为VisualHost
仍然具有所有框架元素,并且滚动导致它们被重新验证。
所以现在我试图产生一个Image
显示,我认为应该更轻。
我在这个假设中错了吗?
现在我正面临着将时间线变成Image
的问题。
我无法将整个时间线渲染成图像,所以我'拼凑'它。我正在打Exceptions
关于图像大小。
对我的代码: 这是我的主要切入点。
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;
}
这里是创建DrawingVisual's
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段代码:
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();
}
}
我所有的PNG段在其单独的文件中正确呈现。 我的时间轴被正确渲染,直到我超过1:20然后事情中断。
请参见:
这就像图像被弄脏或东西。 任何人都知道这是怎么回事?
感谢
“我在这个假设中错了吗?”是。 “它不够轻。”为什么它不够轻?也许你应该考虑虚拟化,只绘制可见的东西而不是一切。不知道你以前是怎么做的,我们无法修复它。但图像的东西绝对不是轻量级的。 – 2013-03-20 21:05:10
我以前使用过'VisualHost',generateHeaderVisualChunks就是我会用的,但没有分块。 它不够轻,因为'VisualHost'会导致我的视频跳过。我的ScrollViewer将当前视频位置保持在ScrollViewer的中心位置,因此ScrollViewer每滚动约10ms。 – jpiccolo 2013-03-20 22:07:07
我在generateHeaderVisualChunks中注意到的一件事是,你的笔,画笔和字体应该在函数之外创建,也许是静态的,不需要通过创建新的对GC施加压力,它们不会改变。我还想知道是否可以在视觉中生成比视觉更大的内容,允许scrollviewer移动它,检测何时接近结束,然后再生成。换句话说,把它分解成更大的块,这样你就不会像往常那样做繁重的工作。 – 2013-03-20 22:54:24