在C中显示颜色数组

时间:2014-02-09 15:14:35

标签: c image graphics bitmap

我的程序都写了一个读取颜色数组,如下所示:

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

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

如何在C屏幕上显示这样的数组?

1 个答案:

答案 0 :(得分:4)

图形渲染:

我已经习惯了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
    

    但在Windows上 ,您可以忘记直接访问

  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,...。它是Windows和您的应用程序之间的 GDI 界面。它有像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位图

    这是特殊对象,它是带有 OS 图形句柄( 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通常为0x00RRGGBB0x00BBGGRR。我认为这种方法对你来说是最好的选择,你也可以将任何 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 实施中有错误)。但对于基本操作,你很好(问题在于更高级的功能)

    英特尔,SiS 等供应商已停止在较新的 OpenGL 版本上实施,至少我不知道任何驱动程序比 OpenGL 3.3更好对他们来说

    要开始使用OpenGL,请参阅OpenGL get Device Context

  6. 我强烈建议先从GDI + Bitmap开始。你可以用它们做很多事情我还在用它来进行非复杂的渲染。

    如前所述,我对borland( VCL 样式)友好,所以如果您使用不同的编译器/ IDE,则更改 GDI 对象名称以符合您的环境。我认为Canvas是相同的,位图是HBitmap,但最好检查一下你的帮助/文档,至少你知道要搜索什么。

    希望它有所帮助。

    [Edit1]其他平台