C windows和linux截屏

记录下几种常见截屏方式。
1.windows下截屏

#include <Windows.h>

typedef struct {
	HDC  hBmpFileDC;
	HDC  hDesktopDC;
	HWND hDesktopWnd;
	void* pBits;
	HBITMAP hBmpFileBitmap;
}win_picture;

win_picture image;

void get_screen_size(int* width, int* height)
{
	*width = GetSystemMetrics(SM_CXSCREEN);
	*height = GetSystemMetrics(SM_CYSCREEN);
}

int init_capture(int* width, int* height, int *image_len)
{
	BITMAPINFO bi;
	BITMAPFILEHEADER bitHead;
	*width = GetSystemMetrics(SM_CXSCREEN);
	*height = GetSystemMetrics(SM_CYSCREEN);
	image.hDesktopWnd = GetDesktopWindow();
	image.hDesktopDC = GetDC(image.hDesktopWnd);

	ZeroMemory(&bi, sizeof(bi));
	bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
	bi.bmiHeader.biHeight = -(*height);
	bi.bmiHeader.biWidth = *width;
	bi.bmiHeader.biPlanes = 1;
	bi.bmiHeader.biBitCount = 24;
	bi.bmiHeader.biCompression = BI_RGB;
	bi.bmiHeader.biSizeImage = 3 * (*height) * (*width);
	image.hBmpFileDC = CreateCompatibleDC(image.hDesktopDC);
	image.hBmpFileBitmap = CreateDIBSection(image.hDesktopDC,
		&bi, DIB_RGB_COLORS, &image.pBits, NULL, 0);
	SelectObject(image.hBmpFileDC, image.hBmpFileBitmap);

	ZeroMemory(&bitHead, sizeof(bitHead));
	bitHead.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
	bitHead.bfSize = bi.bmiHeader.biSizeImage + bitHead.bfOffBits;
	bitHead.bfType = 'MB';
	*image_len = (*width) * (*height) * 3;

	return 0;
}

int capture(unsigned char **dst_buf, int width, int height)
{
	CURSORINFO cursorInfo = { 0 };
	cursorInfo.cbSize = sizeof(cursorInfo);
	//Retrieves information about the global cursor
	GetCursorInfo(&cursorInfo);
	ICONINFO IconInfo = { 0 };
	//Retrieves information about the specified icon or cursor.
	GetIconInfo(cursorInfo.hCursor, &IconInfo);

	BitBlt(image.hBmpFileDC,
		0, 0, width, height,
		image.hDesktopDC, 0, 0, SRCCOPY);

	DeleteObject(IconInfo.hbmColor);
	DeleteObject(IconInfo.hbmMask);
	//Draws an icon or cursor into the specified device context.
	DrawIcon(image.hBmpFileDC,
		cursorInfo.ptScreenPos.x - IconInfo.xHotspot,
		cursorInfo.ptScreenPos.y - IconInfo.yHotspot,
		cursorInfo.hCursor);

	*dst_buf = (unsigned char*)image.pBits;

	return 0;
}

void free_picture()
{
	if (image.hBmpFileBitmap != NULL || image.hBmpFileDC != NULL)
	{
		DeleteDC(image.hBmpFileDC);
		DeleteObject(image.hBmpFileBitmap);
		ReleaseDC(image.hDesktopWnd, image.hDesktopDC);
	}
}

2.linux使用双缓冲FrameBuffer截屏,可以先用cat /dev/fb0 > output,验证是否有图像。

#include <fcntl.h>
#include <linux/fb.h>
#include <sys/mman.h>

int init_image_data(int *fd, long *screensize, int *width, int *height)
{
	static struct fb_var_screeninfo vi;
	static struct fb_fix_screeninfo fi;
	int x = 0, y = 0;

	*fd = open("/dev/fb0", O_RDWR);
	if(ioctl(*fd, FBIOGET_VSCREENINFO, &vi) < 0)
	{
		printf("ioctl FBIOGET_VSCREENINFO failed\n");
		return 0;
	}

	if(ioctl(*fd, FBIOPUT_VSCREENINFO, &vi) < 0)
	{
		printf("ioctl FBIOPUT_VSCREENINFO failed\n");
		return 0;
	}

	if(ioctl(*fd, FBIOGET_FSCREENINFO, &fi) < 0)
	{
		printf("ioctl FBIOGET_FSCREENINFO failed\n");
		return 0;
	}

	*screensize = vi.xres * vi.yres * vi.bits_per_pixel / 8;
	printf("width = %d\n", vi.xres);
	printf("height = %d\n", vi.yres);
	*width = vi.xres;
	*height = vi.yres;
	return 1;

}

void set_image_data(long screensize, int fd, char *buf)
{
	char *bits = mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
	memcpy(bits, buf, screensize);
	munmap(bits, screensize);
}

void get_image_data(long screensize, int fd, char *buf)
{	
	char *bits = mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
	memcpy(buf, bits, screensize);
	munmap(bits, screensize);
}

void free_image(int fd)
{
	close(fd);
}

3.linux使用xcb截屏,需要xcb库。

#include <stdlib.h>
#include <fcntl.h>

#include <xcb/xcb.h>
#include <xcb/xfixes.h>
#include <xcb/xproto.h>

#define FFMAX(a,b) ((a) > (b) ? (a) : (b))
#define FFMIN(a,b) ((a) > (b) ? (b) : (a))
#define BLEND(target, source, alpha) \
	(target) + ((source) * (255 - (alpha)) + 255 / 2) / 255
	
typedef struct xcb_info
{
	xcb_connection_t *con;
	xcb_drawable_t   drawable;
	xcb_get_image_reply_t  *img;
}xcb_info;

xcb_info xcb_info_i;

static xcb_screen_t *get_screen(const xcb_setup_t *setup, int screen_num)
{
	xcb_screen_iterator_t it = xcb_setup_roots_iterator(setup);
	xcb_screen_t *screen = NULL;

	for(;it.rem > 0; xcb_screen_next(&it))
	{
		if(!screen_num)
		{
			screen = it.data;
			break;
		}
		screen_num--;
	}
	return screen;
}

//check draw mouse event
static int check_xfixes(xcb_connection_t *con)
{
	xcb_xfixes_query_version_cookie_t cookie;
	xcb_xfixes_query_version_reply_t *reply;
	
	cookie = xcb_xfixes_query_version(con, XCB_XFIXES_MAJOR_VERSION,
			XCB_XFIXES_MINOR_VERSION);
	reply  = xcb_xfixes_query_version_reply(con, cookie, NULL);

	if(reply)
	{
		free(reply);
		return 1;
	}
	return 0;
}

static void xcbgrab_draw_mouse(xcb_connection_t *con, unsigned char *data_buff,
		int pic_x, int pic_y, int pic_width, int pic_height)
{
	unsigned int *cursor;
	int length;
	xcb_xfixes_get_cursor_image_cookie_t cc;
	xcb_xfixes_get_cursor_image_reply_t *ci;
	int cx, cy, x, y, w, h, c_off, i_off;

	cc = xcb_xfixes_get_cursor_image(con);
	ci = xcb_xfixes_get_cursor_image_reply(con, cc, NULL);
	if(!ci)
		return;

	cursor = xcb_xfixes_get_cursor_image_cursor_image(ci);
	length = xcb_xfixes_get_cursor_image_cursor_image_length(ci);
	
	if(!cursor)
		return;

	cx = ci->x - ci->xhot;
	cy = ci->y - ci->yhot;

	x = FFMAX(cx, pic_x);
	y = FFMAX(cy, pic_y);

	w = FFMIN(cx + ci->width, pic_x + pic_width) - x;
	h = FFMIN(cy + ci->height, pic_y + pic_height) - y;

	c_off = x - cx;
	i_off = x - pic_x;
	
	cursor += (y - cy) * ci->width;
	data_buff += (y - pic_y) * pic_width * 4;           //4 represents the size of a pixel
	
	for(y = 0; y < h; y++)
	{
		cursor += c_off;
		data_buff += i_off * 4;
		for(x = 0; x < w; x++, cursor++, data_buff += 4)
		{
			int r, g, b, a;
			
			r = *cursor         & 0xff;
			g = (*cursor >> 8)  & 0xff;
			b = (*cursor >> 16) & 0xff;
			a = (*cursor >> 24) & 0xff;

			if(!a)
				continue;

			if(a == 255)
			{
				data_buff[0] = r;
				data_buff[1] = g;
				data_buff[2] = b;
			} else
			{
				data_buff[0] = BLEND(r, data_buff[0], a);
				data_buff[1] = BLEND(g, data_buff[1], a);
				data_buff[2] = BLEND(b, data_buff[2], a);
			}
		}
		cursor += ci->width - w - c_off;
		data_buff += (pic_width - w - i_off) * 4;
	}

	free(ci);

//	return length;
}

void init_capture(int *width, int *height, int *stride)
{
	DEBUG("entry init_capture");
	xcb_screen_t       *screen;
	const xcb_setup_t  *setup;
	const xcb_format_t *fmt;
	int                screen_num;
	int                bpp = 0;
	int                length;

	xcb_info_i.con = xcb_connect(":0.0", &screen_num);
	setup = xcb_get_setup(xcb_info_i.con);
	screen = get_screen(setup, screen_num);

	fmt = xcb_setup_pixmap_formats(setup);
	length = xcb_setup_pixmap_formats_length(setup);
	while (length--)
	{
		if (screen->root_depth == fmt->depth)
		{
			bpp = fmt->bits_per_pixel;
			break;
		}
		fmt++;
	}

	*width = screen->width_in_pixels;
	*height = screen->height_in_pixels;
	*stride = (*width) * (bpp >> 3);
	xcb_info_i.drawable = screen->root;
}

void capture(unsigned char **buf, int *size_buf, int width, int height)
{
	xcb_generic_error_t    *err = NULL;
	xcb_get_image_cookie_t iq;
	int ret_mouse;

	if (xcb_info_i.img)
	{
		free(xcb_info_i.img);
		xcb_info_i.img = NULL;
	}

	iq = xcb_get_image(
		xcb_info_i.con, XCB_IMAGE_FORMAT_Z_PIXMAP,
		xcb_info_i.drawable, 0, 0,
		width, height, ~0);
	xcb_info_i.img = xcb_get_image_reply(xcb_info_i.con, iq, &err);
	if (err)
	{
		DEBUG("get image failed\n");
		return;
	}

	*buf = xcb_get_image_data(xcb_info_i.img);
	*size_buf = xcb_get_image_data_length(xcb_info_i.img);
	ret_mouse = check_xfixes(xcb_info_i.con);
	if (!ret_mouse)
	{
		DEBUG("connot draw the mouse\n");
		return;
	}

	xcbgrab_draw_mouse(xcb_info_i.con, *buf,
		0, 0, width, height);
}

void free_picture()
{
	if (xcb_info_i.img)
	{
		free(xcb_info_i.img);
		xcb_info_i.img = NULL;
	}
	if(xcb_info_i.con)
	{
		xcb_disconnect(xcb_info_i.con);
		xcb_info_i.con = NULL;
	}
}

参考ffmpeg中。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值