Freitag, 23. Januar 2009

 

Anzeigen und Laden von Bildern mit Java

Folgendes Beispiel ermöglicht es Bilder anzuzeigen. Die Bilder werden in etwa auf die Fenstergröße skaliert (beim Öffnen). Weiters kann man das angezeigte Bild immer um 90 Grad drehen. Das Beispiel soll nur gewisse Grundfunktionalität zeigen. Es beinhaltet auch einige grafische Hilfsmethoden, die ich gegoogelt habe (rotieren mit rotateImage(), skalieren).
Das Beispiel ist nicht ausgereift sondern ein bisschen buggy (das Skalieren sollte über Menü ausgewählt werden können, das Format des Steuerelements/Bildes passt nach dem Rotieren nicht ganz). Als Basis für weitere Arbeiten ist's jedoch ganz brauchbar.

/**
* Beispiel für Bilderanzeige. Kann Bilddateien öffnen. Bild wird in etwa auf
* Fenstergröße skaliert.
* Rotieren eines Bildes ist möglich.
* Alle nötigen Klassen in dieser Datei.
* FIXME: Ist noch ein bisschen Buggy: Skalieren sollte man extra aufrufen
* können, ImageComponent passt nicht ganz nach rotieren (oder die Grafik?).
*
* @author Harald R. Haberstroh
*/
package image;

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.awt.image.PixelGrabber;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JScrollPane;
import javax.swing.KeyStroke;
import javax.swing.filechooser.FileFilter;

/**
* Bildkomponente, kann Bilder zeichnen, skalieren und rotieren.
*
* @author Harald R. Haberstroh (hh)
*
*/
class ImageComponent extends JComponent {
private static final long serialVersionUID = 8055865896136562197L;

private BufferedImage image; // gelesenes Bild

private Image scaled; // Hilfsvariable für skaliertes Bild

/**
* über diese Methode kann man eine Datei angeben, die geffnet und angezeigt
* wird.
*
* @param file
* Bilddatei
*/
public void setImage(File file) {
try {
if ((image = ImageIO.read(file)) != null) {
// Skalieren, unterscheide Hoch- und Querformat
double scale = 1.0;
if (image.getWidth() > image.getHeight()) { // Querformat
scale = (double)getParent().getWidth() / image.getWidth();
} else { // Hochformat
scale = (double)getParent().getHeight() / image.getHeight();
}
scaled = image.getScaledInstance((int)(image.getWidth() * scale),
(int)(image.getHeight() * scale), Image.SCALE_FAST);
image = toBufferedImage(scaled);
setPreferredSize(new Dimension(image.getWidth(), image.getHeight()));
repaint();
}
} catch (IOException e) {
e.printStackTrace();
}
}

/**
* rotieren der aktuellen Grafik.
*
* @param degrees
* um soviele Grad wird gedreht (im Uhrzeigersinn).
*/
public void rotate(double degrees) {
image = rotateImage(image, degrees);
setPreferredSize(new Dimension(image.getWidth(), image.getHeight()));
repaint();
}

/**
* Hilfsmethode, die eine Grafik (BufferedImage) drehen kann. Verwendet
* AffineTransform zum Drehen. Wichtig ist, den Drehpunkt in die Mitte der
* Grafik zu legen.
*
* @param src
* Grafik
* @param degrees
* um soviele Grad wird gedreht
* @return neue gedrehte Grafik
*/
private static BufferedImage rotateImage(BufferedImage src, double degrees) {
AffineTransform affineTransform = AffineTransform.getRotateInstance(Math
.toRadians(degrees), src.getWidth() / 2, src.getHeight() / 2);
BufferedImage rotatedImage = new BufferedImage(src.getWidth(), src
.getHeight(), src.getType());
Graphics2D g = (Graphics2D)rotatedImage.getGraphics();
g.setTransform(affineTransform);
g.drawImage(src, 0, 0, null);
return rotatedImage;
}

/**
* hier wird gezeichnet..
*/
@Override
protected void paintComponent(Graphics g) {
if (image != null) {
g.drawImage(image, 0, 0, this);
}
}

/**
* Hilfsmethode, die ein Image in ein BufferedImage umwandelt, da direktes
* Umwandeln nicht möglich. Benötigt man z.B. für Saklieren, da dort ein Image
* geliefert wird, sonst aber BufferedIMage benötigt wird.
*
* @param image
* Image
* @return BufferedImage
*/
public static BufferedImage toBufferedImage(Image image) {
if (image instanceof BufferedImage) {
return (BufferedImage)image;
}

// wirklich alle Pixel des image laden:
image = new ImageIcon(image).getImage();

// Gibt es transparente Pixel?
boolean hasAlpha = hasAlpha(image);

BufferedImage bimage = null;
// Erzeuge buffered image mit dem default color model
int type = BufferedImage.TYPE_INT_RGB;
if (hasAlpha == true) {
type = BufferedImage.TYPE_INT_ARGB;
}
bimage = new BufferedImage(image.getWidth(null), image.getHeight(null),
type);

// Kopiere image zu buffered image über den Graphic-Kontext:
Graphics g = bimage.createGraphics();

// Zeichne nun das Image auf den neuen Gracphic-Kontext (und damit auf das
// buffered image)
g.drawImage(image, 0, 0, null);
g.dispose();

return bimage;
}

/**
* Hilfsmethode, die bestimmt, ob Transparenz vorhanden.
*
* @param image
* @return hat Alpha (Transparenz)
*/
public static boolean hasAlpha(Image image) {
// Wenn das image bereits ein buffered image, dann gibt's schon ein color
// model
if (image instanceof BufferedImage) {
return ((BufferedImage)image).getColorModel().hasAlpha();
}

// Verwende einen pixel grabber um das color model (Farbmodell) zu
// bestimmen.
// Ein einzelnes Pixel genügt.
PixelGrabber pg = new PixelGrabber(image, 0, 0, 1, 1, false);
try {
pg.grabPixels();
} catch (InterruptedException e) {
}

// von dem Pixel wird nun das color model bestimmt und zurückgeliefert
return pg.getColorModel().hasAlpha();
}
}

/**
* Aktion für Dateiauswahl.
*
* @author Harald R. Haberstroh (hh)
*
*/
class FileOpenAction implements ActionListener {
private final ImageComponent viewComponent;

public FileOpenAction(ImageComponent viewComponent) {
this.viewComponent = viewComponent;
}

/**
* Dateiauswahldialog anzeigen.
*/
public void actionPerformed(ActionEvent e) {
JFileChooser d = new JFileChooser();
d.setFileFilter(new FileFilter() {
@Override
public boolean accept(File f) {
return f.isDirectory() || f.getName().toLowerCase().endsWith(".jpg")
|| f.getName().toLowerCase().endsWith(".gif");
}

@Override
public String getDescription() {
return "*.jpg;*.gif";
}
});

d.showOpenDialog(null);
File file = d.getSelectedFile();

if (file != null)
viewComponent.setImage(file);
}
}

/**
* Aktion für Rotieren.
*
* @author Harald R. Haberstroh (hh)
*
*/
class RotateAction implements ActionListener {
private final ImageComponent viewComponent;

public RotateAction(ImageComponent viewComponent) {
this.viewComponent = viewComponent;
}

public void actionPerformed(ActionEvent e) {
viewComponent.rotate(90.0);
}

}

/**
* Einfacher Bildbetrachter.
*
* @author Harald R. Haberstroh (hh)
*
*/
public class ImageViewer {
public static void main(String[] args) {
JFrame f = new JFrame("Bildbetrachter");

ImageComponent viewComponent = new ImageComponent();
f.add(new JScrollPane(viewComponent)); // zum Scrollen, falls Bild zu groß

JMenuBar mbar = new JMenuBar();
JMenu menu = new JMenu("Datei");
JMenuItem item = new JMenuItem("Öffnen");
item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O,
InputEvent.CTRL_MASK));
item.addActionListener(new FileOpenAction(viewComponent));
menu.add(item);
item = new JMenuItem("Drehen");
item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_R,
InputEvent.CTRL_MASK));
item.addActionListener(new RotateAction(viewComponent));
menu.add(item);
mbar.add(menu);
f.setJMenuBar(mbar);

f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(600, 400);
f.setLocationRelativeTo(null); // zentrieren auf Bildschirmmitte
f.setVisible(true);
}
}

Labels: ,


Kommentare:

Kommentar veröffentlichen

Abonnieren Kommentare zum Post [Atom]





<< Startseite

This page is powered by Blogger. Isn't yours?

Abonnieren Posts [Atom]