Показать массив цветов в C

Моя программа пишет как читает массивы цветов, как этот:

struct Image {
    size_t width;
    size_t height;
    struct Color *data;
}

struct Color {
    char r;
    char g;
    char b;
}

Как я могу отобразить такой массив на экране в C?

1 ответ

Решение

Рендеринг графики:

Я привык к средам win32 и Borland C++, поэтому придерживаюсь этого, но различия в других средах в основном только в именах классов. Сначала несколько подходов:

  1. консольные / текстовые режимы

    Вы можете использовать текстовую графику ( ASCII art я думаю на английском языке). Где точка представлена символом. Интенсивность определяется более или менее заполненными символами. Обычно есть таблица символов, отсортированная по интенсивности " ..:+*#" и использовать это вместо цветов. Для распечатки можно использовать что-то iostream лайк cout << "text" << endl; или же printf от stdio Я думаю (не использую вывод консоли в старом стиле более десяти лет).

    Видеорам в текстовых режимах (VRAM) начинается с 0B000:0000 если у вас есть привилегии для этого, вы можете сделать прямой доступ следующим образом:

    char far *scr=(char far*)0x0B0000000;
    scr[0]='A'; // print A to left upper corner
    

    а на винде про прямой доступ можно забыть

  2. Режим VGA gfx

    на Windows вы можете забыть об этом также... Вот небольшой пример:

        //==============================================================================
        char far* scr;              // VGA screen
        const _sx= 320;             // physical screen size
        const _sy= 200;
        //==============================================================================
        void gfxinit();
        void cls();
        void pnt(int x,int y,char c);
        //==============================================================================
        void gfxinit()
            {
            asm {   mov ax,19               // this swith VGA to 320*200*256 color mode (fits inside single 64KB segment so no funny stuff is needed)
                int 16
                }
            for (int i=0;i<256;i++) asm { // this overwrites 256 color palette with some BW gradients
                mov dx,0x3C8
                mov ax,i
                out dx,al              // overwrite color al = i 
                inc dx
                shr al,2               // al=al>>2
                out dx,al              // r,g,b or b,g,r not sure now 
                out dx,al              // all values are 6bit long therefore the shr al,2 
                out dx,al
                }
            scr=(char far*)0xA0000000;     // VRAM start address
            }
        //==============================================================================
        void cls()   // this clear screen with zero
            {
            asm {   push    es
                mov ax,0xA000
                mov es,ax
                mov di,0x0000
                sub ax,ax
                mov cx,32000
                rep stosw
                pop es
                }
            }
        //==============================================================================
        void pnt(int x,int y,char c) // this draw single point of color c
            {
            unsigned int adr;
            if (x<_sx)
             if (x>=0)
              if (y<_sy)
               if (y>=0)
                {
                y=y*_sx;
                adr=x+y;
                scr[adr]=c;
                }
            }
        //==============================================================================
    

    Доступ к VESA аналогичен, но вам приходится иметь дело с пересечением сегментов и поиском. Вот небольшой пример Turbo C++:

    VESA.h

    //==============================================================================
    //=== Globals: =================================================================
    //==============================================================================
    char far* scr=(char far*)0xA0000000;    // VGA/VESA memory pointer
    int VESA_page,VESA_pages;       // actaul page and total pages
    int VESA_xs,VESA_ys,VESA_bpp;       // video mode properties
    int VESA_page_xy[64]={-1,-1};       // starting x,y for each page
    const int VESAmodes[]=          // usable video modes table
        {
         320, 200, 8,0x150,
         640, 480, 8,0x101,
         800, 600, 8,0x103,
        1024, 768, 8,0x105,
        1280,1024, 8,0x107,
    
         320, 200,16,0x10E,
         640, 480,16,0x111,
         800, 600,16,0x114,
        1024, 768,16,0x117,
    
         320, 200,32,0x10F,
         640, 480,32,0x112,
         800, 600,32,0x115,
    
        0,0,0,0
        };
    //==============================================================================
    //=== Headers: =================================================================
    //==============================================================================
    int  VESAmode(int xs,int ys,int bpp);   // set video mode
    void VESApage(int page);        // set page
    void VESAexit();            // return to VGA text mode
    void VESAcls();             // clear with 0
    void VESApnt(int x,int y,unsigned int c); // render 8/16 bpp point
    void VESApnt32(int x,int y,int r,int g ,int b); // render 32bpp point
    //==============================================================================
    //=== Graphic: =================================================================
    //==============================================================================
    int VESAmode(int xs,int ys,int bpp)
        {
        int i,mode,x,y;
        unsigned int adr0,adr,dx,dy;
        // find video mode
        for (i=0;VESAmodes[i];i+=4)
         if (VESAmodes[i+0]==xs)
          if (VESAmodes[i+1]==ys)
           if (VESAmodes[i+2]==bpp)
            break;
        if (!VESAmodes[i]) return 0;
        mode=VESAmodes[i+3];
        VESA_xs=xs;
        VESA_ys=ys;
        VESA_bpp=bpp;
        // compute start x,y for each page>0
        dx=bpp>>3;
        dy=xs*dx;
        VESA_pages=1;
        for (adr=i=x=y=0;y<VESA_ys;y++)
            {
            adr0=adr;
            adr+=dy;
            if (adr0>adr)
                {
                while (adr>0) { adr-=dx; x--; }
                while (x<0) { x+=VESA_xs; y--; }
                VESA_page_xy[i]=x; i++;
                VESA_page_xy[i]=y+1; i++;
                VESA_pages++;
                }
            }
        VESA_page_xy[i]=-1; i++;
        VESA_page_xy[i]=-1; i++;
    
        // set vide mode
        asm {
            mov bx,mode
            mov ax,0x4F02
            int 16
            }
        VESApage(0);
    /*
        // set palette to grayscale
        if (VESAbpp==8)
         for (int i=0;i<256;i++) asm {
            mov dx,0x3C8
            mov ax,i
            out dx,al
            inc dx
            shr al,2
            out dx,al
            out dx,al
            out dx,al
            }
    */
        return 1;
        }
    //==============================================================================
    void VESApage(int page)
        {
        int p=page;
        asm {
            mov dx,p
            mov bx,0
            mov ax,0x4f05
            int 16
            }
        VESA_page=page;
        }
    //==============================================================================
    void VESAexit()
        {
        asm     {
            // waut for key press
            mov ax,0
            int 0x16
            // VGA 80x25 text mode
            mov ax,3
            int 16
            }
        }
    //==============================================================================
    void VESAcls()
        {
        int i;
        for (i=0;i<VESA_pages;i++)
            {
            VESApage(i);
            asm     {
                push es
                mov ax,0xA000
                mov es,ax
                mov di,0x0000
                mov ax,0
                mov cx,32000
                rep stosw
                pop es
                }
            }
        }
    //==============================================================================
    void VESApnt(int x,int y,unsigned int c)
        {
        unsigned int adr;
        int p;
        // inside screen?
        if ((x>=0)&&(x<VESA_xs))
         if ((y>=0)&&(y<VESA_ys))
            {
            // low 16 bit of address
            adr=y;
            adr*=VESA_xs;
            adr+=x;
            adr*=(VESA_bpp>>3);
            // page
            for (p=0;VESA_page_xy[p+p+0]>=0;p++)
                {
                if (VESA_page_xy[p+p+1]>y) break;
                if (VESA_page_xy[p+p+1]<y) continue;
                if (VESA_page_xy[p+p+0]>x) break;
                }
            if (p!=VESA_page) VESApage(p);
            // render
            scr[adr]=c;
            if (VESA_bpp==16)
                {
                adr++; if (adr==0) VESApage(p+1);
                scr[adr]=(c>>8);
                }
            }
        }
    //==============================================================================
    void VESApnt32(int x,int y,int r,int g ,int b)
        {
        unsigned int adr;
        int p;
        // inside screen?
        if ((x>=0)&&(x<VESA_xs))
         if ((y>=0)&&(y<VESA_ys))
            {
            // low 16 bit of address
            adr=y;
            adr*=VESA_xs;
            adr+=x;
            adr*=(VESA_bpp>>3);
            // page
            for (p=0;VESA_page_xy[p+p+0]>=0;p++)
                {
                if (VESA_page_xy[p+p+1]>y) break;
                if (VESA_page_xy[p+p+1]<y) continue;
                if (VESA_page_xy[p+p+0]>x) break;
                }
            if (p!=VESA_page) VESApage(p);
            // render
            scr[adr]=b; adr++; if (adr==0) VESApage(p+1);
            scr[adr]=g; adr++; if (adr==0) VESApage(p+1);
            scr[adr]=r;
            }
        }
    //==============================================================================
    //=== End. =====================================================================
    //==============================================================================
    

    main.cpp

    //==============================================================================
    //=== Includes: ================================================================
    //==============================================================================
    #include "vesa.h"
    //==============================================================================
    //=== Main: ====================================================================
    //==============================================================================
    void main()
        {
        if (!VESAmode(800,600,32)) return;
        VESAcls();
        int x,y;
        unsigned int c;
        for (y=0;y<VESA_ys;y++)
         for (x=0;x<VESA_xs;x++)
            {
            if (VESA_bpp== 8)
                {
                c=x+y;
                VESApnt(x,y,c);
                }
            if (VESA_bpp==16)
                {
                c=(x&31)+((y&63)<<5);
                VESApnt(x,y,c);
                }
            if (VESA_bpp==32) VESApnt32(x,y,x,x+y,y);
            }
    
        VESAexit();
        }
    //==============================================================================
    //=== End. =====================================================================
    //==============================================================================
    
  3. GDI

    Canvas является графическим подкомпонентом визуальных компонентов в Windows. В Borland это класс TCanvas названный Canvas, Все окна имеют это также PaintBoxes,Bitmaps,..., Это интерфейс GDI между Windows и вашим приложением. Имеет подкомпоненты, такие как Pen,Brush,Font для строк, заливок или текстовой бумаги, текстовых чернил.

    Form1->Canvas->Pen->Color=clYellow;
    Form1->Canvas->MoveTo(10,10);
    Form1->Canvas->LineTo(100,150);
    

    где Form1 мое окно VCL этот код рисует желтую линию.

    GDI имеет много функций, таких как Arc,Ellipse,Pixels[][],... см. встроенную справку вашей IDE для получения дополнительной информации.

  4. GDI Bitmap

    это специальный объект, это растровое изображение с графическим дескриптором ОС (контекст устройства DC). Это позволяет растровому изображению быть чем-то вроде окна и иметь доступ к GDI

    Graphics::TBitmap *bmp=new Graphics::TBitmap;
    bmp->Width=100;
    bmp->Height=100;
    bmp->HandleType=bmDIB;    // allows use of ScanLine
    bmp->PixelFormat=pf32bit; // 32bit the same as int so we can use int* for pixels pointer
    

    это создает растровое изображение VCL и устанавливает его 100x100x32bit с прямым доступом. Теперь вы можете получить доступ ScanLine имущество. Также bmp->Canvas присутствует, так что вы можете делать все вещи GDI тоже.

    int *p=bmp->ScanLine[10]; // p = pointer to y=10 line of bitmap
    p[20]=0;                    // draw dot on x=20,y=10   color=0x00000000 which is black
    int c = p[15];              // read pixel x=15,y=10 from bitmap to c
    

    Будьте осторожны, чтобы остаться с x,y внутри будет выброшено растровое изображение или исключение. Цветовое кодирование зависит от pixelformat обычно это 0x00RRGGBB или же 0x00BBGGRR, Я думаю, что этот подход является лучшим вариантом для вас, также вы можете нарисовать любой объект GDI для любого другого объекта GDI

    Form1->Canvas->Draw(0,0,bmp);
    

    это рисует ваше растровое изображение в окне, так что вы можете увидеть его на самом деле.

  5. Графическая библиотека

    Их много, но чаще всего используются OpenGL и DirectX. Я предпочитаю OpenGL, потому что его проще реализовать (по крайней мере, для начинающих), а также OpenGL является кроссплатформенным, а DirectX - только для Windows. Кроме того, когда я начал кодировать, не было DirecX. Когда я начал использовать OpenGL, он был включен в драйверы. Теперь единственными поставщиками, которые все еще обновляются, являются nVidia и ATI(AMD). Между ними почти всегда возникают проблемы с драйверами, но в целом nVidia лучше для OpenGL (есть ошибки в реализации DirectX), а ATI(только для версий AMD) лучше для DirectX (есть ошибки в реализации OpenGL). Но с базовыми операциями у вас все в порядке (проблемы переходят на более сложные функции)

    Такие производители, как Intel, SiS,... остановили свои реализации на более новых версиях OpenGL, по крайней мере, я не знаю ни одного драйвера лучше, чем OpenGL 3.3 для них

    Чтобы начать работу с OpenGL, посмотрите OpenGL get Device Context

Я настоятельно рекомендую начать с GDI+Bitmap. Вы можете сделать с ними многое, я все еще использую его для несложного рендеринга.

Как упоминалось ранее, я дружественен к Borland (стиль VCL), поэтому, если вы используете другой компилятор /IDE, измените имена объектов GDI, чтобы они соответствовали вашей среде. Я думаю, что холст такой же, и растровое изображение HBitmap но лучше проверьте свою помощь / документы, по крайней мере, вы знаете, что искать.

Надеюсь, это немного поможет.

[Edit1] другие платформы

Другие вопросы по тегам