Hilfe bei InputStream To File

Bitte aktiviere JavaScript!
Hallo,

ich generiere gerade von einem Stream ein File.
Das File wird auch erstellt, aber es ist leer, also wohl keine Bytes. (Größe ist 0 MB)
Mein InputStream ist allerdings nicht leer.
Wie kann ich das näher analysieren wo nun das eigentliche Problem ist?

Java:
File file = new File("mypath.pdf");
FileUtils.copyInputStreamToFile(uploadFileHelper.getInputStream(), file);
 
OK, dann probier mal
Java:
try(InputStream is = uploadFileHelper.getInputStream()) {
    byte[] buf = new byte[8192];
    int n;
    long total = 0;
    while ((n = is.read(buf)) != -1) {
        total += n;
    }
    System.out.printf("%d bytes read\n", total); // oder was auch immer Du zum Loggen verwendest.
} catch (IOException ex) {
    ex.printStackTrace();
}
 
Also ich bekomme nun die Anzahl an Bytes, die von der anderen Methode kommt.

Allerdings bekomme ich dann nun hier eine Exception:
int bytes = uploadFileHelper.getInputStream().read();

-> java.io.IOException: Stream Closed

Java:
try(InputStream is = uploadFileHelper.getInputStream()) {
                                byte[] buf = new byte[8192];
                                int n;
                                long total = 0;
                                while ((n = is.read(buf)) != -1) {
                                    total += n;
                                }
                                System.out.printf("%d bytes read\n", total); // oder was auch immer Du zum Loggen verwendest.
                            } catch (IOException ex) {
                                ex.printStackTrace();
                            }
                                                        
                            File file = new File(storageAttachment.getFullPath());
                            int bytes = uploadFileHelper.getInputStream().read();
                            int test = uploadFileHelper.getInputStream().available();
                            FileUtils.copyInputStreamToFile(uploadFileHelper.getInputStream(), file);
Warum?
 
Weil try-with-resources den Stream schließt :)

Setz den Spaß mal dort ein, wo Du aktuell FileUtils.copyInputStreamToFile verwendest. Wenn das funktioniert, lass Dir noch das file ausgeben (System.out.println). Wenn auch das passt, dann versuch mal
Java:
try(InputStream is = uploadFileHelper.getInputStream();
        FileOutputStream os = new FileOutputStream(file)) {
    byte[] buf = new byte[8192];
    int n;
    long total = 0;
    while ((n = is.read(buf)) != -1) {
        os.write(buf, 0, n);
        total += n;
    }
    System.out.printf("%d bytes read\n", total); // oder was auch immer Du zum Loggen verwendest.
} catch (IOException ex) {
    ex.printStackTrace();
}
anstelle von FileUtils.copyInputStreamToFile.
 
Also das File wird erstellt, auch mit einer Größe von 1 MB...
Allerdings kann ich es nicht öffnen.. "Die Datei ist beschädigt..."

Bekomme bei
int bytes = uploadFileHelper.getInputStream().read();
-Initial 1036665 Bytes

und dann in der oben genannten Stelle nur noch: 1036664 Bytes?
 
Was auch immer nun der Grund ist, aber so geht es:

Java:
String outputFile = storageAttachment.getFullPath();
Files.copy(uploadFileHelper.getInputStream(), Paths.get(outputFile));
File file = new File(outputFile);
 
Ok, danke...

Wie könnte nun noch das realisieren:
1. Stream umwandeln in eine Bilddatei
2. Bilddatei hat immer eine bestimmte Größe (z.B. 500x500px)
3. Bilddatei wiederum als Stream ausgeben...

Generell auch die Frage wie man sich das mit einem Stream vorstellen kann.
Wird hier temporär (Temp-Folder) auf dem Client anhand der Bytes eine Datei erstellt? Oder auf dem Server?
Was passiert wenn ich einen Stream nicht schließe (weil vergessen), die Aktion aber sowieso in einem "Stateless" EJB Container / @ViewScoped JSF Bean stattfindet?
 
Also was hier etwas unklar ist, ist die Frage, wie das Scaling gemacht werden soll. Sollen die Verhältnisse beibehalten werden oder soll das Bild einfach gedehnt / verzerrt werden?

Eine Utility Klasse, die ich einmal geschrieben habe, behält die Verhältnisse bei:

Java:
package de.kneitzel.images;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;

/**
 * Helper class to scale images
 */
public class ImageScaler {

    public static byte[] createScaledImage(byte[] originalImageBytes, int width, int height) {

        // Validation
        if (originalImageBytes == null) return null;
        if (originalImageBytes.length==0) return originalImageBytes;

        try {
            // Create the image from a byte array.
            BufferedImage originalImage = ImageIO.read(new ByteArrayInputStream(originalImageBytes));

            // Get values required to scale the Image:
            double scaleWidth = (double) width / (double) originalImage.getWidth();
            double scaleHeight = (double) height / (double) originalImage.getHeight();

            double scaleFactor;
            if (scaleWidth > scaleHeight) {
                scaleFactor = scaleHeight;
            } else {
                scaleFactor = scaleWidth;
            }
            int newHeight = (int) (scaleFactor * originalImage.getHeight());
            int newWidth = (int) (scaleFactor * originalImage.getWidth());
            int x = (width - newWidth) / 2;
            int y = (height - newHeight) / 2;

            // Scale the image
            BufferedImage scaledImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
            Graphics2D graphics = scaledImage.createGraphics();
            graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
            graphics.drawImage(originalImage, x, y, newWidth, newHeight, null);

            // Get the bytes of the image
            try (ByteArrayOutputStream stream = new ByteArrayOutputStream()) {
                ImageIO.write(scaledImage, "png", stream);
                return stream.toByteArray();
            }
        } catch (Exception ex) {
            return null;
        }
    }
}
Da Du generell mit Streams arbeiten möchtest, ändert sich lediglich am Anfang und am Ende etwas:
BufferedImage originalImage = ImageIO.read(yourInputStream);
Sprich: statt ein ByteArray zu übergeben wird hier einfach dein InputStream an ImageIO.read gegeben.

Und am Ende kann der ganze Block mit dem ByteArrayOutputStream weg und Du schreibst einfach das neue Bild direkt in den Outputstream:
ImageIO.write(scaledImage, "png", yourOutputStream);

(Ich hatte halt die Bilder in byte Arrays und brauchte diese auch genau so.)
 
Vielen Dank für die Antwort.

Also der Workflow sieht so aus:
1) Upload Beleg (Rechnung) über Web GUI... Kann eine Bilddatei oder PDF sein
2) Beleg wird in Bilddatei umgewandelt um es in der WebGUI als Vorschau anzuzeigen
a) Wenn PDF, dann werden daraus mehrere PNG / JPG -Dateien generiert
b) Wenn Bilddatei, dann skaliere das Bild herunter (macht kein Sinn ein 5MB Bild in der WebGUI als Vorschau anzuzeigen)

1) Funktioniert bereits
2) Umwandlung funktioniert

3) Skalierung fehlt eben noch...
-> Also sprich ich möchte die Vorschau eig. immer in einer fixen Größe haben.

Wie kann ich das mit der fixen Größe machen?
 
Wie kann ich das mit der fixen Größe machen?
Indem Du es in eine "Box" mit einer fixen Größe einpasst. Wenn ich mich gerade nicht vertue (bin nicht ganz bei der Sache), dann sollte das die neue Bildgröße liefern:
Java:
public Dimension calculateScaledDimension(Dimension imgDimension, Dimension boxDimension) {
    int h = boxDimension.height;
    int w = imgDimension.width * boxDimension.height / imgDimension.height;
    if (w > boxDimension.width) {
        w = boxDimension.width;
        h = imgDimension.height * boxDimension.width / imgDimension.width;
    }
    return new Dimension(w, h);
}
 
Vielen Dank für die Antwort.

Also der Workflow sieht so aus:
1) Upload Beleg (Rechnung) über Web GUI... Kann eine Bilddatei oder PDF sein
2) Beleg wird in Bilddatei umgewandelt um es in der WebGUI als Vorschau anzuzeigen
a) Wenn PDF, dann werden daraus mehrere PNG / JPG -Dateien generiert
b) Wenn Bilddatei, dann skaliere das Bild herunter (macht kein Sinn ein 5MB Bild in der WebGUI als Vorschau anzuzeigen)

1) Funktioniert bereits
2) Umwandlung funktioniert

3) Skalierung fehlt eben noch...
-> Also sprich ich möchte die Vorschau eig. immer in einer fixen Größe haben.

Wie kann ich das mit der fixen Größe machen?
Das mit dem runter skalieren sollte mit dem Code von mir doch gehen. Also wenn die Größe 500x500 sein soll, dann gibst Du das so an. Wenn die Bilder in der Regel A4 Format oder so hatten, dann passt Du es etwas an. Und bei der scalierung bleiben die Verhältnisse gleich.

Alternative könnte für Dich sein, dass Du die Ränder weg lassen willst, d.h. Du bekommst als Ergebnis ein Bild der Größe 500xAAA oder AAAx500 mit AAA<500.
Alles was sich dann im Code ändern würde:
newWidth und newHeight wurde ja berechnet. Statt das Bild nun in die vorgegebene Größe zu bauen, erzeugst Du ein Bild in genau dieser berechneten Größe.
 
Ja ich meinte so?

Code:
      int newHeight = 500;
            int newWidth = 500;
            int x = (width - newWidth) / 2;
            int y = (height - newHeight) / 2;

            // Scale the image
            BufferedImage scaledImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
            Graphics2D graphics = scaledImage.createGraphics();
            graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
            graphics.drawImage(originalImage, x, y, newWidth, newHeight, null);
 
Ich überlege gerade, woran es gerade scheitert....

Also ein ganz wichtiger Aspekt ist das Seitenverhältnis. Wenn Du ein Bild vergrößerst oder verkleinerst, dann kannst du das Seitenverhältnis beibehalten oder eben nicht beibehalten.

Wenn das Seitenverhältnis gleich bleibt, bedeutet dies:
a) Du kannst nicht auf beliebige Größen gehen. Beispiel: Bild ist 100x50 gross. Dann kannst Du es auf 500x250 vergrößern, aber eben nicht auf 500x500.
b) Das Bild selbst bleibt aber (mehr oder weniger) gleich, d.h. ein Quadrat bleibt ein Quadrat.

Wenn die Seitenverhältnisse nicht gleich bleiben, bedeutet dies:
a) Du kannst auf beliebige Größen gehen. Also ein Bild von 100x50 kannst Du auf 500x500 vergrößern.
b) Der Inhalt wird aber dann verzerrt. Ein Quadrat im 100x50 Bild wird im 500x500 Bild kein Quadrat mehr sein sondern ein Rechteck (Wo eine Kante doppelt so lang ist wie die andere).

Du willst es als Vorschau oder so speichern, d.h. die Seitenverhältnisse müssen gleich bleiben, damit die Vorschau nicht verzerrt ist.
Dadurch kannst Du aber nicht mehr die Zielgröße 500x500 erreichen, sondern - je nach Größe des Bildes - entstehen Ränder.

Daraus folgt dann:
a) es muss die neue Größe berechnet werden. Dies macht mein Code in den Zeilen, in denen new* berechnet wird.
b) es muss berechnet werden, wo das Bild dargestellt werden muss (Die Ränder recht/links oder oben/unten sollen gleich groß sein). Dazu berechne ich die Werte x und y.

Wenn man da hat, kann man ein neues Bild erzeugen und dann das vorhandene Bild in dieses neue Bild mit der richtigen Größe an die berechnete Position malen.

Das ist also die Beschreibung von meinem Code.

Wenn Du generell mit Streams arbeiten willst, dann wäre die Funktion - wie schon beschrieben - anzupassen:
Java:
package de.kneitzel.images;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;

/**
 * Helper class to scale images
 */
public class ImageScaler {

    public static void createScaledImage(InputStream inStream, OutputStream outStream, int width, int height) {

        try {
            // Create the image from a byte array.
            BufferedImage originalImage = ImageIO.read(inStream);

            // Get values required to scale the Image:
            double scaleWidth = (double) width / (double) originalImage.getWidth();
            double scaleHeight = (double) height / (double) originalImage.getHeight();

            double scaleFactor;
            if (scaleWidth > scaleHeight) {
                scaleFactor = scaleHeight;
            } else {
                scaleFactor = scaleWidth;
            }
            int newHeight = (int) (scaleFactor * originalImage.getHeight());
            int newWidth = (int) (scaleFactor * originalImage.getWidth());
            int x = (width - newWidth) / 2;
            int y = (height - newHeight) / 2;

            // Scale the image
            BufferedImage scaledImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
            Graphics2D graphics = scaledImage.createGraphics();
            graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
            graphics.drawImage(originalImage, x, y, newWidth, newHeight, null);

            // Write the image
            ImageIO.write(scaledImage, "png", outStream);
        } catch (Exception ex) {
            System.out.println("Exception occured: " + ex.getMessage());
            e.printStackTrace();
        }
    }
}
(Direkt hier im Editor geschrieben, also kann ggf. Fehler beinhalten!)

Diese Methode kannst Du nun direkt verwenden: createScaledImage(yourInStream, yourOutStream, 500, 500);

createScaledImage passt evtl. nicht mehr als Name ... scaleImage würde mir jetzt besser gefallen für diese Version, aber da kannst Du ja frei walten.

Wurde das jetzt etwas deutlicher?

Und evtl. noch die Variante, wo ein Bild ohne Ränder erzeugt wird, also ggf. kleiner als die Vorgabe:
Java:
package de.kneitzel.images;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;

/**
 * Helper class to scale images
 */
public class ImageScaler {

    public static void createScaledImage(InputStream inStream, OutputStream outStream, int maxWidth, int maxHeight) {

        try {
            // Create the image from a byte array.
            BufferedImage originalImage = ImageIO.read(inStream);

            // Get values required to scale the Image:
            double scaleWidth = (double) maxWidth / (double) originalImage.getWidth();
            double scaleHeight = (double) maxHeight / (double) originalImage.getHeight();

            double scaleFactor;
            if (scaleWidth > scaleHeight) {
                scaleFactor = scaleHeight;
            } else {
                scaleFactor = scaleWidth;
            }
            int height = (int) (scaleFactor * originalImage.getHeight());
            int width = (int) (scaleFactor * originalImage.getWidth());

            // Scale the image
            BufferedImage scaledImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
            Graphics2D graphics = scaledImage.createGraphics();
            graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
            graphics.drawImage(originalImage, 0, 0, width, height, null);

            // Write the image
            ImageIO.write(scaledImage, "png", outStream);
        } catch (Exception ex) {
            System.out.println("Exception occured: " + ex.getMessage());
            e.printStackTrace();
        }
    }
}
Sprich: Wenn Du ein Bild hast: 1000x500 und du rufst es mit 500x500 auf, damm hast Du im outStream ein Bild der Größe 500x250 erhalten. (Wieder ungetestet - nur zur Verdeutlichung der Möglichkeiten!)
 
Passende Stellenanzeigen aus deiner Region:

Neue Themen

Oben