# Java Class zum komprimieren von Jpeg-Images zum Einbinden in Oracle DB - Bild als blob (in und out)



## hkoelzer (6. Mai 2021)

Hey,

erstmal vorweg: Ich bin Datenbankprogrammierer im Oracleumfeld und habe so gut wie keine Ahnung von Java (mal abgesehen von meinen Erkenntnissen der letzten 5 Tage ;-)

Hintergrund meiner Anliegens: Wir verwenden derzeit in der Oracle Datenbank (19.1) ein Programm von Oracle selber (ordimage), um Bilder zu konvertieren und und teils zu komprimieren.
Diese Programm wird in den neuen Versionen der Datenbank nicht mehr zu Verfügung stehen. Daher suchen wir nach Alternativen.
Da man Java in die Datenbank einbinden kann und dann keine weiteren Installationen oder kostenpflichtige Programme benötigen würde, ist unsere Wahl auf Java gefallen.

Ich habe auch schon rumgegoogled und auch schon ein Programm gefunden, was die die Konvertierung vornimmt und mit einem blob als Parameter(rein und raus) funktioniert.
Ich habe auch schon ein Programm gefunden (https://examples.javacodegeeks.com/desktop-java/imageio/compress-a-jpeg-file/) welches die komprimierung vornehmen kann. Dies setzt aber ein Bild auf dem Filesystem voraus und schreibt auch das komprimierte Bild wieder ins Filesystem. Das habe ich lokal bei mir auch ausprobiert und das erzeugte neue Bild ist auch kompremiert.
Ich habe versucht das Programm so anzupassen, das er mit blob zurecht kommt und auch einen blob mit dem komprimierten Image zurückgibt.


Um mein Programm lokal auf meinem Rechner Test zu können, hole ich ein jpg-Bild aus meiner Datenbank als Blob über odbc und rufe dann compressJPEG (myBlobCopy) mit dem Blob auf. Um zu zeigen, was passiert ist, mache ich einige Ausgaben in den Klassen. Die Größe des BLOBs vor und nach dem Aufruf von compressJPEG ist gleich.

Hier die Ausgabe: 126 23190 myimage.jpg Länge des abgerufenen Blob: 4284416 

Länge des kopierten Blob: 4284416 

Aufruf von compressJPEG (myBlobCopy)

 jetzt in compressJPEG 

Zurück von compressJPEG: Länge des abgerufenen Blob: 4284416

Hier die Klasse. Es scheint, dass das komprimierte Bild (Blob) nicht zurückgegeben wird. Bitte können Sie mir helfen!!!!!!

[CODE lang="java" title="Java Klasse"]    import java.sql.*;
    import javax.imageio.ImageIO;
    import java.io.File;
    import java.io.IOException;
    import java.awt.image.BufferedImage;
    import java.awt.image.RenderedImage;
    import java.sql.Blob;
    import java.iutputStream;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.InputStream;
    import java.iutputStream;
    import java.util.Iterator;
    import javax.imageio.IIOImage;
    import javax.imageio.ImageWriteParam;
    import javax.imageio.ImageWriter;
    import javax.imageio.stream.ImageOutputStream;
    //import java.sql.SQLException;     
    class OracleConCompressBLOB{ 
    public static void main(String args[]){ 
    try{ 
    //step1 load the driver class 
     Blob myBlob = null;
     Blob myBlobCopy = null;

    Class.forName("oracle.jdbc.driver.OracleDriver"); 
    String dbURL = "jdbcracle:thin(DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = xxxx)(PORT = 1521)) (CONNECT_DATA = (SERVER = DEDICATED)(SERVICE_NAME = xxxx) ) )";
    String strUserID = "xxxx";
    String strPassword = "xxxxx";
    //step2 create  the connection object 

    Connection con=DriverManager.getConnection(dbURL,strUserID,strPassword);


    //step3 create the statement object 
    Statement stmt=con.createStatement(); 

    //step4 execute query 
    // fuer pbent   ResultSet rs=stmt.executeQuery("select PRFO_ID, PRFO_PRAX_ID , PRFO_DATEINAME, PRFO_FOTO from T_PRAFOTO where PRFO_ID = 17");
    ResultSet rs=stmt.executeQuery("select PRFO_ID, PRFO_PRAX_ID , PRFO_DATEINAME, PRFO_FOTO from T_PRAFOTO where PRFO_ID = 166  FOR UPDATE");


       if (rs.next()) {
          myBlob = rs.getBlob(4);
          myBlobCopy = myBlob;
          System.out.println(rs.getInt(1)+"  "+rs.getInt(2)+"  "+rs.getString(3)+" Length of retrieved Blob: " + myBlob.length()); 
          System.out.println(" Length of copy Blob: " + myBlobCopy.length()); 
          System.out.println("Call compressJPEG (myBlobCopy) ");   
         compressJPEG (myBlobCopy)   ;           
        System.out.println("back from compressJPEG: Length of retrieved Blob: " + myBlobCopy.length()); 
      }


    //step5 close the connection object 
    con.close(); 

    }catch(Exception e){ System.out.println(e);} 

    } 


    public static void compressJPEG(Blob blob) throws IOException {

    //     File imageFile = new File("myimage.jpg");
    //     File compressedImageFile = new File("myimage_compressed.jpg");

    //     InputStream is = new FileInputStream(imageFile);
    //     OutputStream os = new FileOutputStream(compressed ImageFile);
        System.out.println("now in compressJPEG"); 

       BufferedImage bufferedImage = null;
       OutputStream outputStream = null;
       float quality = 0.5f;
        try {
        // create a BufferedImage as the result of decoding the supplied InputStream
    //    BufferedImage image = ImageIO.read(is);
        bufferedImage = ImageIO.read(blob.getBinaryStream());
        outputStream = blob.setBinaryStream(0);
        // test
        // get all image writers for JPG format
        Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName("jpg");

        if (!writers.hasNext())
            throw new IllegalStateException("No writers found");

        ImageWriter writer = (ImageWriter) writers.next();
        ImageOutputStream ios = ImageIO.createImageOutputStream(outputStream);

        writer.setOutput(ios);

        ImageWriteParam param = writer.getDefaultWriteParam();

        // compress to a given quality
        param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
        param.setCompressionQuality(quality);

        // appends a complete image stream containing a single image and
        //associated stream and image metadata and thumbnails to the output
        writer.write(null, new IIOImage(bufferedImage, null, null), param);

        // close all streams
       // is.close();
      //  os.close();
      //  ios.close();
      //  writer.dispose();
                    outputStream.flush();
                    ios.close();
                    outputStream.close();
                   writer.dispose();     
        } catch (IOException e) {
            e.printStackTrace();
        }
        catch (SQLException e) {
            e.printStackTrace();
        }
        catch(IllegalArgumentException e) {
            e.printStackTrace();
        }

      }
    } [/CODE]


----------



## Barista (6. Mai 2021)

Du liest und schreibst in das selbe Blob.

Besser aus einem Blob lesen und in ein neues schreiben.


----------



## hkoelzer (6. Mai 2021)

Meinst du, ich soll der Klasse public static void compressJPEG(Blob blob)
einen Returnwert Blob geben, also eine Funktion daraus machen?

Oder was meinst du? Dann vielleicht am besten mit Beispiel, wie gesagt, Java Dummie ;-)


----------



## Mart (6. Mai 2021)

myBlobCopy = myBlob ist kein deep Copy da hast wahrseinlcih den Fehler


```
while ((line = br.readLine()) != null) {
            File file = new File("/myPath/" + name + ".png");
            FileInputStream fis = new FileInputStream(file);
            ps.setBinaryStream(2, fis, (int) file.length());
```
so kannst du png einlesen musst halt umändern auf deinen datentyp


```
private void readImageFromServer(InputStream inputStream) throws IOException
  {

  byte byteStream[];
  File files=new File("/home/legacy/Bilder/image1.png");
  FileOutputStream fos=new FileOutputStream(files); byteStream =
  (inputStream.readAllBytes());
  fos.write(byteStream, 0, byteStream.length);
  fos.close(); }
```
so kannst du dir dann dein die datei Image1.png erzeugen von deinem inpuitstream den du oben hast dann kannst du deine datensätze hin und her werfen wie du willst

```
ResultSet rs = statement.executeQuery("select * from table");
while(rs.next())
{
readImageFromServer(rs.getBinaryStream(2));
}
closesConnection(ps);
fis.close();
```
die methode würde dir alle blobs auslesen diese kannst du dir dann in read einsetzen und dann irgendwo hin tun ..wo auch immer du es haben willst

das selecten sollte eig prepared sein aber ich war zu faul weil das sowieso nur zum ausprobieren war


----------



## Mart (6. Mai 2021)

Nur um das klar zu stellen ein BLOB = Binary Large Object  dh du wandelst deine jped datei um in ein Binary das kann unter umständen größer und kleiner sein als "komprimieren" verstehe ich eher Zip oder tar






						Binary large object - Wikipedia
					






					en.wikipedia.org
				





nicht dass du jetzt mit blob rum haust und dann die datenbank admins dich umbringen weil du zu viel platz brauchst


----------



## hkoelzer (6. Mai 2021)

Hey Mart,

erstmal danke für deine Anmerkungen, auch wenn ich zugegebener Massen damit jetzt nicht so richtig etwas anfangen kann.

1. myBlobCopy = myBlob ist kein deep Copy
Ich verstehe das mal so, das der BLOB nicht wirklich kopiert wird, sondern eventuell nur ein Zeiger auf das Objekt übergeben wird ?
Wie kann ich das ändern?

2. Wie helfen mir dann 2 Anmerkungen (Java Code) weiter - ich lese ja kein File vom Laufwerk, sondern haben einen BLOB?
Wenn meine Klasse ja mal funktioniert, rufe ich sie mit einem BLOB aus der Datenbank auf.


----------



## hkoelzer (6. Mai 2021)

Ja, das Bild wird in einer Apexanwendung in die Datenbank geladen und in einer blob-Spalte abgelegt.


----------



## Mart (6. Mai 2021)

hkoelzer hat gesagt.:


> Hey Mart,
> 
> erstmal danke für deine Anmerkungen, auch wenn ich zugegebener Massen damit jetzt nicht so richtig etwas anfangen kann.
> 
> ...


die 3te anmerkungen liest dir einen Blob aus aus einer datenbank
die 2te Anmerkung wandelt einen blob in ein Jpeg
die 1te Anmerkung speichert ein jpeg als blob

deine aufgabe ist es nun den binary Inputstream wert weiter zu leiten in eine andere datenbank ...die lösungen msust du schon selber machen 

deep copy kannst du mit cloneable erreichen oder du erstellst einen neuen blob un der bekommt die werte die in den anderen blob drin stehen ...deep copy ist aber nicht sooooooo...

ich denke auch nicht dass du unbedingt eine copy brauchst


----------



## Mart (6. Mai 2021)

ps.set Binary Stream = otherps.getBinaryStream(2)


----------



## Mart (6. Mai 2021)

du kannst ja den blob komprimieren


und ja dein kopieren bezieht sich nur auf den pointer der dateien..du erzeugst kein neues objekt mit den gleichen werten sondern nur die pointer


----------



## hkoelzer (6. Mai 2021)

Hallo Mart,

1-3 sind ja nicht meine Probleme.

Ich befinde mich ja vor Aufruf der Java Klasse in der Datebank. 
Das jpeg ist in einer Tabelle mit einem blob gespeichert wo ich den blob ja abfragen kann, um diesen dann weiter an die java Klasse zu geben.
Von dort erwarte ich das umgewandelte jpeg wieder als blob und lege es wieder in der tabelle mit dem Spaltentyp blob ab.
Die Umwandlung der blob in ein Jpeg aus der Datebankheraus ist dann auch wieder kein Problem.


----------



## Mart (6. Mai 2021)

hkoelzer hat gesagt.:


> Hallo Mart,
> 
> 1-3 sind ja nicht meine Probleme.
> 
> ...


also blob holen -> umwandeln in jpeg -> umwandeln in blob -> blob woanders speichern? ist das so richtig?


----------



## hkoelzer (6. Mai 2021)

vielleicht muss ich etwas weiter ausholen - es geht mir nicht um Platz sparen in der Datenbank
Die JPG´s werden innerhalb eines pdf-Generieres in der Datebank in ein pdf eingebunden.
Bei bestimmten jpg´s schlägt das Generieren des pdf fehls, bzw. die Bilder werden da nicht angezeigt (was vermutlich ein Problem des PDF-Programms ist).
Es hat sich aber gezeigt, wenn wir das jpeg etwas komprimieren, ist die Generierung des pdf erfolgreich.


----------



## hkoelzer (6. Mai 2021)

nicht ganz, blob holen (enthält jpeg) -> komprimieren > blob wieder zurückgeben an die gleiche Datenbank.


----------



## Mart (6. Mai 2021)

also der user speichert ein beschädigtes jpeg und sobald du so eins findest willst du es mit einem komprimierten jpeg austuaschen dass es wieder funktioniert?


----------



## Mart (6. Mai 2021)

Compress PNG, JPEG, and TIFF Images in Java
					

Use Java image compression API to compress PNG, JPEG, and TIFF images using Java. Use lossless image compression to reduce the image's size.




					blog.aspose.com
				



damit wäre die idee -> blob holen -> in jpeg umwandeln -> komprimieren -> blob speichern 

nur ist es nicht problematisch wenn du in einer tabelle 2 daten hast...1 mal komprimiert einmal unkomprimiert?


----------



## hkoelzer (6. Mai 2021)

Ich glaube nicht, das das Bild beschädigt ist. Ich kann das Bild ja auch aufmachen. Nur dem pdf-Generator scheint irgendetwas nicht zu passen und zeigt dann nur einen Rahmen aber kein Bild im pdf an - eine Fehlermeldung gibt es dann auch nicht
Kommt auch nicht oft vor, aber es passiert halt. 
Das komprimieren bekämpft also nur die Symptome. Die Ursache ist der pdf-Generator


----------



## Mart (6. Mai 2021)

dannn bist du wahrscheinlich auch der von hkoelzer von stackoverflow


----------



## hkoelzer (6. Mai 2021)

Die Daten (das komprimierte Bild) wird dann nur einmal abgelegt. Der blob befindet sich vor der Konvertierung noch in einer temporären Tabelle.

Ja, bei stackoverflow habe ich mein Glück auch schon versucht.

Das Problem ist, das ich das mit dem blob benötige und nicht auf einem Filesystem bin und ich nicht genau weiß, wie es funktioniert.


----------



## Mart (6. Mai 2021)

meins liest blobs und kann blobs einlesen
du brauchst den datentyp blob nicht extra

meine Datenbank hat auch den blob als datentyp aber der input stream kann den als bytestream lesen und dann steht da der blob schon drin mach eifnach mal meins mit rs.getBinaryStream(2) anstatt dein rs.getBlob


----------



## hkoelzer (6. Mai 2021)

Das ich eine odbc aufmache, soll ja in Wirklichkeit nicht passieren. Das war ja nur en Behelf, damit ich das lokal testen kann und auch mal Fehlermeldungen etc. sehen kann.
In Wirklichkeit rufe ich ja dann die Java Klasse  compressJPEG(Blob blob) mit dem blob aus der Datenban direkt auf - alles was in main steht (odbc, select ..., war nur für den Test lokal)


----------



## Barista (6. Mai 2021)

hkoelzer hat gesagt.:


> Meinst du, ich soll der Klasse public static void compressJPEG(Blob blob)
> einen Returnwert Blob geben, also eine Funktion daraus machen?


Ja


----------



## mrBrown (6. Mai 2021)

Mart hat gesagt.:


> Nur um das klar zu stellen ein BLOB = Binary Large Object dh du wandelst deine jped datei um in ein Binary das kann unter umständen größer und kleiner sein als "komprimieren" verstehe ich eher Zip oder tar


Ich habe keine Ahnung, ob ich dich auch nur ansatzweise richtig versteht, aber: ein JPG *ist* ein Binary, Blob ist einfach nur die Repräsentation der binär-Daten in der Datenbank, und JPG *ist* ein Kompressions-Verfahren/Format.

Ein JPG ist als Blob höchstens durch Metadaten größer als das eigentliche Bild, aber nicht plötzlich auf magische Art und Weise deutlich größer oder kleiner, und ein JPG ist immer komprimiert, das ist der ganze Sinn des Formats.

BTW: Zeichen wie Punkt und Komma gibt es auch gutem Grund, du solltest sie auch mal probiere


----------



## Gelöschtes Mitglied 65838 (6. Mai 2021)

mrBrown hat gesagt.:


> Ich habe keine Ahnung, ob ich dich auch nur ansatzweise richtig versteht, aber: ein JPG *ist* ein Binary, Blob ist einfach nur die Repräsentation der binär-Daten in der Datenbank, und JPG *ist* ein Kompressions-Verfahren/Format.
> 
> Ein JPG ist als Blob höchstens durch Metadaten größer als das eigentliche Bild, aber nicht plötzlich auf magische Art und Weise deutlich größer oder kleiner, und ein JPG ist immer komprimiert, das ist der ganze Sinn des Formats.
> 
> BTW: Zeichen wie Punkt und Komma gibt es auch gutem Grund, du solltest sie auch mal probiere


ich hatte ihn falsch verstanden gehabt und deswegen ergibt der satz von mir keinen Sinn mehr 😁


----------

