• Liebe Freunde!
    Ich hoffe (nicht), daß Ihr Euch vor lauter Spannung und Ungeduld die Nägel blutig gekaut und die Neu-laden-Schaltfläche des Browsers bis auf den untersten Pixel abgenutzt habt! Für den letzten Fall bliebe dann nur, das Browser-Fenster zu verschieben oder besser gleich einen neuen Monitor zu holen.

    Wie geht die Reise weiter? Sie geht zurück! Zurück zum Ursprung, wo alles begann. So wie Antäus (für die Kreta-Liebhaber Ανταιος) immer wieder neue Kraft von seiner Mutter erhielt, widmen auch wir uns zur Stärkung der Mutter aller Bildformate und zugleich dem Format, das dies Programm gebar – MacPaint.
    Dies war das erste kodierte Bildformat. Entsprechend Patina hatten die Routinen angesetzt. Ich brachte sie auf den neuesten Stand und polierte auch gleich noch die Darstellung der MacPaint-Pinselmuster. Hier hatte noch die Darstellung als 1-Bit-Bitmap gefehlt.

    Exkurs: In einer 1-Bit-Bitmap kodiert ein Bit ein Pixel. Und ein Byte damit acht Pixel. So ein MacPaint-Muster ist acht Pixel breit. Also ein Byte groß. Man braucht also nur das Muster-Byte zur Anzeige in die Bitmap übertragen. So weit, so einfach. Doch erst mit einem Rahmen werden die Muster schön. Und kompliziert:

    • Denn nun beginnt das Bild mit einem Rahmen. ist er ein Pixel breit, benötigt er ein Bit.

    • Somit bleiben für das folgende Muster nur sieben Bit. Diese müssen aus dem Muster-Byte extrahiert und in das erste Bild-Byte übertragen werden.

    • Das achte Muster-Bit sollte jetzt nicht großzügig entsorgt, sondern als erstes Bit in nächste Bild-Byte eingesetzt werden.

    • Dort folgt dann als zweites Bit das neue Rahmen-Bit. Somit bleiben für das nächste Muster nur noch sechs Bit.

    • Also muß das Muster-Byte 6:2 geteilt und in zwei Byte untergebracht werden. Worauf dann der nächste Rahmen ...


    Fast berstend vor frisch gezapfter Kraft tippte ich rastlos weiter und schuf nun endlich auch den Optionsdialog für die MacPaint-Pinselmuster-Darstellung. Analog zu den Farbpaletten gestattete ich auch hier einen hellen Rahmen, der natürlich auch im Code umgesetzt sein wollte.

    Die Beispiele zeigen eine Pinselmuster-Palette in der Standardansicht und in einer individuellen Variante zusammen mit dem Optionsdialog.

    Wir werden dann noch etwas bleiben, bei Muttern. Und futtern. Und mit dieser Kraft noch richtig auf die Torte hauen!

  • Während ich mir so einige MacPaint-Bilder genüßlich betrachtete, stellte ich fest, daß der neue Code zwar schön, aber auch recht langsam war. Also warf ich meinen PPP (pompösen Programmierplan) etwas um und begab mich auf Optimimierungsmission. Die interessanten Ergebnisse möchte ich hier teilen und darauf hinweisen, daß der heutige Beitrag etwas code-lastiger ausfallen wird.

    Zum besseren Verständnis der nachfolgenden Ausführungen hier einige Hinweise zum Aufbau von MacPaint-Bildern und dem ursprünglichen Darstellungs-Code:

    • Die typischen MacPaint-Bilder, die mir vorliegen, zeigen kein Bild über ihre gesamte Größe, sondern eher ein kleineres Bild in ca. der Mitte und rundherum viel weißen Raum. So ein Bild nahm ich mir als Testobjekt.
    • MacPaint-Bilder haben eine feste Größe von 576 x 720 Pixeln und eine Farbtiefe 1 Bit. Es sind also Schwarz-Weiß-Bilder.
    • Jede Zeile ist mit dem PackBit-Algorithmus komprimiert. Dieser unterteilt die Bilddaten in einzelne Pakete.
    • Es gibt zwei Sorten Pakete. Der Typ „Wiederholung“ sagt: Wiederhole das nächste Byte n-mal! Der Typ „Übernehmen“ möchte: Übernimm die folgenden n Byte!
    • Im Wesentlichen geht das Programm so vor: Es liest Daten aus der Datei. Es entpackt jedes Paket und schreibt jedes der entstandenen Bytes mit dem Befehl poke ins VRAM, einem R-Basic-Puffer (hierbei muß eine Speicheradresse angegeben werden). Ist eine Bildzeile komplett, wird sie mittels peekline in das entstehende Bild übertragen.
    • Hinweis: Die gezeigten Code-Beispiele enthalten keinen vollständigen und korrekten Code, sondern sind eine Mischung aus R-Basic- und Pseudo-Code, der die Wahrscheinlichkeit der Verständlichkeit auch für Nichtprogrammierer erhöhen soll.

      Code
      if wiederholungsmodus = true then byteValue = readNextByte()
      for n = 1 to anzahl
          if wiederholungsmodus = false then byteValue = readNextByte()
          poke byteValue, adresse
          adresse = adresse + 1
      
      
          if zeile = komplett then bitmap.peekline 0, zeile
      next n


    So nahm das Fitness-Programm Mac-Rakete seinen Lauf:

    • 23,8 s benötigte das Programm initial, um das Bild darzustellen.
    • 20,0 s waren es nach der ersten Optimierung.
      Bislang wurde nach jedem ins VRAM geschriebenen Byte geprüft, ob das Bildzeilenende erreicht ist. Das ist aber nicht nötig, da MacPaint-Bilder zeilenweise kodiert sind. Eine Bildzeile endet daher nie in, sondern nur mit einer Kodierung. Daher verschob ich die Prüfung if zeile = komplett then hinter die Schleife, was immerhin (für eine einfache if-Prüfung!) 3,8 s und damit 16 % brachte.
    • 13,4 s waren es nur noch nach einer Schleifenaufteilung!
      Jetzt spendierte ich jedem der beiden Kodiermodi eine eigene Schleife. Im Wiederholungsmodus wird n-fach das gleiche Byte geschrieben. Wenn n nun eine gerade Zahl ist, lassen sich die Schleifendurchläufe und Schreiboperationen halbieren. Denn so läßt sich der Befehl doke verwenden, der zwei Byte auf einmal schreibt.

      Code
      for n = 1 to anzahl / 2
          doke 2*byteValue, adresse
          adresse = adresse + 2
      next n
    • 13,0 s dauerte es noch nach dem nächsten Trick.
      Nun behandelte ich den Fall, daß die Wiederholungsanzahl eine ungerade Zahl ist. Dann wird zuerst ein einzelnes Byte geschrieben, wodurch eine gerade Anzahl noch zu schreibender Bytes übrigbleibt, die mit der soeben erstellten doke-Schleife abgearbeitet werden. Vor der Schleife aus dem vorherigen Punkt steht nun also:

      Code
      if anzahl = ungerade then
          poke byteValue, adresse
          adresse = adresse + 1
          anzahl = anzahl - 1
      end if
    • 11,3 s verstrichen noch, nachdem ich den Übernehmen-Modus ähnlich strukturiert hatte.
      Auch hier wird bei einer ungeraden Anzahl an Bytes erst eines geschrieben und dann werden die geraden in einer halbierten Schleife abgearbeitet. Hier müssen dann aber immer zwei neue Byte aus dem Puffer gelesen werden. Durch diesen etwas höheren Aufwand und weil wohl dieser Modus im Beispielbild seltener vorkommt, fällt die Zeitersparnis geringer als beim Wiederholungsmodus aus.
    • 8,8 s verblieben nur noch, nachdem das Programm gleich ganze Zeilen schreiben konnte.
      Da ein Großteil des Bildes aus weißen Zeilen besteht, dachte ich, ich könnte die 10-Sekunden-Marke knacken, wenn eine ganze Zeile mit einem Befehl geschrieben werden könnte! Da MacPaint-Bilder eine feste Größe haben, hat auch eine Bildzeile eine fixe Größe von 72 Byte. Dadurch konnte ich eine sog. Struktur anlegen, die aus 72 Byte mit jeweils dem Wert null besteht. Also einer weißen Zeile:

      Code
      if anzahl = 72 then
          spoke struktur, adresse
          adresse = adresse + 72
      end if


      Das brachte zwar 2,5 s Sekunden und den einstelligen Bereich, aber insgeheim hatte ich mir sogar mehr erhofft. Und falls ein Bild lauter schwarze Zeilen haben sollte, profitiert es nicht davon.


    Fazit: Durch die Anpassungen des Codes an die Eigenheiten der zu verarbeitenden Daten wurde etwas erreicht, was leicht widersprüchlich klingt: Es gibt mehr Code und der Code ist schneller. Die Reduzierung der Ausführungszeit auf ca. drei Achtel sind die Redundanzen aber wert, finde ich. So kann man noch begeisterter stundenlang MacPaint-Bilder anschauen :).

    Einmal editiert, zuletzt von sebi (30. November 2022 um 11:03)

  • Der letzte Beitrag wurde sehr gut angenommen – herzlichen Dank! – und unter der Hand bekam ich sogar Insider-Tips, was ich noch ausprobieren könnte, um der Mac-Rakete noch etwas Extraschub zu verpassen, damit sie sich vielleicht sogar asymptotisch der Photonengeschwindigkeit annähert. Neue Universen kämen dann in Reichweite!

    Aus dem geheimen Schreiben destillierte ich drei Ideen, die ich hier ausprobieren möchte:

    • Nicht direkt in das R-Basic-VRAM mit poke und doke schreiben, sondern erstmal in eine Struktur schreiben und diese dann auf einen Schlag ins VRAM übertragen.
    • Die Zählvariablen nicht manuell, sondern mittels der R-Basic-Befehle incr und decr rauf- bzw. runterzählen.
    • Das Schreiben der Bytes mit dem Aktualisieren der Zählvariablen zu einer Befehlszeile zusammenfassen. Das geschieht in R-Basic mittels Doppelpunkt in der Form befehl1 : befehl2.


    Zuerst ergänzte ich den gestrigen Programm-Code um eine neue Variante, bei der die entpackten Bytes nicht direkt ins VRAM, sondern in eine Struktur geschrieben werden. Ist die Zeile komplett, wird die Struktur mittels spoke ins VRAM übertragen und von dort in die Bitmap.


    Dieser kurz-knackige Code gefiel mir so gut, daß ich ihn auch (zwecks erweiterter Vergleichbarkeit) für eine weitere, reine poke-Variante übernahm.


    Ich entschied mich, die benötigte Zeit in sechs Szenarien zu messen: in der reinen poke-, der optimierten poke/doke- und der Strukturvariante. Und jeweils mit der weißen Bildzeile auf einen Schlag (siehe gestern) und einmal ohne, weil dieser Trick nicht neutral, sondern stark vom Bildinhalt abhängig ist.
    Die unter unbestechlichen Zeugen (einer kleiner Statue) festgestellten, quasi amtlichen Ergebnisse lauten:

    • Variante pures poke: 16,7 s
    • Variante poke/doke: 12,2 s
    • Variante Struktur: 17,2 s
    • Variante pures poke mit weißer Zeile: 10,2 s
    • Variante poke/doke mit weißer Zeile: 9,1 s
    • Variante Struktur mit weißer Zeile: 10,3 s


    Diese Ergebnisse würde ich so interpretieren:

    • Das Lesen und Schreiben von Strukturen ist in etwa zeitäquivalent zum Lesen und Schreiben des VRAMs.
      Die VRAM-Variante hat dabei den Vorteil – der ihr die entscheidende Nasenspitze verlängert haben könnte –, daß die Daten gleich am gewünschten Ort sind, während die Struktur noch mit einem zusätzlichen Befehl ins VRAM übertragen werden muß.
    • Es lohnt sich, Schleifendurchläufe zu minimieren. Deswegen ist die doke-Variante um Etliches schneller. Deswegen hat die weiße Bildzeile einen großen Effekt bei den anderen beiden Varianten, weil hier die hohe Schleifenzahl drastisch verringert wird.
      Deswegen waren es gestern auch 8,8 s statt der heutigen 9,1 s, weil es da noch zusätzlichen Code – den ich nonchalant verschwieg – für den Fall anzahl = 8 gab. Dort stand dann keine Schleife, sondern vier doke-Befehle. Das hatte ich schon früher festgestellt, daß sich mehr Code oft lohnt, wenn er Schleifen verkürzt.


    Weiter geht’s im nächsten Teil!

    2 Mal editiert, zuletzt von sebi (30. November 2022 um 14:46)

  • Doch kommen wir nun im zweiten Teil zu den anderen beiden Vorschlägen. Die hatte ich bislang selber noch nicht ausprobiert und war auf die Ergebnisse gespannt. Und wurde sehr überrascht!

    Der Code wurde in denselben sechs Szenarien wie oben getestet. Zuerst änderte ich die Zählervariablenberechnung:

    Code
    poke adresse, byteValue
    adresse = adresse + 1
    
    
    //wurde geändert zu:
    
    
    poke adresse, byteValue
    incr adresse


    Im nächsten Testdurchlauf faßte ich die beiden Code-Zeilen zusammen. So werden sie von R-Basic auf einmal geladen und direkt hintereinander ausgeführt. Es entfällt also ein Ladeschritt.

    Code
    poke adresse, byteValue
    incr adresse
    
    
    //wurde geändert zu:
    
    
    poke adresse, byteValue : incr adresse


    Nach zahllosen Versuchsreihen, durchgearbeiteten Nächten bei Vollmond, Wolfsgeheul und sorgenvollem Blick zum Kellerfenster mit dem rostig-wackligen Schloß ergaben sich diese Zahlenreihen:

    • Variante pures poke: 16,7 s — 15,2 s — 14,4 s
    • Variante poke/doke: 12,2 s — 11,5 s — 11,1 s
    • Variante Struktur: 17,2 s — 15,6 s — 14,9 s
    • Variante pures poke mit weißer Zeile: 10,2 s — 9,7 s — 9,5 s
    • Variante poke/doke mit weißer Zeile: 9,1 s — 8,8 s — 8,7 s
    • Variante Struktur mit weißer Zeile: 10,3 s — 9,8 s — 9,6 s


    In einer Reihe stehen dabei von links nach rechts: Zeit für adresse = adresse + 1 — Zeit für incr adresse — Zeit für : incr adresse.

    Und nun ist wieder Zeit für einige conclusiones sapientes:

    • Die kleinen Code-Änderungen bringen überraschend deutliche Ergebnisse!
    • Dabei ist der Effekt von incr/decr in etwa doppelt so groß wie der des Zusammenfassens in einer Zeile.
    • Auch hier gilt (logischerweise): Je höher die Schleifenzahl, um so größer die meßbare Ersparnis.


    Fazit: Es lohnt sich auf jeden Fall, mal in seiner Routine innezuhalten und neue Lösungswege auszuprobieren. Herzlichen Dank für die Tips also! Von nun an werde ich möglichst die incr/decr-Funktionen nutzen und auch, wo es paßt, zwei Befehle in einer Zeile zusammenfassen. Bei der Bilderstellung werde ich wohl bei der VRAM-Methode bleiben. Da dräut aber schon die erste Ausnahme am Horizont: Bei einem der nächsten Unterprojekte kann es temporär Pixel mit negativen Werten geben. Die lassen sich im VRAM mit seinem Byte-Datentyp aber nicht abbilden. Also muß ich zum Array oder zur Struktur greifen. Da sich ein Array aber nicht so einfach ins VRAM kopieren läßt, wird hier wohl doch die Struktur zum Einsatz gelangen!

    Ich hoffe, Ihr konntet von diesen technischen Testreihen auch Einiges mitnehmen. Am besten greift Ihr jetzt selber zu R-Basic und probiert es in Eurem neuen, eigenen Programm aus :thumbup: !

  • Ich finde das auch sehr spannend und toll geschrieben. Sei nicht traurig, wenn nicht jedes Mal Feedback kommt, ich lese trotzdem mit!


    Danke :) :) !

    Bin nicht mehr traurig, weiß ja jetzt, daß viele/alle mitlesen :P . Und habe noch zwei weitere Strategien:

    • Wollte schon immer mal einen Blog schreiben. Wußte aber nie so recht worüber. Hier hat sich nun ein Thema ergeben, das sogar ständig selber Nachschub liefert!
    • Beim Schreiben stelle ich mir einfach vor, draußen wartet ein unersättliches Millionenpublikum auf die neuesten Nachrichten und möchte unterhalten werden.


    Und so macht es derzeit verdammt viel Spaß!
    Salute!

    PS: Ab und zu eine Rückmeldung erfreut natürlich trotzdem das Herz :)

  • Bevor ich mich wieder den ganz normalen aufregend-phantastischen neuen Funktionen widme, gehe ich noch einem weiteren Beschleunigungstip nach, der mir nachts noch zugespielt wurde. Oder eher zugeworfen. Mit einem Stein. Durchs Fenster. Das geschlossen war.

    Die dem Gedanken zugrunde liegende Idee versucht berechtigterweise, die Zahl der Schleifendurchläufe zu verringern. Die meisten Durchläufe entstehen offenbar im Wiederholungsmodus. Dort wird es öfter vorkommen, daß rein weiße oder rein schwarze Bytes (jeweils acht Pixel) wiederholt werden. Nun könnte man eine Struktur für eine weiße Zeile (gibt es schon) und für eine schwarze Zeile anlegen und jedesmal, wenn weiße oder schwarze Bytes wiederholt werden sollen, die gesamte Struktur (also eine gesamte Zeile) mit nur einem Befehl spoke ins VRAM schreiben. Das ist jetzt der Trick: Nicht mehr die Byte-Anzahl zählen und schleifenweise reinschreiben, sondern mit voller Breitseite feuern. Die zuviel geschriebenen Bilddaten werden dann von den nächsten überschrieben oder von der Bitmap einfach nicht beachtet.

    Um den Aufwand überschaubar zu halten, vergleiche ich die heutige neue Version nur mit den bislang schnellsten Varianten pures poke und optimiertes poke/doke mit weißer Zeile und : incr adresse.

    • Variante pures poke mit weißer Zeile: 9,5 s
    • Variante poke/doke mit weißer Zeile: 8,7 s
    • Variante pures poke mit ganzen Zeilen: 8,5 s
    • Variante poke/doke mit ganzen Zeilen: 8,0 s


    Die Breitseite hat voll eingeschlagen :D! Eine neue Bestzeit, ein neuer Champion krönt den Abschluß unserer Testreihe! Das erste Adventstürchen hat gleich den Weg zu himmlischen Rekorden geöffnet. (Johannes möge diese billige Blasphemie verzeihen!)
    Der offizielle Programm-Code besteht nun aus poke/doke-Optimierungen mit weißer und schwarzer Zeile und : incr adresse.
    Vielen Dank fürs Mitmachen!

  • Wofür ist das gut, bzw. kann man es benutzen? ?(

    Gut ist, dass sich mittlerweile einige Entwickler gefunden haben, die die Möglichkeiten, die R-BASIC bietet, auch tatsächlich nutzen können.

    Gut finde ich, dass weitere Grafikformate unter GEOS zugänglich werden.

    Besonders gut finde ich, dass Sebi mit seiner Arbeit auf das QOI-Grafikformat aufmerksam gemacht hat. Vielleicht hat das Format das Potenzial, unter GEOS zukünftig 24bit Grafiken schnell anzuzeigen.

  • Besonders gut finde ich, dass Sebi mit seiner Arbeit auf das QOI-Grafikformat aufmerksam gemacht hat. Vielleicht hat das Format das Potenzial, unter GEOS zukünftig 24bit Grafiken schnell anzuzeigen


    .. und dabei weniger Platz zu brauchen als eine 24-Bit-BMP (zumindest auf der Platte) und sogar noch Transparenz zu unterstützen.
    Rainer

    Es gibt 10 Arten von Menschen - die einen wissen was binär ist, die anderen nicht.

  • Ich frage mich:
    Was ist da alles an mir vorbei gegangen? Wofür ist das gut, bzw. kann man es benutzen? ?(

    Hallo Achim!
    Danke für Dein Interesse :)!
    Das ist ein kleines Programm, das verschiedene, meist alte, Grafikformate einlesen kann. Damit kann es dann:

    • Bildinfos, z.B. Breite, Höhe, Farbtiefe u.a., anzeigen. Das ist der (ursprünglich angedachte) Hauptzweck.
    • Einige Formate kann es auch darstellen. Das ist jetzt fast schon der neue Hauptzweck.
    • Die Formate, die es darstellen kann, kann es als BMP speichern.
    • Bei einigen Formaten kann es auch die verwendeten Farbpaletten anzeigen und nach HTML exportieren.
    • Bei einigen Formaten mit Transparenzen kann es auch die Transparenzmaske anzeigen.

    Einmal editiert, zuletzt von sebi (8. Dezember 2022 um 22:16)

  • Ursprünglich wollte ich nach den Optimierungen noch weitere Pläne mit dem MacPaint-Format verfolgen. Doch nach einigen anstrengenden Tagen war mir nach Abwechslung, ich wollte etwas Kleines, Neues, das ich auch fix abschließen kann.
    Nach etwas Recherche fand ich dann auch gleich zwei passende Bildformate: Naïve Image Format und Dune HD Skin!

    • Das Naïve Image Format, mit der Endung .nie, ist noch brankaktueller als das kürzlich vorgestellte QOI-Format und Teil des Google-Projekts Wuffs. Hier geht es nicht um animierte Hunde, sondern um eine Programm-Bibliothek, die einfache Formate für die Weiterverarbeitung bereitstellen soll. Durch die Einfachheit soll die Software-Sicherheit gesteigert werden.
    • Das Format ist auch sehr einfach aufgebaut. Es besteht aus den unkomprimierten Bilddaten, die einfach aneinandergereiht sind. Zu jedem Pixel sind die RGBA-Werte (bzw. eigentlich BGRA) gespeichert.
    • Bei der Bearbeitung stolperte ich dann aber doch über zwei Falltüren:

      • Das Format unterstützt die Auflösungen 8 Bit und 16 Bit pro Farbkanal. Damit feierte gleich nach den Transparenzen eine weitere Neuheit ihre rauschende Premiere: Mein erstes Format mit 16 Bit! Die werden zur Darstellung in Geos auf 8 Bit heruntergerechnet. Doch grau, mein Freund, grau ist alle Theorie. Grau bleibt auch das Bild, denn das Google-Projekt bietet keine Beispielbilder mit 16 Bit, so daß ich, wir und die Welt dem Code nur vertrauen können!
        Habe jetzt mal Google geschrieben, ob sie dem Geos-Programm nicht einige Beispielbilder reichen können. Bin gespannt!
      • Eine Ballnacht rauscht in die andere hinüber, denn eine weitere Neuigkeit tanzte auf die Bühne: Die premultiplied transparence! Hier ist die Transparenz in die Bilddaten gleich eingerechnet.
        Zum Beispiel würde ein 100er Rotton mit 20 % Sichtbarkeit normalerweise in der RGBA-Form als (100, 0, 0, 51) gespeichert werden. Wird die Transparenz gleich eingerechnet, sehen die Bilddaten so aus: (20, 0, 0, 51). Das vereinfacht die Berechnung der darzustellenden Pixel. Allerdings kann die Ursprungsfarbe, sollte man sie mal kennenlernen wollen, nicht mehr eindeutig ermittelt werden. Insbesondere bei einer Transparenz von 100 % wäre bei dem Tupel (0, 0, 0, 0) dann jede Farbe möglich.
    • Das Programm Bildinfos kann hier die Bildinformationen sowie das Bild selber und die Transparenzmaske anzeigen. Zudem beherrscht es alle der mit QOI eingeführten Transparenzoptionen und fügte sogar noch die vorberechnete Transparenz hinzu.


    Da dieses Ablenkungsprojekt so erfolgreich lief, wechselte ich bei rasanter Fahrt einfach ins nächste Cabrio und fuhr in die Dünen:

    • Das Format mit der Endung .aai hat keinen richtigen Namen. Ich nenne es mal Dune HD Skin, da es dazu dient, bei den Dune HD Media Playern die Oberfläche, also eine skin, zu gestalten.
    • Damit ist es ein aktuelles Format mit praktischem Anwendungsbezug :)!
    • Das Format gleicht dem Naïve-Format, aber ist noch einfacher aufgebaut. Auch hier stehen die RGBA-Daten einfach hintereinander, aber es gibt keine Optionen für 16 Bit und vorberechneten Transparenzen. So konnte ich den Programm-Code weiterverwenden, brauchte ihn nur etwas entschlacken.
    • Auf den meisten aai-Bildern sieht man nicht viel, da sie zum Großteil aus Transparenzen bestehen und erst mit dem passenden Hintergrund wirken. Oder man läßt sich die Transparenzmaske anzeigen!


    Schöne Grüße!

  • Hallo Achim!
    Danke für Dein Interesse :)!
    Das ist ein kleines Programm, das verschiedene, meist alte, Grafikformate einlesen kann. Damit kann es dann:

    • Bildinfos, z.B. Breite, Höhe, Farbtiefe u.a., anzeigen. Das ist der (ursprünglich angedachte) Hauptzweck.
    • Einige Formate kann es auch darstellen. Das ist jetzt fast schon der neue Hauptzweck.
    • Die Formate, die es darstellen kann, kann es BMP speichern.
    • Bei einigen Formaten kann es auch die verwendeten Farbpaletten anzeigen und nach HTML exportieren.
    • Bei einigen Formaten mit Transparenzen kann es auch die Transparenzmaske anzeigen.

    ... ein bescheidenes kleines Programm von 30.000 Zeilen R-Basic Code...

  • Hallo Sebi,
    Das sieht mir nach einer Sammelleidenschaft an Grafikformaten aus. Zu DOS-Zeiten war ich immer fasziniert von der Software "Image Alchemy", welche dazumal glaube ich 300 verschiedene Formate konvertieren konnte. Da waren auch echte Exoten dabei. Auf Archive.org findest du noch eine Dokumentation, wo auch auf die Formate eingegangen wird und sicher auch die Software selbst, welche als einzige Shareware-Einschränkung nur bis 640x480 konvertieren konnte.

    Das wäre noch bisschen Futter für die nächsten Tage.. :thumbup:

    Mario


  • .. mehr als 32769, um genau zu sein -- was mal wieder einen Bug in R-BASIC enttarnt hat.
    Ein Update folgt ...
    Gruß
    Rainer

    Jupp, ich mach das ja auch nur als groß angelegten R-Basic-Belastungstest :D .

    Von den 30.000 sind aber vielleicht die Hälfte echte Code-Zeilen. Der Rest sind (nützliche?) Kommentare, die ich immer dazugebe.

    Nun hat mich die Zahl der verfaßten Zeilen über alle Code-Fenster hinweg mal selber interessiert. Der aktuelle Stand lautet:

    • Deklarationen: 1135 Zeilen
    • UI-Code: 2047 Zeilen
    • Programm-Code: 39.965 Zeilen


    Dabei sind die Definitionen und Erzeugung der vielen Farbpaletten schon in eine Library ausgelagert worden.
    Schon erstaunlich, was so an Text zusammenkommt. Mit einer anderen Buchstabenzusammenstellung hätte es auch mein erster Roman werden können!

  • Nach den diversen Vergnügungsausflügen geht's jetzt wieder zurück zur Arbeit! Der Plan ruft!
    Da das Programm jetzt MacPaint-Bilder schön und schnell anzeigen kann, wäre es doch eine feine Sache, so dachte ich mir, wenn es auch – Überraschung! – im MacPaint-Format speichern könnte! Denn erst so wird ja die Hommage komplett. Gesagt, getan. Ein Mann, ein Wort. Bei der Umsetzung legten sich mir diese kantigen, schwefelatmenden, glutrotstrahlenden Steine in den Weg:

    • Die Bilddaten sind zeilenweise mit dem PackBit-Verfahren zu komprimieren. Dabei kann man nicht nur das aktuelle Bild-Byte nehmen und es (aktuell weihnachtlich) einpacken, sondern muß auch immer ein bißchen vorausschauen, in die Zukunft und auf die nächsten Bytes.
    • Das MacPaint-Format hat ja eine fixe Größe von 576 x 720 Pixeln und eine feste Farbtiefe von 1 Bit. Somit lassen sich nur Schwarz-Weiß-Bilder als MacPaint speichern. Bei der Größe sollte es aber flexibler zugehen, denn sonst ließen sich praktisch nur MacPaint-Bilder als MacPaint speichern, was nach dem ausweglosen Labyrinth des Minotaurus klingt. Oder nach einem Kreisverkehr ohne Ausfahrt. Jedenfalls waren dafür neue Optionen notwendig:

      • Wenn das zu speichernde Bild niedriger und/oder schmaler als das MacPaint-Format ist, bleiben freie Bereiche übrig. Diese können entweder mit schwarzen oder mit weißen Pixeln gefüllt werden.
      • Ist das zu speichernde Bild kleiner als das MacPaint-Format, kann es an verschiedenen Stellen in demselben positioniert werden. Zum Beispiel oben am Rand, in der Mitte, am linken Rand. Oder auf ästhetische Art und Weise. So wie es das Programm vorschlägt: horizontal zentriert und vertikal nach dem Goldenen Schnitt ausgerichtet.
        Und auch ein zu großes Bild möchte sinnvoll positioniert werden. Da hinausragende Bildbereiche abgeschnitten werden, sollte hier der gewünschte sichtbare Bildinhalt über die Ausrichtung entscheiden.

        Exkurs Goldener Schnitt: Dieses berühmte, als ästethisch empfundene, dem Menschen seit der Antike und der Natur seit Äonen bekannte Teilungsverhältnis läßt sich so definieren, daß die längere Teilstrecke zur kürzeren in demselben Verhältnisse steht wie die Gesamtstrecke zur längeren Teilstrecke. Oder einfach als (1 + √5) / 2. Wer Phobien gegen Bohrer und Wurzelziehen entwickelt hat, merkt sich wohl lieber die gerundeten 1,6180339887498948482045868343656381177.
        Mit Entsetzen mußte ich feststellen, daß R-Basic die berühmte Schwester π mit einer eigenen Konstante würdigt, die schöne
        sectio aurea – vom Gemeinen Vulgärlateiner gerne forsch mit sexy Aura übersetzt – jedoch verschmäht und verschweigt. Rainer, was ist da los?

      • Derzeit werden Transparenzen im Bild einfach nicht beachtet, die bislang ausgeblendeten Pixel kommen somit zum Vorschein.
    • Im Programm mußte neue Infrastruktur geschaffen, quasi eine neue Autobahn gebaut werden.
      Bislang gab es ja nur die Schaltfläche „Speichern“, die das angezeigte Bild kommentarlos mit der R-Basic-eigenen Funktion als BMP speicherte. (Bei Tests fiel mir jetzt übrigens auf, daß 1-Bit-Bilder nicht als 1-Bit-BMP, sondern als 8-Bit-BMP gespeichert werden! Rainer, was ist da los?)
      Nun wird ein ganz neuer Speichern-Dialog angezeigt, in dem sich das gewünschte Format auswählen läßt. Dann blenden sich, je nach Format, weitere Optionen ein, mit denen der Nutzer das Ergebnis nach seinen Wünschen zu justieren vermag. Und erst danach geht die Speichern-Funktion ihrer gestalterischen Aufgabe nach.


    Anbei wieder ein Beispiel zur Visualisierung. Unser beliebtes Elmer-Bild wird von Neochrome nach MacPaint mit den gezeigten Einstellungen gewandelt. Dann folgt noch eine zweite Variante mit dunklem Hintergrund und der Bildanordnung rechts unten.

  • Als kleines, buntes Appetithäppchen habe ich den für die Bilddarstellung auswählbaren Farbpaletten die des BeOS-Nachfolgers Haiku hinzugefügt.
    Während die klassischen 16-Farben-Paletten die Farben angaben, die aufgrund der Hardware-Beschränkungen wirklich nur (gleichzeitig) dargestellt werden konnten, enthält die Haiku-Palette jene Farben, die zur Gestaltung der Benutzeroberfläche verwendet werden. Da ich BeOS sehr mag und damit auch deren Tochter Haiku – die natürlich trotzdem nur die Geliebten neben der Geos-Braut sind! – entschloß ich mich, diesen angenehmen Farbreigen aufzunehmen, auch wenn es sich nicht um eine herkömmliche Farbpalette handelt.