Startseite < Informatik < Algorithmen Datenstrukturen / Software-Engineering / Programmiersprachen < Compiler Interpreter < Setty Tinyray < Tinyray-Scanner Tinyray-Parser / Tinyray-Language Tinyray-Raytracer < Tinyray-RaytracerKit Tinyray-Elements [ DRUCK , 2004 , 2005 , 2006 , 2007 , 2008 , 2009 ] Tinyray-Viewport > / Tinyray-Wallpapers > > / Java C/C++ POV-Ray LaTeX > / Künstliche Intelligenz > Schach Privates / Inhalt >
Tinyray-Viewport
Der Viewport repräsentiert das Ausgabebild des Tinyray-Raytracers.
Ausgabebild Das Ausgabebild des Raytracers
Der Raytracer berechnet Farbwerte für das Ausgabebild. Alle Strahlen, die in der Kamera ihren Ursprung haben, gelangen über den sogenannten Viewport in die Szene. Der Raytracer sichert die aufwendig berechneten 3D-Farbvektoren im Viewport.
Rasterung
Der Viewport besitzt eine Breiten- und eine Höhenangabe. Die einzelnen Bildpixel (Vector3D) können über die x-y-Koordinaten des Viewport angesprochen und gesetzt werden. Der Viewport ist also nichts anderes als eine Rastergrafik.
Farbvektoren
Die Farbvektoren sind dreigeteilt: ein Teil rot, ein Teil grün und ein Teil blau. Einige Farbbeispiele sind:
  • Schwarz = new Vector3D(0.0, 0.0, 0.0);
  • Weiß = new Vector3D(1.0, 1.0, 1.0);
  • Rot = new Vector3D(1.0, 0.0, 0.0);
  • Grün = new Vector3D(0.0, 1.0, 0.0);
  • Blau = new Vector3D(0.0, 0.0, 1.0);
  • Gelb = new Vector3D(1.0, 1.0, 0.0);
Die einzelne Komponente des Farbvektors sollte zwischen den Bereichsgrenzen 0.0 und 1.0 liegen (Bereichsgrenzen eingeschlossen).
Implementierung Implementierung der Viewport-Klasse
Die Klasse Viewport ist eine recht einfache Klasse. Sie kapselt eine 2D-Matrix von 3D-Farbvektoren (Vector3D). Diese Matrix kann in unterschiedliche Bildformate gespeichert werden: PPM (ascii und binary), RAW, BMP, PNG und JPG.

Die 2D-Matrix heißt pixels und hat folgende Bereiche:
  1. pixels[0 .. width-1][0 .. height-1].
Sowohl die Mindestbreite als auch die Mindesthöhe des Viewport liegt bei 1. Das Pixel[0][0] befindet sich links oben im Viewport. Der Zugriff auf die Pixel ist bereichsgesichert. Liegt ein angegebenes Pixel außerhalb des Bildbereichs, so führt dies nicht zum Fehler bzw. Programmabsturz.

Der hier vorgestellte Viewport toleriert aber auch Farbübersteuerungen wie beispielsweise
  1. new Vector3D(2.0, 3.0, 9.0).
Das eben gezeigte Beispiel würde der Viewport als Weiß interpretieren bzw. darstellen.
Viewport.java
package tinyray.raytracer;

import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;

import javax.imageio.ImageIO;

/**
 * Die Klasse Viewport repräsentiert den visuellen Bereich, der zum Beispiel
 * nach dem Rendervorgang das Bild darstellt.
 */

public class Viewport {

    /**
     * Die Bildelemente als zweidimensionale Matrix. Jedes Bildelement wird
     * dargestellt durch einen dreidimensionalen Farbvektor.
     */

    protected Vector3D[][] pixels;

    /**
     * Initialisiert das Bild mit der Höhe und der Breite.
     * @param width Die Breite.
     * @param height Die Höhe.
     */

    public Viewport(int width, int height) {

        this.pixels = new Vector3D[Math.max(1, width)][Math.max(1, height)];

        // Alle Pixel auf Schwarz setzen.
        for (int y = 0; y < this.getHeight(); y++) {
            for (int x = 0; x < this.getWidth(); x++) {
                this.pixels[x][y] = Vector3D.ZERO;
            }
        }
    }

    /**
     * Gibt die Breite des Bildes zurück.
     * @return Die Breite.
     */

    public int getWidth() {
        return this.pixels.length;
    }

    /**
     * Gibt die Höhe des Bildes zurück.
     * @return Die Höhe.
     */

    public int getHeight() {
        return this.pixels[0].length;
    }

    /**
     * Prüft, ob sich die Koordinate (x, y) innerhalb des Bildes befindet.
     * @param x Die x-Komponente.
     * @param y Die y-Komponente.
     * @return true, falls ja.
     */

    public boolean isInViewport(int x, int y) {
        return (0 <= x) && (< this.getWidth())
            && (0 <= y) && (< this.getHeight());
    }

    /**
     * Gibt ein durch die Koordinate (x, y) bestimmtes Bildelement
     * als Farbvektor zurück.
     * Falls die Koordinate (x, y) nicht im Bereich des Bildes liegen sollte,
     * ist der Farbvektor der Nullvektor (schwarz).
     * @param x Die x-Komponente.
     * @param y Die y-Komponente.
     * @return Der Farbvektor.
     */

    public Vector3D getPixel(int x, int y) {
        if (this.isInViewport(x, y)) {
            return this.pixels[x][y];
        } else {
            return Vector3D.ZERO;
        }
    }

    /**
     * Setzt ein durch die Koordinate (x, y) bestimmtes Bildelement.
     * @param x Die x-Komponente.
     * @param y Die y-Komponente.
     * @param color Das Bildelement als Farbvektor.
     */

    public void setPixel(int x, int y, Vector3D color) {
        if (this.isInViewport(x, y)) {
            this.pixels[x][y] = color;
        }
    }

    /**
     * Speichert das Bild als ASCII-PPM-Format in eine Datei.
     * @param filename Der Name der Datei.
     * @throws IOException Wird geworfen, wenn sich ein I/O-Fehler ereignet.
     */

    public void storeAsAsciiPPM(String filename) throws IOException {
        FileOutputStream file = new FileOutputStream(filename);
        BufferedOutputStream buffered = new BufferedOutputStream(file);
        this.storeAsAsciiPPM(buffered);
        buffered.flush();
        file.close();
    }

    /**
     * Speichert das Bild als binäres PPM-Format in eine Datei.
     * @param filename Der Name der Datei.
     * @throws IOException Wird geworfen, wenn sich ein I/O-Fehler ereignet.
     */

    public void storeAsBinaryPPM(String filename) throws IOException {
        FileOutputStream file = new FileOutputStream(filename);
        BufferedOutputStream buffered = new BufferedOutputStream(file);
        this.storeAsBinaryPPM(buffered);
        buffered.flush();
        file.close();
    }

    /**
     * Speichert das Bild als RAW-Format in eine Datei.
     * @param filename Der Name der Datei.
     * @throws IOException Wird geworfen, wenn sich ein I/O-Fehler ereignet.
     */

    public void storeAsRAW(String filename) throws IOException {
        FileOutputStream file = new FileOutputStream(filename);
        BufferedOutputStream buffered = new BufferedOutputStream(file);
        this.storeAsRAW(buffered);
        buffered.flush();
        file.close();
    }

    /**
     * Speichert das Bild als BMP-Format in eine Datei.
     * @param filename Der Name der Datei.
     * @throws IOException Wird geworfen, wenn sich ein I/O-Fehler ereignet.
     */

    public void storeAsBMP(String filename) throws IOException {
        FileOutputStream file = new FileOutputStream(filename);
        BufferedOutputStream buffered = new BufferedOutputStream(file);
        this.storeAsBMP(buffered);
        buffered.flush();
        file.close();
    }

    /**
     * Speichert das Bild als PNG-Format in eine Datei.
     * @param filename Der Name der Datei.
     * @throws IOException Wird geworfen, wenn sich ein I/O-Fehler ereignet.
     */

    public void storeAsPNG(String filename) throws IOException {
        FileOutputStream file = new FileOutputStream(filename);
        BufferedOutputStream buffered = new BufferedOutputStream(file);
        this.storeAsPNG(buffered);
        buffered.flush();
        file.close();
    }

    /**
     * Speichert das Bild als JPG-Format in eine Datei.
     * @param filename Der Name der Datei.
     * @throws IOException Wird geworfen, wenn sich ein I/O-Fehler ereignet.
     */

    public void storeAsJPG(String filename) throws IOException {
        FileOutputStream file = new FileOutputStream(filename);
        BufferedOutputStream buffered = new BufferedOutputStream(file);
        this.storeAsJPG(buffered);
        buffered.flush();
        file.close();
    }

    /**
     * Speichert das Bild als ASCII-PPM-Format in einen Ausgabestrom.
     * @param output Der Ausgabestrom.
     * @throws IOException Wird geworfen, wenn sich ein I/O-Fehler ereignet.
     */

    public void storeAsAsciiPPM(OutputStream output) throws IOException {

        PrintStream printStream = new PrintStream(output);

        // Header
        printStream.print("P3\n");
        printStream.print(this.getWidth() + " " + this.getHeight() + "\n");
        printStream.print("255\n");

        // Bildpixel
        for (int y = 0; y < this.getHeight(); y++) {
            for (int x = 0; x < this.getWidth(); x++) {
                Vector3D pixel = this.pixels[x][y];
                printStream.print(" " + (red(pixel) & 0xFF));
                printStream.print(" " + (green(pixel) & 0xFF));
                printStream.print(" " + (blue(pixel) & 0xFF));
            }
            printStream.print("\n");
        }
    }

    /**
     * Speichert das Bild als binäres PPM-Format in einen Ausgabestrom.
     * @param output Der Ausgabestrom.
     * @throws IOException Wird geworfen, wenn sich ein I/O-Fehler ereignet.
     */

    public void storeAsBinaryPPM(OutputStream output) throws IOException {

        PrintStream printStream = new PrintStream(output);

        // Header
        printStream.print("P6\n");
        printStream.print(this.getWidth() + " " + this.getHeight() + "\n");
        printStream.print("255\n");

        // Bildpixel
        for (int y = 0; y < this.getHeight(); y++) {
            for (int x = 0; x < this.getWidth(); x++) {
                printStream.write(rgb(this.pixels[x][y]));
            }
        }
    }

    /**
     * Speichert das Bild als RAW-Format in einen Ausgabestrom.
     * @param output Der Ausgabestrom.
     * @throws IOException Wird geworfen, wenn sich ein I/O-Fehler ereignet.
     */

    public void storeAsRAW(OutputStream output) throws IOException {

        PrintStream printStream = new PrintStream(output);

        // Nur Bildpixel, keine Headerangaben!
        for (int y = 0; y < this.getHeight(); y++) {
            for (int x = 0; x < this.getWidth(); x++) {
                printStream.write(rgb(this.pixels[x][y]));
            }
        }
    }

    /**
     * Speichert das Bild als BMP-Format in einen Ausgabestrom.
     * @param output Der Ausgabestrom.
     * @throws IOException Wird geworfen, wenn sich ein I/O-Fehler ereignet.
     */

    public void storeAsBMP(OutputStream output) throws IOException {

        PrintStream printStream = new PrintStream(output);

        // Header
        printStream.print("BM");

        long imgsize = 4;
        imgsize *= this.getHeight();
        imgsize *= ((3 * 8 * this.getWidth() + 31) / 32);

        long size = 14 + 40 + imgsize;

        for (int shift = 0; shift < 64; shift += 8) {
            printStream.write((int)((size >> shift) & 0xFF));
        }

        printStream.write((int)(14 + 40));
        printStream.write((int)0x00);
        printStream.write((int)0x00);
        printStream.write((int)0x00);

        printStream.write((int)(40));
        printStream.write((int)0x00);
        printStream.write((int)0x00);
        printStream.write((int)0x00);

        for (int shift = 0; shift < 32; shift += 8) {
            printStream.write((int)((this.getWidth() >> shift) & 0xFF));
        }

        for (int shift = 0; shift < 32; shift += 8) {
            printStream.write((int)((this.getHeight() >> shift) & 0xFF));
        }

        printStream.write((int)(1));
        printStream.write((int)0x00);

        printStream.write((int)(24));
        printStream.write((int)0x00);

        // BI_RGB
        printStream.write((int)0x00);
        printStream.write((int)0x00);
        printStream.write((int)0x00);
        printStream.write((int)0x00);

        for (int shift = 0; shift < 64; shift += 8) {
            printStream.write((int)((imgsize >> shift) & 0xFF));
        }

        printStream.write((int)0x00);
        printStream.write((int)0x00);
        printStream.write((int)0x00);
        printStream.write((int)0x00);

        printStream.write((int)0x00);
        printStream.write((int)0x00);
        printStream.write((int)0x00);
        printStream.write((int)0x00);

        printStream.write((int)0x00);
        printStream.write((int)0x00);
        printStream.write((int)0x00);
        printStream.write((int)0x00);

        // Bildpixel
        for (int y = this.getHeight() - 1; y >= 0; y--) {
            for (int x = 0; x < this.getWidth(); x++) {
                printStream.write(bgr(this.pixels[x][y]));
            }
            // Zeilenumbruch
            int pad = (4 - ((3 * this.getWidth()) % 4)) & 0x03;
            for (int i = 0; i < pad; i++) {
                printStream.write((int)0x00);
            }
        }
    }

    /**
     * Speichert das Bild als PNG-Format in einen Ausgabestrom.
     * @param output Der Ausgabestrom.
     * @throws IOException Wird geworfen, wenn sich ein I/O-Fehler ereignet.
     */

    public void storeAsPNG(OutputStream output) throws IOException {

        BufferedImage bi = new BufferedImage(
                this.getWidth(),
                this.getHeight(),
                BufferedImage.TYPE_INT_RGB);

        // Nur Bildpixel, keine Headerangaben!
        for (int y = 0; y < this.getHeight(); y++) {
            for (int x = 0; x < this.getWidth(); x++) {
                bi.setRGB(x, y, RGB(this.pixels[x][y]));
            }
        }

        ImageIO.write(bi, "png", output);
    }

    /**
     * Speichert das Bild als JPG-Format in einen Ausgabestrom.
     * @param output Der Ausgabestrom.
     * @throws IOException Wird geworfen, wenn sich ein I/O-Fehler ereignet.
     */

    public void storeAsJPG(OutputStream output) throws IOException {

        BufferedImage bi = new BufferedImage(
                this.getWidth(),
                this.getHeight(),
                BufferedImage.TYPE_INT_RGB);

        // Nur Bildpixel, keine Headerangaben!
        for (int y = 0; y < this.getHeight(); y++) {
            for (int x = 0; x < this.getWidth(); x++) {
                bi.setRGB(x, y, RGB(this.pixels[x][y]));
            }
        }

        ImageIO.write(bi, "jpg", output);
    }

    /* Hilfsmethoden */

    /**
     * Rechnet einen Double-Wert in einen 8-Bit-Wert um.
     * @param value Der Double-Wert.
     * @return Der 8-Bit-Wert.
     */

    private static byte component(double value) {
        if (value <= 0.0) {
            return (byte)0;
        } else if (value >= 1.0) {
            return (byte)255;
        } else {
            return (byte)(255 * value);
        }
    }

    /**
     * Berechnet von einem Farbvektor den 8-Bit-Rot-Wert.
     * @param color Der Farbvektor.
     * @return Der 8-Bit-Rot-Wert.
     */

    public static byte red(Vector3D color) {
        return component(color.getX());
    }

    /**
     * Berechnet von einem Farbvektor den 8-Bit-Grün-Wert.
     * @param color Der Farbvektor.
     * @return Der 8-Bit-Grün-Wert.
     */

    public static byte green(Vector3D color) {
        return component(color.getY());
    }

    /**
     * Berechnet von einem Farbvektor den 8-Bit-Blau-Wert.
     * @param color Der Farbvektor.
     * @return Der 8-Bit-Blau-Wert.
     */

    public static byte blue(Vector3D color) {
        return component(color.getZ());
    }

    /**
     * Berechnet von einem Farbvektor die Rot-Grün-Blau-Werte.
     * @param color Der Farbvektor.
     * @return Die Rot-Grün-Blau-Werte.
     */

    public static byte[] rgb(Vector3D color) {
        byte[] result = new byte[3];
        result[0] = red(color);
        result[1] = green(color);
        result[2] = blue(color);
        return result;
    }

    /**
     * Berechnet von einem Farbvektor den Rot-Grün-Blau-Wert.
     * @param color Der Farbvektor.
     * @return Der Rot-Grün-Blau-Wert.
     */

    public static int RGB(Vector3D color) {
        return ((red(color) & 0xFF) << 16)
            | ((green(color) & 0xFF) << 8)
            | (blue(color) & 0xFF);
    }

    /**
     * Berechnet von einem Farbvektor die Blau-Grün-Rot-Werte.
     * @param color Der Farbvektor.
     * @return Die Blau-Grün-Rot-Werte.
     */

    public static byte[] bgr(Vector3D color) {
        byte[] result = new byte[3];
        result[0] = blue(color);
        result[1] = green(color);
        result[2] = red(color);
        return result;
    }

    /**
     * Berechnet von einem Farbvektor eine Color-Instanz.
     * @param color Der Farbvektor.
     * @return Die Color-Instanz.
     */

    public static Color color(Vector3D color) {
        return new Color(
                red(color) & 0xFF,
                green(color) & 0xFF,
                blue(color) & 0xFF);
    }
}
Anmerkung
Wenn Sie mit Java unterschiedliche Bildformate generieren möchten, können Sie den vorliegenden Viewport gerne als Vorlage nutzen. Ich zum Beispiel habe das Bitmap-Format (BMP) in diesem Viewport einmal detailliert entwickelt, sodass ich, wenn ich in einem anderen Projekt wieder einmal ein Bitmap-Format generieren muss, diesen Viewport als Vorlage wiederverwenden kann.
Beispiele Beispiele zur Verwendung der Viewport-Klasse
Im Folgenden werden zwei kleine Beispiele vorgestellt, welche die Benutzung des Viewport unabhängig vom Raytracer demonstrieren. Die Farbwerte werden durch Vector3D-Instanzen angegeben. Die Beispielklassen heißen Plus und Deutschland.
Plus.java
package tinyray.examples;

import java.io.IOException;

import tinyray.raytracer.Vector3D;
import tinyray.raytracer.Viewport;


public class Plus {

    public static void main(String[] arguments) {

        // 7x7 Rasterbild erzeugen.
        Viewport viewport = new Viewport(7, 7);

        // Horizontalen Strich zeichnen.
        viewport.setPixel(1, 3, new Vector3D(1.0, 1.0, 1.0));
        viewport.setPixel(2, 3, new Vector3D(1.0, 1.0, 1.0));
        viewport.setPixel(3, 3, new Vector3D(1.0, 1.0, 1.0));
        viewport.setPixel(4, 3, new Vector3D(1.0, 1.0, 1.0));
        viewport.setPixel(5, 3, new Vector3D(1.0, 1.0, 1.0));

        // Vertikalen Strich zeichnen.
        viewport.setPixel(3, 1, new Vector3D(1.0, 1.0, 1.0));
        viewport.setPixel(3, 2, new Vector3D(1.0, 1.0, 1.0));
        viewport.setPixel(3, 3, new Vector3D(1.0, 1.0, 1.0));
        viewport.setPixel(3, 4, new Vector3D(1.0, 1.0, 1.0));
        viewport.setPixel(3, 5, new Vector3D(1.0, 1.0, 1.0));

        try {
            // Pluszeichen in den verfügbaren Formaten speichern.
            viewport.storeAsPNG("plus.png");
            viewport.storeAsJPG("plus.jpg");
            viewport.storeAsAsciiPPM("plus.ascii.ppm");
            viewport.storeAsBinaryPPM("plus.binary.ppm");
            viewport.storeAsRAW("plus.raw");
            viewport.storeAsBMP("plus.bmp");

            System.out.println("Plus wurde in 6 Formate gespeichert!");

        } catch (IOException e) {
            System.err.println(e.getMessage());
        }
    }
}
java Plus
Diese Beispielanwendung speichert eine 7x7-Rastergrafik in sechs unterschiedliche Bildformate:
  1. plus.png (Portable Network Graphics) ist eine verlustfrei komprimierte Grafikdatei.
  2. plus.jpg ist eine verlustbehaftete komprimierte Grafikdatei.
  3. plus.ascii.ppm ist eine unkomprimierte Grafikdatei, die als Text gelesen werden kann. Dieses Format eignet sich besonders gut während der Entwicklungsphase zur Aufspürung von Fehlern.
  4. plus.binary.ppm ist eine unkomprimierte Grafikdatei.
  5. plus.raw ist eine unkomprimierte Grafikdatei, die nur die Farbwerte, jedoch keine Informationen über die Höhe und Breite der Grafik enthält.
  6. plus.bmp ist eine unkomprimierte Grafikdatei, m. E. jedoch mit einigen redundanten, geradezu überflüssigen Informationen.
Die Grafik selbst repräsentiert — wie sollte es auch anders sein — ein Pluszeichen wie folgt.
plus.png
plus.png

plus.jpg
plus.jpg

plus.ascii.ppm
P3
7 7
255
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 255 255 255 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 255 255 255 0 0 0 0 0 0 0 0 0
 0 0 0 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 0 0 0
 0 0 0 0 0 0 0 0 0 255 255 255 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 255 255 255 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
plus.binary.ppm
Zeile 00 01 02 03 04 05 06 07  08 09 10 11 12 13 14 15 Text
000
016
032
048
064
080
096
112

128
144
50 36 0A 37 20 37 0A 32  35 35 0A 00 00 00 00 00
00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00  00 FF FF FF 00 00 00 00
00 00 00 00 00 00 00 00  00 00 00 00 00 00 FF FF
FF 00 00 00 00 00 00 00  00 00 00 00 00 FF FF FF
FF FF FF FF FF FF FF FF  FF FF FF FF 00 00 00 00
00 00 00 00 00 00 00 00  FF FF FF 00 00 00 00 00
00 00 00 00 00 00 00 00  00 00 00 00 00 FF FF FF

00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00  00 00 00 00 00 00
P6·7 7·255······
················
·········•••····
··············••
•············•••
••••••••••••····
········•••·····
·············•••

················
··············
plus.raw
Zeile 00 01 02 03 04 05 06 07  08 09 10 11 12 13 14 15 Text
000
016
032
048
064
080
096
112

128
144
00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00  00 00 00 00 00 00 FF FF
FF 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
00 00 00 FF FF FF 00 00  00 00 00 00 00 00 00 00
00 00 FF FF FF FF FF FF  FF FF FF FF FF FF FF FF
FF 00 00 00 00 00 00 00  00 00 00 00 00 FF FF FF
00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
00 00 FF FF FF 00 00 00  00 00 00 00 00 00 00 00

00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
00 00 00
················
··············••
•···············
···•••··········
··••••••••••••••
•············•••
················
··•••···········

················
···
plus.bmp
Zeile 00 01 02 03 04 05 06 07  08 09 10 11 12 13 14 15 Text
000
016
032
048
064
080
096
112

128
144
160
176
192
208
42 4D DE 00 00 00 00 00  00 00 36 00 00 00 28 00
00 00 07 00 00 00 07 00  00 00 01 00 18 00 00 00
00 00 A8 00 00 00 00 00  00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 FF  FF FF 00 00 00 00 00 00
00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 FF
FF FF 00 00 00 00 00 00  00 00 00 00 00 00 00 00

00 FF FF FF FF FF FF FF  FF FF FF FF FF FF FF FF
00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 FF
FF FF 00 00 00 00 00 00  00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 FF  FF FF 00 00 00 00 00 00
00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00  00 00 00 00 00 00
BM•·······6···(·
················
··•·············
················
················
·······•••······
···············•
••··············

·•••••••••••••••
···············•
••··············
·······•••······
················
··············
Folgende Beispielanwendung heißt Deutschland und speichert bei Ausführung eine Deutschlandfahne im JPG-Format mit dem Namen „deutschland.jpg”.
Deutschland.java
package tinyray.examples;

import java.io.IOException;

import tinyray.raytracer.Vector3D;
import tinyray.raytracer.Viewport;


public class Deutschland {

    /* Die drei Farben definieren. */

    private static Vector3D SCHWARZ = Vector3D.ZERO;
    private static Vector3D ROT = Vector3D.X;
    private static Vector3D GOLD = new Vector3D(1.0, 1.0, 0.0);

    /* Hauptprogramm */

    public static void main(String[] arguments) {

        // 50x30 Rasterbild erzeugen.
        Viewport viewport = new Viewport(50, 3 * 10);

        // Farben der Deutschlandfahne richtig plazieren.
        for (int x = 0; x < 50; x++) {
            for (int y = 0; y < 10; y++) {
                viewport.setPixel(x, y, SCHWARZ);
            }
            for (int y = 10; y < 20; y++) {
                viewport.setPixel(x, y, ROT);
            }
            for (int y = 20; y < 30; y++) {
                viewport.setPixel(x, y, GOLD);
            }
        }

        try {
            // Deutschlandfahne speichern.
            viewport.storeAsJPG("deutschland.jpg");

            System.out.println("Fahne 'deutschland.jpg' wurde gespeichert!");

        } catch (IOException e) {
            // Falls Probleme beim Speichern :-(
            System.err.println(e.getMessage());
        }
    }
}
deutschland.jpg
deutschland.jpg