WPF RenderTargetBitmap Отсутствующие элементы

У меня есть TreeView с маленькими значками, отображаемыми в шаблоне данных. Я пытаюсь сохранить Treeview как PNG с помощью RenderTargetBitmap.

Изображение правильно сохраняется на небольших наборах данных. Однако, если набор данных становится слишком большим, некоторые значки исключаются из окончательного изображения. Кажется, что магическое число составляет 200 единиц. Кажется, не имеет значения, является ли дерево глубоким или широким, после 200 элементов значки не отображаются.

Добавлен код

Итак, вот мой код, который я использую для создания изображения.

        RenderTargetBitmap targetBitmap = new RenderTargetBitmap(
            (int)_treeView.ActualWidth,
            (int)_treeView.ActualHeight,
            96, 96, PixelFormats.Default);

        targetBitmap.Render(_treeView);

Добавлен снимок экрана

Обратите внимание на отсутствующие значки справа от дерева. Снимок экрана с отсутствующими значками

Теперь, если я сверну несколько веток, скрыв некоторые другие значки, эти значки будут включены. Это почти похоже на RenderTargetBitmap.Render не имеет возможности отображать все значки. Или это может иметь какое-то отношение к виртуальным панелям. Снимок экрана с включенными значками

Вот более подробный взгляд. введите описание изображения здесь


person Jesse Seger    schedule 12.03.2013    source источник
comment
Вы можете попробовать что-нибудь для меня; Просто установите для всех изображений изображение 2x2. Вы по-прежнему получаете лимит в 200 предметов?   -  person Meirion Hughes    schedule 16.03.2013
comment
@MeirionHughes Эй! Интересный. При 2x2 иконки не отображались. Я немного увеличил размер, а затем только несколько значков, например 10. Итак, когда я задал вопрос, шаблон был установлен на 100x100, поэтому я изменил его на 150x150, и все значки были отрисованы! Так что, черт возьми, происходит ??   -  person Jesse Seger    schedule 18.03.2013
comment
Понятия не имею ... Очень странно, я хочу сказать, что у вас есть проблемы с виртуализацией и кешированием. Вы ничего не делаете с изображениями, например, храните все в одном растровом изображении или что-то в этом роде?   -  person Meirion Hughes    schedule 18.03.2013
comment
Я создаю изображения из потока памяти размером 256x256. Если я изменю размер на 512x512, будет отображаться меньше значков. Если я перейду на 100x100, появится больше значков. Это другое и противоположное изменению размера шаблона данных.   -  person Jesse Seger    schedule 18.03.2013
comment
Отображаются ли значки в вашем приложении? Я имею в виду не визуализированное изображение, а просто окно, в котором находится ваше древовидное представление.   -  person terry    schedule 25.11.2013
comment
Да, значки в приложении отображаются нормально. RenderTargetBitmap не включает все значки.   -  person Jesse Seger    schedule 25.11.2013
comment
Можно ли изменить формат пикселей на PixelFormats.Pbgra32 и сохранить как файл PNG? Изображения все еще отсутствуют?   -  person XAMeLi    schedule 25.11.2013
comment
Изображения все еще отсутствуют.   -  person Jesse Seger    schedule 25.11.2013
comment
Просто идея: какой у изображений исходный размер? Может быть, это тайм-аут, потому что он должен больше работать, чтобы изменить размер изображений? Что вы получите в натуральную величину?   -  person klugerama    schedule 27.11.2013
comment
Это хорошая мысль. Команда «Открыть» открывает несколько файлов для создания моделей представления, создает миниатюру заданного размера (скажем, 256X256), после чего начинается привязка данных. Для элемента изображения установлен любой размер (скажем, 150X150), и он привязывается к миниатюре в модели представления. Сейчас я занимаюсь рефакторингом, чтобы получить миниатюру во время привязки данных с помощью конвертера, который изменяет размер изображения до фактического размера элемента изображения. Пока не знаю, решится ли проблема, но пока работает отлично. Я обновлю, если найду что-то новое.   -  person Jesse Seger    schedule 27.11.2013
comment
Может таймаут в механизме верстки? Я бы попытался (просто чтобы убедиться, что проблемы нет) явно разметить все внутренние изображения перед рендерингом с помощью Measure (), Arrange () и UpdateLayout (). Возможно, это заставит ленивую загрузку изображений, которые не загружаются до макета.   -  person MaMazav    schedule 01.12.2013


Ответы (2)


На что я сразу обратил внимание, что у вас ОГРОМНЫЙ имидж. Ширина 12000. Я удивлен, что вы даже подошли так близко.

Как указано в MSDN, ширина и высота текстуры ограничены пределами текстуры DirectX.

Максимальный размер визуализируемого визуального дерева XAML ограничен максимальными размерами текстуры Microsoft DirectX; для получения дополнительной информации см. Ограничения ресурсов (Direct3D). Это ограничение может варьироваться в зависимости от оборудования, на котором работает приложение. Очень большой контент, превышающий этот предел, может быть увеличен до нужного размера. Если ограничения масштабирования применяются таким образом, визуализированный размер после масштабирования можно запросить с помощью свойств PixelWidth и PixelHeight. Например, визуальное дерево XAML размером 10000 на 10000 пикселей может быть масштабировано до 4096 на 4096 пикселей, что является примером конкретного ограничения, установленного оборудованием, на котором выполняется приложение. http://msdn.microsoft.com/library/windows/apps/dn298548

Я подозреваю такие вещи:

  • Виртуализация отсекала некоторые вещи - в прошлом у меня была точно такая же проблема с DataGrid, и проблема заключалась в виртуализации. Однако твой случай не похож на него.
  • Слишком большая текстура может вызвать неопределенное поведение.

Вы можете попробовать отключить аппаратное ускорение. Вещь вызывает довольно много серьезных ошибок. http://msdn.microsoft.com/en-us/library/system.windows.media.renderoptions.processrendermode.aspx

В остальном - это будет сложно, но я почти уверен, что все будет работать красиво:

1) начните с корневого объекта и рекурсивно просматривайте дочерние объекты корневого объекта, пока не найдете объект размером менее 1000 x 1000. Сделайте его снимок с помощью RenderTargetBitmap (BMP) и объедините его с IN-MEMORY-BMP. Сделайте это для каждого ребенка.

Вы должны уметь все это посчитать.

person Erti-Chris Eelmaa    schedule 27.11.2013
comment
Это могло бы быть решением, но мне нужно несколько дней, чтобы проверить. Тем не менее, это очень хороший совет! - person Jesse Seger; 02.12.2013
comment
Как упоминалось в моем комментарии, это не связано с виртуализацией: хотя исходный плакат, вероятно, использовал виртуализацию, я определенно не использовал. Я также сомневаюсь, что это связано с аппаратным ускорением, поскольку RenderTargetBitmap не использует аппаратное ускорение. Это не со страницы RenderTargetBitmap MSDN, а из других сообщений MSDN, где люди жаловались на скорость RenderTargetBitmap. - person Cosmin Prund; 02.12.2013
comment
Об ограничениях ресурсов для RenderTargetBitmap; Если я нацелен на 64bit процессор, я могу успешно сгенерировать 15000x15000 png-изображение. Попытка 30000x30000 изображения вызывает ошибку памяти при попытке сохранить png. Попытка 30000x30000 на 32-битном процессоре вызывает ошибку памяти при создании RenderTargetBitmap. Попытка использовать 60000x60000 изображение вызывает ошибку при вызове Render(). Определенная комбинация настроек генерирует `общую ошибку GDI + при попытке сохранения. Мой момент: ошибки из-за ограничений ресурсов не проглатываются молча - поэтому я не думаю, что это ошибка ресурса. - person Cosmin Prund; 02.12.2013
comment
Прикрепите тестовый пример, который выдает ошибку, и я расскажу вам, почему это происходит. (exe & .sln) - person Erti-Chris Eelmaa; 04.12.2013

Для записей: есть обходной путь.

Вместо рендеринга визуала напрямую с помощью RenderTargetBitmap используйте промежуточный DrawingVisual. Нарисуйте визуал в DrawingVisual с помощью VisualBrush, а затем используйте RenderTargetBitmap с DrawingVisual.

Нравится:

    public BitmapSource RenderVisualToBitmap(Visual visual)
    {
        var contentBounds = VisualTreeHelper.GetContentBounds(visual);

        var drawingVisual = new DrawingVisual();
        using (var drawingContext = drawingVisual.RenderOpen())
        {
            var visualBrush = new VisualBrush(visual);
            drawingContext.DrawRectangle(visualBrush, null, contentBounds);
        }

        var renderTargetBitmap = new RenderTargetBitmap((int)contentBounds.Width, (int)contentBounds.Height, 96, 96, PixelFormats.Default);
        renderTargetBitmap.Render(drawingVisual);

        return renderTargetBitmap;
    }

Однако обратите внимание, что по мере того, как VisualBrush становится больше, результирующее изображение становится все более и более нечетким (при рендеринге с высоким DPI). Чтобы обойти эту проблему, используйте серию меньших «плиток» VisualBrush, как описано здесь: https://srndolha.wordpress.com/2012/10/16/exported-drawingvisual-quality-when-using-visualbrush/

person Vizu    schedule 02.09.2015