Oracle Resize eines Images in Java und Rückgabe des Image als BLOB an die Oracle Datebank

hkoelzer

Mitglied
Hey,

ich habe mal wieder ein Problem beim Zusammenspiel Oracle Datenbank und einer embedded Java Klasse.
Ich möchte eine Image (als blob) aus der Datenbank an die Java Klasse übergeben, dort erfolgt dann ein resizen des Bildes auf die gewünschte Höhe und Breite und dann soll das Image wieder als blob zurück an die die aufrufenden Funktion übergeben werden.

Für das Resizen des Bildes habe ich bei www.codejava.net auch ein Beispiel gefunden, welches ein lokal liegendes Bild resized und wieder auf lokal ablegt.

Das Funktioniert lokal auch sehr gut. Mein Katzenbeispiel - Jpg wird auf 50% der Originalgröße (1024 x 811 WxH) also auf 512 x 405 verkleinert.
Dabei verringert sich natürlich auch die Dateigröße - in dem Fall von 192 KB auf 39 KB.

Mein angepasstes Programm (siehe Anhang HKRCALL.java) nimmt auch den aus der Datenbank übergebenen BLOB, ermittelt die Größe des Originalbildes,
berechnet 50 % der Breite udn Höhe und gibt dann letztendlich auch wieder ein blob zurück. Dieser wird dann wieder in einer Tabelle abgelegt.
Ich habe mal ein paar Ausgaben in mein Java Programm gebaut und lasse mir diese per dbms-Output mal während der Ausführung der PL/SQL Prozedur (welche dann wiederum die Java Klasse aufruft) ausgeben (s.u.)

Leider ist dieser blob nur 3955 Byte groß.

Wenn ich mir das zurückgegebene Bild von der Datebank mal herunterlade, ist das durchaus Jpeg und die Bildinformationen zeigen auch die Masse 512 x 405 an.
Leider ist das Bild schwarz.

Kann sich das vielleicht mal jemand anschauen, wo mein Fehler liegen könnte (ImageOutputStream ?)
Ich bin gerade am verzweifeln :-(




resizeJpegCall: Groesse des uebergebenen Blob: 194334
Original scaledWidth = 1024
Original scaledHeight = 811
50 % scaledWidth = 512
50 % scaledHeight = 405
resizeJpeg: BufferedImage outputImage
resizeJpeg: Graphics2D g2d = outputImage.createGraphics()
resizeJpeg: g2d.drawImage(inputImage, 0, 0, scaledWidth, scaledHeight, null)
resizeJpeg: g2d.dispose()
ImageIO.write(outputImage, JPG, ios)
Image resized successfully.
Image resized successfully.
Groesse des Return Blob: 3955
 

Anhänge

Mit ORDImage/ORD_IMAGE kann man die Bilder als Teil des Prozesses zum Hochladen des Bildes in die Datenbank skalieren. Oder man kann die Bilder kurz nach dem Hochladen als Teil eines Hintergrundprozesses (DBMS_SCHEDULER) skalieren. ORDImage benötigt Java. Die Oracle Express Edition [XE] unterstützt kein Java. Daher ist ORDImage für XE-Datenbanken nicht verfügbar.

SQL:
CREATE OR REPLACE FUNCTION fixed_img(p_blob       BLOB,

                                     in_width     NUMBER,

                                     in_height    NUMBER)

   RETURN BLOB

IS

   vimagedata    BLOB;

   vsizedimage   BLOB;

BEGIN

   vimagedata := p_blob;

   DBMS_LOB.createtemporary(vsizedimage, FALSE, DBMS_LOB.call);

   ordsys.ordimage.processcopy(vimagedata,

                               'fixedScale=' || in_width || ' ' || in_height,

                               vsizedimage);

   RETURN vsizedimage;

END;

Ergänzung: https://www.doag.org/formes/pubfile...-Czarski-Bildbearbeitung-in-der-Datenbank.pdf
 
Zuletzt bearbeitet:
Mit ORDImage/ORD_IMAGE kann man die Bilder als Teil des Prozesses zum Hochladen des Bildes in die Datenbank skalieren. Oder man kann die Bilder kurz nach dem Hochladen als Teil eines Hintergrundprozesses (DBMS_SCHEDULER) skalieren. ORDImage benötigt Java. Die Oracle Express Edition [XE] unterstützt kein Java. Daher ist ORDImage für XE-Datenbanken nicht verfügbar.

SQL:
CREATE OR REPLACE FUNCTION fixed_img(p_blob       BLOB,

                                     in_width     NUMBER,

                                     in_height    NUMBER)

   RETURN BLOB

IS

   vimagedata    BLOB;

   vsizedimage   BLOB;

BEGIN

   vimagedata := p_blob;

   DBMS_LOB.createtemporary(vsizedimage, FALSE, DBMS_LOB.call);

   ordsys.ordimage.processcopy(vimagedata,

                               'fixedScale=' || in_width || ' ' || in_height,

                               vsizedimage);

   RETURN vsizedimage;

END;

Ergänzung: https://www.doag.org/formes/pubfile...-Czarski-Bildbearbeitung-in-der-Datenbank.pdf
Danke, aber leider ist ordimage von Oralce abgekündigt worden und steht in neueren Datenbankversionen nicht mehr zu Verfügung.
Das ist der Grund, warum ich mich überhaupt mit der Bildbearbeitung in Java beschäftige.
Wir verwenden derzeit ordimage und müssen es ersetzen.
 
In der API steht:
OutputStream setBinaryStream(long pos) - pos - the position in the BLOB value at which to start writing; the first position is 1
Also müsstest du ändern:
Java:
OutputStream os = retBlob.setBinaryStream(1L);
 
Und das hier: float percent_float = (float) 0.50; tut mir richtig weh! -> float scaleFactor = .5F; Eigentlich ist das aber eine Konstante und gehört als solche deklariert.
 
Hey,

erstmal danke für deine Rückmeldung.

Leider führte die Umstellung auf
OutputStream os = retBlob.setBinaryStream(1L);
zu keinem anderen Ergebnis.


Das float percent_float = (float) 0.50; habe ich nur temporär eingebaut für den Test.
Normalerweise soll die Breite und Höhe des Bildes beim Aufruf Java Klasse mitgegeben werden.

Hättest du sonst noch eine Idee, warum nicht das korrekte Bild zurückgegeben wird?
 
Ich denke du solltest beim Schreiben der Daten: oracle.sql.BLOB statt java.sql.Blob verwenden:

Java:
outstream = ((BLOB) retBlob).getBinaryOutputStream();
ios = ImageIO.createImageOutputStream(outstream);
 
Ich habe das Deprecated gesehen. Ausprobieren hätte ja nicht geschadet. Java verwenden wir eigentlich nicht in der Ora, weil es zu umständlich ist. Unser Stand ist die 12 und wir werden, auf Grund rechtlicher Vorgaben, niemals in die Cloud wechseln. Die DB's müssen immer in unseren Rechenzentren und unter unserer Kontrolle bleiben. Oracle versucht das so schwer wie nur irgend möglich zu machen. So wird es wohl noch dauern, bis wir nach 19+ migrieren oder gar den Hersteller wechseln. Ich werde es nächste Woche aber mal ausprobieren, vorher bin ich nicht in der Arbeit. Mit JDBC bin ich auch etwas aus der Übung seit es JPA gibt. Wenn jetzt Oracle Multimedia desupported ist, kann man zu APEX Media Extension (AME) https://www.apexmediaextension.com/index.html wechseln.
 
Hey,

AME wäre die Alternative. Ist allerdings kostenpflichtig, außerdem mann muss seine(n) eigenen Server aufbauen (wenn man seine Bilder nicht über den Äther an deren Server schicken möchte) .

Wir müssen demnächst migrieren, daher jetzt meine Bemühungen, das mit Java hinzubekommen (auch wenn ich bis dato nichts mit Java am Hut hatte ;-)

Die Konvertierung von einem GIF, BMP zu JPG habe ich auch hinbekommen.
Auch die Kompremierung von JPEG Files klappt - da schicke ich auch BLOB hin und her.

Nur das Resizen sträubt sich und ich weiß nicht warum.

Wenn ich das ganze lokal mache, mir den blob per odbc connect aus der Tabelle hole und dann resize, hat sowohl der blob (in der Java Umgebung) die richtig Größe und das rausgeschriebene Bild ist dann auch resized.

Echt zum Verzweifeln!!!
 
Ich finde das "kostenpflichtig" Argument in Bezug zur Oracle-DB lustig. Ich weiß nicht wie viele Millionen Euro die DB's an Kosten verursachen - aber in irgend einem Lizenz-Paket wird das schon mit drin sein. Man muss einfach mal mit den zuständigen Leuten reden. Ich kenne mich nicht so genau aus, habe mal so nebenbei gehört die Lizenzen gehen wohl pro Core + Ausstattung an Software + Support-Level, so würde ich schätzungsweise nur bei einer vollständig genutzten ExaData auf ca. 640000 € im Jahr kommen + 350000 € für die Hardware + Infrastruktur und das Ganze mal 2 für das Backup-Rechenzentrum. Natürlich wird das alles noch verhandelt aber trotzdem fällt da AME garantiert nicht ins Gewicht.
 
Hey,

natürlich hast du bezüglich der Kosten der Datenbank vollkommen recht. Dagegen sind die 2000 EUR ein Klacks.
Allerdings sind wir nicht die Betreiber der Datenbank, so das die Installation zusätzlicher Software etc. immer ein Graus sind.

Außerdem wollten wir das mal ausprobieren und grundsätzlich geht es ja auch mit Java.
Ich habe das Problem ein wenig eingrenzen können.
Es liegt nicht an der Rückgabe des blob, sondern der eigentliche Kopiervorgang beim drawimage.

g2d.drawImage(inputImage, 0, 0, scaledWidth, scaledHeight, null);

Das scheint beim eingebetteten Java innerhalb der Datenbank nicht zu funktionieren. Es liegt aber nicht grundsätzlich an Graphics2D

Wenn ich statt des Kopiervorgangs des Originalimages in das neue Image einfach mal ein Gesicht male,
so wird das korrekt in den blob zurückgebeben - und das Bild landet in meiner Datenbanktabelle (s.u.)

// Fill background with white
g2d.setColor(Color.WHITE);
g2d.fillRect(0, 0, scaledWidth, scaledHeight);

// Draw a smiley face
g2d.setColor(Color.YELLOW);
g2d.fillOval(10, 10, 180, 180);
g2d.setColor(Color.BLACK);
g2d.fillOval(40, 40, 40, 40);
g2d.fillOval(120, 40, 40, 40);
g2d.fillRect(50, 150, 100, 10);

1621356665832.png
 
So,

jetzt klappt es.

Ich habe umgestellt und benutze jetzt Image:

Image resultingImage = inputImage.getScaledInstance(scaledWidth, scaledHeight, Image.SCALE_DEFAULT);
BufferedImage outputImage = new BufferedImage(scaledWidth, scaledHeight, BufferedImage.TYPE_INT_RGB);
outputImage.getGraphics().drawImage(resultingImage, 0, 0, null);
ImageIO.write(outputImage, "jpg", os);
 
Moin,

nach vielem hin und her habe ich es heute mit deiner Hilfe ebenso zum laufen gebracht.
ein paar kleinere Sachen hatte ich noch angepasst, sodass es nun die Funktion erhalten hat, die sie von Anfang an haben sollte.

Den fertigen Code hab ich im Anhang und sollte nun ohne Probleme laufen (jedenfalls bei mir)
 

Anhänge


Zurück
Oben