由于需要动态的将相机取得到图像数据动态的在窗口中显示,开始时试过好几个开源的显示库都没有达到想要到效果,SDL是最接近想要的效果的,可是目前到版本对于多窗口的显示支持还不完善,最终决定应用xlib来直接显示,归根结底这些库最终都是应用xlib来显示的。
在linux下 的xlib显示内存图像数据,几个需要的对象是:
unsigned long m_WinID;窗口句柄
Display * m_display;
GC m_gc;
XImage * m_pDSPImage;
pthread_mutex_t m_lock_Screen; //显示对象的互斥
// 绘图控制
int m_nDrawStartX; //起始坐标 x
int m_nDrawStartY; //起始坐标 y
int m_nDrawWidth; //绘图宽度
int m_nDrawHeight; //绘图高度
这些对象需要初始化:
根据传入的图像的宽高和位深来初始化相关对象资源
void DIBCreate(ULONG Width, ULONG Height, ULONG nColor) {
if (0 == m_WinID)
return;
pthread_mutex_lock(&m_lock_Screen);
m_display = XOpenDisplay(NULL);
if (!m_display) { return;
}
unsigned long valuemask = 0;
XGCValues values;
m_gc = XCreateGC(m_display, (Window) m_WinID, valuemask, &values);
if (!m_gc) {
XCloseDisplay(m_display);
m_display = NULL;
return;
}
Visual *visual = DefaultVisual(m_display, DefaultScreen(m_display));
int imagedepth = DefaultDepth(m_display,DefaultScreen(m_display));
//
//创建屏幕大小的XImage的图像缓冲区,主要由于图像再大显示最大也超不出屏幕,提高显示效率
unsigned int display_width, display_height;//屏幕尺寸
display_width = DisplayWidth(m_display, DefaultScreen(m_display));
display_height = DisplayHeight(m_display, DefaultScreen(m_display));
m_pDSPImage = XCreateImage(m_display, visual, imagedepth, ZPixmap, 0, NULL,
display_width, display_height, 32, 0);
if (m_pDSPImage) {
m_pDSPImage->data = new char[display_width * display_height
* m_pDSPImage->bits_per_pixel / 8];
}
pthread_mutex_unlock(&m_lock_Screen);
}
void DIBFree() { pthread_mutex_lock(&m_lock_Screen); if (m_gc) { XFreeGC(m_display, m_gc); m_gc = NULL; } if (m_display) { XCloseDisplay(m_display); m_display = NULL; } if (m_pDSPImage) { XDestroyImage(m_pDSPImage);
//XDestroyImage方法会删除ximage对象的图像数据的内存
m_pDSPImage = NULL;}pthread_mutex_unlock(&m_lock_Screen);}
显示时的处理:
下面方法可以根据上面初始化的对象获得窗口的具体大小
XWindowAttributes win_attr;
XGetWindowAttributes(m_display, (Window) m_WinID, &win_attr); //主要获得显示窗口的大小
下面的显示部分充分考虑到窗口的大小在小于图像大小时的部分刷新跟缩放的操作,缩放时应用临近插值方法,提高显示效率。
pthread_mutex_lock(&m_lock_Screen);
XWindowAttributes win_attr;
XGetWindowAttributes(m_display, (Window) m_WinID, &win_attr); //主要获得显示窗口的大小
int DrawWidth;
int DrawHeight;
if (m_nDrawStartX > 0) {
DrawWidth
= (win_attr.width - m_nDrawStartX) < m_nDrawWidth ? (win_attr.width
- m_nDrawStartX)
: m_nDrawWidth;
} else {
DrawWidth
= win_attr.width > m_nDrawWidth + m_nDrawStartX ? m_nDrawWidth
+ m_nDrawStartX
: win_attr.width;
}
if (m_nDrawStartY > 0) {
DrawHeight
= (win_attr.height - m_nDrawStartY) < m_nDrawHeight ? (win_attr.height
- m_nDrawStartY)
: m_nDrawHeight;
} else {
DrawHeight
= win_attr.height > m_nDrawHeight + m_nDrawStartY ? m_nDrawHeight
+ m_nDrawStartY
: win_attr.height;
}
ImageData2DisplayData(pData, nColor, uWidth, uHeight,
DefaultVisual(m_display, DefaultScreen(m_display)),
m_pDSPImage,
OffX, OffY, uWidth, uHeight,//内存图像的偏移位置及图像数据的长宽
m_nDrawStartX, m_nDrawStartY, m_nDrawWidth, m_nDrawHeight,
DrawWidth, DrawHeight);//需要将图像数据转换为ARGB格式的数据
XPutImage(m_display, (Drawable) m_WinID, m_gc, m_pDSPImage, 0, 0,
m_nDrawStartX > 0 ? m_nDrawStartX : 0,
m_nDrawStartY > 0 ? m_nDrawStartY : 0, //需要考虑窗口绘制的偏移为负值的情况
DrawWidth, DrawHeight);
pthread_mutex_unlock(&m_lock_Screen);
图像数据转换为显示数据方法:
//显示需要转换的函数,应用临近插值方式进行缩放
int ImageData2DisplayData(PUCHAR pSrc, int SrcBpp, DWORD Width, DWORD Height,
Visual *visual, XImage *DstImage,
DWORD offX, DWORD offY, DWORD offWidth, DWORD offHeight, //源数据的区域
int offX_dst, int offY_dst, DWORD dstWidth, DWORD dstHeight, //绘制到屏幕上的区域
int windowWidth, int windowHeight); //窗口的大小
{
unsigned long r, g, b, rmask, gmask, bmask, xcol;
int rshift, gshift, bshift, bperpix, bperline, border;
rmask = visual->red_mask;
gmask = visual->green_mask;
bmask = visual->blue_mask;
rshift = 7 - CImageAlgorithm::highbit(rmask);
gshift = 7 - CImageAlgorithm::highbit(gmask);
bshift = 7 - CImageAlgorithm::highbit(bmask);
bperline = DstImage->bytes_per_line;
bperpix = DstImage->bits_per_pixel;
border = DstImage->bitmap_bit_order;
int nSrcBit = SrcBpp/8;
int nSrcLineBit = Width*nSrcBit;
int nImgBit = bperpix/8;
int srcOffx = -(offX_dst>0?0:offX_dst)*offWidth/dstWidth + offX;
int srcOffy = -(offY_dst>0?0:offY_dst)*offHeight/dstHeight + offY;
if(24==SrcBpp)
{
if(32 == bperpix)
{
PUCHAR ip, pp;
pp = pSrc;
for(int i = 0; i < dstHeight; i++){
int srcH = i * offHeight/dstHeight + srcOffy;
if(srcH>=Height || i>=(DstImage->height)||i>=windowHeight)
break;
pp = pSrc + (Height-1-srcH)*nSrcLineBit; //显示图像要上下对调
ip = (PUCHAR)DstImage->data + i*bperline;
for(int j = 0; j < dstWidth; j++){
int srcW = j * offWidth/dstWidth + srcOffx;
if(srcW>=Width || j>=(DstImage->width)||j>=windowWidth)
break;
memcpy(ip,pp+3*srcW,3);
ip+=4;
}
}
}
else if(24 == bperpix){
PUCHAR ip, pp;
pp = pSrc;
for(int i = 0; i < dstHeight; i++){
int srcH = i * offHeight/dstHeight + srcOffy;
if(srcH>=Height || i>=(DstImage->height)||i>=windowHeight)break;
pp = pSrc + (Height-1-srcH)*nSrcLineBit;
ip = (PUCHAR)DstImage->data + i*bperline;
for(int j = 0; j < dstWidth; j++){
int srcW = j * offWidth/dstWidth + srcOffx;
if(srcW>=Width || j>=(DstImage->width)||j>=windowWidth)break;
memcpy(ip,pp+3*srcW,3);
ip+=3;
}
}
}
}
else if(8==SrcBpp){
if(32 == bperpix)
{
PUCHAR ip, pp;
pp = pSrc;
for(int i = 0; i < dstHeight; i++){
int srcH = i * offHeight/dstHeight + srcOffy;
if(srcH>=Height || i>=(DstImage->height)||i>=windowHeight)break;
pp = pSrc + (Height-1-srcH)*nSrcLineBit;
ip = (PUCHAR)DstImage->data + i*bperline;
for(int j = 0; j < dstWidth; j++){
int srcW = j * offWidth/dstWidth + srcOffx;
if(srcW>=Width || j>=(DstImage->width)||j>=windowWidth)break;
memset(ip,*(pp+srcW),3);
ip+=4;
}
}
}
else if(24 == bperpix){
PUCHAR ip, pp;
pp = pSrc;
for(int i = 0; i < dstHeight; i++){
int srcH = i * offHeight/dstHeight + srcOffy;
if(srcH>=Height || i>=(DstImage->height)||i>=windowHeight)break;
pp = pSrc + srcH*nSrcLineBit;
ip = (PUCHAR)DstImage->data + (dstHeight - 1 - i)*bperline; //显示图像要上下对调
for(int j = 0; j < dstWidth; j++){
int srcW = j * offWidth/dstWidth + srcOffx;
if(srcW>=Width || j>=(DstImage->width)||j>=windowWidth)break;
memset(ip,*(pp+srcW),3);
ip+=3;
}
}
}
}
return 0;
}