首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Windows RenderTargetBitmap创建一个大小不正确的位图

Windows RenderTargetBitmap创建一个大小不正确的位图
EN

Stack Overflow用户
提问于 2016-06-28 08:55:03
回答 3查看 206关注 0票数 3

我试图在我的应用程序拍摄的照片上加一个水印。我能想到的最简单的方法是使用FrameworkElement来构建图层,然后使用RenderTargetBitmap创建水标记的图像。

这是我的XAML的一个例子。

代码语言:javascript
复制
    <ScrollViewer x:Name="Zoom" Grid.Column="1" HorizontalScrollMode="Enabled" VerticalScrollMode="Enabled" VerticalScrollBarVisibility="Hidden" HorizontalScrollBarVisibility="Hidden" ZoomMode="Enabled">
        <Border x:Name="BgBorder">
            <Grid x:Name="ImageGird" SizeChanged="ImageGird_SizeChanged">
                <Grid x:Name="CaptureGird">
                    <Image x:Name="CapturedImage" Stretch="None" Source="ms-appx:///Assets/Photo.jpg" />
                    <StackPanel x:Name="Watermark" VerticalAlignment="Top" HorizontalAlignment="Left" Background="#6FFFFFFF" Margin="10">
                        <TextBlock Text="Name" Foreground="Black" Margin="10,2.5,10,2.5" />
                        <TextBlock Text="12345" Foreground="Black" Margin="10,2.5,10,2.5"/>
                        <TextBlock Text="54321" Foreground="Black" Margin="10,2.5,10,2.5" />
                    </StackPanel>
                </Grid>
            </Grid>
        </Border>
    </ScrollViewer>

由于他们所需要的图像的分辨率,它被包装在一个ScrollViewer中,这样它就可以放大,但是当我试图用下面的代码创建这个图像的位图时,呈现的位图比FrameworkElement要小。

代码语言:javascript
复制
private async void Button_Click(object sender, RoutedEventArgs e)
{
    try
    {
        var displayI = DisplayInformation.GetForCurrentView();
        var renderTargetBitmap = new RenderTargetBitmap();
        await renderTargetBitmap.RenderAsync(ImageGird, (int)ImageGird.ActualWidth, (int)ImageGird.ActualHeight);
        IBuffer pixels = await renderTargetBitmap.GetPixelsAsync();
        CapturedImage2.Source = renderTargetBitmap;

        Debug.WriteLine("Button_Click: ImageGrid: " + ImageGird.ActualWidth + "x" + ImageGird.ActualHeight + " RenderTargetBitmap: " + renderTargetBitmap.PixelWidth + "x" + renderTargetBitmap.PixelHeight);
    }
    catch (Exception )
    {
    }
}

调试输出是

代码语言:javascript
复制
Button_Click: ImageGrid: 5344x3008 RenderTargetBitmap: 4096x2306

有人能告诉我为什么呈现的位图比我创建它的实际元素小得多吗?

还有更好的方法来水印一个图像吗?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2016-07-11 11:00:56

由于@A.J.Bauer向我指出了Win2D,我成功地解决了这个问题。

代码语言:javascript
复制
    /// <summary>
    /// Create a watermarked image from an image stream
    /// </summary>
    /// <param name="sender">Jpeg image stream.</param>
    private async Task<ImageSource> CreateWaterMarkedImage(IRandomAccessStream stream)
    {
        // Ensure our stream is at the beginning.
        stream.Seek(0);
        // Create our Win2D in memory renderer.
        CanvasDevice device = CanvasDevice.GetSharedDevice();
        CanvasRenderTarget offscreen = new CanvasRenderTarget(device, (float)ImageGird.ActualWidth, (float)ImageGird.ActualHeight, 96);
        // Create our Win2D bitmap
        CanvasBitmap bmp = await CanvasBitmap.LoadAsync(offscreen, stream, 96);
        // Create a text formatter for our watermark
        var format = new CanvasTextFormat()
        {
            FontSize = 40,
            HorizontalAlignment = CanvasHorizontalAlignment.Left,
            VerticalAlignment = CanvasVerticalAlignment.Top,
            WordWrapping = CanvasWordWrapping.Wrap,
            FontFamily = "Arial",
            FontWeight = FontWeights.SemiBold
        };
        // Get a Win2D drawing session instance
        using (CanvasDrawingSession ds = offscreen.CreateDrawingSession())
        {
            // Layer our resulting Watermarked image.
            ds.DrawImage(bmp);
            // Create the Win2D text layout so we can get the bounds.
            var tl = new CanvasTextLayout(ds, "Name\r\n12345\r\n54321", format, 1000, 1000);
            // Create a background for the text
            ds.FillRectangle(10, 10, (float)tl.DrawBounds.Width + 20f, (float)tl.DrawBounds.Height + 20f, new Color() { A = 0x6F, R = 0xFF, G = 0xFF, B = 0xFF });
            // Add the text layout.
            ds.DrawTextLayout(tl, 10, 10, Colors.Black);
            // Clear up the memory.
            tl.Dispose();
        }

        // Create our bitmap so we can return an ImageSource
        BitmapImage im = new BitmapImage();
        using (InMemoryRandomAccessStream oStream = new InMemoryRandomAccessStream())
        {
            // Save the Win2D canvas renderer a stream.
            await offscreen.SaveAsync(oStream, CanvasBitmapFileFormat.Jpeg, 1.0f);
            stream.Seek(0);
            // Stream our Win2D pixels into the Bitmap
            await im.SetSourceAsync(oStream);
            Debug.WriteLine("CreateWaterMarkedImage: ImageGrid: " + ImageGird.ActualWidth + "x" + ImageGird.ActualHeight + " Bitmap: " + im.PixelWidth + "x" + im.PixelHeight);
        }
        // Tidy Up.
        format.Dispose();
        bmp.Dispose();
        offscreen.Dispose();
        device.Dispose();
        return im;
    }

由此产生的调试给了我。

代码语言:javascript
复制
CreateWaterMarkedImage: ImageGrid: 5344x3008 Bitmap: 5344x3008

如果设置了Image UIElement的源,则显示有水印的图像。

代码语言:javascript
复制
CapturedImage2.Source = await CreateWaterMarkedImage(photoStream);

这个示例非常适合我的需要,但是如果您使用Win2D XAML控件,任何人都应该能够轻松地修改它。

票数 2
EN

Stack Overflow用户

发布于 2016-07-07 01:05:36

ActualWidth和ActualHeight是计算值。因此,特别是对于网格,这些值可能会更改超时是有意义的。我的猜测是,当您设置的图像源,实际的宽度和高度正在重新计算。

我认为您应该能够使堆栈面板成为图像的子块,并将其相对于父图像定位,这将使其适用于可变的图像大小。您也可以尝试在网格上设置一些约束,并使用这些约束来确定位图大小,而不是使用实际的宽度/高度。

票数 1
EN

Stack Overflow用户

发布于 2016-07-07 05:51:57

看一看Win2D并使用屏幕外绘图.

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38071489

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档