summaryrefslogtreecommitdiffstats
path: root/qtjava/javalib/examples/showimg/ImageViewer.java
diff options
context:
space:
mode:
Diffstat (limited to 'qtjava/javalib/examples/showimg/ImageViewer.java')
-rw-r--r--qtjava/javalib/examples/showimg/ImageViewer.java703
1 files changed, 703 insertions, 0 deletions
diff --git a/qtjava/javalib/examples/showimg/ImageViewer.java b/qtjava/javalib/examples/showimg/ImageViewer.java
new file mode 100644
index 00000000..0b419ea9
--- /dev/null
+++ b/qtjava/javalib/examples/showimg/ImageViewer.java
@@ -0,0 +1,703 @@
+/***************************************************************************
+* $Id$
+**
+* Copyright (C) 1992-2000 Trolltech AS. All rights reserved.
+**
+* This file is part of an example program for Qt. This example
+* program may be used, distributed and modified without limitation.
+**
+****************************************************************************/
+
+import org.kde.qt.*;
+import java.util.*;
+
+class ImageViewer extends QWidget
+{
+private int conversion_flags;
+private int alloc_context;
+private String filename;
+private QImage image = new QImage(); // the loaded image
+private QPixmap pm = new QPixmap(); // the converted pixmap
+private QPixmap pmScaled; // the scaled pixmap
+
+private QMenuBar menubar;
+private QPopupMenu file;
+private QPopupMenu saveimage;
+private QPopupMenu savepixmap;
+private QPopupMenu edit;
+private QPopupMenu options;
+
+private QWidget helpmsg;
+private QLabel status;
+private int si, sp, ac, co, mo, fd, bd, // Menu item ids
+ td, ta, ba, fa, au, ad, dd,
+ ss, cc, t1, t8, t32;
+private int[] pickx = { 0 };
+private int[] picky = { 0 };
+private int[] clickx = { 0 };
+private int[] clicky = { 0 };
+private boolean may_be_other;
+private static ImageViewer other = null;
+
+
+
+
+/*
+ In the constructor, we just pass the standard parameters on to
+ QWidget.
+
+ The menu uses a single slot to simplify the process of adding
+ more items to the options menu.
+*/
+ImageViewer( QWidget parent, String name, int wFlags )
+{
+ super( parent, name, wFlags );
+ conversion_flags = PreferDither;
+ filename = "";
+ helpmsg = null;
+ pickx[0] = -1;
+ picky[0] = -1;
+ clickx[0] = -1;
+ clicky[0] = -1;
+ alloc_context = 0;
+
+ menubar = new QMenuBar(this);
+ menubar.setSeparator( QMenuBar.InWindowsStyle );
+
+ ArrayList fmt = QImage.outputFormats();
+ saveimage = new QPopupMenu( menubar );
+ savepixmap = new QPopupMenu( menubar );
+ Iterator it = fmt.iterator();
+ while (it.hasNext()) {
+ String f = (String) it.next();
+ saveimage.insertItem( f );
+ savepixmap.insertItem( f );
+ }
+ connect( saveimage, SIGNAL("activated(int)"), this, SLOT("saveImage(int)") );
+ connect( savepixmap, SIGNAL("activated(int)"), this, SLOT("savePixmap(int)") );
+
+ file = new QPopupMenu( menubar );
+ menubar.insertItem( "&File", file );
+ file.insertItem( "&New window", this, SLOT("newWindow()"), new QKeySequence(CTRL+Key_N) );
+ file.insertItem( "&Open...", this, SLOT("openFile()"), new QKeySequence(CTRL+Key_O) );
+ si = file.insertItem( "Save image", saveimage );
+ sp = file.insertItem( "Save pixmap", savepixmap );
+ file.insertSeparator();
+ file.insertItem( "E&xit", qApp(), SLOT("quit()"), new QKeySequence(CTRL+Key_Q) );
+
+ edit = new QPopupMenu( menubar );
+ menubar.insertItem( "&Edit", edit );
+ edit.insertItem("&Copy", this, SLOT("copy()"), new QKeySequence(CTRL+Key_C));
+ edit.insertItem("&Paste", this, SLOT("paste()"), new QKeySequence(CTRL+Key_V));
+ edit.insertSeparator();
+ edit.insertItem("&Horizontal flip", this, SLOT("hFlip()"), new QKeySequence(ALT+Key_H));
+ edit.insertItem("&Vertical flip", this, SLOT("vFlip()"), new QKeySequence(ALT+Key_V));
+ edit.insertItem("&Rotate 180", this, SLOT("rot180()"), new QKeySequence(ALT+Key_R));
+ edit.insertSeparator();
+ edit.insertItem("&Text...", this, SLOT("editText()"));
+ edit.insertSeparator();
+ t1 = edit.insertItem( "Convert to &1 bit", this, SLOT("to1Bit()") );
+ t8 = edit.insertItem( "Convert to &8 bit", this, SLOT("to8Bit()") );
+ t32 = edit.insertItem( "Convert to &32 bit", this, SLOT("to32Bit()") );
+
+ options = new QPopupMenu( menubar );
+ menubar.insertItem( "&Options", options );
+ ac = options.insertItem( "AutoColor" );
+ co = options.insertItem( "ColorOnly" );
+ mo = options.insertItem( "MonoOnly" );
+ options.insertSeparator();
+ fd = options.insertItem( "DiffuseDither" );
+ bd = options.insertItem( "OrderedDither" );
+ td = options.insertItem( "ThresholdDither" );
+ options.insertSeparator();
+ ta = options.insertItem( "ThresholdAlphaDither" );
+ ba = options.insertItem( "OrderedAlphaDither" );
+ fa = options.insertItem( "DiffuseAlphaDither" );
+ options.insertSeparator();
+ ad = options.insertItem( "PreferDither" );
+ dd = options.insertItem( "AvoidDither" );
+ options.insertSeparator();
+ ss = options.insertItem( "Smooth scaling" );
+ cc = options.insertItem( "Use color context" );
+ if ( QApplication.colorSpec() == QApplication.ManyColor )
+ options.setItemEnabled( cc, false );
+ options.setCheckable( true );
+ setMenuItemFlags();
+
+ menubar.insertSeparator();
+
+ QPopupMenu help = new QPopupMenu( menubar );
+ menubar.insertItem( "&Help", help );
+ help.insertItem( "Help!", this, SLOT("giveHelp()"), new QKeySequence(CTRL+Key_H) );
+
+ connect( options, SIGNAL("activated(int)"), this, SLOT("doOption(int)") );
+
+ status = new QLabel(this);
+ status.setFrameStyle( QFrame.WinPanel | QFrame.Sunken );
+ status.setFixedHeight( fontMetrics().height() + 4 );
+
+ setMouseTracking( true );
+}
+
+void cleanUp()
+{
+ if ( alloc_context != 0 )
+ QColor.destroyAllocContext( alloc_context );
+ if ( other == this )
+ other = null;
+}
+
+/*
+ This function modifies the conversion_flags when an options menu item
+ is selected, then ensures all menu items are up to date, and reconverts
+ the image if possibly necessary.
+*/
+void doOption(int item)
+{
+ if ( item == ss || item == cc ) {
+ // Toggle
+ boolean newboolean = !options.isItemChecked(item);
+ options.setItemChecked(item, newboolean);
+ // And reconvert...
+ reconvertImage();
+ repaint(image.hasAlphaBuffer()); // show image in widget
+ return;
+ }
+
+ if ( options.isItemChecked( item ) ) return; // They are all radio buttons
+
+ int ocf = conversion_flags;
+
+ if ( item == ac ) {
+ conversion_flags = conversion_flags & ~ColorMode_Mask | AutoColor;
+ } else if ( item == co ) {
+ conversion_flags = conversion_flags & ~ColorMode_Mask | ColorOnly;
+ } else if ( item == mo ) {
+ conversion_flags = conversion_flags & ~ColorMode_Mask | MonoOnly;
+ } else if ( item == fd ) {
+ conversion_flags = conversion_flags & ~Dither_Mask | DiffuseDither;
+ } else if ( item == bd ) {
+ conversion_flags = conversion_flags & ~Dither_Mask | OrderedDither;
+ } else if ( item == td ) {
+ conversion_flags = conversion_flags & ~Dither_Mask | ThresholdDither;
+ } else if ( item == ta ) {
+ conversion_flags = conversion_flags & ~AlphaDither_Mask | ThresholdAlphaDither;
+ } else if ( item == fa ) {
+ conversion_flags = conversion_flags & ~AlphaDither_Mask | DiffuseAlphaDither;
+ } else if ( item == ba ) {
+ conversion_flags = conversion_flags & ~AlphaDither_Mask | OrderedAlphaDither;
+ } else if ( item == ad ) {
+ conversion_flags = conversion_flags & ~DitherMode_Mask | PreferDither;
+ } else if ( item == dd ) {
+ conversion_flags = conversion_flags & ~DitherMode_Mask | AvoidDither;
+ }
+
+ if ( ocf != conversion_flags ) {
+ setMenuItemFlags();
+ // And reconvert...
+ reconvertImage();
+ repaint(image.hasAlphaBuffer()); // show image in widget
+ }
+}
+
+/*
+ Set the options menu to reflect the conversion_flags value.
+*/
+void setMenuItemFlags()
+{
+ // File
+ boolean valid_image = pm.size().width() != 0 || pm.size().height() != 0;
+ file.setItemEnabled( si, valid_image );
+ file.setItemEnabled( sp, valid_image );
+
+ // Edit
+ edit.setItemEnabled( t1, image.depth() != 1 );
+ edit.setItemEnabled( t8, image.depth() != 8 );
+ edit.setItemEnabled( t32, image.depth() != 32 );
+
+ // Options
+ boolean may_need_color_dithering =
+ !valid_image
+ || image.depth() == 32 && QPixmap.defaultDepth() < 24;
+ boolean may_need_dithering = may_need_color_dithering
+ || image.depth() > 1 && options.isItemChecked(mo)
+ || image.depth() > 1 && QPixmap.defaultDepth() == 1;
+ boolean has_alpha_mask = !valid_image || image.hasAlphaBuffer();
+
+ options.setItemEnabled( fd, may_need_dithering );
+ options.setItemEnabled( bd, may_need_dithering );
+ options.setItemEnabled( td, may_need_dithering );
+
+ options.setItemEnabled( ta, has_alpha_mask );
+ options.setItemEnabled( fa, has_alpha_mask );
+ options.setItemEnabled( ba, has_alpha_mask );
+
+ options.setItemEnabled( ad, may_need_color_dithering );
+ options.setItemEnabled( dd, may_need_color_dithering );
+
+ options.setItemChecked( ac, (conversion_flags & ColorMode_Mask) == AutoColor );
+ options.setItemChecked( co, (conversion_flags & ColorMode_Mask) == ColorOnly );
+ options.setItemChecked( mo, (conversion_flags & ColorMode_Mask) == MonoOnly );
+ options.setItemChecked( fd, (conversion_flags & Dither_Mask) == DiffuseDither );
+ options.setItemChecked( bd, (conversion_flags & Dither_Mask) == OrderedDither );
+ options.setItemChecked( td, (conversion_flags & Dither_Mask) == ThresholdDither );
+ options.setItemChecked( ta, (conversion_flags & AlphaDither_Mask) == ThresholdAlphaDither );
+ options.setItemChecked( fa, (conversion_flags & AlphaDither_Mask) == DiffuseAlphaDither );
+ options.setItemChecked( ba, (conversion_flags & AlphaDither_Mask) == OrderedAlphaDither );
+ options.setItemChecked( ad, (conversion_flags & DitherMode_Mask) == PreferDither );
+ options.setItemChecked( dd, (conversion_flags & DitherMode_Mask) == AvoidDither );
+}
+
+void updateStatus()
+{
+ if ( pm.size().width() == 0 && pm.size().height() == 0 ) {
+ if ( !filename.equals("") )
+ status.setText("Could not load image");
+ else
+ status.setText("No image - select Open from File menu.");
+ } else {
+ String message, moremsg;
+ message = "" + image.width() + "x" + image.height();
+ if ( pm.size().width() != pmScaled.size().width()
+ || pm.size().height() != pmScaled.size().height() )
+ {
+ moremsg = " [" + pmScaled.width() + "x" + pmScaled.height() + "]";
+ message += moremsg;
+ }
+ moremsg = ", " + image.depth() + " bits ";
+ message += moremsg;
+ if (image.valid(pickx[0],picky[0])) {
+ moremsg = "("
+ + pickx[0] + "," + picky[0] + ")=#"
+ + Integer.toHexString(image.pixel(pickx[0],picky[0]))
+ + " ";
+ message += moremsg;
+ }
+ if ( image.numColors() > 0 ) {
+ if (image.valid(pickx[0],picky[0])) {
+ moremsg = ", " + image.pixelIndex(pickx[0],picky[0]) + "/"
+ + image.numColors() + " colors";
+ } else {
+ moremsg = ", " + image.numColors() + " colors";
+ }
+ message += moremsg;
+ }
+ if ( image.hasAlphaBuffer() ) {
+ if ( image.depth() == 8 ) {
+ int i;
+ boolean alpha[] = new boolean[256];
+ int nalpha=0;
+
+ for (i=0; i<256; i++)
+ alpha[i] = false;
+
+ for (i=0; i<image.numColors(); i++) {
+ int alevel = image.color(i) >> 24;
+ // Hack - image.color() returns a C++ unsigned int, but alevel is a signed int.
+ // If the top 8 bits are 0xffffffff, alevel is -1, not 255, and needs fixing up
+ if (alevel == -1) {
+ alevel = 255;
+ }
+ if (!alpha[alevel]) {
+ alpha[alevel] = true;
+ nalpha++;
+ }
+ }
+ moremsg = ", " + nalpha + " alpha levels";
+ } else {
+ // Too many pixels to bother counting.
+ moremsg = ", 8-bit alpha channel";
+ }
+ message += moremsg;
+ }
+ status.setText(message);
+ }
+}
+
+/*
+ This function saves the image.
+*/
+void saveImage( int item )
+{
+ String fmt = saveimage.text(item);
+ String savefilename = QFileDialog.getSaveFileName("", "",
+ this, filename);
+ if ( !savefilename.equals("") )
+ if ( !image.save( savefilename, fmt ) )
+ QMessageBox.warning( this, "Save failed", "Error saving file" );
+}
+
+/*
+ This function saves the converted image.
+*/
+void savePixmap( int item )
+{
+ String fmt = savepixmap.text(item);
+ String savefilename = QFileDialog.getSaveFileName("",
+ "", this, filename);
+ if ( !savefilename.equals("") )
+ if ( !pmScaled.save( savefilename, fmt ) )
+ QMessageBox.warning( this, "Save failed", "Error saving file" );
+}
+
+
+void newWindow()
+{
+ ImageViewer that = new ImageViewer(null, "new window", WDestructiveClose);
+ that.options.setItemChecked( that.cc, useColorContext() );
+ that.show();
+}
+
+/*
+ This function is the slot for processing the Open menu item.
+*/
+void openFile()
+{
+ String newfilename = QFileDialog.getOpenFileName();
+ if ( !newfilename.equals("") ) {
+ loadImage( newfilename ) ;
+ repaint(); // show image in widget
+ }
+}
+
+/*
+ This function loads an image from a file and resizes the widget to
+ exactly fit the image size. If the file was not found or the image
+ format was unknown it will resize the widget to fit the errorText
+ message (see above) displayed in the current font.
+
+ Returns true if the image was successfully loaded.
+*/
+
+boolean loadImage( String fileName )
+{
+ filename = fileName;
+ boolean ok = false;
+ if ( ! filename.equals("") ) {
+ QApplication.setOverrideCursor( waitCursor() ); // this might take time
+ ok = image.load(filename, null);
+ pickx[0] = -1;
+ clickx[0] = -1;
+ if ( ok )
+ ok = reconvertImage();
+ if ( ok ) {
+ setCaption( filename ); // set window caption
+ int w = pm.width();
+ int h = pm.height();
+
+ int reasonable_width = 128;
+ if ( w < reasonable_width ) {
+ // Integer scale up to something reasonable
+ int multiply = ( reasonable_width + w - 1 ) / w;
+ w *= multiply;
+ h *= multiply;
+ }
+
+ h += menubar.heightForWidth(w) + status.height();
+ resize( w, h ); // we resize to fit image
+ } else {
+ pm.resize(0,0); // couldn't load image
+ update();
+ }
+ QApplication.restoreOverrideCursor(); // restore original cursor
+ }
+ updateStatus();
+ setMenuItemFlags();
+ return ok;
+}
+
+boolean reconvertImage()
+{
+ boolean success = false;
+
+ if ( image.isNull() ) return false;
+
+ if ( alloc_context != 0 ) {
+ QColor.destroyAllocContext( alloc_context );
+ alloc_context = 0;
+ }
+ if ( useColorContext() ) {
+ alloc_context = QColor.enterAllocContext();
+ // Clear the image to hide flickering palette
+ QPainter painter = new QPainter(this);
+ painter.eraseRect(0, menubar.heightForWidth( width() ), width(), height());
+ }
+
+ QApplication.setOverrideCursor( waitCursor() ); // this might take time
+ if ( pm.convertFromImage(image, conversion_flags) )
+ {
+ pmScaled = new QPixmap();
+ scale();
+ resize( width(), height() );
+ success = true; // load successful
+ } else {
+ pm.resize(0,0); // couldn't load image
+ }
+ updateStatus();
+ setMenuItemFlags();
+ QApplication.restoreOverrideCursor(); // restore original cursor
+
+ if ( useColorContext() )
+ QColor.leaveAllocContext();
+
+ return success; // true if loaded OK
+}
+
+boolean smooth()
+{
+ return options.isItemChecked(ss);
+}
+
+boolean useColorContext()
+{
+ return options.isItemChecked(cc);
+}
+
+/*
+ This functions scales the pixmap in the member variable "pm" to fit the
+ widget size and puts the resulting pixmap in the member variable "pmScaled".
+*/
+
+void scale()
+{
+ int h = height() - menubar.heightForWidth( width() ) - status.height();
+
+ if ( image.isNull() ) return;
+
+ QApplication.setOverrideCursor( waitCursor() ); // this might take time
+ if ( width() == pm.width() && h == pm.height() )
+ { // no need to scale if widget
+ pmScaled = pm; // size equals pixmap size
+ } else {
+ if (smooth()) {
+ pmScaled.convertFromImage(image.smoothScale(width(), h),
+ conversion_flags);
+ } else {
+ QWMatrix m = new QWMatrix(); // transformation matrix
+ m.scale(((double)width())/pm.width(),// define scale factors
+ ((double)h)/pm.height());
+ pmScaled = (QPixmap) pm.xForm( m ); // create scaled pixmap
+ }
+ }
+ QApplication.restoreOverrideCursor(); // restore original cursor
+}
+
+/*
+ The resize event handler, if a valid pixmap was loaded it will call
+ scale() to fit the pixmap to the new widget size.
+*/
+
+protected void resizeEvent( QResizeEvent e )
+{
+ status.setGeometry(0, height() - status.height(),
+ width(), status.height());
+
+ if ( pm.size().width() == 0 && pm.size().height() == 0 ) // we couldn't load the image
+ return;
+
+ int h = height() - menubar.heightForWidth( width() ) - status.height();
+ if ( width() != pmScaled.width() || h != pmScaled.height())
+ { // if new size,
+ scale(); // scale pmScaled to window
+ updateStatus();
+ }
+ if ( image.hasAlphaBuffer() )
+ erase();
+}
+
+protected boolean convertEvent( QMouseEvent e, int[] x, int[] y)
+{
+ if ( pm.size().width() != 0 || pm.size().height() != 0 ) {
+ int h = height() - menubar.heightForWidth( width() ) - status.height();
+ int nx = e.x() * image.width() / width();
+ int ny = (e.y()-menubar.heightForWidth( width() )) * image.height() / h;
+ if (nx != x[0] || ny != y[0] ) {
+ x[0] = nx;
+ y[0] = ny;
+ updateStatus();
+ return true;
+ }
+ }
+ return false;
+}
+
+protected void mousePressEvent( QMouseEvent e )
+{
+ may_be_other = convertEvent(e, clickx, clicky);
+}
+
+protected void mouseReleaseEvent( QMouseEvent e )
+{
+ if ( may_be_other )
+ other = this;
+}
+
+/*
+ Record the pixel position of interest.
+*/
+protected void mouseMoveEvent( QMouseEvent e )
+{
+ if (convertEvent(e,pickx,picky)) {
+ updateStatus();
+ if ((e.state()&LeftButton) != 0) {
+ may_be_other = false;
+ if ( clickx[0] >= 0 && other != null) {
+ copyFrom(other);
+ }
+ }
+ }
+}
+
+/*
+ Draws the portion of the scaled pixmap that needs to be updated or prints
+ an error message if no legal pixmap has been loaded.
+*/
+
+protected void paintEvent( QPaintEvent e )
+{
+ if ( pm.size().width() != 0 || pm.size().height() != 0 ) { // is an image loaded?
+ QPainter painter = new QPainter(this);
+ painter.setClipRect(e.rect());
+ painter.drawPixmap(0, menubar.heightForWidth( width() ), pmScaled);
+ }
+}
+
+
+/*
+ Explain anything that might be confusing.
+*/
+void giveHelp()
+{
+ if (helpmsg == null) {
+ String helptext =
+ "<b>Usage:</b> <tt>showimg [-m] <i>filename ...</i></tt>"
+ + "<blockquote>"
+ + "<tt>-m</tt> - use <i>ManyColor</i> color spec"
+ + "</blockquote>"
+ + "<p>Supported input formats:"
+ + "<blockquote>";
+ Iterator it = QImage.inputFormatList().iterator();
+ if (it.hasNext())
+ helptext += (String) it.next();
+ while (it.hasNext()) {
+ helptext += ", " + (String) it.next();
+ }
+ helptext += "</blockquote>";
+
+ helpmsg = new QMessageBox( "Help", helptext,
+ QMessageBox.Information, QMessageBox.Ok, 0, 0, null, null, false );
+ }
+ helpmsg.show();
+ helpmsg.raise();
+}
+
+void copyFrom(ImageViewer s)
+{
+ if ( clickx[0] >= 0 ) {
+ int dx = clickx[0];
+ int dy = clicky[0];
+ int sx = s.clickx[0];
+ int sy = s.clicky[0];
+ int sw = Math.abs(clickx[0] - pickx[0])+1;
+ int sh = Math.abs(clicky[0] - picky[0])+1;
+ if ( clickx[0] > pickx[0] ) {
+ dx = pickx[0];
+ sx -= sw-1;
+ }
+ if ( clicky[0] > picky[0] ) {
+ dy = picky[0];
+ sy -= sh-1;
+ }
+ bitBlt( new QPixmap(image), dx, dy, new QPixmap(s.image), sx, sy, sw, sh );
+ reconvertImage();
+ repaint( image.hasAlphaBuffer() );
+ }
+}
+
+void hFlip()
+{
+ setImage(image.mirror(true,false));
+}
+
+void vFlip()
+{
+ setImage(image.mirror(false,true));
+}
+
+void rot180()
+{
+ setImage(image.mirror(true,true));
+}
+
+void copy()
+{
+ QApplication.clipboard().setImage(image); // Less information loss
+}
+
+void paste()
+{
+ QImage p = QApplication.clipboard().image();
+ if ( !p.isNull() ) {
+ filename = "pasted";
+ setImage(p);
+ }
+}
+
+void setImage(QImage newimage)
+{
+ image = newimage;
+
+ pickx[0] = -1;
+ clickx[0] = -1;
+ setCaption( filename ); // set window caption
+ int w = image.width();
+ int h = image.height();
+ if ( w == 0 )
+ return;
+
+ int reasonable_width = 128;
+ if ( w < reasonable_width ) {
+ // Integer scale up to something reasonable
+ int multiply = ( reasonable_width + w - 1 ) / w;
+ w = multiply;
+ h = multiply;
+ }
+
+ h += menubar.heightForWidth(w) + status.height();
+ resize( w, h ); // we resize to fit image
+
+ reconvertImage();
+ repaint( image.hasAlphaBuffer() );
+
+ updateStatus();
+ setMenuItemFlags();
+}
+
+void editText()
+{
+ ImageTextEditor editor = new ImageTextEditor(image,this);
+ editor.exec();
+}
+
+void to1Bit()
+{
+ toBitDepth(1);
+}
+
+void to8Bit()
+{
+ toBitDepth(8);
+}
+
+void to32Bit()
+{
+ toBitDepth(32);
+}
+
+void toBitDepth(int d)
+{
+ image = image.convertDepth(d);
+ reconvertImage();
+ repaint( image.hasAlphaBuffer() );
+}
+}