Cómo convertir una matriz de bytes de 19200 bytes en tamaño donde cada byte representa 4 píxeles (2 bits por píxel) a un mapa de bits dispuesto como 320x240 caracteres

StackOverflow https://stackoverflow.com/questions/2969208

  •  24-10-2019
  •  | 
  •  

Pregunta

Me estoy comunicando con un instrumento (controlándolo remoto) y
Una de las cosas que necesito hacer es dibujar la pantalla del instrumento.

Para obtener la pantalla, emito un comando y el instrumento
responde con una matriz de bytes que representa la pantalla.

A continuación se muestra lo que el manual del instrumento tiene que decir sobre la conversión de la respuesta a la pantalla real:

El comando recupera los datos de FrameBuffer utilizados para la pantalla.
Tiene 19200 bytes de tamaño, 2 bits por píxel, 4 píxeles por byte dispuesto como
320x240 caracteres.
Los datos se envían en forma codificada RLE.
Para convertir estos datos en un BMP para su uso en Windows, debe ser
se convirtió en un 4bpp. También tenga en cuenta que los archivos BMP están al revés relativos
A estos datos, es decir, la línea de visualización superior es la última línea en el BMP.

Me las arreglé para desempacar los datos, pero ahora estoy atrapado en cómo realmente
Ve de la matriz de byte desempaquetada a un mapa de bits.

Mi experiencia en esto está bastante cerca de cero y mis búsquedas
tampoco he revelado mucho.

Estoy buscando instrucciones y/o artículos que pueda usar para ayudarme
Dusta cómo hacer esto.

Cualquier código o incluso el código pseudo también ayudaría. :-)

Entonces, solo para resumirlo todo:

Cómo convertir una matriz de bytes de 19200 bytes en tamaño, donde
Cada byte representa 4 píxeles (2 bits por píxel),
a un mapa de bits dispuesto como 320x240 caracteres.

Gracias por adelantado.

¿Fue útil?

Solución

Para hacer algo como esto, querrás una rutina como esta:

Bitmap ConvertToBitmap(byte[] data, int width, int height)
{
    Bitmap bm = new Bitmap(width, height, PixelFormat.Format24bppRgb);
    for (int y=0; y < height; y++) {
        for (int x=0; x < width; x++) {
            int value = ReadPixelValue(data, x, y, width);
            Color c = ConvertValToColor(value);
            bm.SetPixel(x, y, c);
        }
    }
    return bm;
}

Desde aquí, necesita ReadPixElvalue y Convervaltocolor.

static int ReadPixelValue(byte[] data, int x, int y, width)
{
    int pixelsPerByte = 4;
    // added the % pixelsPerByte to deal with width not being a multiple of pixelsPerByte,
    // which won't happen in your case, but will in the general case
    int bytesPerLine = width / pixelsPerByte + (width % pixelsPerByte != 0 ? 1 : 0);
    int index = y * bytesPerLine + (x / pixelsPerByte);
    byte b = data[index];

    int pixelIndex = (x % pixelsPerByte) * 2;
    // if every 4 pixels are reversed, try this:
    // int pixelIndex = 8 - (x % pixelsPerByte) * 2;
    return ((int b) >> pixelIndex) & 0x3;        
}

Básicamente, saco cada conjunto de dos bits de cada byte y lo devuelvo como un int.

En cuanto a convertir en color que depende de usted cómo hacer cabezas o cola de los 4 valores que regresan. Lo más probable es que puedas hacer algo como esto:

static Color[] _colors = new Color[] { Color.Black, Color.Red, Color.Blue, Color.White };
static Color ConvertValToColor(int val)
{
    if (val < 0 || val > _colors.Length)
        throw new ArgumentOutOfRangeException("val");
    return _colors[val];
}

Otros consejos

Si tiene dos bits por píxel, para cada píxel tiene 4 colores posibles diferentes. Probablemente los colores están indexados o simplemente codificados (es decir, 0 significa negro, 1 blanco, etc.).

No sé si esto es de mucha ayuda (no sé qué objeto de mapa de bits está utilizando, pero tal vez tenga un esquema RGB o argb regular con 1 byte por canal), pero en pseudocionscript, creo que debería Haz algo como esto.

//  80 -> 320 / 4
for(var x:int = 0; x < 80; x++) {
    for(var y:int = 0; y < 240; y++) {
        var byteVal:int = readByte();

        var px_1:int = (byteVal >> 6) & 0x03;
        var px_2:int = (byteVal >> 4) & 0x03;
        var px_3:int = (byteVal >> 2) & 0x03;
        var px_4:int = (byteVal) & 0x03;

        //  map your pixel value to ARGB 
        px_1 = getPixelValue(px_1);
        px_2 = getPixelValue(px_2);
        px_3 = getPixelValue(px_3);
        px_4 = getPixelValue(px_4);     
        //  assuming setPixel(x,y,pixelValue)
        setPixel((x * 4), y, px_1);
        setPixel((x * 4) + 1, y, px_2);
        setPixel((x * 4) + 2, y, px_3);
        setPixel((x * 4) + 3, y, px_4);


    }
}

function getPixelValue(idx:int):uint {
    //   just an example...
    switch(idx) {
        case 0:     return 0xff000000;  //  black
        case 1:     return 0xffffffff;  //  white
        case 2:     return 0xffff0000;  //  red
        case 3:     return 0xff0000ff;  //  blue
    }
}

El código anterior, es suficiente decir, es solo darle una idea (¡con suerte!) Y se basa en algunas suposiciones como cómo se almacenan estos cuatro píxeles en un byte.

Espero que tenga sentido.

No sé si esto ayuda, uso esto para los datos que obtuve de un hardware antiguo raro:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.IO;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            byte[] imageBytes = new byte[19201];
            //(Fill it with the data from the unit before doing the rest).
            Bitmap bmp_workarea = new Bitmap(320, 240, System.Drawing.Imaging.PixelFormat.Format4bppIndexed);
            Image newImage = Image.FromStream(new MemoryStream(imageBytes));
            using (Graphics gr = Graphics.FromImage(bmp_workarea))
            {
                gr.DrawImage(newImage, new Rectangle(0, 0, bmp_workarea.Width, bmp_workarea.Height));
            }
            //now you can use newImage, for example picturebox1.image=newimage

        }
    }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top