2013-03-20 88 views
2

我试图在Adobe Premiere中像这样创建时间比例尺: enter image description here 但是,我必须下降到0.01秒的增量。当图像超过40,000宽时,渲染图像失败

我的时间轴控制的样子: enter image description here

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个标签。在Canvas10000'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然后事情中断。

请参见: enter image description here

这就像图像被弄脏或东西。 任何人都知道这是怎么回事?

感谢

+0

“我在这个假设中错了吗?”是。 “它不够轻。”为什么它不够轻?也许你应该考虑虚拟化,只绘制可见的东西而不是一切。不知道你以前是怎么做的,我们无法修复它。但图像的东西绝对不是轻量级的。 – 2013-03-20 21:05:10

+0

我以前使用过'VisualHost',generateHeaderVisualChunks就是我会用的,但没有分块。 它不够轻,因为'VisualHost'会导致我的视​​频跳过。我的ScrollViewer将当前视频位置保持在ScrollViewer的中心位置,因此ScrollViewer每滚动约10ms。 – jpiccolo 2013-03-20 22:07:07

+0

我在generateHeaderVisualChunks中注意到的一件事是,你的笔,画笔和字体应该在函数之外创建,也许是静态的,不需要通过创建新的对GC施加压力,它们不会改变。我还想知道是否可以在视觉中生成比视觉更大的内容,允许scrollviewer移动它,检测何时接近结束,然后再生成。换句话说,把它分解成更大的块,这样你就不会像往常那样做繁重的工作。 – 2013-03-20 22:54:24

回答

3

我在等待这一天,当我住的房间将与水平分辨率,这将需要一些你的方法一台电视机。

将你刚才演示的代码全部废弃,它永远不会变得可用可维护,你只能设法挤出其中的一个。

然后了解VisualBrush,也有很多教程在那里,它可以重复你的视觉模板,无需PNG格式的,它会更好的规模时屏幕分辨率更改(可达40001px宽)

对于数字那些出现在标记上方的数百种不同的方法,其中一些可以与上面提到的视觉刷相结合,例如代表时间轴单位的用户控件(两个较大标记之间的空间)。现在将它们中的一些放置在网格中(堆叠面板,画布...如您所愿)并调整(动态)它们的偏移和标签 - 突然间,您可以用屏幕上的10个控件表示无限时间轴。