Чтение / сохранение растрового изображения PNG PixelFormat.Format48bppRgb в.NET?

Я смог создать файл Format48bppRgb .PNG (из некоторых внутренних данных HDR), используя следующий код C#:

Bitmap bmp16 = new Bitmap(_viewer.Width, _viewer.Height, System.Drawing.Imaging.PixelFormat.Format48bppRgb);
System.Drawing.Imaging.BitmapData data16 = bmp16.LockBits(_viewer.ClientRectangle, System.Drawing.Imaging.ImageLockMode.WriteOnly, bmp16.PixelFormat);
unsafe {  (populates bmp16) }
bmp16.Save( "C:/temp/48bpp.png", System.Drawing.Imaging.ImageFormat.Png );

ImageMagik (и другие приложения) проверяют, что это действительно изображение 16bpp:

C:\temp>identify 48bpp.png
48bpp.png PNG 1022x1125 1022x1125+0+0 DirectClass 16-bit 900.963kb

Однако я был разочарован, обнаружив, что при чтении PNG он был преобразован в Format32bppRgb при использовании:

Bitmap bmp = new Bitmap( "c:/temp/48bpp.png", false );
String info = String.Format("PixelFormat: {0}", bmp.PixelFormat );
...

Учитывая, что кодек PNG может записывать Format48bppRgb, есть ли способ использовать.NET для чтения без преобразования? Я не против, если это будет сделано для вызова DrawImage, но я хотел бы получить доступ к распакованным исходным данным для некоторой работы по обработке гистограммы / изображения.

2 ответа

Решение

К вашему сведению - я нашел решение.NET для этого с помощью System.Windows.Media.Imaging (я использовал строго WinForms/GDI+ - это требует добавления сборок WPF, но работает.) С этим я получаю Format64bppArgb PixelFormat, поэтому нет потерянная информация:

using System.Windows.Media.Imaging; // Add PresentationCore, WindowsBase, System.Xaml
...

    // Open a Stream and decode a PNG image
Stream imageStreamSource = new FileStream(fd.FileName, FileMode.Open, FileAccess.Read, FileShare.Read);
PngBitmapDecoder decoder = new PngBitmapDecoder(imageStreamSource, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
BitmapSource bitmapSource = decoder.Frames[0];

    // Convert WPF BitmapSource to GDI+ Bitmap
Bitmap bmp = _bitmapFromSource(bitmapSource);
String info = String.Format("PixelFormat: {0}", bmp.PixelFormat );
MessageBox.Show(info);

...

И этот фрагмент кода от: http://www.generoso.info/blog/wpf-system.drawing.bitmap-to-bitmapsource-and-viceversa.html

private System.Drawing.Bitmap _bitmapFromSource(BitmapSource bitmapsource) 
{ 
    System.Drawing.Bitmap bitmap; 
    using (MemoryStream outStream = new MemoryStream()) 
    { 
        // from System.Media.BitmapImage to System.Drawing.Bitmap 
        BitmapEncoder enc = new BmpBitmapEncoder(); 
        enc.Frames.Add(BitmapFrame.Create(bitmapsource)); 
        enc.Save(outStream); 
        bitmap = new System.Drawing.Bitmap(outStream); 
    } 
    return bitmap; 
} 

Если кто-нибудь знает способ сделать это, который не требует WPF, пожалуйста, поделитесь!

Использование Image.FromFile(String, Boolean) или же Bitmap.FromFile(String, Boolean)

И установите для логического значения значение true. Все свойства изображения будут сохранены в новом изображении.

Здесь String это имя файла с полным путем...

Если изображение уже загружено в программу и вы хотите создать новый растровый рисунок, вы также можете использовать

MemoryStream ms = new MemoryStream();
img.Save(ms, ImageFormat.Bmp); // img is any Image, previously opened or came as a parameter
Bitmap bmp = (Bitmap)Bitmap.FromStream(ms,true);

Общая альтернатива

Bitmap bmp = new Bitmap(img); // this won't preserve img.PixelFormat
Другие вопросы по тегам