1.首先找到代码能实现截图:
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <time.h>
#include <string.h>
#include <fcntl.h>
#include <malloc.h>
#include <linux/fb.h>
#include <jpeglib.h>
#include <jerror.h>
#include <errno.h>
extern int errno;
/*
功能: 获取当前系统时间
返回值: 指向时间字符串的开始位置
*/
static const char* getCurTime() // 获取当前系统时间
{
static char ret[30] = {0};
time_t t;
struct tm *tp;
t = time(NULL);
tp = localtime(&t);
memset(ret, 0, sizeof(ret));
sprintf(ret, "%02d%02d%02d_%02d%02d%02d", tp->tm_year+1900, tp->tm_mon+1, tp->tm_mday, tp->tm_hour, tp->tm_min, tp->tm_sec);
return ret;
}
/*
功能: RGB565转RGB24函数
rgb565: 指向存放rgb565数据的起始地址
rgb24: 指向存放rgb24数据的起始地址
width: 屏幕(分辨率)的宽度
height: 屏幕(分辨率)的高度
*/
int RGB565_to_RGB24(unsigned char *rgb565, unsigned char *rgb24, int width, int height)
{
int i;
int whole = width * height; // 屏幕像素点个数
unsigned char r, g, b; // 目标缓冲区是RGB格式, 每个分量占1字节, 所以用uchar
unsigned short int *pix565; // 每像素信息占2字节, 所以用short类型
pix565 = (unsigned short int *)rgb565;
for(i = 0; i < whole; i++)
{
r = ((*pix565) >> 11) & 0x1f;
*rgb24 = (r << 3) | (r >> 2);
rgb24++; // 目标像素点后移
g = ((*pix565) >> 5) & 0x3f;
*rgb24 = (g << 2) | (g >> 4);
rgb24++;
b = (*pix565) & 0x1f;
*rgb24 = (b << 3) | (b >> 2);
rgb24++;
pix565++; // 源像素点后移
}
return 0;
}
/*
功能: 将ARGB1555格式的图片数据转换成RGB24的图片数据
返回值: 0
argb1555:[in] 源缓冲区地址, 指向存放argb1555数据的起始地址
rgb24: [out] 目标缓冲区地址, 指向存放rgb24数据的起始地址
xres: 屏幕分辨率的宽度
yres: 屏幕分辨率的高度
*/
int ARGB1555_to_RGB24(unsigned char *argb1555, unsigned char *rgb24, int xres, int yres)
{
int i;
int whole = xres * yres;
unsigned char r, g, b;
unsigned short int *pix1555;
pix1555 = (unsigned short int *)argb1555;
for(i = 0; i < whole; i++)
{
// *pix1555 &= 0x7FFFFF; // 透明分量置为0
r = ((*pix1555) >> 10) & 0x1f; // 取颜色分量: R
*rgb24++ = (r << 3) | (r >> 2);
g = ((*pix1555) >> 5) & 0x1f; // 取分量: G
*rgb24++ = (g << 3) | (g >> 2);
b = (*pix1555) & 0x1f; // 取分量: B
*rgb24++ = (b << 3) | (b >> 2);
pix1555++;
if(rgb24[-3] == 0xFF && rgb24[-2] == 0 && rgb24[-1] == 0xFF) // RGB = 0xFF00FF
rgb24[-3] = 0; // 修改RGB = 0x0000FF(将粉红色替换成蓝色)
}
return 0;
}
/*
功能: jpeg压缩函数
返回值: 0: 成功, -1: 失败
rgb: 指向存放rgb24数据的起始地址
width: 屏幕(分辨率)的宽度
height: 屏幕(分辨率)的高度
*/
int jpeg_compress(unsigned char *rgb, int width, int height)
{
char outfile[100] = {0};
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
FILE * pf = NULL;
JSAMPROW row_pointer[1];
int row_stride;
sprintf(outfile, "snap_%s.jpg", getCurTime());
if ((pf = fopen(outfile, "wb")) == NULL)
{
printf("Can not create output file, please check!\n");
return -1;
}
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_compress(&cinfo);
jpeg_stdio_dest(&cinfo, pf);
cinfo.image_width = width;
cinfo.image_height = height;
cinfo.input_components = 3; // 1-灰度图,3-彩色图
// 输入数据格式为RGB
cinfo.in_color_space = JCS_RGB; // JCS_GRAYSCALE-灰度图,JCS_RGB-彩色图
jpeg_set_defaults(&cinfo);
jpeg_set_quality(&cinfo, 80, TRUE); // 设置压缩质量:80
jpeg_start_compress(&cinfo, TRUE); // 开始压缩过程
row_stride = width * 3; // row_stride: 每一行的字节数
while (cinfo.next_scanline < cinfo.image_height)
{
row_pointer[0] = &rgb[cinfo.next_scanline * row_stride];
(void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
}
jpeg_finish_compress(&cinfo); // 完成压缩过程
fclose(pf);
jpeg_destroy_compress(&cinfo); // 释放资源
return 0;
}
int main()
{
int fd;
struct fb_var_screeninfo fb_var_info;
struct fb_fix_screeninfo fb_fix_info;
unsigned char *trgb;
unsigned char *rgb;
int buffer_size;
const char *dev = "/dev/fb0";
// 打开framebuffer设备
fd = open(dev, O_RDONLY);
if(fd < 0)
{
printf("fd=%d, error=[%d: %s]\n", fd, errno, strerror(errno));
return -1;
}
// 获取LCD的可变参数
ioctl(fd, FBIOGET_VSCREENINFO, &fb_var_info);
// 一个像素多少位
printf("bits_per_pixel: %d\n", fb_var_info.bits_per_pixel);
printf("分辨率: %d x %d\n", fb_var_info.xres, fb_var_info.yres);
printf("颜色分量值: (A, R, G, B) = (%d, %d, %d, %d)bits\n", fb_var_info.transp.length, fb_var_info.red.length, fb_var_info.green.length, fb_var_info.blue.length);
printf("颜色分量偏移: (A, R, G, B) = (%d, %d, %d, %d)\n", fb_var_info.transp.offset, fb_var_info.red.offset, fb_var_info.green.offset, fb_var_info.blue.offset);
// 获取LCD的固定参数
ioctl(fd, FBIOGET_FSCREENINFO, &fb_fix_info);
// 一帧大小
printf("smem_len: %#X\n", fb_fix_info.smem_len);
// 一行大小
printf("line_length: %#X\n", fb_fix_info.line_length);
// 一帧大小
buffer_size = (fb_var_info.xres * fb_var_info.yres * fb_var_info.bits_per_pixel / 8);
trgb = (unsigned char *)malloc(buffer_size);
if(trgb == NULL)
exit(0);
rgb = (unsigned char *)malloc(fb_var_info.xres * fb_var_info.yres * 3);
if(rgb == NULL)
goto here;
if(read(fd, trgb, buffer_size) < 0) // 获取一帧数据
{
printf("read failed!\n");
goto read_fail;
}
// RGB565_to_RGB24(trgb, rgb, fb_var_info.xres, fb_var_info.yres); // 将RGB565转换成RGB24格式
ARGB1555_to_RGB24(trgb, rgb, fb_var_info.xres, fb_var_info.yres); // 将ARGB1555转换成RGB24格式
if(jpeg_compress(rgb, fb_var_info.xres, fb_var_info.yres) < 0) // jpeg压缩失败
printf("Jpeg compress failed!\n");
read_fail:
free(rgb);
here:
free(trgb);
close(fd);
return 0;
}
运行结果是 黑的 多:
2.为什么是 黑的 ?
查资料,说是:
利用framebuffer做出的这个截图工具,fb0里的内容截图出来的是字符界面,并不是Linux上的GUI界面。
使用C语言来做Linux的截图,标准C没有可用于此目的的库函数。标准C也不知道屏幕,不能用于特定于系统的调用;Linux核心是CLI,核心库里没有图形功能,Linux里用的gnome截图命令是用的GTK工具包,是属于第三方工具。
原文链接:Linux上如何不用第三方库实现截图!!(C/C++)-编程语言-CSDN问答
3.实现:
flameshot ----QT
gnome ---- GTK
用 system()调用截图程序运行