diff options
author | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
---|---|---|
committer | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
commit | 90825e2392b2d70e43c7a25b8a3752299a933894 (patch) | |
tree | e33aa27f02b74604afbfd0ea4f1cfca8833d882a /qtjava/javalib/examples/showimg/ImageViewer.java | |
download | tdebindings-90825e2392b2d70e43c7a25b8a3752299a933894.tar.gz tdebindings-90825e2392b2d70e43c7a25b8a3752299a933894.zip |
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdebindings@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'qtjava/javalib/examples/showimg/ImageViewer.java')
-rw-r--r-- | qtjava/javalib/examples/showimg/ImageViewer.java | 703 |
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() ); +} +} |