Come convertire un array di byte di 19200 byte dimensioni dove ogni byte rappresenta 4 pixel (2 bit per pixel) a una bitmap organizzato come 320x240 caratteri

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

  •  24-10-2019
  •  | 
  •  

Domanda

sto comunicando con uno strumento (controllo a distanza) e
una delle cose che devo fare è quello di disegnare lo schermo dello strumento.

Al fine di ottenere lo schermo ho emettere un comando e lo strumento
risponde con un array di byte che rappresenta lo schermo.

Di seguito è ciò che il manuale dello strumento ha da dire sulla conversione della risposta allo schermo vero e proprio:

Il comando recupera i dati framebuffer utilizzati per la visualizzazione.
E '19200 byte di dimensione, 2 bit per pixel, 4 pixel per byte disposti come
320x240 characteres.
I dati vengono inviati in RLE codificato modulo.
Per convertire questi dati in un file BMP per l'uso in Windows, ha bisogno di essere
trasformato in un 4bpp. Si noti inoltre che i file BMP sono a testa in giù relativi
a questi dati, cioè la riga superiore del display è l'ultima linea nel BMP.

Sono riuscito a decomprimere i dati, ma ora mi sono bloccato su come in realtà
andare dalla matrice di byte decompressi bitmap.

La mia formazione su questo è abbastanza vicino a zero e le mie ricerche
non hanno rivelato molto.

Sto cercando le direzioni e / o articoli ho potuto usare per aiutarmi
undestand come per ottenere questo fatto.

Qualsiasi codice o addirittura pseudo contribuirebbe anche. :-)

Così, tanto per riassumere il tutto:

Come convertire un array di byte di 19200 byte in termini di dimensioni, dove
ogni byte rappresenta 4 pixel (2 bit per pixel),
a una bitmap disposti come 320x240 caratteri.

Grazie in anticipo.

È stato utile?

Soluzione

Per fare una cosa del genere, ti consigliamo una routine come questa:

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;
}

da qui, è necessario ReadPixelValue e ConvertValToColor.

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;        
}

Fondamentalmente, tirare ogni serie di due bit di ciascun byte e lo restituisce come int.

Per quanto riguarda la conversione in colore che sta a voi come fare testa o la coda dei 4 valori che ritornano. Molto probabilmente si può fare qualcosa di simile:

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];
}

Altri suggerimenti

Se si dispone di due bit per pixel, per ogni pixel si dispone di 4 diversi colori possibili. Probabilmente i colori sono indicizzati o solo hardcoded (cioè 0 significa nero, 1 bianco, ecc).

Non so se questo è di grande aiuto (non so quale oggetto bitmap che si sta utilizzando, ma forse ha un normale schema RGB o ARGB con 1 byte per canale), ma in pseudo-codice ActionScript, I pensa di dover fare qualcosa di simile.

//  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
    }
}

Il codice di cui sopra, è sufficiente dire, è solo per dare un'idea (si spera!) E si basa su alcune ipotesi come come questi quattro pixel sono memorizzati in un byte.

La speranza ha un senso.

Non so se questo aiuta, io uso questo per i dati che ho avuto da un raro vecchio hardware:

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

        }
    }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top