再聊.NET解相機RAW格式照片
上次我發了一篇文章《用.NET解索尼相機ARW格式照片》,提到通過安裝Sony Raw File Decoder的方式,然后調用Windows Imaging Components來解析RAW格式文件。后來我經過進一步研究、探索,發現還有更簡單的辦法。
新的方法實在是太簡單、好用了,相比之下,我前一篇文章簡直就是在“挖坑”。
其實啥都不裝,什么相機都支持!
其實Windows 10自帶了一個RAW格式解碼器,也集成在Windows Imaging Components中,通過SharpDX.Direct2D1的幾行代碼,可以將這個解碼器的信息調出來:
// 安裝NuGet包:SharpDX.Direct2D1
using var wic = new ImagingFactory2();
using var decoder = new BitmapDecoder(wic, file, DecodeOptions.CacheOnDemand);
string json = JsonSerializer.Serialize(decoder.DecoderInfo, new JsonSerializerOptions { WriteIndented = true });
Console.WriteLine(json);
運行結果如下(為突出重點,有少量刪減):
{
"PixelFormats": [
"6fddc324-4e03-4bfe-b185-3d77768dc90d"
],
"ColorManagementVersion": "1.0.0.0\u0000",
"MimeTypes": "image/3FR,image/ARI,image/ARW,image/BAY,image/CAP,image/CR2,image/CR3,image/CRW,image/DCS,image/DCR,image/DRF,image/EIP,image/ERF,image/FFF,image/IIQ,image/K25,image/KDC,image/MEF,image/MOS,image/MRW,image/NEF,image/NRW,image/ORF,image/ORI,image/PEF,image/PTX,image/PXN,image/RAF,image/RAW,image/RW2,image/RWL,image/SR2,image/SRF,image/SRW,image/X3F,image/DNG\u0000",
"FileExtensions": ".3FR,.ARI,.ARW,.BAY,.CAP,.CR2,.CR3,.CRW,.DCS,.DCR,.DRF,.EIP,.ERF,.FFF,.IIQ,.K25,.KDC,.MEF,.MOS,.MRW,.NEF,.NRW,.ORF,.ORI,.PEF,.PTX,.PXN,.RAF,.RAW,.RW2,.RWL,.SR2,.SRF,.SRW,.X3F,.DNG\u0000",
"ContainerFormat": "fe99ce60-f19c-433c-a3ae-00acefa9ca21",
"IsAnimationSupported": false,
"IsChromakeySupported": false,
"IsLosslessSupported": true,
"IsMultiframeSupported": false,
"Author": "Microsoft Corporation\u0000",
"Version": "10.0.18362.1\u0000",
"SpecVersion": "1.0.0.0\u0000",
"FriendlyName": "Microsoft Raw Image Decoder\u0000",
"ComponentType": 1,
"CLSID": "41945702-8302-44a6-9445-ac98e8afa086",
"SigningStatus": 1,
"VendorGUID": "f0e749ca-edef-4589-a73a-ee0e626a2a2b",
}
可見,什么都不用裝,就已經支持了高達36種RAW格式文件,索尼的.ARW、佳能的.CR2和.CR3和尼康的.NEF都在列——就可能就是為什么Windows 10可以直接打開相機的RAW格式文件。
使用上次文章中的同樣代碼,即可將.ARW格式文件轉換為jpeg:
// 依賴於WPF,不用裝NuGet包
var decoder = BitmapDecoder.Create(new Uri(@"DSC05458.ARW"), BitmapCreateOptions.None, BitmapCacheOption.Default);
var transformedBitmap = new TransformedBitmap(decoder.Frames[0], Transform.Identity);
var jpg = new JpegBitmapEncoder();
jpg.Frames.Add(BitmapFrame.Create(transformedBitmap));
using var stream = new MemoryStream();
jpg.Save(stream);
上次還挖了個坑說如果是我,一般會選擇用SharpDX而不是WPF,但我又沒說SharpDX的代碼該怎么寫,這里面我將SharpDX的代碼貼出來(運行效果完全一樣):
// 安裝NuGet包:SharpDX.Direct2D1
using var wic = new ImagingFactory2();
using FormatConverter converter = LoadImage(wic, @"DSC00115.ARW");
Util.Image(SaveToJpeg(wic, converter)).Dump();
static byte[] SaveToJpeg(ImagingFactory2 wic, BitmapSource source)
{
using var ms = new MemoryStream();
using (var encoder = new JpegBitmapEncoder(wic, ms))
{
using (var frame = new BitmapFrameEncode(encoder))
{
frame.Options.ImageQuality = 0.7f;
frame.Initialize();
frame.WriteSource(source);
frame.Commit();
}
encoder.Commit();
}
return ms.ToArray();
}
static FormatConverter LoadImage(ImagingFactory2 wic, string file)
{
using var decoder = new BitmapDecoder(wic, file, DecodeOptions.CacheOnDemand);
decoder.Dump();
var converter = new FormatConverter(wic);
converter.Initialize(decoder.GetFrame(0), PixelFormat.Format32bppPBGRA);
return converter;
}
代碼中我加入了縮放,運行上次的.ARW文件后,可以得出一樣的jpeg圖片。
跨平台?沒問題!
故名思義Windows Imaging Componnets,顯然只有Windows上才能運行。想跨平台讀取相機RAW格式文件就必須另找一個庫——Magick.NET,其使用也非常簡單,甚至比WIC更簡單,只要兩行代碼!:
// 安裝NuGet包:Magick.NET-Q8-AnyCPU
using var image = new MagickImage(@"DSC00115.ARW");
byte[] bytes = image.ToByteArray(MagickFormat.Jpeg);
除了讀取保存,Magick.NET還能縮放圖片、轉換pdf、加水印、讀取Exif數據、無損壓縮、繪圖等功能,具體功能可以參見:https://github.com/dlemstra/Magick.NET/blob/master/docs/Readme.md。
另外,Magick.NET還支持超過200種圖片格式,其中甚至還包括Photoshop的psd文件。可以在這個鏈接中查看是否支持你所需要的格式:https://imagemagick.org/index.php
……更別它還可以跨平台。
有一點需要注意,它的NuGet包有許多個,初一看可能會一驚:

這里可以說一下,首先它有Q8、Q16和Q16-HDRI三種版本:
Q8表示一個像素使用8位顏色深度,它占用內存最小;Q16表示一個像素使用16位顏色深度,比Q8多一倍;Q16-HDRI則使用32位浮點型來表示顏色,比Q16再多一倍;
正常使用建議Q8即可,有微單/單反修圖需求的,可以考慮Q16/Q16-HDRI。
另外它還有x86、x64和AnyCPU三個平台版本,一般選AnyCPU,但注意Magick.NET是基於本地代碼,因此它需要下載多個平台,因此AnyCPU大小(45.34MB)比x64(20.85MB)大一倍。
缺點?
有這么多優點,還要什么自行車?……其實它也是有缺點的,有個明顯的缺點,就是性能慢。我測試了上次那張ARW格式文件,性能分析如下(平均需要3.7秒):
| 次數 | 分配內存 | 內存提高 | 耗時 |
|---|---|---|---|
| 1 | 43,918,792 | 1,080 | 3739 |
| 2 | 43,884,944 | 160 | 3748 |
| 3 | 43,966,000 | 664 | 3878 |
| 4 | 44,015,928 | 80 | 3778 |
| 5 | 43,902,784 | 416 | 3747 |
換成WIC,性能數據如下,耗時只要705毫秒,明顯快得多:
| 次數 | 分配內存 | 內存提高 | 耗時 |
|---|---|---|---|
| 1 | 11,939,072 | 1,488 | 713 |
| 2 | 11,939,768 | 10,256 | 709 |
| 3 | 12,013,872 | 4,608 | 705 |
| 4 | 11,931,664 | 96 | 705 |
| 5 | 11,919,384 | -25,968 | 704 |
總結
如果你用Windows 10,則什么都不用裝,就能體驗到極致性能的RAW解析工具,因為系統自帶了Microsoft Raw Image Decoder。
如果你想跨平台(但不特別在意性能),則可以使用開源的Magick.NET,它提供最便利的API和最省心的功能、格式支持,特別強大。但話又說回來,RAW這種東西一般都是騷操作才需要,誰在意跨平台呢?
我也特意試了一下收費的Aspose.Imaging,但解析RAW格式文件不是它的長項,直接不支持。
本想研究一下libraw,但它只提供了C API——也不是不能用。正准備用P/Invoke時剛正面就有了本文中的發現。
喜歡的朋友 請關注我的微信公眾號:【DotNet騷操作】

