65.9K
CodeProject 正在变化。 阅读更多。
Home

在捕获 Windows 应用商店应用图像时粘贴日期时间戳

emptyStarIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

0/5 (0投票)

2012年12月20日

CPOL

4分钟阅读

viewsIcon

28944

downloadIcon

458

在这里,我将向您展示如何在照片中粘贴日期时间。本文将有助于那些希望在其应用程序中添加 CamaraCaptureUI 的开发人员。

介绍 

在现代数码相机中,您会发现有一个选项可以在拍照时粘贴日期和时间戳。突然我想,Windows 8 的(即 WinRT 的)CamaraCaptureUI 是否提供这样的选项,但遗憾的是,它没有此功能 Frown | <img src=  

日期时间戳在共享或打印照片时非常有用。是的,您可以在任何图像处理软件中进行编辑并添加日期时间戳,但如果已有现成的解决方案,谁愿意参与这样的过程呢。因此,在这里我将向您展示如何在照片中粘贴日期时间。本文将有助于那些希望在其应用程序中添加 CamaraCaptureUI 的开发人员。

背景 

首先,我感谢 SharpDX 团队为 DirectX 提供了托管应用程序的包装器。其次,我感谢 Christoph Wille。本文和项目在很大程度上基于 Christoph Wille 在 GitHub 上的项目。最后但同样重要的是,我还要感谢 Can Bilgin 提供的将 byte 数组转换为 IRandomAccessStream 的辅助类。

开发人员对 WinRT 的 WritableBitmap 不满意

在 WPF 和 Silverlight 中,WritableBitmap 在开发图形化应用程序时非常有用。遗憾的是,WinRT 的 WritableBitmap 用处不大。甚至 WritableBitmapEx 也有一些限制,其中一个限制就是本文的主要目标:在图像上渲染文本。

用户界面

用户界面非常简单。它只包含一个带有 Image 控件和一个按钮的页面。按钮允许您使用内置的 CameraCaptureUI 捕获图像,并将带有日期时间戳的捕获图像保存到图片库。

所需功能

您必须设置这些功能。如果您没有设置相机权限,CameraCaptureUI 会告诉您没有添加该功能。如果您没有设置图片库访问权限,代码将抛出异常。


1. 图片库
2. 网络摄像头

相机捕获

现在在 Windows 应用商店应用中捕获图像变得非常容易。Windows.Media.Capture 命名空间具有 CameraCaptureUI,它允许用户捕获图像以及视频。它还具有裁剪功能和计时器。现在无需导入第三方 DLL,也无需再使用 DllImport Smile | <img src=

CameraCaptureUI 将图像保存在应用程序的 TempState 文件夹中。关闭应用程序后,TempState 将被清除。

var dialog = new CameraCaptureUI();
dialog.PhotoSettings.AllowCropping = true;
var ImageFile = await dialog.CaptureFileAsync(CameraCaptureUIMode.Photo);

SharpDX

SharpDX 是一个用于 .NET 环境的开源平台无关的托管 DirectX API。这个新 API 直接从 DirectX C++ SDK 头文件自动生成,并且生成的代码完全用 C# 编写,不使用任何 C++/CLI 程序集,同时仍能实现可比的性能。API 命名约定已尽可能保持与众所周知的 SlimDX API 相似,SlimDX 目前使用 C++/CLI 程序集。此外,SharpDX 的目标是在低级 API(Direct3D11、DXGI、D3DCompiler...)之上提供一个类似于 XNA 的更高级 API,但使用最新的 DirectX 技术。

致谢:维基百科

SharpDX 在此的作用

在我们的应用程序中,SharpDX 用于将捕获的图像加载为 SharpDX 兼容的 BitmapSource。它解码图像的像素,并且 FormatConverter 通过 ImagingFactory2 类返回一个专用的 BitmapSource

public static SharpDX.WIC.BitmapSource LoadBitmap(ImagingFactory2 factory, string ImageFilePath)
{
    var bitmapDecoder = new BitmapDecoder(
        factory,
        ImageFilePath,
        DecodeOptions.CacheOnDemand
        );
    var formatConverter = new FormatConverter(factory);
    formatConverter.Initialize(
        bitmapDecoder.GetFrame(0),
        SharpDX.WIC.PixelFormat.Format32bppPRGBA,
        BitmapDitherType.None,
        null,
        0.0,
        BitmapPaletteType.Custom);
    return formatConverter;
}

获取 BitmapSource 后,现在该渲染文本了,但在调用 WicRenderTarget 类的 BeginDraw() 方法之前,我们将设置文本和图像的格式。在这里,我将图像的宽度和高度设置为与源相同,并使用带红色画笔的 Segoe UI 字体。

TextFormat 类还具有设置文本对齐、段落对齐、字词换行、字体粗细、字体大小、流方向等的属性,并且对于图像格式,您可以设置高度、宽度、水平和垂直 DPI。设置格式后,WicRenderTarget 具有 DrawText() 方法,该方法接受四个参数。


1. 要粘贴的字符串,在这里是当前日期时间
2. 文本格式
3. 布局矩形(您可以使用 RectangleF 类设置)
4. 文本画笔


然后,我们将使用 EndDraw() 方法完成绘图。现在我们将进行编码。您可以选择多种 BitmapEncoder。在这里,我选择了 PngBitmapEncoderJpegBitmapEncoder。我根据源文件的扩展名设置了条件。最后,它返回一个继承自 System.IO.StreamMemoryStream,因为 SharpDX 使用这种类型的流。

private async Task<MemoryStream> RenderStaticTextToBitmap(StorageFile ImageFile)
{
    var bitmap = new BitmapImage();
    using (var strm = await ImageFile.OpenAsync(FileAccessMode.Read))
    {
        bitmap.SetSource(strm);
    }
    var width = bitmap.PixelWidth;
    var height = bitmap.PixelHeight;
    var pixelFormat = WicPixelFormat.Format32bppBGR;
    var wicFactory = new ImagingFactory2();
    var dddFactory = new SharpDX.Direct2D1.Factory();
    var dwFactory = new SharpDX.DirectWrite.Factory();
    WicRenderTarget renderTarget;
    Bitmap wicBitmap;
    using (var bitmapSource = LoadBitmap(wicFactory, ImageFile.Path))
    {
        wicBitmap = new Bitmap(wicFactory, bitmapSource, BitmapCreateCacheOption.CacheOnLoad);
        int pixelWidth = (int)(wicBitmap.Size.Width * DisplayProperties.LogicalDpi / 96.0);
        int pixelHeight = (int)(wicBitmap.Size.Height * DisplayProperties.LogicalDpi / 96.0);
        var renderTargetProperties = new RenderTargetProperties(RenderTargetType.Default,
            new D2DPixelFormat(Format.Unknown, AlphaMode.Unknown), 0, 0, RenderTargetUsage.None,
            FeatureLevel.Level_DEFAULT);
        renderTarget = new WicRenderTarget(
        dddFactory,
        wicBitmap,
        renderTargetProperties)
        {
            TextAntialiasMode = TextAntialiasMode.Cleartype
        };
    }    
    renderTarget.BeginDraw();
    var textFormat = new TextFormat(dwFactory, "Segoe UI Light", 25)
    {
        TextAlignment = SharpDX.DirectWrite.TextAlignment.Leading,
        ParagraphAlignment = ParagraphAlignment.Far
    };
    var textBrush = new SharpDX.Direct2D1.SolidColorBrush(
        renderTarget,
        SharpDX.Colors.Red);
    renderTarget.DrawText(
        DateTime.Now.ToString("t") + "\n" + DateTime.Now.ToString("d") + "\n",
        textFormat,
        new RectangleF(width - 150, 0, width, height + 25),
        textBrush);
    renderTarget.EndDraw();
    var ms = new MemoryStream();
    var stream = new WICStream(
        wicFactory,
        ms);
    BitmapEncoder encoder = null;
    if (ImageFile.FileType == ".png")
        encoder = new PngBitmapEncoder(wicFactory);
    else if (ImageFile.FileType == ".jpg")
        encoder = new JpegBitmapEncoder(wicFactory);
    encoder.Initialize(stream);
    var frameEncoder = new BitmapFrameEncode(encoder);
    frameEncoder.Initialize();
    frameEncoder.SetSize(width, height);
    frameEncoder.PixelFormat = WicPixelFormat.FormatDontCare;
    frameEncoder.WriteSource(wicBitmap);
    frameEncoder.Commit();
    encoder.Commit();
    frameEncoder.Dispose();
    encoder.Dispose();
    stream.Dispose(); 
    ms.Position = 0;
    return ms;
}

MemoryRandomAccessStream 在此的作用

现在,辅助类 MemoryRandomAccessStream 用于将 System.IO.Stream 转换为 IRandomAccessStreamIRandomAccessStream 在生成 StorageFile 时非常有用。获得 IRandomAccessStream 后,我们在用户的图片库中写入一个 StorageFile,图像也会被显示出来。

var ms = await RenderStaticTextToBitmap(ImageFile);
var msrandom = new MemoryRandomAccessStream(ms);
Byte[] bytes = new Byte[ms.Length];
await ms.ReadAsync(bytes, 0, (int)ms.Length);
StorageFile file = await KnownFolders.PicturesLibrary.CreateFileAsync("Image.png", Windows.Storage.CreationCollisionOption.GenerateUniqueName);
using (var strm = await file.OpenStreamForWriteAsync())
{
    await strm.WriteAsync(bytes, 0, bytes.Length);
    strm.Flush();
}
BitmapImage image = new BitmapImage();
await image.SetSourceAsync(msrandom);
RenderedImage.Source = image;  

看点

这里的主要兴趣点在于利用 CamaraCaptureUI 以及如何使用 SharpDX 进行图像处理。您的评论、建议和投票将鼓励我,并对我有所帮助。我请求您分享这篇文章,并尝试改进我。谢谢。

© . All rights reserved.