Копировать изображение с альфа-каналом в буфер обмена с пользовательским цветом фона?


Код:

private void Foo(Canvas canvas)
{
    // The content is a bit larger...
    Size size = new Size(canvas.ActualWidth * 1.1, canvas.ActualHeight * 1.2);

    // Create a render bitmap and push the surface to it
    RenderTargetBitmap renderBitmap =
        new RenderTargetBitmap(
        (int)size.Width,
        (int)size.Height,
        96d,
        96d,
        PixelFormats.Pbgra32
    );
    renderBitmap.Render(canvas);

    // Then copy to clipboard
    Clipboard.SetImage(renderBitmap);
}

Что мне нужно:

Визуализируйте холст с прозрачным фоном в изображение, а затем скопируйте его в буфер обмена (выйти просто? Не совсем)

Задача:

При вставке я получаю уродливое изображение с черным фоном

Решение 1 :

canvas.Background = new SolidColorBrush(Colors.White);

Нет. Этот толстый не работает, фон canvas не изменится в следующем renderBitmap.Render(canvas);

Вместо этого я должен использовать таймер, дать WPF некоторое время, чтобы измените фон, а затем визуализируйте его в событии тика этого таймера. Это работает, но, к сожалению, содержание canvas больше, чем это size...so белый фон может покрыть только часть его, все равно уродливый результат. (Кстати, кто-нибудь знает, почему требуется время, чтобы изменить фон? Я думал, что это должно быть изменено немедленно)

Я сделал что-то не так? Как я могу получить изображение белого фона ex-transparent в буфере обмена?

Более того, я заметил, что фон некоторых PNG-изображения остаются белыми, если вставить их в mspaint.exe, которые не поддерживают альфа-канал, но некоторые другие становятся черными.

Есть ли что-то вроде, скажем, alternative color, которое используется в качестве фона, если место, куда вы вставляете свое изображение, не поддерживает альфа-канал? Можем ли мы его настроить?

Теперь я отрисовал другой BitmapSource с белым содержимым, если есть способ объединить его с renderBitmap в качестве фона, проблема решена, но я не знаю, как...
int dWidth = (int)size.Width;
int dHeight = (int)size.Height;
int dStride = dWidth * 4;
byte[] pixels = new byte[dHeight * dStride];
for (int i = 0; i < pixels.Length; i++)
{
    pixels[i] = 0xFF;
}
BitmapSource bg = BitmapSource.Create(
    dWidth,
    dHeight,
    96,
    96,
    PixelFormats.Pbgra32,
    null,
    pixels,
    dStride
);
// Combine bg with renderBitmap
2 4

2 ответа:

Вот мое последнее решение, надеюсь, что оно поможет другим с той же проблемой

// Create a render bitmap and push the surface to it
RenderTargetBitmap renderBitmap =
    new RenderTargetBitmap(
    (int)size.Width,
    (int)size.Height,
    96d,
    96d,
    PixelFormats.Pbgra32
);
renderBitmap.Render(surface);

// Create a white background render bitmap
int dWidth = (int)size.Width;
int dHeight = (int)size.Height;
int dStride = dWidth * 4;
byte[] pixels = new byte[dHeight * dStride];
for (int i = 0; i < pixels.Length; i++)
{
    pixels[i] = 0xFF;
}
BitmapSource bg = BitmapSource.Create(
    dWidth,
    dHeight,
    96,
    96,
    PixelFormats.Pbgra32,
    null,
    pixels,
    dStride
);

// Adding those two render bitmap to the same drawing visual
DrawingVisual dv = new DrawingVisual();
DrawingContext dc = dv.RenderOpen();
dc.DrawImage(bg, new Rect(size));
dc.DrawImage(renderBitmap, new Rect(size));
dc.Close();

// Render the result
RenderTargetBitmap resultBitmap =
    new RenderTargetBitmap(
    (int)size.Width,
    (int)size.Height,
    96d,
    96d,
    PixelFormats.Pbgra32
);
resultBitmap.Render(dv);

// Copy it to clipboard
try
{
    Clipboard.SetImage(resultBitmap);
} catch { ... }

Я нашел меньшее и лучшее для чтения решение, я нашел его в https://social.msdn.microsoft.com/Forums/vstudio/en-US/a6972b7f-5ccb-422d-b203-134ef9f10084/how-to-capture-entire-usercontrol-image-to-clipboard?forum=wpf:

// Create a render bitmap and push the surface to it
RenderTargetBitmap renderBitmap =
    new RenderTargetBitmap(
    (int)size.Width,
    (int)size.Height,
    96d,
    96d,
    PixelFormats.Pbgra32
);

// Render a white background into buffer for clipboard to avoid black background on some elements
Rectangle vRect = new Rectangle()
{
    Width = (int)size.Width,
    Height = (int)size.Height,
    Fill = Brushes.White,
};
vRect.Arrange(new Rect(size));
renderBitmap.Render(vRect);

// renderBitmap is now white, so render your object on it
renderBitmap.Render(surface);

// Copy it to clipboard
try
{
    Clipboard.SetImage(resultBitmap);
} catch { ... }