给MediaComposition添加背景颜色

10

我正在尝试创建一个MediaComposition。我已经成功地将多个PNG图像合并成一个视频,但是创建的文件具有黑色背景。起初,我以为这可能是因为文件是PNG文件,但对于JPG文件,相同的情况也发生了。以下是我保存图像的方式:

public async Task<bool> Save(InkCanvas canvas, StorageFile file)
{

    if (canvas != null && canvas.InkPresenter.StrokeContainer.GetStrokes().Count > 0)
    {
        if (file != null)
        {
            using (IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.ReadWrite))
            {
                await canvas.InkPresenter.StrokeContainer.SaveAsync(stream);
            }
        }
        Clear(canvas);
        return true;
    }
    return false;
}

它可以保存图像,但背景是透明的。这意味着当我尝试将它们链接到媒体组合中时,没有背景,并且呈现为黑色。我尝试在创建MediaComposition时使用叠加来纠正这个问题:

MediaClip overlayVideoClip = MediaClip.CreateFromColor(Colors.White, new TimeSpan(0, 1, 0));
MediaOverlay mo = new MediaOverlay(overlayVideoClip);
MediaOverlayLayer mol = new MediaOverlayLayer();
mol.Overlays.Add(mo);

composition.OverlayLayers.Add(mol);

但是没有效果。我怀疑我在这种情况下误解了叠加层的意思。我的问题是:是否有可能在合成时叠加视频?如果可以,如何操作?或者,如果需要在图像本身中完成,则如何保存带有背景的图像?

编辑:

我在这方面取得了一些进展(?);以下代码可以编译并运行,但创建了一个纯黑色图像:

    public async Task TestSave(InkCanvas canvas, StorageFile file)
    {
        RenderTargetBitmap rtb = 
           new RenderTargetBitmap();
        PixelFormats.Pbgra32);
        await rtb.RenderAsync(canvas);
        var pixelBuffer = await rtb.GetPixelsAsync();

        using (IRandomAccessStream stream = 
             await file.OpenAsync(FileAccessMode.ReadWrite))
        {                
            BitmapEncoder encoder = 
                 await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, stream);

            encoder.SetPixelData(BitmapPixelFormat.Bgra8,
                BitmapAlphaMode.Straight,
                (uint)rtb.PixelWidth,
                (uint)rtb.PixelHeight,
                96d, 96d,
                pixelBuffer.ToArray());

            await encoder.FlushAsync();                
        }
    }

编辑:

我发现这个答案,它通过使用Win2D库来解决问题; 虽然它没有解决我的实际问题,但它让我绕开了它。 希望有更好的解决方案。


不清楚你想做什么。只是保存没有透明背景的图像吗? - Seth Kitchen
要么保存带有背景的图像,要么在创建视频文件时将背景叠加进去(目前使用MediaComposition)。 - Paul Michaels
1个回答

5

我理解的是您想要保存一个带有背景的图片。我的建议是,先将您拥有的透明图片保存为

<StackPanel x:Name="AreaWhichWillBeSavedToImage" Background=*Some Color*>
  <Image x:Name="theAlphaImage">
</StackPanel>

如果您不希望图像显示在GUI上,请将其设置为隐藏。

然后,您可以使用您选择的背景颜色保存文件。

var bitmap = await SaveToFileAsync(AreaWhichWillBeSavedToImage, await StorageFile.GetFileFromPathAsync(Windows.ApplicationModel.Package.Current.InstalledLocation.Path + @"someimage.jpg"));

  async Task<RenderTargetBitmap> SaveToFileAsync(FrameworkElement uielement, StorageFile file)
    {
        if (file != null)
        {
            CachedFileManager.DeferUpdates(file);

            Guid encoderId = GetBitmapEncoder(file.FileType);

            try
            {
                using (var stream = await file.OpenAsync(FileAccessMode.ReadWrite))
                {
                    return await CaptureToStreamAsync(uielement, stream, encoderId);
                }
            }
            catch (Exception ex)
            {
                //DisplayMessage(ex.Message);
            }

            var status = await CachedFileManager.CompleteUpdatesAsync(file);
        }

        return null;
    }

    async Task<RenderTargetBitmap> CaptureToStreamAsync(FrameworkElement uielement, IRandomAccessStream stream, Guid encoderId)
    {
        try
        {
            var renderTargetBitmap = new RenderTargetBitmap();
            await renderTargetBitmap.RenderAsync(uielement);

            var pixels = await renderTargetBitmap.GetPixelsAsync();

            var logicalDpi = DisplayInformation.GetForCurrentView().LogicalDpi;
            var encoder = await BitmapEncoder.CreateAsync(encoderId, stream);
            encoder.SetPixelData(
                BitmapPixelFormat.Bgra8,
                BitmapAlphaMode.Ignore,
                (uint)renderTargetBitmap.PixelWidth,
                (uint)renderTargetBitmap.PixelHeight,
                logicalDpi,
                logicalDpi,
                pixels.ToArray());

            await encoder.FlushAsync();

            return renderTargetBitmap;
        }
        catch (Exception ex)
        {
            //DisplayMessage(ex.Message);
        }

        return null;
    }

    Guid GetBitmapEncoder(string fileType)
    {
        Guid encoderId = BitmapEncoder.JpegEncoderId;
        switch (fileType)
        {
            case ".bmp":
                encoderId = BitmapEncoder.BmpEncoderId;
                break;
            case ".gif":
                encoderId = BitmapEncoder.GifEncoderId;
                break;
            case ".png":
                encoderId = BitmapEncoder.PngEncoderId;
                break;
            case ".tif":
                encoderId = BitmapEncoder.TiffEncoderId;
                break;
        }

        return encoderId;
    }

将InkCanvas图像保存为AlphaImage的ImageSource,然后它就可以工作了。 - Seth Kitchen
如果你的意思是这样的:<Image x:Name="theAlphaImage" Source="{Binding ElementName=myInkCanvas}"> 那似乎不起作用。 - Paul Michaels
你正在将你的inkCanvas保存到一个IRandomAccessStream中。该流很容易转换为Render Bitmap或WritableBitmap等位图类型。一旦你将其转换为位图类型,就可以将图像源设置为该位图。 - Seth Kitchen
1
虽然这种方法确实有效(非常感谢),但在可视化树中看得见图像时,它才会被保存。否则,只会保存为空白。 - Paul Michaels

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接