Как сохранить нечеткое изображение элемента управления в WPF?

Я использую DrawingContext для рисования изображений. Затем я визуализирую результат в RenderTargetBitmap. Я также визуализирую Canvas в тот же RenderTargetBitmap. Несмотря на то, что границы пикселей на экране четкие, при сохранении они становятся размытыми и нечеткими.

На снимке экрана ниже вы можете увидеть проблему (с BitmapScalingMode = NearestNeighbor). введите здесь описание изображения

Вот он с BitmapScalingMode = HighQuality. Он более гладкий, но не четкий и чистый. введите здесь описание изображения

Вот соответствующий раздел моего кода. Вы можете видеть, что я пытался установить RenderOptions в нескольких местах, но, похоже, это не дало никакого эффекта.

        DrawingVisual drawingVisual = new DrawingVisual();
        RenderTargetBitmap result = new RenderTargetBitmap((int)size.Width, (int)size.Height, 96, 96, PixelFormats.Pbgra32);

        RenderOptions.SetBitmapScalingMode(drawingVisual, BitmapScalingMode.NearestNeighbor);   // This forces the scaling to be on even-pixel boundaries
        RenderOptions.SetBitmapScalingMode(drawCanvas, BitmapScalingMode.NearestNeighbor);  // This forces the scaling to be on even-pixel boundaries
        RenderOptions.SetBitmapScalingMode(result, BitmapScalingMode.NearestNeighbor);  // This forces the scaling to be on even-pixel boundaries

        using (DrawingContext context = drawingVisual.RenderOpen()) {
            context.DrawRectangle(Brushes.Black, null, new Rect(new Point(), new Size(size.Width, size.Height)));

            if (layers.Count >= 1 && layers[0].LayerImage != null && layers[0].LayerImage.Source != null && gridImage.Children[1].Visibility == System.Windows.Visibility.Visible)
                context.DrawImage(layers[0].LayerImage.Source, new Rect(size)); // Draw first image.

            context.Close();
        }

        result.Render(drawingVisual);

        drawCanvas.Measure(drawCanvas.RenderSize);
        drawCanvas.Arrange(new Rect(drawCanvas.RenderSize));

        for (int i = 0; i < drawCanvas.Children.Count; i++) {
            RenderOptions.SetBitmapScalingMode(drawCanvas.Children[i], BitmapScalingMode.NearestNeighbor);  // This forces the scaling to be on even-pixel boundaries
        }

        result.Render(drawCanvas);

        BitmapEncoder encoder = new PngBitmapEncoder();
        if (result!= null) {
            encoder.Frames.Add(BitmapFrame.Create((BitmapSource)result));
            encoder.Save(fileStream);
        }

person nb1forxp    schedule 25.04.2014    source источник
comment
Попробуйте изменить BitmapScalingMode на HighQuality   -  person 123 456 789 0    schedule 25.04.2014
comment
В последний раз, когда я думал, что у меня есть эта проблема, это действительно была опция отображения IfranView.   -  person TaW    schedule 25.04.2014
comment
@lll: я пробовал HighQuality, но это не очень помогло. Смотрите скриншот в редактировании выше.   -  person nb1forxp    schedule 25.04.2014
comment
@TAW: я пробовал это во многих программах, включая мою собственную, и все они выглядят одинаково, поэтому я думаю, что это мой код сохранения, а не средство просмотра.   -  person nb1forxp    schedule 25.04.2014
comment
ХОРОШО. Просто мысль. Изображения выглядят сглаженными. Я заметил, что вы используете PixelFormats.Pbgra32; Вы пробовали PixelFormats.Bgra32?   -  person TaW    schedule 25.04.2014
comment
Жестко заданный выходной DPI, равный 96, может быть проблемой. WPF не всегда использует один и тот же DPI; это будет зависеть от настроек вашего экрана. Несоответствие DPI может вызвать размытие.   -  person RogerN    schedule 25.04.2014
comment
Использование этого формата System.Drawing.Imaging.PixelFormat.Format32bppArgb помогло мне сохранить четкие изображения.   -  person TaW    schedule 25.04.2014
comment
@RogerN: Какой DPI я бы использовал вместо этого?   -  person nb1forxp    schedule 26.04.2014
comment
@TAW: RenderTargetBitmap не поддерживает предложенные вами форматы. Я получаю ошибки времени выполнения и времени компиляции (соответственно) по вашим двум предложениям формата.   -  person nb1forxp    schedule 26.04.2014
comment
@TaW вы не можете смешивать System.Drawing и WPF   -  person springy76    schedule 13.07.2015
comment
@ nb1forxp, вы когда-нибудь находили решение этой проблемы?   -  person springy76    schedule 13.07.2015
comment
@ springy76 Я еще не нашел решения.   -  person nb1forxp    schedule 15.07.2015
comment
@ nb1forxp, ты уже это исправил?   -  person gmetax    schedule 06.02.2016
comment
Какое значение имеют переменная size и drawCanvas.RenderSize при вызове 'result.Render(drawingVisual);'?   -  person Liero    schedule 06.02.2016
comment
Если кто-то сталкивается с подобной проблемой, RenderOptions.SetEdgeMode(canvas, EdgeMode.Aliased) может помочь вам перед вызовом метода Render.   -  person Erik W    schedule 14.05.2019


Ответы (1)


Я не знаю, исправили ли вы это, но эта функция работает очень хорошо на моей стороне.

    public BitmapSource SnapShotPNG(UIElement source)
    {
        double actualWidth = source.RenderSize.Width;
        double actualHeight = source.RenderSize.Height;

        RenderTargetBitmap renderTarget = new RenderTargetBitmap((int)actualWidth, (int)actualHeight, 96, 96, PixelFormats.Pbgra32);


        DrawingVisual visual = new DrawingVisual();

        using (DrawingContext context = visual.RenderOpen())
        {
            VisualBrush sourceBrush = new VisualBrush(source);
            context.DrawRectangle(sourceBrush, null, new Rect(new Point(0, 0), new Point(actualWidth, actualHeight)));
        }
        source.Measure(source.RenderSize); //Important
        source.Arrange(new Rect(source.RenderSize)); //Important

        renderTarget.Render(visual);

        try
        {
            return new CroppedBitmap(renderTarget, new Int32Rect(0, 0, (int)actualWidth, (int)actualHeight));
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
            return null;
        }
    }
person gmetax    schedule 06.02.2016
comment
Спасибо! Я попробую. - person nb1forxp; 07.02.2016
comment
еще нет, извините! мой код был переформатирован с тех пор, как я разместил сообщение, поэтому мне нужно развернуть его, чтобы выяснить, как проверить вашу функцию. Следите за обновлениями! - person nb1forxp; 10.02.2016
comment
Некоторое время я использовал что-то подобное, но на самом деле мне пришлось выполнить измерение + упорядочить с увеличением ширины и высоты на 1 пиксель, а затем снова запустить его с правильным размером. Если вы видите какие-либо странности с вещами, которые не отображаются, попробуйте это [так в оригинале] - person Simon_Weaver; 28.07.2019