2016-09-21 4 views
0

У меня есть эта функция, которая преобразует массив ushort в изображение в оттенках серого. Я преобразую конверты для преобразования значений в байтовый массив, а затем использую BitmapEncoder.Unsupported PixelFormat - SetPixelData

public static async Task<StorageFile> WriteableBitmapToStorageFile(ushort[,] image, bool isScaleValues, List<KeyValuePair<string, BitmapTypedValue>> metadata) 
    { 
     //Setup image 
     var imgHeight = image.GetLength(0); 
     var imgWidth = image.GetLength(1); 
     float maxVal = 1; 
     if (isScaleValues) 
     { 
      for (int i = 0; i < imgHeight; i++) 
      { 
       for (int j = 0; j < imgWidth; j++) 
       { 
        if (maxVal < image[i, j]) 
        { 
         maxVal = image[i, j]; 
        } 
       } 
      } 
     } 
     byte[] data = new byte[imgWidth * imgHeight]; 
     if (image != null) 
     { 
      if (isScaleValues) 
      { 
       for (int x = 0; x < imgHeight; x++) 
        for (int y = 0; y < imgWidth; y++) 
         data[x * imgWidth + y] = (byte)(((double)UInt16.MaxValue * (double)image[x, y])/(double)maxVal); 
      } 
      else 
      { 
       for (int x = 0; x < imgHeight; x++) 
        for (int y = 0; y < imgWidth; y++) 
         data[x * imgWidth + y] = (byte)image[x, y]; 
      } 
     } 

     string FileName = "MyFile.png"; 
     var file = 
      await 
       Windows.Storage.ApplicationData.Current.TemporaryFolder.CreateFileAsync(FileName, 
        CreationCollisionOption.GenerateUniqueName); 
     using (IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.ReadWrite)) 
     { 
      BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, stream); 
      encoder.SetPixelData(BitmapPixelFormat.Gray16, BitmapAlphaMode.Ignore, 
       (uint) imgWidth, 
       (uint) imgHeight, 
       2822.222222222222, 
       2822.222222222222, 
       data); 
      await encoder.BitmapProperties.SetPropertiesAsync(metadata); 
      await encoder.FlushAsync(); 
     } 
     return file; 
    } 

Я получаю это исключение в SetPixelData:

Исключение типа 'System.ArgumentException' произошло в mscorlib.ni.dll, но не был обработан в пользовательском коде

WinRT информация: Windows.Graphics.Imaging: формат растрового пикселя не поддерживается.

Дополнительная информация: Неверный параметр.

Windows.Graphics.Imaging: Формат растрового изображения не поддерживается.

Спасибо в продвинутом виде.

E: Двухмерный массив ushort уже представляет собой 16-битное изображение в оттенках серого, а первое измерение - это высота, а второе - ширина. Поскольку оттенки серого, по-видимому, не поддерживаются, мне нужно будет сохранить его как Rgba16, Soo вопрос: How to convert grayscale to RBG ? ... AFAK, мне просто нужно установить все R, G, B на одно и то же значение, но как бы поместить значения в массив.

Что такое формат RGBA16 в двоичном формате?

+0

Выбор формата пикселей в оттенках серого 16bpp кажется странным. Исходные данные имеют разрешение 8bpp. Кодирование с 16bpp не волшебным образом добавляет какую-либо информацию. В чем смысл этого? 'BitmapPixelFormat.Gray8' представляется более подходящим. – IInspectable

+0

Оба не работают. Но, чтобы уточнить, массив байтов изначально был также массивом ushort, но мне пришлось изменить его на байт, потому что 'SetPixelData' принимает только 8-битный байт. Хотя у него есть опция для оттенков серого 16 .. вот где это становится действительно странным. – Ahmad45123

+0

Перечисление «BitmapPixelFormat» также используется в других местах. Это не придумано только для интерфейса растрового кодировщика. Во всяком случае, вы уже знаете, что формат пикселей не поддерживается (из описания исключения). Нет смысла использовать его. – IInspectable

ответ

0

Поскольку у вас был двумерный массив ushort, он содержит 16 градаций серого. Я бы предложил вам использовать этот массив, чтобы создать SoftwareBitmap с Gray16 пиксельным форматом, а затем использовать метод SoftwareBitmap.Convert для его преобразования в Rgba16 пикселей.

BitmapPixelFormat.Gray16 представляет собой 16 пикселей в пикселях в пикселях, что означает, что каждый пиксель занимает два байта. Таким образом, нам нужен массив байтов, длина которого вдвое превышает массив ushort и использует метод BitConverter.GetBytes(UInt16) для преобразования ushort в byte[]. Ниже приведен простой пример:

ushort[,] image = { { ushort.MinValue, ushort.MaxValue, ushort.MaxValue }, { ushort.MaxValue, ushort.MinValue, ushort.MaxValue }, { ushort.MaxValue, ushort.MaxValue, ushort.MinValue } }; 

var imgHeight = image.GetLength(0); 
var imgWidth = image.GetLength(1); 

byte[] data = new byte[image.Length * 2]; 

for (int i = 0; i < imgHeight; i++) 
{ 
    for (int j = 0; j < imgWidth; j++) 
    { 
     byte[] byteArray = BitConverter.GetBytes(image[i, j]); 

     data[i * imgWidth * 2 + j * 2] = byteArray[0]; 

     data[i * imgWidth * 2 + j * 2 + 1] = byteArray[1]; 
    } 
} 

//Create a SoftwareBitmap with 16 bpp grayscale pixel format 
var softwareBitmap = new SoftwareBitmap(BitmapPixelFormat.Gray16, imgWidth, imgHeight); 
softwareBitmap.CopyFromBuffer(data.AsBuffer()); 

//Convert pixel format to Rgba16 so that we can save it to the file 
softwareBitmap = SoftwareBitmap.Convert(softwareBitmap, BitmapPixelFormat.Rgba16); 

var outputFile = await ApplicationData.Current.TemporaryFolder.CreateFileAsync("MyFile.png", CreationCollisionOption.GenerateUniqueName); 

//Save softwareBitmap to file 
using (IRandomAccessStream stream = await outputFile.OpenAsync(FileAccessMode.ReadWrite)) 
{ 
    // Create an encoder with the desired format 
    BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, stream); 

    // Set the software bitmap 
    encoder.SetSoftwareBitmap(softwareBitmap); 

    await encoder.FlushAsync(); 
} 
+0

Просто увидел это сейчас .. Я использовал стороннюю библиотеку. Я посмотрю, будет ли это работать, я буду отмечать это как ответ. – Ahmad45123

+0

Привет @ Ahmad45123, любое обновление? Дозировать мое решение? Если у вас все еще есть проблемы, пожалуйста, сообщите мне. –