简体   繁体   中英

Convert RGB 444 to a displayable image

I have a weird image format here used in an embedded device, and as usual the documentation is not helping ...

Here are the two lines of doc:

The image is:

Full color bitmap (4+4+4bit per pixel), 3 bytes per two pixels (pixelorder from left to right).

So, in order to be able to get an image our of a sequence of bytes, I have coded the following:

// size_x and size_y are known at this point
QImage img(size_x, size_y, QImage::Format_RGB444); 
int xctr = 0;
int yctr = 0;
for(int c1 = 0; c1 < bsize; ) // bsize is the size of image bytes
{
    static const int M = 1; // a multiplier to make the image brighter
    uint8_t b1 = *(p_pos + c1++); // p_pos points to the first image byte
    uint8_t b2 = *(p_pos + c1++);
    uint8_t b3 = *(p_pos + c1++);

    uint8_t pix1_r =( (b1 & 0xF0) >> 4 ) * M;
    uint8_t pix1_g =( (b1 & 0xF) ) * M;
    uint8_t pix1_b =( (b2 & 0xF0) >> 4 ) * M;

    uint8_t pix2_r =( (b2 & 0xF) ) * M;
    uint8_t pix2_g =( (b3 & 0xF0) >> 4 ) * M;
    uint8_t pix2_b =( (b3 & 0xF) ) * M;

    // old code
    //unsigned int pix1 = pix1_r << 8 | pix1_g << 4 | pix1_b;
    //unsigned int pix2 = pix2_r << 8 | pix2_g << 4 | pix2_b;

    // new code
    unsigned int pix1 = ((unsigned int)pix1_r) << 8 | pix1_g << 4 | pix1_b;
    unsigned int pix2 = ((unsigned int)pix2_r) << 8 | pix2_g << 4 | pix2_b;

    // set the first pixel
    img.setPixel(xctr, yctr, pix1);
    xctr ++;
    if(xctr == size_x) {
        xctr = 0;
        yctr ++;
    }

    // set the second pixel
    img.setPixel(xctr, yctr, pix2);
    xctr ++;
    if(xctr == size_x) {
        xctr = 0;
        yctr ++;
    }
}

And here is the image I get as a result from this:

我的形象

And here is an image (very similar to what) I am supposed to get (only the blue/magenta parts, please don't consider the black background and the snow :) ):

我所期待的

For the brave ones, the image data: http://pastebin.com/m4y8qamB and please feel free to use this Python creating an array from hex bytes to convert the raw data to "real" hex bytes.

And the question: Now, ignoring the image palette, which is embedded in the device itself, what am I doing wrongly that I do not obtain a similar image to the one expected? And what should I do obtain a similar image?

Edit After adding some printout of the decoded values (and printing chars), I get something like:

PPPPPPPPPPPPPPPPPPPAPPPPPPPPPPPP
PPPPPPPAPPPPPPPPPPPPPPPPPPPAPPPP
PPPPPPPPPPPPPPPAPPPPPPPPPPPPPPPP
PPPAPPPPPPPPPPPPPPPPPPPAPPPPPPPP
PPPPPPPPPPPAPPPPPPPPPPPPPPPPPPPA
PPPPPPPPPPPPPPPPPPPAPPPPPPPPPPPP
PPPPPPPAPPPPPPPPPPPPPPPPPPPAPPPP
PGPPPPPPPPPPPPPAPPPPPCANMMMMMMMM
MMMMAMMMMOPCALDDDDDDDDDDDADDDMPC
ANODDDDDDDDDDDDADDKPANPCAGMMMMMM
MMMMMMAMMNPCANPCANPCANPCANPCANPC
ANPCANPPPAPPANPCANPCANPCANPCANPC
ANPCANPCADDADDPCANPCANPCANPCANPC
ANPCANPCANPCMMAMMMMMMMMMMMMMMMMM
MMAMMMMMMMMMMMMMMMMMMMAMMMMMMMMM
MMMMMMMMMMAMMMMMMMMMMMMMMMMMMMAM
MMMMMMMMMMMMMMMMMMAMMMMMMMMMMMMM
MMMMMMAMMMMMMMMMMMMMMMMMMMAMMMMM
MMMMMMMMMMMMMMAMMMMMMMMMMMMMMMMM
MMAMMMMMMMMMMMMMMMMMMMAMMMMMMMMM

I converted the pastebin data to a binary file using

perl -pe 's/([0-9a-f]{2})\s+/chr(hex($1))/ige' > tempfile

which seems correct when i look at the hex dump of that file.

Then i wrote a program to decode that file:

    #include <stdio.h>

    typedef unsigned char uint8_t;
    #define M 1

    int main(void) {
            FILE *fp;

            int sizex, sizey;
            int xctr, yctr;
            int i=0;

            if ((fp=fopen("tempfile", "rb"))==NULL) {
                    perror("tempfile"); exit(1);
            }
            sizey=getc(fp);
            sizex=getc(fp);
            int bsize=getc(fp)*256;
            bsize+=getc(fp);

            xctr=yctr=0;
            for (i=0; i<bsize/3; i++) {
                    uint8_t b1=getc(fp);
                    uint8_t b2=getc(fp);
                    uint8_t b3=getc(fp);

                    uint8_t pix1_r =( (b1 & 0xF0) >> 4 ) * M;
                    uint8_t pix1_g =( (b1 & 0xF) ) * M;
                    uint8_t pix1_b =( (b2 & 0xF0) >> 4 ) * M;

                    uint8_t pix2_r =( (b2 & 0xF) ) * M;
                    uint8_t pix2_g =( (b3 & 0xF0) >> 4 ) * M;
                    uint8_t pix2_b =( (b3 & 0xF) ) * M;

                    unsigned int pix1 = ((unsigned int)pix1_r) << 8 | pix1_g << 4 | pix1_b;
                    unsigned int pix2 = ((unsigned int)pix2_r) << 8 | pix2_g << 4 | pix2_b;

                    printf("%3x ", pix1);
                    xctr++;
                    if (xctr==sizex) {
                            putchar('\n');
                            xctr=0;
                    }
                    printf("%3x ", pix2);
                    xctr++;
                    if (xctr==sizex) {
                            putchar('\n');
                            xctr=0;
                    }
            }
    }

which does more or less what yours does, and has the output:

    393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393
    393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393
    393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393
    393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393
    393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393
    393 393 393 393 393 393 393 999 ddd eee bcc 393 393 999 fd0 2fd 02f d02 fd0 2f9 993 933 933 933 939 99f fd0 2fd
    02f d02 fd0 2fd 02f ccc 666 ffd 02f d02 fd0 2fd 02f d02 fd0 2fd 029 993 933 933 93d ddf fd0 2fd 02f d02 fd0 2fd
    02f d02 fd0 2ee eff d02 fd0 2fd 02f d02 fd0 2fd 02f d02 ddd 393 393 393 fd0 2fd 02f d02 bbb 393 bcc ffd 02f d02
    fd0 1ee 393 393 bbb ffd 02f d02 f39 339 339 3fd 02f d02 fd0 239 339 339 3ee efd 02f 999 393 393 393 ffd 02f d02
    f39 339 339 3fd 02f d02 fd0 2aa a39 399 9ff d02 fd0 2fd 01e e39 339 399 9ff d02 fd0 2f3 933 933 93d ddf fd0 2fd
    02f d02 fd0 2fd 02f d02 fd0 2fd 02f d02 fd0 2fd 02f d01 eef d02 fd0 2fd 02d dd3 933 933 938 88f fd0 2fd 02f d02
    fd0 2fd 02f aaa 999 ffd 02f d02 fd0 2fd 02f d02 fd0 2fd 029 993 933 933 933 938 88c ccc cc9 993 933 93a aaf d02
    fd0 2fd 02f d02 f99 939 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339
    339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339
    339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339
    339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339

which seems like the decoding process is ok, but the output still doesn't look like an image.

Looking at your original pastebin data again, i'm almost certain there's some error in that data. At the start, the sequence '39 33 93' repeats a few time, which translates nicely to 393 393. But later, you have 'FD 02 FD 02 FD 02 FD 02'. This would translate to 'FD0 2FD 02F D02 FD0 2..', i can't imagine that this is correct. Is it possible that some bytes are missing (like \\0 bytes not getting transferred) and the ending 339's are actually data that belongs to the next image?

I couldn't let the question rest ;) I noticed my file has 2F7 (hex) bytes, but the header says 02A0, so there must be something that's in the file but has to be ignored on output. Then, I had the idea of what happens if you omit all 'F' half bytes from the input (and omit the 393 from the output), but the result didn't look very nice, especially, the 39 33 93 was shifted sometimes to decode to 933 933 933.

Next, i omitted all F and E half bytes, resulting in this:


    start of image









                999 ddd bcc         999 d02 d02 d02 d02 999
            999 d02 d02 d02 d02 d02 ccc 666 d02 d02 d02 d02 d02 d02
    d02 999             ddd d02 d02 d02 d02 d02 d02 d02 d02 d02 d02
    d02 d02 d02 d02 ddd             d02 d02 d02 bbb     bcc d02 d02
    d01         bbb d02 d02             d02 d02 d02             d02
    999             d02 d02             d02 d02 d02 aaa     999 d02
    d02 d01         999 d02 d02             ddd d02 d02 d02 d02 d02
    d02 d02 d02 d02 d02 d02 d01 d02 d02 d02 ddd             888 d02
    d02 d02 d02 d02 aaa 999 d02 d02 d02 d02 d02 d02 d02 999
            888 ccc ccc 999         aaa d02 d02 d02 d02 999









    I'm now at 02df
    end of image

which doesn't look completely correct, but much better than everything we had until now. I assume something more has to be omitted, since the code reads until 0x2df, not 0x2f7, but maybe this helps you in finding what else you have to do. Here's my code; note i read sizey first, then sizex, since this seems to yield a better picture:

    #include <stdio.h>

    typedef unsigned char uint8_t;
    #define M 1

    int sizex, sizey;
    int xctr, yctr;

    int main(void) {
            FILE *fp;

            int i=0, c;
            int flag;

            if ((fp=fopen("tempfile", "rb"))==NULL) {
                    perror("tempfile"); exit(1);
            }
            sizey=getc(fp);
            sizex=getc(fp);
            int bsize=getc(fp)*256;
            bsize+=getc(fp);

            xctr=yctr=0;
            for (i=0; i<bsize*2;) {
                    c=getc(fp);
                    if ((c&0xf0) != 0xf0 && (c&0xf0) != 0xe0) {
                            push ((c>>4)&0x0f);
                            i++;
                    }
                    if ((c&0x0f) != 0x0f && (c&0x0f) != 0x0e) {
                            push (c&0x0f);
                            i++;
                    }

            }
            printf("I'm now at %04x\n", ftell(fp));
    }


    int push(int c) {
            static int pos=0;
            static uint8_t red, green, blue;

            if      (pos==0) { pos=1; red=c; }
            else if (pos==1) { pos=2; green=c; }
            else if (pos==2) { pos=0; blue=c; }

            if (pos==0) {
                    if (red==3 && green==9 && blue==3)
                            printf("    ");
                    else
                            printf("%01x%01x%01x ", red, green, blue);
                    xctr++;
                    if (xctr==sizex) {
                            putchar('\n');
                            xctr=0;
                    }
            }
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM