41

私は最近、/dev/urandom から入力を取得し、関連する文字をランダムな整数に変換し、それらの整数をピクセルの RGB/XY 値として使用して画面に描画するという興味深いアイデアに感銘を受けました。

私はいくつかの調査を行いました (ここでは StackOverflow および他の場所で)、/dev/fb0 はデバイスのファイル表現であるため、単純に直接書き込むことができると多くの人が提案しています。残念ながら、これは視覚的に明らかな結果をもたらさないようです。

mmap を使用してバッファーに書き込む QT チュートリアル (現在は使用できません) からのサンプル C プログラムを見つけました。プログラムは正常に実行されますが、やはり画面に何も出力されません。興味深いことに、ラップトップをサスペンド状態にしてから復元すると、フレームバッファに以前に書き込まれた画像 (赤い四角形) が一瞬点滅しました。フレームバッファへの書き込みは、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;
}
4

7 に答える 7

13

次のいくつかの実験で成功しました。

まず、X が 32 ビットにパディングされた TrueColor RGB を使用しているかどうかを確認します (または、これが事実であると仮定します)。次に、fb0 への書き込み権限があるかどうか (およびそれが存在するかどうか) を調べます。これらが当てはまる場合 (そして、多くの最新のツールキット/デスクトップ/PC がこれらをデフォルトとして使用する可能性があると思います)、次のことを実行できるはずです (これらのデフォルトが保持されない場合でも、おそらくいくつかの成功を収めることができます詳細は異なる場合がありますが、次のテスト):

テスト 1: (X で) 仮想端末を開き、次のように入力します。結果は、エコー文字列の長さと有効にしたピクセル解像度に応じて、画面の上部に 1 つまたは複数の (部分的な) 灰色の線が表示されます。任意の文字を選択することもできます (ASCII 値はすべて 0x80 未満であるため、生成される色は濃い灰色になります。灰色以外の文字が必要な場合は、文字を変更します)。明らかに、これはシェル ループに一般化できます。また、大きなファイルを cat して効果をより明確に確認することもできます。例: $ cat /lib/libc.so.6 >/dev/fb0 fsf サポーター ;-P

画面の大部分が上書きされても心配しないでください。X は引き続きマウス ポインターを制御でき、ウィンドウがどこにマップされているかを把握できます。あなたがしなければならないのは、ウィンドウをつかんで少しドラッグしてノイズを消すことだけです.

テスト 2: cat /dev/fb0 > xxx 次に、デスクトップの外観を変更します (たとえば、新しいウィンドウを開き、他のウィンドウを閉じます)。最後に、逆の操作を行います: cat xxx > /dev/fb0 古いデスクトップを取り戻すために!

は、まあ、そうではありません。古いデスクトップのイメージは幻想であり、ウィンドウを開いて全画面表示にすると、すぐに不要になります。

テスト 3: /dev/fb0 の以前のダンプを取得し、ピクセルの色を変更する小さなアプリを作成します。たとえば、赤のコンポーネントを削除したり、青を増強したり、赤と緑を反転したりします。次に、これらを書き戻します。ピクセルを新しいファイルに変換し、後でテスト 2 の単純なシェル アプローチを使用して調べることができます。これは、4 番目のバイトごとに無視し、各セットの最初のバイトを青のコンポーネントとして扱うことを意味します。「ARGB」はビッグエンディアンであるため、C 配列のインデックスを増やしてこれらのバイトにアクセスすると、青が最初に来て、次に緑、次に赤になります。つまり、BGRA (ARGB ではない) です。

テスト 4: ビデオ速度でループし、非正方形の画像 (xeyes を考える) を画面の一部に送信して、ウィンドウの境界線のないアニメーションを作成するアプリを任意の言語で作成します。余分なポイントについては、アニメーションを画面全体に移動させます。小さな行に相当するピクセルを描画した後は、必ず大きなスペースをスキップする必要があります (アニメーション化されている画像よりもはるかに広い画面幅を補うため)。

テスト 5: 友達にいたずらをします。たとえば、テスト 4 を拡張して、アニメの人物の写真がデスクトップに表示されるようにします (ピクセル データを取得するために自分自身を撮影することもできます)。その後、重要なデスクトップの 1 つに移動しますフォルダーを拾い上げて細断し、ヒステリックに笑い始め、火の玉が出てデスクトップ全体を飲み込みます。これはすべて幻想ですが、彼らは少しびっくりするかもしれません..しかし、それを学習体験として使用して、Linux とオープンソースを誇示し、初心者にとって実際よりもはるかに恐ろしいものであることを示します。[「ウイルス」は一般的に Linux では無害な幻想です]

于 2011-05-08T12:39:43.180 に答える
8

X11を実行している場合は、X11APIを使用して画面に描画する必要があります。Xサーバーを一周することは非常に壊れています(そして、あなたが見てきたように、しばしば機能しません)。また、クラッシュや一般的なディスプレイの破損を引き起こす可能性があります。

どこでも(コンソールとXの下の両方で)実行できるようにしたい場合は、SDLまたはGGIを調べてください。X11だけが気になる場合は、GTK、QT、さらにはXlibを使用できます。多くの、多くのオプションがあります...

于 2011-02-14T21:13:31.233 に答える
3

上で提案したように、/ dev/fb0に書き込もうとする前に注意してください。私はubuntu10.04のXで試してみましたが、a)視覚的に何も起こらなかった、b)すべてのシェルウィンドウ、さらには他のttyを破壊し、カーネルエラーと機能の欠如を引き起こしました。

于 2012-06-28T17:06:24.330 に答える