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

Metro 中的图像处理

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.35/5 (14投票s)

2011年11月7日

CPOL

2分钟阅读

viewsIcon

65947

downloadIcon

2915

如何在新的 Metro 风格应用中进行第三方图像处理。

引言

我终于有机会试用 Windows 8 开发者预览版和 Metro 应用了。在试用新的开始菜单和应用之后,我决定尝试一个简单的图像显示和处理 Metro 应用。

Using the Code

首先,我使用 2 个按钮、一个图像和一个标签创建了一个基本的布局,用于显示一些元数据。我很高兴看到他们坚持使用 XAML,因此学习曲线非常小。

<Grid x:Name="LayoutRoot" Background="#FF0C0C0C">
   <StackPanel>
      <StackPanel Orientation="Horizontal">
         <Button Content="Load" FontSize="24" Width="200" Height="60" Click="Load_Click" />
         <Button Content="Process" FontSize="24" Width="200" Height="60" 
            Click="Process_Click" />
      </StackPanel>
      <Image x:Name="Image1" Width="800" Height="600" Stretch="Uniform" 
         Source="Windows8Logo.png"/>
      <TextBlock x:Name="DisplayText" FontSize="48" Foreground="White" />
   </StackPanel>
</Grid> 

为了加载图像,我使用了新的 FileOpenPicker。我非常喜欢这个控件的外观和感觉,并且认为它的文件过滤器比旧 WinForms 使用单个 string 方式有所改进。

FileOpenPicker openPicker = new FileOpenPicker();
openPicker.FileTypeFilter.Add(".jpg");
openPicker.FileTypeFilter.Add(".cmp");
openPicker.FileTypeFilter.Add(".png");
openPicker.FileTypeFilter.Add(".tif");
openPicker.FileTypeFilter.Add(".gif");
openPicker.FileTypeFilter.Add(".bmp");
StorageFile file = await openPicker.PickSingleFileAsync();
int loadBitsPerPixel = 0;
RasterCodecs codecs = new RasterCodecs();
if (file != null)
{
   string fileName = file.Path;
   var winRTStream = await file.OpenAsync(FileAccessMode.ReadWrite);
   IInputStream inputStream = winRTStream.GetInputStreamAt(0);
   DataReader dataReader = new DataReader(inputStream);
   await dataReader.LoadAsync((uint)winRTStream.Size);
   var buffer = dataReader.ReadBuffer((uint)winRTStream.Size);
   using (System.IO.Stream oldRTStream = buffer.AsStream())
   {
      using (RasterImage rasterImage = codecs.Load(oldRTStream, loadBitsPerPixel, 
         CodecsLoadByteOrder.BgrOrGray, 1, 1))
      {
         DisplayText.Text = string.Format("Filename: {0} - {1}x{2}x{3} - {4}", 
            file.FileName, 
            rasterImage.Width, 
            rasterImage.Height, 
            rasterImage.BitsPerPixel, 
            rasterImage.OriginalFormat.ToString());
         Image1.Source = RasterImageConverter.ConvertToSource(rasterImage, 
            ConvertToSourceOptions.None);
      }
   }
}  

metroimageprocessing/filepicker_screen.jpg

我一直觉得原生图像处理功能不足,并且不介意使用第三方库,所以我尝试了之前项目中的 LEADTOOLS 评估版,看看它是否适用于新的 Windows 8。 .NET 4 库可以工作,但是为了将 LEADTOOLS RasterImage 类转换为新的 Metro ImageSource,我使用了他们的支持部门提供的预发布 DLL。

using (RasterImage image = RasterImageConverter.ConvertFromSource(Image1.Source, 
   ConvertFromSourceOptions.None))
{ 
   BricksTextureCommand cmd = new BricksTextureCommand(60, 20, 4, 3);
   cmd.Run(image);
   Image1.Source = RasterImageConverter.ConvertToSource(image, 
      ConvertToSourceOptions.None);
}

metroimageprocessing/ip_screen.jpg

总的来说,我喜欢新的 Metro 风格应用。试用开发者预览版很有趣,看到学习曲线很小,并且第三方组件也已经开始参与进来,而不是等待 Windows 8 “正式”发布,这让我感到欣慰。

关于 Visual Studio 11 Beta 和 Windows 8 消费者预览版的说明

当我最初编写这篇文章时,我使用了 Visual Studio 11 开发者预览版。 自那以后,我尝试了相同的示例,使用了 Visual Studio 11 Beta 和 Windows 8 消费者预览版,但由于 Metro 应用现在使用 .Netcore 而不是接受 .NET Framework 4.0 库,它不再起作用(有关更多详细信息,请参阅此论坛帖子)。

原生代码示例

应一些用户的要求,我附上了一个不使用任何第三方工具的图像处理应用。

这是我使用 FileOpenPicker 以编程方式加载图像的方式

FileOpenPicker openPicker = new FileOpenPicker();
openPicker.FileTypeFilter.Add(".jpg");
openPicker.FileTypeFilter.Add(".cmp");
openPicker.FileTypeFilter.Add(".png");
openPicker.FileTypeFilter.Add(".tif");
openPicker.FileTypeFilter.Add(".gif");
openPicker.FileTypeFilter.Add(".bmp");
StorageFile file = await openPicker.PickSingleFileAsync();
IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.Read);
BitmapImage bmp = new BitmapImage();
bmp.SetSource(stream);
Image1.Source = bmp;

这是翻转图像的代码。第一步是通过创建一个 WriteableBitmap 来访问像素数据。然后从图像的顶部和底部读取并交换行。

// Cast the image in the viewer as a WriteableBitmap
WriteableBitmap wb = Image1.Source as WriteableBitmap;

// If it's a WriteableBitmap, just use it, otherwise create one
if (wb == null) 
{
   BitmapSource bs = Image1.Source as BitmapSource;
   wb = new WriteableBitmap(bs);
}

// Assume 32 bits since that is what Metro currently supports
int stride = wb.PixelWidth * 4; 

// extension method defined in System.Runtime.InteropServices.WindowsRuntime
System.IO.Stream pixelStream = wb.PixelBuffer.AsStream(); 

byte[] row1 = new byte[stride];
byte[] row2 = new byte[stride];

// flip the image
for (int row = 0; row < wb.PixelHeight / 2; row++)
{
   pixelStream.Read(row2, 0, stride);
   pixelStream.Seek((wb.PixelHeight - row - 1) * stride, SeekOrigin.Begin);
   pixelStream.Read(row1, 0, stride);
   pixelStream.Seek(-stride, SeekOrigin.Current);
   pixelStream.Write(row2, 0, stride);
   pixelStream.Seek(row * stride, SeekOrigin.Begin);
   pixelStream.Write(row1, 0, stride);
}

wb.Invalidate();
Image1.Source = wb; 

metroimageprocessing/flip.jpg

历史

  • 2011 年 11 月 7 日:初始发布
  • 2011 年 11 月 11 日:添加了非第三方示例
  • 2012 年 4 月 4 日:添加了关于消费者预览版的说明
© . All rights reserved.