2013-07-11 45 views
1

我正在为我的游戏和其他应用程序开发自己的图像格式,并且我想让这些图像的图像查看器。问题是,当我总是尝试渲染更大的图像(1920x1080)时,需要至少10秒钟,然后应用程序停止响应几秒钟,所有内容都会消失。在屏幕上快速绘制自定义格式图像

class Renderer{ 
    //... 
    inline void GetRGB(unsigned int color,unsigned char &r,unsigned char &g,unsigned char &b){ 
     r=((color>>16)&0xff); g=((color>>8)&0xff); b=((color)&0xff); 
    } 
    inline bool IsValidPos(unsigned int x,unsigned int y){ 
     if((x>=0&&x<width)&&(y>=0&&y<height))return true; 
     else return false; 
    } 
    inline void GetPoint(unsigned int x,unsigned int y,unsigned int &color){ 
     if(IsValidPos(x,y)) 
      color=photostream[y*height+x]; 
    } 
    void DrawPoint(unsigned int& x,unsigned int& y){ 
     unsigned char r,g,b; 
     unsigned int col; 
     GetPoint(x,y,col); 
     //GetRGB(col,r,g,b); 
     SetPixel(hDC,x,y,col); 
    } 
}; 
void RenderSHMP(ImageSHMP<unsigned int>& img,Renderer *renderer){ 
    ImageSHMP<unsigned int> tmpImg(img.GetX(),img.GetY()); //create new image, this one will be shown 
    for(unsigned int x=0;x<tmpImg.GetX();x++) 
     for(unsigned int y=0;y<tmpImg.GetY();y++) 
      tmpImg.SetPoint(x,y,img.GetPoint(x,y)); //copy all data 
    if(img.GetX()>WIDTH||img.GetY()>HEIGHT){ //resize image if it is bigger than window resolution 
     double scale=1.0; 
     scale=static_cast<double>(WIDTH)/static_cast<double>(img.GetX()); 
     tmpImg.Scale(scale); 
    } 
    //code above takes max. 0,2 seconds to execute 
    unsigned int col=0; 
    for(unsigned int x=0;x<tmpImg.GetX();x++) 
     for(unsigned int y=0;y<tmpImg.GetY();y++){ 
      col=tmpImg.GetPoint(x,y); 
      renderer->SetPoint(x,y,col); //sets color in memory for later use 
      renderer->DrawPoint(x,y); 
     } 
} 

ImageSHMP包含类型T的简单缓冲区,它等于宽度*高度。 所有的数据都保存在这个缓冲区中,例如点[20,30]位于[30 * height + 20]。 如何让它绘制得更快,所以窗口不会处于“未响应”状态? 我的意思是和简单的Windows Image Viewer一样快。


最终代码:

void RenderSHMP(ImageSHMP<unsigned int>& img,Renderer *renderer){ 
    ImageSHMP<unsigned int> tmpImg(img.GetX(),img.GetY()); 
    for(unsigned int x=0;x<tmpImg.GetX();x++) 
     for(unsigned int y=0;y<tmpImg.GetY();y++) 
      tmpImg.SetPoint(x,y,img.GetPoint(x,y)); 
    if(img.GetX()>WIDTH||img.GetY()>HEIGHT){ 
     double scale=1.0; 
     scale=static_cast<double>(WIDTH)/static_cast<double>(img.GetX()); 
     tmpImg.Scale(scale); 
    } 
    int w=tmpImg.GetX(),h=tmpImg.GetY(); 
    unsigned char r=0,g=0,b=0; 
    BITMAPINFO bmi; 
    HBITMAP hbm; 
    unsigned char *bytes=new unsigned char[w*h*3]; 
    HDC hdc; 
    renderer->GetHDC(hdc); 
    unsigned int ctr=0; 
    ZeroMemory(&bmi, sizeof(bmi)); 
    bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader); 
    bmi.bmiHeader.biWidth = w; 
    bmi.bmiHeader.biHeight = h; 
    bmi.bmiHeader.biPlanes = 1; 
    bmi.bmiHeader.biBitCount = 24; 
    bmi.bmiHeader.biCompression = BI_RGB; 
    hbm = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS,(void **)&bytes, NULL, 0); 
    HDC compatibleDC=CreateCompatibleDC(hdc); 
    HBITMAP hbmp = CreateCompatibleBitmap (hdc, w, h); 
    for(int y=int(h)-1;y>=0;--y){ 
     for(int x=0;x<int(w);++x){ 
      renderer->GetRGB(tmpImg.GetPoint(x,y),r,g,b); 
      bytes[ctr++]=b; 
      bytes[ctr++]=g; 
      bytes[ctr++]=r; 
     } 
    } 
    SetDIBits (hdc, hbmp, 0, h, bytes,&bmi, DIB_RGB_COLORS); 
    hbmp=(HBITMAP)SelectObject (compatibleDC, hbmp); 
    BitBlt(hdc, 0, 0, w, h, compatibleDC, 0, 0, SRCCOPY); 
    DeleteObject(SelectObject(compatibleDC, hbmp)); 
    DeleteDC(compatibleDC); 
    delete [] bytes; 
} 

回答

2

调用SetPixel 2M次将需要一些时间。我认为你最好将图像调整为位图,然后将其绘制到屏幕上。使用例如CreateDIBSection,然后通过ppvBits填充,并使用BitBlit()绘制到屏幕本身。

1

简单的Windows图像查看器来做它。

图像浏览器不会逐像素地绘制图像。您需要在一次系统调用中绘制整个图像。为此,您需要将图像解压缩到操作系统可以绘制的某个表示中,然后将解压缩的图像绘制到屏幕上。在一个电话。

在windows平台上,您可以使用SetDIBitsToDeviceStretchDIBits函数。只要您正确填写BITMAPINFO,这些功能允许您将像素绘制到内存阵列的窗口中。