Bilder manipulieren und bearbeiten: Mit Application Express

Geht nicht gibt's nicht: Der heutige Community Tipp beschäftigt sich mit dem etwas ungewöhnlichen Thema Bildmanipulation und stellt vor, wie Sie in Application Express hochgeladene Bilder verändern können. Zu diesem Thema wurde vor einiger Zeit schonmal ein Tipp veröffentlicht; dieser beschäftigte sich mit dem Datentypen ORDIMAGE und wie man Bilder skalieren, aufhellen oder in Graustufen umrechnen kann. Der heutige Tipp geht noch etwas weiter: Erfahren Sie, wie Sie "in Ihre Bilder hineinzeichnen" oder Texte direkt in die Bilder einsetzen können. Gerade letzteres kann in der Praxis durchaus hilfreich sein, wenn es daran geht, den Bildern eines Produktkatalogs bspw. Copyright-Vermerke hinzuzufügen.

Basis der Bildbearbeitung ist das PL/SQL-Paket IMAGE_GENERATOR; dieses wurde ebenfalls im Rahmen eines älteren Community Tipps Diagramme erzeugen: "Nativ" und ohne Browser Plugin! vorgestellt und erlaubt es, aus PL/SQL heraus direkt Bilder zu generieren oder bestehende Bilder zu verändern.

Systemvoraussetzungen

Die gute Nachricht vorab: Da die Oracle-Datenbank mit einer Java-Engine ausgestattet ist, ist alles Nötige zur Erzeugung und Bearbeitung von Bilddateien bereits vorhanden - es muss lediglich für Application Express nutzbar gemacht werden. Allerdings ergeben sich zwei Einschränkungen hinsichtlich Datenbankversion und -Edition.

  • Die Datenbankversion muss mindestens 10g Release 2 (Version 10.2) sein. Frühere Versionen sind nicht mit dem sog. Headless AWT ausgestattet, welches eine Voraussetzung für diesen Tipp ist.
  • Die Datenbank muss wenigstens eine "Standard Edition (One)" sein; Der Tipp läuft nicht in einer OracleXE, da OracleXE die Java-Engine nicht enthält.
  • Wenn Sie Bilder im recht verbreiteten PNG-Format verändern möchten, funktioniert dies nur mit Oracle11g - in Oracle 10.2 bekommen Sie eine Fehlermeldung. Die anderen populären Bildformate GIF oder JPEG werden auch in Oracle 10.2 unterstützt.

Vorbereitungen

Betrachten Sie das SQL-Skript setup.sql (Download). Es erzeugt im Datenbankschema zunächst eine Java-Klasse, welche die eigentliche Arbeit übernimmt und anschließend ein PL/SQL-Paket, welches die Java-Klasse nach außen zugänglich macht. Wenn Sie mit Java vertraut sind, ist die Erweiterung der Java-Klasse um zusätzliche Funktionalität ein Leichtes für Sie.

Lassen Sie das Skript in SQL*Plus oder im SQL Workshop laufen. Anschließend steht Ihnen das PL/SQL-Paket IMAGE_GENERATOR zur Verfügung.

Für Texte, die in die Bilder gesetzt werden sollen, gibt es noch eine wichtige Vorbereitung zu erledigen - "von Haus aus" ist die Datenbank nur mit einem Minimum an Schriftarten ausgestattet. Dies ist jedoch einfach zu beheben: Sie können grundsätzlich alle Truetype-Schriftarten nutzen. Um weitere Schriftarten verfügbar zu machen, benötigen Sie allerdings die Hilfe des Datenbankadministrators: Navigieren Sie in Oracle10g auf dem Datenbankserver zur Datei $ORACLE_HOME/javavm/lib/ojvmjava/font.properties (auf machen Plattformen heißt das Verzeichnis ojvmfonts anstelle von ojvmjava) und fügen Sie dieser am Ende folgende Zeile hinzu:

appendedfontpath=[pfad-zum-Verzeichnis-mit-den-TTF-dateien]

In Oracle11g ist diese Datei nicht mehr vorhanden. Setzen Sie hier vor Ihren im folgenden beschriebenen Aufrufen ins Paket IMAGE_GENERATOR folgenden Aufruf ab:

begin
  image_generator.set_font_path('[pfad-zum-Verzeichnis-mit-den-TTF-dateien]');
end;

Sie benötigen dazu ein entsprechendes Java-Privileg, welches Ihnen der Datenabnkadministrator wie folgt einrichten kann.

call dbms_java.grant_permission( 
  '[APEX Parsing Schema]',
  'SYS:java.util.PropertyPermission', 
  'sun.java2d.fontpath', 
  'write' 
);

Sowohl für Oracle10g als auch Oracle11g muss der Pfad zu einem Verzeichnis mit Truetype-Schriftartdateien verwendet werden. Sie erkennen diese Dateien normalerweise am Suffix .ttf. Achten Sie (speziell unter Linux/UNIX) weiterhin darauf, dass die im diesem Verzeichnis liegenden TTF-Dateien vom Betriebssystem-User "oracle" gelesen werden können - die Rechte sollten typischerweise so aussehen:

:
-rw-r--r--  1 root root    55220 2004-03-19 09:27 SUSESerif-Roman.ttf
-rw-r--r--  1 root root    53564 2004-03-19 09:27 SUSESerif-Bold.ttf
-rw-r--r--  1 root root    56708 2004-03-19 09:27 SUSESans-Roman.ttf
-rw-r--r--  1 root root    58804 2004-03-19 09:27 SUSESans-Oblique.ttf
-rw-r--r--  1 root root    44848 2004-03-19 09:27 SUSESansMono-Roman.ttf
:

Damit die neuen Schriftarten von der Datenbank erkannt werden, muss für Oracle10g der Apache Web Server von Application Express neu gestartet werden. In Oracle11g ist es wichtig, dass obiger Aufruf bei der Arbeit mit IMAGE_GENERATOR stets zu Beginn ausgeführt wird (bspw. durch einen eigenen Prozeß). Die verwendbaren Schriftarten können Sie bspw. im SQL*Plus mit folgender SQL-Abfrage anzeigen lassen (Abbildung 1).

select * from table(image_generator.get_font_names)

Verwendbare Schriftarten anzeigen

Abbildung 1: Verwendbare Schriftarten anzeigen

Damit Sie die Applikation zum Hoch- und Herunterladen der Bilddateien nicht komplett neu erstellen müssen (das können Sie natürlich trotzdem tun), steht Ihnen die Beispielapplikation des oben genannten Tipps Bildbearbeitung mit Application Express und ORDIMAGE hier zum Download bereit. Spielen Sie diese normal mit dem Import-Assistenten von Application Express ein.

Ausgangsanwendung für die Bildbearbeitung installieren

Abbildung 2: Ausgangsanwendung für die Bildbearbeitung installieren

Laden Sie anschließend einige Bilder hoch, so dass Ihre Anwendungsseite in etwa wie in Abbildung 3 aussieht.

Anwendungsseite nach dem Hochladen einiger Bilder

Abbildung 3: Anwendungsseite nach dem Hochladen einiger Bilder

Damit sind die Vorbereitungen abgeschlossen und Sie können damit beginnen, die Anwendung zu erweitern. Es soll dem Endanwender ermöglicht werden, einen beliebigen Text an eine beliebige Stelle des Bildes zu platzieren (bspw. einen Copyright-Text).

Anwendung erweitern

Fügen Sie der Anwendungsseite zunächst eine neue HTML-Region, welche die Formularelemente aufnehmen soll, hinzu. Es werden folgende Elemente benötigt:

ElementnameElementtypZweck
PX_X Textfeld X-Position (von links), an welche der Text platziert werden soll
PX_Y Textfeld Y-Position (von unten), an welche der Text platziert werden soll
PX_TEXT Textfeld Text, welcher gesetzt werden soll
PX_COLOR Popup-Farbauswahl Farbe, in welcher der Text gesetzt werden soll
PX_IMAGEFILE Auswahlliste Das Bild in der Tabelle INTERMEDIA_IMAGE , in welches der Text gesetzt werden soll.
Erzeugen Sie hierfür eine dynamische Werteliste mit folgendem SQL:

select substr(name, instr(name,'/') +1 ) r, id d
from intermedia_image

Vergessen Sie die Schaltfläche zum Absenden nicht. Anschließend sollte Ihre Anwendungsseite in etwa wie in Abbildung 4 aussehen:

erweiterte Anwendungsseite

Abbildung 4: erweiterte Anwendungsseite

Hinterlegen Sie nun den Prozeß, der den eingegebenen Text ins Bild schreibt. Erzeugen Sie einen neuen Prozeß vom Typ PL/SQL, nennen Sie ihn Text ins Bild schreiben und hinterlegen Sie folgenden PL/SQL-Code. Achten Sie darauf, die Ausführung bei den Bedingungen an die soeben erzeugte Schaltfläche zu knüpfen. Der PL/SQL-Code ist ein wenig länger, aber einfach zu verstehen. Erläuterungen finden Sie in den Kommentaren.

declare
  v_content   ordimage;
  v_thumbnail ordimage;
  v_image varchar2(100);
begin
  -- Bilddaten (BLOB) in Variable einlesen
  select e.dokument, e.thumbnail into v_content, v_thumbnail
  from intermedia_image e 
  where id = :P2_IMAGEFILE
  for update;

  -- Nur in Oracle11g: Pfad zu den TTF-Fontdateien eintragen; mehr Information
  -- Beginn des Community Tipps. In Oracle10g ist dieser Aufruf ohne Wirkung; die
  -- Fonts müssen in der Datei "font.properties" eingerichtet werden.
  image_generator.set_font_path('/usr/X11R6/lib/X11/fonts/TTF');

  -- Bild aus der Variable v_content in den IMAGE_GENERATOR laden ...
  v_image := image_generator.get_image_handle(v_content.source.localdata);

  -- Font setzen 
  IMAGE_GENERATOR.SET_FONT(
    P_IMG_NAME    => v_image,
    P_FONT_FAMILY => 'SansSerif',
    P_FONT_STYLE  => 'BOLD',
    P_FONT_SIZE   => 40
  );

  -- Farbe setzen; wenn keine Farbe angegeben wird, wird "Weiss" genommen.
  :P2_COLOR := nvl (:P2_COLOR, '#FFFFFF');
  IMAGE_GENERATOR.SET_COLOR(
    P_IMG_NAME => v_image,
    P_R        => to_number(substr(:P2_COLOR, 2, 2), 'XX'),
    P_G        => to_number(substr(:P2_COLOR, 4, 2), 'XX'),
    P_B        => to_number(substr(:P2_COLOR, 6, 2), 'XX')
  );

  -- HIER PASSIERT ES: Der Text wird ins Bild geschrieben!
  IMAGE_GENERATOR.DRAW_TEXT(
    P_IMG_NAME => v_image,
    P_X        => :P2_X,
    P_Y        => image_generator.get_height(v_image) - :P2_Y,
    P_TEXT     => :P2_TEXT,
    P_ALIGN    => IMAGE_GENERATOR.TEXTALIGN_LEFT,
    P_DEGREE   => 0
  );

  -- Verändertes Bild aus dem IMGAE_GENERATOR abrufen und in die
  -- Variable v_content schreiben
  v_content.source.localdata := image_generator.get_image(v_image, 'png');
  v_content.setProperties();

  -- Thumbnail (Kleinversion des Bildes) neu generieren
  v_content.processCopy('maxScale=75 75',v_thumbnail);

  -- Verändertes Bild und Thumbnail in die Tabelle zurückschreiben
  update intermedia_image 
  set dokument = v_content, thumbnail = v_thumbnail 
  where id = :P2_IMAGEFILE;

  -- Speicher freigeben
  image_generator.destroy_image(v_image);
end;

Probieren Sie es nun aus. Abbildung 5 zeigt, wie der Text (c) ORACLE Corporation in ein Bild des Oracle Hauptquartiers gesetzt wird.

Das Ergebnis: Ein Text wurde in das Bild gesetzt

Abbildung 5: Das Ergebnis: Ein Text wurde in das Bild gesetzt

Die veränderten Bilder müssen übrigens nicht persistent gemacht werden; denkbar ist auch das Setzen eines Textes nur für den Download. Erzeugen Sie hierzu im SQL Workshop eine neue Prozedur DISPLAY_EDITED_IMAGE mit folgendem Code:

create or replace procedure display_edited_image (p_id in number) is
  v_content   blob;
  v_image varchar2(100);
begin
  -- Bilddaten (BLOB) in Variable einlesen
  select e.dokument.source.localdata into v_content
  from intermedia_image e 
  where id = p_id;

  -- Nur in Oracle11g: Pfad zu den TTF-Fontdateien eintragen; mehr Information
  -- Beginn des Community Tipps. In Oracle10g ist dieser Aufruf ohne Wirkung; die
  -- Fonts müssen in der Datei "font.properties" eingerichtet werden.
  image_generator.set_font_path('/usr/X11R6/lib/X11/fonts/TTF');

  -- Bild aus der Variable v_content in den IMAGE_GENERATOR laden ...
  v_image := image_generator.get_image_handle(v_content);

  -- Font setzen 
  IMAGE_GENERATOR.SET_FONT(
    P_IMG_NAME    => v_image,
    P_FONT_FAMILY => 'Monospace',
    P_FONT_STYLE  => 'BOLD',
    P_FONT_SIZE   => 12
  );

  -- Farbe "Grün" setzen
  IMAGE_GENERATOR.SET_COLOR(
    P_IMG_NAME => v_image,
    P_R        => 0,
    P_G        => 255,
    P_B        => 0
  );

  -- HIER PASSIERT ES: Der Text wird ins Bild geschrieben!
  IMAGE_GENERATOR.DRAW_TEXT(
    P_IMG_NAME => v_image,
    P_X        => 5, 
    P_Y        => image_generator.get_height(v_image) - 20,
    P_TEXT     => 'Heruntergeladen von APEX am '||to_char(sysdate, 'DD.MM.YYYY HH24:MI'),
    P_ALIGN    => IMAGE_GENERATOR.TEXTALIGN_LEFT,
    P_DEGREE   => 0
  );

  -- Verändertes Bild in die Variable vom Typ BLOB übernehmen
  v_content := image_generator.get_image(v_image, 'png');

  -- Speicher freigeben
  image_generator.destroy_image(v_image);

  -- Standard-Code zum Absenden des Bildes an den Browser
  owa_util.mime_header('image/png', false);
  htp.p('content-length: '||dbms_lob.getlength(v_content));
  owa_util.http_header_close;
  wpg_docload.download_file(v_content);
end;

Navigieren Sie nun u den Anwendungsprozessen und dort zum Prozeß Bild anzeigen . Ersetzen Sie den vorhandenen Aufruf durch die neue Prozedur ...

DISPLAY_EDITED_IMAGE(p_ID => :F1000000108_ID);

Nun wird am gespeicherten Bild selbst nichts verändert; wenn Sie es jedoch herunterladen, wird der Text vor der "Auslieferung" an den Browser hineingeschrieben.

Heruntergeladenes Bild mit hinzugefügtem Text

Abbildung 6: Heruntergeladenes Bild mit hinzugefügtem Text

Die Anwendungsmöglichkeiten sind vielfältig; so können die X- und die Y-Position des Texted auch per JavaScript direkt durch einen Mausklick ermittelt werden. Darüber hinaus enthält das Paket IMAGE_GENERATOR auch zahlreiche Funktionen zum Zeichnen diverser Elemente in das Bild - probieren Sie es einfach mal aus ...

Zurück zur Community-Seite