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





0/5 (0投票)
在这里,我将向您展示如何在照片中粘贴日期时间。本文将有助于那些希望在其应用程序中添加 CamaraCaptureUI 的开发人员。
介绍
在现代数码相机中,您会发现有一个选项可以在拍照时粘贴日期和时间戳。突然我想,Windows 8 的(即 WinRT 的)CamaraCaptureUI
是否提供这样的选项,但遗憾的是,它没有此功能
日期时间戳在共享或打印照片时非常有用。是的,您可以在任何图像处理软件中进行编辑并添加日期时间戳,但如果已有现成的解决方案,谁愿意参与这样的过程呢。因此,在这里我将向您展示如何在照片中粘贴日期时间。本文将有助于那些希望在其应用程序中添加 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
此 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
。在这里,我选择了 PngBitmapEncoder
和 JpegBitmapEncoder
。我根据源文件的扩展名设置了条件。最后,它返回一个继承自 System.IO.Stream
的 MemoryStream
,因为 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
转换为 IRandomAccessStream
。IRandomAccessStream
在生成 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 进行图像处理。您的评论、建议和投票将鼓励我,并对我有所帮助。我请求您分享这篇文章,并尝试改进我。谢谢。