【问题标题】:Windows Store App - RenderTargetBitmap creating a bitmap of incorrect sizeWindows 应用商店应用程序 - RenderTargetBitmap 创建大小不正确的位图
【发布时间】:2016-06-28 08:55:03
【问题描述】:

我正在尝试在我的应用拍摄的照片上添加水印。我能想到的最简单的方法是使用FrameworkElement 构建图层,然后使用RenderTargetBitmap 创建水印图像。

这是我的 XAML 示例。

    <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 中,因此可以缩小,但是当我尝试使用以下代码创建此图像的位图时,渲染的位图小于@ 987654325@

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 )
    {
    }
}

调试输出是

Button_Click: ImageGrid: 5344x3008 RenderTargetBitmap: 4096x2306

谁能告诉我为什么渲染的位图比我创建它的实际元素小得多?

还有更好的方法给图片加水印吗?

【问题讨论】:

    标签: bitmap windows-phone-8.1 windows-store-apps windows-8.1


    【解决方案1】:

    感谢@A.J.Bauer 将我指向 Win2D,我已经设法非常优雅地解决了这个问题。

        /// <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;
        }
    

    产生的调试给了我。

    CreateWaterMarkedImage: ImageGrid: 5344x3008 Bitmap: 5344x3008
    

    如果设置ImageUIElement的来源,则显示带水印的图像。

    CapturedImage2.Source = await CreateWaterMarkedImage(photoStream);
    

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

    【讨论】:

      【解决方案2】:

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

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

      【讨论】:

        【解决方案3】:

        查看Win2D 并使用屏幕外绘图。

        【讨论】:

        • 这看起来很有趣。我会检查一下,我很惊讶我没有偶然发现那个库。
        • 顺便说一句:示例库也可在 Windows 10 应用商店中找到。搜索:Win2D
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多