Necesito enmascarar la imagen de los búferes de memoria (área rectangular llena de negro). Así que ingenuamente reutilizo clase de mapa de bits con ImageFormat.MemoryBmp para mi API. Esto funciona bastante bien en mi máquina local:

public static void MaskBitmap(Bitmap input, Rectangle maskRegion)
{
    var bytesPerPixel = Image.GetPixelFormatSize(input.PixelFormat) / 8;
    var row = new byte[maskRegion.Width * bytesPerPixel];

    var maskData = input.LockBits(maskRegion, ImageLockMode.WriteOnly, input.PixelFormat);
    for (var i = 0; i < maskData.Height; ++i)
    {
        Marshal.Copy(row, 0, maskData.Scan0 + (i * maskData.Stride), row.Length);
    }
    input.UnlockBits(maskData);
}

Sin embargo, cuando se implementa en producción, resulta que lo siguiente arroja un NotImplementedException:

var image16 = new Bitmap(512, 512, PixelFormat.Format16bppGrayScale);

Finalmente lo rastreé hasta aquí:

Entonces mi pregunta es: ¿hay alguna clase existente en c # que pueda reutilizar para contener imágenes de pixelformat tipo:

  • PixelFormat.Format8bppIndexed:
  • PixelFormat.Format16bppGrayScale:
  • PixelFormat.Format24bppRgb:

Sé que GDI + no admite guardar / mostrar imágenes de 16 bits, simplemente necesito una estructura de memoria con acceso de estilo de imagen.


Solo como referencia, probé el siguiente truco:

var image = new Bitmap(512,512,PixelFormat.Format24bppRgb);
image.Flags = ImageFlags.ColorSpaceGray;

Pero Flags es de solo lectura.

1
malat 5 oct. 2021 a las 12:12

2 respuestas

La mejor respuesta

Como puede ver, GDI + Bitmap no es compatible con el formato de píxeles en escala de grises de 16bpp en Linux y, en realidad, su compatibilidad también es bastante limitada en Windows. Una vez que haya recopilado las limitaciones para ambas plataformas, consulte la tabla en la sección Restricciones de posibles formatos de píxeles en diferentes plataformas aquí.

Necesito enmascarar la imagen de los búferes de memoria

Para usar una representación en memoria completamente administrada de un mapa de bits tanto en Linux como en Windows, puede usar esta biblioteca (descargo de responsabilidad: escrito por mí). Puede crear datos de mapa de bits en escala de grises de 16bpp con Bitmap. / code>, que devuelve un IReadWriteBitmapData < / code> que permite una gran cantidad de operaciones administradas (consulte el enlace que incluye los métodos de extensión utilizables). Incluso puede convertirlo en un mapa de bits real con ToBitmap extensión, pero en Linux esto convierte el resultado en un Bitmap con formato de píxel RGB de 24bpp.

Ejemplo:

var image16 = BitmapDataFactory.CreateBitmapData(new Size(512, 512), PixelFormat.Format16bppGrayScale);
var row = image16.FirstRow;
do
{
    for (int x = 0; x < image16.Width; x++)
    {
        // row[x] uses a Color32 structure (8 bit per color) but raw access
        // enables you to use the full 16-bit color range:
        row.WriteRaw<ushort>(x, 32768); // 50% gray
    }
} while (row.MoveNextRow());


En cuanto a los formatos 8bpp indexados y 24bpp RGB, estos son compatibles con el Bitmap nativo también en Linux, pero tenga en cuenta que a partir de la versión .NET 6 System.Drawing se admitirá solo en Windows de forma predeterminada . Microsoft recomienda usar otras bibliotecas en su lugar, pero aún puede habilitar el soporte de Unix agregando "System.Drawing.EnableUnixSupport": true a runtimeconfig.json. O, si decide usar mi biblioteca que mencioné anteriormente, simplemente llame a DrawingModule.Initialize() antes que nada, que habilita la compatibilidad con Unix sin editar ningún archivo de configuración.

1
György Kőszeg 5 oct. 2021 a las 10:38

Creo que Wpf los mapas de bits deberían admitir una escala de grises de 16 bits.

Sin embargo, la mayoría de los sistemas en los que he trabajado que utilizan imágenes en escala de grises de 16 bits utilizan un tipo de datos personalizado. Algo como:

public class My16BitImage{
    public ushort[] Data {get;}
    public int Width {get;}
    public int Height {get;}
}

Tenga en cuenta que para mostrar la imagen probablemente necesite convertirla en una imagen de 8 bits de todos modos, y probablemente necesite escalar los valores para hacer que los valores máximo / mínimo se asignen a los valores de 8 bits más grandes / más pequeños.

1
JonasH 5 oct. 2021 a las 09:31