当图像超过40,000宽时,渲染图像失败

时间:2013-03-20 19:33:42

标签: c# wpf image bitmap png

我正在尝试创建像Adobe Premiere这样的时间刻度: enter image description here 但是,我必须降低到0.01秒的增量。

我的时间轴控制如下: enter image description here

更新 我使用了@Sten Petrov的建议并使用了VisualBrush

但是现在我被困在如何为Seconds实现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个标签。

之前我问了一个先前的问题:10000's+ UI elements, bind or draw?

最初我是在Canvas直接画线。 然后我开始使用VisualHost,因为它应该是更轻的重量。

嗯,它不够轻。

我有MediaElement播放视频,时间轴与视频位置同步滚动。 ScrollViewer包裹我的时间轴,大约每10毫秒.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

这就像是图像被涂抹了什么的。 有人知道这是怎么回事吗?

由于

1 个答案:

答案 0 :(得分:3)

我正在等待我的起居室将有一台水平分辨率需要像你的方法一样的电视的那一天。

废弃你在这里演示的整段代码,它永远不会变得可用可维护,你只能设法挤出其中的一个。

然后了解VisualBrush,有很多教程,它可以重复你的视觉模板,不需要PNG,当屏幕分辨率变化时,它会更好地扩展(最大40001px宽)

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