我正在为我的游戏和其他应用程序开发自己的图像格式,我想制作这些图像的图像查看器。问题是,当我总是尝试渲染更大的图像(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的简单缓冲区,它等于width * height。 所有数据都保存在此缓冲区中,因此例如点[20,30]位于[30 *高度+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;
}
答案 0 :(得分:2)
调用SetPixel 2M次会花费一些时间。我认为你最好将图像调整为位图,然后将其绘制到屏幕上。使用例如CreateDIBSection
,然后通过ppvBits
填充它,并使用BitBlit()绘制到屏幕本身。
答案 1 :(得分:1)
简单的Windows Image Viewer就可以了。
图像查看器不会逐像素地绘制图像。您需要在一个系统调用中绘制整个图像。为此,您需要将图像解压缩到一些表示操作系统可以绘制,然后将解压缩的图像绘制到屏幕上。在一个电话中。
在Windows平台上,您可以使用SetDIBitsToDevice和StretchDIBits功能。只要正确填充BITMAPINFO,这些功能就可以让您从内存数组中将像素绘制到窗口上。