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

2024-02-24

最近,我被一个奇怪的想法所震惊,从 /dev/urandom 获取输入,将相关字符转换为随机整数,然后使用这些整数作为像素的 rgb/x-y 值来绘制到屏幕上。

我做了一些研究(在 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.\n");

    // 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\n", 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.\n");

    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;
}

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

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

测试 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 方法查看。另外,请注意,您可能会处理每个像素的 B-G-R-A 4 字节数量。这意味着您要忽略每第 4 个字节,并将每组中的第一个字节视为蓝色分量。 “ARGB”是大端字节序,因此如果您通过 C 数组的递增索引访问这些字节,蓝色会先出现,然后是绿色,然后是红色..即 B-G-R-A (不是 A-R-G-B)。

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

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

通过 Linux FrameBuffer 将像素绘制到屏幕 的相关文章

随机推荐