# Foto Uploading Tool



## Upriser (4. Okt 2010)

Hallo zusammen,

Ich bin atm daran ein Tool zu bauen, bei welchem man Fotos aus einem Verzeichnis laden kann, die Seitenverhältnisse bestimmen kann und anschliessend diese per SFTP Verbindung in eine Webgalerie stellen kann.

Nun stehe ich bei folgendem Problem an:
Ein Foto ist durchschnittlich 3.5MB gross. Davon habe ich ca. 60-80 Stück pro Verzeichnis.
Wenn ich nun ein Foto auf die grösse 800x600 skalieren will und danach noch komprimieren will. Dauert dies pro Foto ca. 3 sek. Was hochgerechnet ca. 4-5 min dauert. Zu lange für mich 

Gibt es eine alternative Möglichekeit Fotos zu skalieren und zu komprimieren?

Source:


```
public class FotoCompresser {

private String tempPathImages = "C:/Programme/MetalNetFU/Temp";
private String tempPathThumbs = "C:/Programme/MetalNetFU/Temp/Thumbs";
private int x;
private int y;
private RenderedImage rendImage;

public FotoCompresser(int x, int y) {
this.x = x;
this.y = y;
}

public void compress(File file) {

int scaledX, scaledY;

try {

Image img = new ImageIcon(ImageIO.read(file)).getImage();
if (img.getHeight(null) < img.getWidth(null)) {
scaledX = x;
scaledY = y;
} else {
scaledX = y;
scaledY = x;
}

Image scaledImage = img.getScaledInstance(scaledX, scaledY,
Image.SCALE_SMOOTH);
BufferedImage bufferedImage = new BufferedImage(scaledX, scaledY,
BufferedImage.TYPE_INT_RGB);

Graphics2D g = (Graphics2D) bufferedImage.getGraphics();
g.drawImage(scaledImage, 0, 0, null);

try {
File f = new File(tempPathImages + "/" + file.getName());
JimiRasterImage jrf = Jimi.createRasterImage(scaledImage
.getSource());
Jimi.putImage("image/jpeg", jrf, new FileOutputStream(f));
} catch (JimiException je) {
je.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}

}
```

Danke für eure Hilfe.


----------



## slawaweis (4. Okt 2010)

Ich kenne hier 2 Möglichkeiten. Erstens, einen externen Konverter verwenden, welcher nativ auf dem Betriebsystem läuft, auf die Bilderverarbeitung optimiert ist und über die Kommandozeile gesteuert werden kann. Mir fällt auf die schnelle jetzt aber keiner ein.

Zweite Variante: über ImageIO. Dort gibt es die Möglichkeit noch während des Ladens anzugeben, wie viel vom dem Bild man laden will. Das geht so:


```
// Eingabestream
InputStream is = ...;

// ImageIO
ImageInputStream iis = ImageIO.createImageInputStream(is);
Iterator iter = ImageIO.getImageReaders(iis);

// prüfen, ob mindestens ein Codec zum Eingabestream
// in ImageIO vorhanden ist
if(!iter.hasNext())
  {
  // Fehler: Bildfomat nicht erkannt
  // oder wird von ImageIO nicht unterstützt
  }

// Codec(s) gefunden, ersten nehmen
ImageReader reader = (ImageReader)iter.next();

// Eingabestream in den Codec setzen
reader.setInput(iis);

// Standardparameter für das Lesen holen
ImageReadParam irp = reader.getDefaultReadParam();

// nur jede 6 Zeile und jede 6 Spalte des Bildes lesen bzw. laden
// so wird z.B. aus einem 600x600 Pixel Bild auf der Festplatte
// nur eine 100x100 Pixel Version geladen
irp.setSourceSubsampling(6, 6, 0, 0);

// erstes Bild im Stream mit eigenen Ladeparametern holen
BufferedImage image = reader.read(0, irp);

// ImageInputStream schließen
iis.close();
```

Slawa


----------



## madboy (4. Okt 2010)

slawaweis hat gesagt.:


> Ich kenne hier 2 Möglichkeiten. Erstens, einen externen Konverter verwenden, welcher nativ auf dem Betriebsystem läuft, auf die Bilderverarbeitung optimiert ist und über die Kommandozeile gesteuert werden kann.


ImageMagick: Convert, Edit, and Compose Images würde sich hier anbieten. Schnell und sehr mächtig.


----------



## Upriser (21. Okt 2010)

So das mit der Fotokomprimierung und Skalierung geht nun.

Nun stehe an folgendem Problem. Auf meinem GUI hat es ein JTextPane in welchem ich während der Verarbeitung auflisten möchte welches Foto gerade bearbeitet wird und danach welches Foto gerade auf den FTP geladen wird.

Wenn ich nun aber die Verarbeitung starte, also auf den Start-Button klicke, friert mir das GUI ein bis die Verarbeitung durchgelaufen ist. Erst dann wird das GUI upgedatet mit allen Daten im TextPane angezeigt.

Wie kann ich das machen, dass während im Hintergrund die Verarbeitung läuft ich den Status auf dem GUI anzeigen kann?


----------



## mjdv (21. Okt 2010)

Mit Threads!


----------



## Geeeee (21. Okt 2010)

> So das mit der Fotokomprimierung und Skalierung geht nun.


Rein interessehalber sei mal nachgefragt wie?
Hast du ImageIO oder externe Tools wie z.B. imagemagick verwendet?


----------



## Upriser (21. Okt 2010)

In einem ersten Schritt kopiere ich alle Fotos in ein Temp verzeichnis. Danach Skaliere ich sie und schreibe Sie mit ImageIO. Ist nicht die schnellste möglichkeit aber es ist genug schnell um es einem Benutzer zuumuten.


```
private BufferedImage scaleImage(File file) {
		Image imageSource = new ImageIcon(file.getPath()).getImage();
		int scaleX, scaleY;
		if (imageSource.getHeight(null) > imageSource.getWidth(null)) {
			scaleX = y;
			scaleY = x;
		} else {
			scaleX = x;
			scaleY = y;
		}

		return toBufferedImage(imageSource.getScaledInstance(scaleX, scaleY, 0));
	}

	private void saveImage(BufferedImage image, File file) {
		image.createGraphics().drawImage(image, image.getWidth(),
				image.getHeight(), null);
		try {
			ImageIO.write(image, "jpg", new File(tempPathImages + "/"
					+ categoryName + "_" + generateFileNumber()+".jpg"));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
```


----------



## JohannisderKaeufer (21. Okt 2010)

Image.getScaledInstance() ist nicht unbedingt die beste/schnellste Wahl um Bilder zu skalieren.

Fast Image Scaling/Resizing in Java  Frickelblog

und

The Perils of Image.getScaledInstance() | Java.net

haben sich mit dem Thema befaßt und zeigen wie es schneller und besser geht.

Bild jeweils 20x skalieren=

Image.getScaledInstance(): 35781 ms
mein Scaler:  ~234 ms

um mal die Größenordnung aufzuzeigen, die zwischen den Varianten liegen kann.

Die Geschichte mit dem Einfrieren hängt meist damit zusammen, das Aufgaben, wie hier "das Skalieren von Bildern" im EventDispatchingThread abläuft, was es nicht sollte.

Ein Sysout in der Methode scaleImage mit java.awt.EventQueue.isDispatchThread() sollte wenn es korrekt ist false zurückliefern. Genauso wie in saveImage.

Wie das ganze richtig geht damit der GUI nicht kalt wird, findet man unter dem Stichwort SwingWorker, bzw. löst das Problem mit gleichnamigem.


----------

