title logo
title right side
27.04.2026 02:20:00 Lokal:
Serverstatus: (4.12/5.05/6.5026.33/1528 GByte  
Aussentemperatur : 7.7 °C  Luftdruck : 1023.65 hPas/mbar
Impressions: 2 
Visits heute: 41 
Home  

Das ist die Krönung von Elaras bisherigem Wissen. Sie kombiniert alles: Bildskalierung, Aspect Ratio, ANSI-Farben und Terminal-Steuerung. Ein Bildbetrachter für die Shell (oft „ASCII-Art“-Viewer genannt, obwohl wir hier echte Farben nutzen) ist ein echtes Hacker-Tool.

Der Clou: Da ein Terminal-Zeichen meistens doppelt so hoch wie breit ist, nutzen wir den Unicode-Block <upper half block> (Upper Half Block \u2580). Ein Terminal-Zeichen kann so zwei vertikale "Pixel" gleichzeitig darstellen (Vordergrundfarbe für oben, Hintergrundfarbe für unten). So erhalten wir ein perfektes 1:1 quadratisches Pixel-Layout trotz rechteckiger Schrift!

Kapitel 23: Das Auge des Terminals (TrueColor Image Viewer)

Die Story: Elara muss Beweisfotos auf einem Server sichten, der keine grafische Oberfläche hat. Sie schreibt view, ein Programm, das Bilder direkt in die SSH-Session rendert. Sie nutzt den "Halbblock-Trick", um die Auflösung zu verdoppeln. Als das erste farbechte Foto in der schwarzen Konsole erscheint, fühlt es sich an, als hätte sie ein Fenster in eine andere Welt geöffnet.


Das Programm: shellview.c

Wir nutzen wieder stb_image.h. Lade sie herunter und lege sie in den Ordner. Dieses Programm unterstützt JPEG, PNG, BMP, GIF und mehr "out of the box".

// Compile: gcc shellview.c -lm -o shellview
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#include <stdio.h>
#include <sys/ioctl.h>
#include <unistd.h>

void print_pixel(uint8_t* top, uint8_t* bottom) {
    if (bottom) {
        // Vordergrund (oben) und Hintergrund (unten) setzen
        printf("\033[38;2;%d;%d;%dm\033[48;2;%d;%d;%dm\u2580", 
               top[0], top[1], top[2], 
               bottom[0], bottom[1], bottom[2]);
    } else {
        // Nur ein Pixel (für ungerade Höhen)
        printf("\033[38;2;%d;%d;%dm\u2580", top[0], top[1], top[2]);
    }
}

int main(int argc, char** argv) {
    if (argc < 2) {
        printf("Usage: %s <image_file>\n", argv[0]);
        return 1;
    }

    // 1. Terminal-Größe ermitteln
    struct winsize w;
    ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
    int term_w = w.ws_col;
    int term_h = (w.ws_row - 1) * 2; // *2 wegen Halbblock-Trick

    // 2. Bild laden
    int img_w, img_h, channels;
    unsigned char* data = stbi_load(argv[1], &img_w, &img_h, &channels, 3);
    if (!data) {
        fprintf(stderr, "Fehler beim Laden.\n");
        return 1;
    }

    // 3. Aspect Ratio Scaler (Keep Aspect)
    float scale = (float)term_w / img_w;
    if ((float)term_h / img_h < scale) scale = (float)term_h / img_h;

    int target_w = (int)(img_w * scale);
    int target_h = (int)(img_h * scale);

    // 4. Rendering mit Halbblock-Trick
    // Wir springen immer 2 vertikale Pixel pro Terminal-Zeile
    for (int y = 0; y < target_h; y += 2) {
        for (int x = 0; x < target_w; x++) {
            // Nearest Neighbor Sampling
            int src_x = (int)(x / scale);
            int src_y_top = (int)(y / scale);
            int src_y_bot = (int)((y + 1) / scale);

            uint8_t* p_top = &data[(src_y_top * img_w + src_x) * 3];
            uint8_t* p_bot = (y + 1 < target_h) ? &data[(src_y_bot * img_w + src_x) * 3] : NULL;

            print_pixel(p_top, p_bot);
        }
        printf("\033[0m\n"); // Reset am Zeilenende
    }

    stbi_image_free(data);
    return 0;
}

Die Technik hinter dem "Shell-Pixel"

Die Magie liegt in der ANSI-Sequenz und dem Unicode-Zeichen:

  • \033[38;2;R;G;Bm setzt die Vordergrundfarbe (Textfarbe).
  • \033[48;2;R;G;Bm setzt die Hintergrundfarbe.
  • Das Zeichen upper half block füllt genau die obere Hälfte des Zeichens mit der Textfarbe aus. Die untere Hälfte zeigt automatisch die Hintergrundfarbe.

Dadurch wird ein einzelnes Terminal-Zeichen (das 1:2 rechteckig ist) zu zwei quadratischen 1:1 Pixeln.

Elaras Meisterschaft

Das Bild ist gestochen scharf (für Terminal-Verhältnisse) und die Proportionen stimmen. Thorne ist beeindruckt, aber er hat einen letzten Trumpf: Er schickt Elara ein animiertes GIF. Ihr aktuelles Programm zeigt nur den ersten Frame.

Soll Elara im nächsten Kapitel lernen, wie sie GIF-Animationen in der Shell abspielt, indem sie die verschiedenen "Frames" extrahiert und mit ihrem nanosleep-Timing synchronisiert?