Maskierter Text in Processing

Hinzugefügt am von Steffen Fiedler

Powered by Processing.js

In diesem Beispiel maskieren wir einen Text mittels zwei Bildern. Zu Begin wird der Text mit weißer Füllung in das Dunkle Sketchfenter gezeichnet und dient als Ausgangspunkt. Der Aufruf von textAlign() mit CENTER und die Positionierung bei width/2 und height/2 zentrieren den String auf der Zeichenfläche.
background (76);
fill (255);
textFont (font);
textAlign (CENTER);
text ("Text goes here", width/2, height/2 + 10);
Im nächsten Abschnitt kopieren wir den Inhalt des Sketchfensters in das Bild (PImage) imgText und erzeugen ein weiteres, leeres namens imgMask. Beide Bilder haben wir damit nicht wie üblich geladen, sondern dynamisch angelegt. Ein Weg dies zu tun ist die von Processing zur Verfügung gestellte Funktion createImage(). Der Parameter ARGB steht für ein Bild im RGB Farbraum, welches ebenfalls Transparenz unterstützt (A = alpha).

Dies waren bisher alles Vorbereitungen im setup(). Im draw() gilt es nun die Maske mit den Balken zu befüllen und final auf den Text anzuwenden. Durch den Aufruf der Funktion updateMask() löschen wir zu Anfang den Inhalt des Sketchfensters und zeichnen weiß gefüllte Balken. Dieses Bild wird anschließend in die Maske kopieret und mit mask() auf das Bild imgText angewendet.

Damit haben wir die Maske aktualisiert und alle Balken nach unten verschoben. Was nun geschieht ist der letzte Schritt. Wir zeichnen den Text auf farblich angepasstem Hintergrund:
background (138, 170, 178);
fill (229, 90, 38);
text ("Text goes here", width/2, height/2 + 10);
Und stellen das maskierte Bild deckungsgleich dar:
image (imgText, 0, 0);

Der Sketch

// Leere Bilder für Text und Maske
PImage imgText;
PImage imgMask;
// Variable für die Schrift
PFont font;

// Höhe der Balken
int barHeight = 17;
// Verschiebung in Pixeln
float offset = 0;
// Verschiebung pro Bild
float offsetTick = 0.3;

void setup () {
  size (550, 200);
  noStroke ();
  
  // Kantenglättung aktivieren
  smooth ();
  // Laden und Erstellen der Schrift
  font = createFont ("Arial", 67);
  
  // Zeichne weißen Text auf dunklen
  // Hintergrund in das Sketchfenster
  background (76);
  fill (255);
  textFont (font);
  textAlign (CENTER);
  text ("Text goes here", width/2, height/2 + 10);
  
  // Kopiere den Inhalt des Sketchfensters in
  // das temporäre Bild 'imgText'
  imgText = createImage (width, height, ARGB);
  copySketchIntoImage (imgText);
  
  // Erstelle ein weiteres leeres Bild
  // für die Maske
  imgMask = createImage (width, height, ARGB);
}

void draw () {
  
  // Verschiebe die Balken weiter nach unten
  offset += offsetTick;
  if (offset > barHeight * 2) {
    offset = 0;
  }
  
  // Aktualisiere die Makse mit der
  // aktuellen Verschiebung
  updateMask (offset);
  // Setze das Bild 'imgMask' als Maske
  imgText.mask (imgMask);
  
  // Zeichne die invertierte Version
  background (138, 170, 178);
  fill (229, 90, 38);
  text ("Text goes here", width/2, height/2 + 10);
  
  // Zeige das maskierte Bild an
  image (imgText, 0, 0);
}

// Funktion um die Maske zu aktualisieren
void updateMask (float theOffset) {
  background (0);
  fill (255);
  for (float i=theOffset - barHeight; i < height; i += barHeight * 2) {
    rect (0, i, width, barHeight);
  }
  copySketchIntoImage (imgMask);
}

// Funktion um alle Pixel des Sketchfensters
// in ein Bild zu kopieren.
void copySketchIntoImage (PImage theDestImage) {
  loadPixels ();
  theDestImage.loadPixels ();
  for (int i=0; i < pixels.length; i++) {
    theDestImage.pixels[i] = pixels[i];
  }
  theDestImage.updatePixels ();
}

// Funktion um alle Pixel eines Bildes in ein
// anderes Bild zu kopieren.
void copyImage (PImage theSource, PImage theDestination) {
  theSource.loadPixels ();
  theDestination.loadPixels ();
  
  if (theSource.pixels.length != theDestination.pixels.length) {
    return;
  }
  
  for (int i=0; i < theSource.pixels.length; i++) {
    theDestination.pixels[i] = theSource.pixels[i];
  }
  
  theDestination.updatePixels ();
}