如何将大小为 19200 字节的字节数组(每个字节代表 4 个像素(每个像素 2 位))转换为按 320x240 字符排列的位图

发布于 2024-09-04 11:56:43 字数 663 浏览 5 评论 0原文

我正在与仪器通信(远程控制它)并且
我需要做的事情之一是绘制仪器屏幕。

为了获得屏幕,我发出命令和仪器
使用代表屏幕的字节数组进行回复。

以下是仪器手册有关将响应转换为实际屏幕的说明:

该命令检索用于显示的帧缓冲区数据。
它的大小为 19200 字节,每像素 2 位,每字节 4 像素排列为
320x240 字符。
数据以 RLE 编码形式发送。
要将这些数据转换为 BMP 以在 Windows 中使用,需要
变成了4BPP。另请注意,BMP 文件是相对颠倒的
对于此数据,即顶部显示行是 BMP 中的最后一行。

我设法解压数据,但现在我不知道如何实际
从解压的字节数组转换为位图。

我对此的背景几乎为零,我的搜索
也没有透露太多。

我正在寻找可以帮助我的方向和/或文章
了解如何完成这项工作。

任何代码甚至伪代码也会有帮助。 :-)

所以,总结一下:

如何转换大小为19200字节的字节数组,其中
每个字节代表 4 个像素(每个像素 2 位),
排列为 320x240 字符的位图。

提前致谢。

I am communicating with an instrument (remote controlling it) and
one of the things I need to do is to draw the instrument screen.

In order to get the screen I issue a command and the instrument
replies with an array of bytes that represents the screen.

Below is what the instrument manual has to say about converting the response to the actual screen:

The command retrieves the framebuffer data used for the display.
It is 19200 bytes in size, 2-bits per pixel, 4 pixels per byte arranged as
320x240 characteres.
The data is sent in RLE encoded form.
To convert this data into a BMP for use in Windows, it needs to be
turned into a 4BPP. Also note that BMP files are upside down relative
to this data, i.e. the top display line is the last line in the BMP.

I managed to unpack the data, but now I am stuck on how to actually
go from the unpacked byte array to a bitmap.

My background on this is pretty close to zero and my searches
have not revealed much either.

I am looking for directions and/or articles I could use to help me
undestand how to get this done.

Any code or even pseudo code would also help. :-)

So, just to summarize it all:

How to convert a byte array of 19200 bytes in size, where
each byte represents 4 pixels (2 bits per pixel),
to a bitmap arranged as 320x240 characters.

Thanks in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

暮倦 2024-09-11 11:56:43

要执行这样的操作,您需要这样的例程:

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

从这里开始,您需要 ReadPixelValue 和 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;        
}

基本上,我从每个字节中取出每组两位并将其作为 int 返回。

至于转换为颜色,这取决于您如何使返回的 4 个值成为头部或尾部。
您很可能可以这样做:

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

To do something like this, you'll want a routine like this:

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

from here, you need ReadPixelValue and 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;        
}

Basically, I pull each set of two bits out of each byte and return it as an int.

As for converting to color that's up to you how to make heads or tail of the 4 values that come back.
Most likely you can do something like this:

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];
}
活雷疯 2024-09-11 11:56:43

如果每个像素有两位,则每个像素有 4 种不同的可能颜色。颜色可能已索引或只是硬编码(即 0 表示黑色,1 表示白色等)。

不知道这是否有很大帮助(我不知道您正在使用什么位图对象,但也许它有一个常规的 RGB 或 ARGB 方案,每个通道 1 个字节),但在伪动作脚本中,我认为您应该做这样的事情。

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

可以说,上面的代码只是为了给您一个想法(希望如此!),并且基于一些假设,例如这四个像素如何存储在一个字节中。

希望这是有道理的。

If you have two bits per pixel, for each pixel you have 4 different possible colors. Probably the colors are indexed or just hardcoded (i.e. 0 means black, 1 white, etc).

Don't know if this is of much help ( I don't know what bitmap object you are using, but perhaps it has a regular RGB or ARGB scheme with 1 byte per channel), but in pseudo-actionscript, I think you should do something like this.

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

The above code, suffice it to say, is just to give you an idea (hopefully!) and is based on some assumptions like how these four pixels are stored in a byte.

Hope it makes sense.

九厘米的零° 2024-09-11 11:56:43

我不知道这是否有帮助,我将其用于从罕见的旧硬件获得的数据:

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

        }
    }
}

I dont know if this helps, I use this for data I got from a rare old 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

        }
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文