通过 Linux FrameBuffer 将像素绘制到屏幕上

2024-11-13 08:36:00
admin
原创
24
摘要:问题描述:最近我突然有了一个奇怪的想法,从 /dev/urandom 获取输入,将相关字符转换为随机整数,并使用这些整数作为像素的 rgb/xy 值来绘制到屏幕上。我做了一些研究(在 StackOverflow 和其他地方),许多人建议你可以直接写入 /dev/fb0,因为它是设备的文件表示。不幸的是,这似乎...

问题描述:

最近我突然有了一个奇怪的想法,从 /dev/urandom 获取输入,将相关字符转换为随机整数,并使用这些整数作为像素的 rgb/xy 值来绘制到屏幕上。

我做了一些研究(在 StackOverflow 和其他地方),许多人建议你可以直接写入 /dev/fb0,因为它是设备的文件表示。不幸的是,这似乎没有产生任何视觉上明显的结果。

我找到了一个来自 QT 教程(不再可用)的示例 C 程序,它使用 mmap 写入缓冲区。该程序成功运行,但同样没有输出到屏幕。有趣的是,当我将笔记本电脑置于暂停状态并随后恢复时,我看到图像(红色方块)瞬间闪烁,该图像更早写入帧缓冲区。在 Linux 中,写入帧缓冲区是否还可以用于绘制到屏幕上?理想情况下,我想编写一个 (ba)sh 脚本,但 C 或类似脚本也可以。谢谢!

编辑:这是示例程序……对兽医来说可能看起来很熟悉。

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include <sys/ioctl.h>

int main()
{
    int fbfd = 0;
    struct fb_var_screeninfo vinfo;
    struct fb_fix_screeninfo finfo;
    long int screensize = 0;
    char *fbp = 0;
    int x = 0, y = 0;
    long int location = 0;

    // Open the file for reading and writing
    fbfd = open("/dev/fb0", O_RDWR);
    if (fbfd == -1) {
        perror("Error: cannot open framebuffer device");
        exit(1);
    }
    printf("The framebuffer device was opened successfully.
");

    // Get fixed screen information
    if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo) == -1) {
        perror("Error reading fixed information");
        exit(2);
    }

    // Get variable screen information
    if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo) == -1) {
        perror("Error reading variable information");
        exit(3);
    }

    printf("%dx%d, %dbpp
", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel);

    // Figure out the size of the screen in bytes
    screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;

    // Map the device to memory
    fbp = (char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0);
    if ((int)fbp == -1) {
        perror("Error: failed to map framebuffer device to memory");
        exit(4);
    }
    printf("The framebuffer device was mapped to memory successfully.
");

    x = 100; y = 100;       // Where we are going to put the pixel

    // Figure out where in memory to put the pixel
    for (y = 100; y < 300; y++)
        for (x = 100; x < 300; x++) {

            location = (x+vinfo.xoffset) * (vinfo.bits_per_pixel/8) +
                       (y+vinfo.yoffset) * finfo.line_length;

            if (vinfo.bits_per_pixel == 32) {
                *(fbp + location) = 100;        // Some blue
                *(fbp + location + 1) = 15+(x-100)/2;     // A little green
                *(fbp + location + 2) = 200-(y-100)/5;    // A lot of red
                *(fbp + location + 3) = 0;      // No transparency
        //location += 4;
            } else  { //assume 16bpp
                int b = 10;
                int g = (x-100)/6;     // A little green
                int r = 31-(y-100)/16;    // A lot of red
                unsigned short int t = r<<11 | g << 5 | b;
                *((unsigned short int*)(fbp + location)) = t;
            }

        }
    munmap(fbp, screensize);
    close(fbfd);
    return 0;
}

解决方案 1:

我通过以下几个实验取得了成功。

首先,确定 X 是否使用填充为 32 位的 TrueColor RGB(或者假设是这种情况)。然后确定您是否具有 fb0 的写入权限(并且它存在)。如果这些是真的(并且我预计许多现代工具包/台式机/ PC 可能会使用这些作为默认值),那么您应该能够执行以下操作(如果这些默认值不成立,那么您可能仍可以通过以下测试获得一些成功,尽管细节可能会有所不同):

测试 1:打开虚拟终端(在 X 中)并输入:$ echo "ddd ... ddd" >/dev/fb0 其中 ... 实际上是几个屏幕的 d。结果将是屏幕顶部出现一行或多行(部分)灰色,具体取决于您的回显字符串的长度以及您启用的像素分辨率。您还可以选择任何字母(ascii 值都小于 0x80,因此产生的颜色将是深灰色……如果您想要灰色以外的颜色,请改变字母)。显然,这可以推广到 shell 循环,或者您可以 cat 一个大文件以更清楚地看到效果:例如:$ cat /lib/libc.so.6 >/dev/fb0 以查看一些 fsf 支持者的真实颜色 ;-P

如果屏幕上的一大块内容被覆盖,请不要担心。X 仍可控制鼠标指针,并且仍可知道窗口的映射位置。您所要做的就是抓住任何窗口并将其拖动一小段以消除噪音。

测试 2:cat /dev/fb0 > xxx 然后更改桌面的外观(例如,打开新窗口并关闭其他窗口)。最后,执行相反的操作:cat xxx > /dev/fb0 以恢复旧桌面!

哈,其实不完全是。旧桌面的图像只是一种幻觉,当你将任意窗口全屏打开时,你很快就会摆脱它。

测试 3:编写一个小应用程序,抓取 /dev/fb0 的先前转储并修改像素的颜色,例如,删除红色成分或增加蓝色,或翻转红色和绿色等。然后将这些像素写回到新文件中,稍后您可以通过测试 2 的简单 shell 方法查看该文件。另外,请注意,您可能会处理每个像素的 BGRA 4 字节数量。这意味着您要忽略每个第 4 个字节,并将每组中的第一个字节视为蓝色成分。“ARGB”是大端字节序,因此如果您通过增加 C 数组的索引来访问这些字节,蓝色将首先出现,然后是绿色,然后是红色……即 BGRA(不是 ARGB)。

测试 4:用任何语言编写一个应用程序,以视频速度循环,向屏幕的某个部分发送非方形图片(比如 xeyes),从而创建没有任何窗口边框的动画。为了获得加分,让动画在整个屏幕上移动。您必须确保在绘制一小行像素后跳过一大片空间(以弥补可能比动画图片宽得多的屏幕宽度)。

测试 5:捉弄朋友,例如,扩展测试 4,让一张动画人物的图片弹出到他们的桌面上(也许可以自己拍摄以获取像素数据),然后走到他们的一个重要的桌面文件夹前,拿起文件夹并将其撕碎,然后开始歇斯底里地大笑,然后让一个火球出来吞噬他们的整个桌面。虽然这一切都是幻觉,但他们可能会有点害怕……但可以将其作为学习经验来炫耀 Linux 和开源,并向新手展示它看起来比实际上可怕得多。[Linux 上的“病毒”通常是无害的幻觉]

解决方案 2:

如果您正在运行 X11,则必须通过 X11 API 来绘制到屏幕上。绕过 X 服务器非常不方便(而且,正如您所见,通常不起作用)。它还可能导致崩溃,或者只是一般的显示损坏。

如果您希望能够在任何地方运行(控制台和 X 下),请查看 SDL 或 GGI。如果您只关心 X11,您可以使用 GTK、QT 甚至 Xlib。有很多选择……

解决方案 3:

我想说,在尝试写入 /dev/fb0 之前要小心,如上所述。我在 ubuntu 10.04 的 X 下尝试过,结果 a) 没有任何视觉效果,b) 它破坏了所有 shell 窗口,甚至其他 tty,导致内核错误和功能缺失。

解决方案 4:

我正在考虑编写一个基于帧缓冲区的程序,因为我需要能够滚动(SDR 瀑布图)。请参阅https://www.raspberrypi.org/forums/viewtopic.php?f=28&t=232493&p=1425567#p1425567 我认为滚动测试是成功的。在我们通过 ioctl 获取信息的这两个结构中,还有关于颜色深度的内容。您的程序似乎基于我所做的相同示例。如何在 Linux 上从帧缓冲区获取像素颜色(Raspberry Pi)

我的程序在我的 Raspberry Pi 上运行良好,无论是否使用 X。它对我的笔记本电脑的屏幕没有影响。它有一个 /dev/fb0,程序运行并且数字看起来正确,但它在视觉上没有任何作用。也许是双缓冲之类的。

在 X 下,它实际上不会造成任何损害。如果你拖动一些窗口,让一切重新绘制,一切都会恢复。然后我决定备份屏幕上的内容,并在完成后将其放回原位,这也有效。我移动并放回的窗口工作起来就像我从未碰过它一样。X 没有意识到我弄乱了屏幕缓冲区,它知道它在那里放了什么,并相应地记录鼠标点击。如果我移动了一个窗口但没有把它放回去,点击仍然会在原来的位置起作用。

解决方案 5:

您应该使用 fb_fix_screeninfo.smem_len 来计算屏幕尺寸,而不是自己进行乘法运算。缓冲区可能对齐 4 个字节或其他内容。

screensize = finfo.smem_len;

解决方案 6:

如果你调试你的程序,你会发现这一行:

 screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;

screensize为 0. 因为 vinfo.xres 为 0. 您应该将其更改为:

long ppc_fx = (((long)fixed_info.smem_start) - ((long) fixed_info.smem_start & ~(PAGE_SIZE-1)));
screensize = finfo.smem_len + ppc_fx;

从 Linux 2.6.2 开始,mmap() 的第二个参数screensize不能为 0。否则 mmap() 将返回 MAP_FAILED。

解决方案 7:

当我使用该程序来全屏写入时它崩溃了,这是由于屏幕尺寸计算错误。

// Figure out the size of the screen in bytes     
screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;

这应该是:

/* Calculate the size of the screen in bytes */   
screensize = vinfo.xres_virtual * vinfo.yres_virtual * (vinfo.bits_per_pixel / 8);
相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   609  
  在现代项目管理中,资源的有效利用是确保项目成功的关键因素之一。随着技术的不断进步,越来越多的工具和软件被开发出来,以帮助项目经理和团队更高效地管理资源。本文将介绍10款工具,这些工具可以帮助项目团队提升资源利用效率,从而实现项目目标。禅道项目管理软件禅道项目管理软件是一款开源的项目管理工具,广泛应用于软件开发和其他行业...
项目管理系统   3  
  在项目管理领域,软件工具的不断升级和创新是推动效率和协作的关键。2024年,众多项目管理软件将迎来一系列令人期待的升级功能,这些新特性不仅将提升团队的工作效率,还将增强用户体验和数据分析能力。本文将详细介绍10款项目管理软件的最新升级功能,帮助项目经理和团队成员更好地规划和执行项目。禅道项目管理软件禅道项目管理软件一直...
开源项目管理工具   2  
  信创国产系统的10个关键厂商及其技术生态随着全球信息技术格局的不断演变,信创(信息技术应用创新)产业作为国产化替代的重要阶段,正逐步成为推动我国信息技术自主可控、安全可靠的核心力量。信创产业不仅关乎国家信息安全,也是数字经济高质量发展的关键支撑。本文将深入探讨信创国产系统中的10个关键厂商及其技术生态,分析它们在信创浪...
项目管理流程   0  
  在探讨项目管理的广阔领域中,成功并非偶然,而是精心策划、高效执行与持续优化的结果。项目管理的成功之道,可以从明确的目标设定与规划、高效的团队协作与沟通、以及灵活的风险管理与适应变化这三个核心方面进行深入解析。每个方面都是项目成功的基石,它们相互交织,共同支撑起项目的顺利推进与最终成就。明确的目标设定与规划项目管理的首要...
建筑工程项目管理规范   0  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用