1 | /****************************************************************************
|
---|
2 | ** $Id: showimg.cpp 2 2005-11-16 15:49:26Z dmik $
|
---|
3 | **
|
---|
4 | ** Copyright (C) 1992-2000 Trolltech AS. All rights reserved.
|
---|
5 | **
|
---|
6 | ** This file is part of an example program for Qt. This example
|
---|
7 | ** program may be used, distributed and modified without limitation.
|
---|
8 | **
|
---|
9 | *****************************************************************************/
|
---|
10 |
|
---|
11 | #include "showimg.h"
|
---|
12 | #include "imagetexteditor.h"
|
---|
13 | #include <qmenubar.h>
|
---|
14 | #include <qfiledialog.h>
|
---|
15 | #include <qmessagebox.h>
|
---|
16 | #include <qpopupmenu.h>
|
---|
17 | #include <qlabel.h>
|
---|
18 | #include <qpainter.h>
|
---|
19 | #include <qapplication.h>
|
---|
20 | #include <qclipboard.h>
|
---|
21 |
|
---|
22 |
|
---|
23 | /*
|
---|
24 | In the constructor, we just pass the standard parameters on to
|
---|
25 | QWidget.
|
---|
26 |
|
---|
27 | The menu uses a single slot to simplify the process of adding
|
---|
28 | more items to the options menu.
|
---|
29 | */
|
---|
30 | ImageViewer::ImageViewer( QWidget *parent, const char *name, int wFlags )
|
---|
31 | : QWidget( parent, name, wFlags ),
|
---|
32 | conversion_flags( PreferDither ),
|
---|
33 | helpmsg( 0 )
|
---|
34 | {
|
---|
35 | pickx = -1;
|
---|
36 | picky = -1;
|
---|
37 | clickx = -1;
|
---|
38 | clicky = -1;
|
---|
39 | alloc_context = 0;
|
---|
40 |
|
---|
41 | menubar = new QMenuBar(this);
|
---|
42 | menubar->setSeparator( QMenuBar::InWindowsStyle );
|
---|
43 |
|
---|
44 | QStrList fmt = QImage::outputFormats();
|
---|
45 | saveimage = new QPopupMenu( menubar );
|
---|
46 | savepixmap = new QPopupMenu( menubar );
|
---|
47 | for (const char* f = fmt.first(); f; f = fmt.next()) {
|
---|
48 | saveimage->insertItem( f );
|
---|
49 | savepixmap->insertItem( f );
|
---|
50 | }
|
---|
51 | connect( saveimage, SIGNAL(activated(int)), this, SLOT(saveImage(int)) );
|
---|
52 | connect( savepixmap, SIGNAL(activated(int)), this, SLOT(savePixmap(int)) );
|
---|
53 |
|
---|
54 | file = new QPopupMenu( menubar );
|
---|
55 | menubar->insertItem( "&File", file );
|
---|
56 | file->insertItem( "&New window", this, SLOT(newWindow()), CTRL+Key_N );
|
---|
57 | file->insertItem( "&Open...", this, SLOT(openFile()), CTRL+Key_O );
|
---|
58 | si = file->insertItem( "Save image", saveimage );
|
---|
59 | sp = file->insertItem( "Save pixmap", savepixmap );
|
---|
60 | file->insertSeparator();
|
---|
61 | file->insertItem( "E&xit", qApp, SLOT(quit()), CTRL+Key_Q );
|
---|
62 |
|
---|
63 | edit = new QPopupMenu( menubar );
|
---|
64 | menubar->insertItem( "&Edit", edit );
|
---|
65 | edit->insertItem("&Copy", this, SLOT(copy()), CTRL+Key_C);
|
---|
66 | edit->insertItem("&Paste", this, SLOT(paste()), CTRL+Key_V);
|
---|
67 | edit->insertSeparator();
|
---|
68 | edit->insertItem("&Horizontal flip", this, SLOT(hFlip()), ALT+Key_H);
|
---|
69 | edit->insertItem("&Vertical flip", this, SLOT(vFlip()), ALT+Key_V);
|
---|
70 | edit->insertItem("&Rotate 180", this, SLOT(rot180()), ALT+Key_R);
|
---|
71 | edit->insertSeparator();
|
---|
72 | edit->insertItem("&Text...", this, SLOT(editText()));
|
---|
73 | edit->insertSeparator();
|
---|
74 | t1 = edit->insertItem( "Convert to &1 bit", this, SLOT(to1Bit()) );
|
---|
75 | t8 = edit->insertItem( "Convert to &8 bit", this, SLOT(to8Bit()) );
|
---|
76 | t32 = edit->insertItem( "Convert to &32 bit", this, SLOT(to32Bit()) );
|
---|
77 |
|
---|
78 | options = new QPopupMenu( menubar );
|
---|
79 | menubar->insertItem( "&Options", options );
|
---|
80 | ac = options->insertItem( "AutoColor" );
|
---|
81 | co = options->insertItem( "ColorOnly" );
|
---|
82 | mo = options->insertItem( "MonoOnly" );
|
---|
83 | options->insertSeparator();
|
---|
84 | fd = options->insertItem( "DiffuseDither" );
|
---|
85 | bd = options->insertItem( "OrderedDither" );
|
---|
86 | td = options->insertItem( "ThresholdDither" );
|
---|
87 | options->insertSeparator();
|
---|
88 | ta = options->insertItem( "ThresholdAlphaDither" );
|
---|
89 | ba = options->insertItem( "OrderedAlphaDither" );
|
---|
90 | fa = options->insertItem( "DiffuseAlphaDither" );
|
---|
91 | options->insertSeparator();
|
---|
92 | ad = options->insertItem( "PreferDither" );
|
---|
93 | dd = options->insertItem( "AvoidDither" );
|
---|
94 | options->insertSeparator();
|
---|
95 | ss = options->insertItem( "Smooth scaling" );
|
---|
96 | cc = options->insertItem( "Use color context" );
|
---|
97 | if ( QApplication::colorSpec() == QApplication::ManyColor )
|
---|
98 | options->setItemEnabled( cc, FALSE );
|
---|
99 | options->setCheckable( TRUE );
|
---|
100 | setMenuItemFlags();
|
---|
101 |
|
---|
102 | menubar->insertSeparator();
|
---|
103 |
|
---|
104 | QPopupMenu* help = new QPopupMenu( menubar );
|
---|
105 | menubar->insertItem( "&Help", help );
|
---|
106 | help->insertItem( "Help!", this, SLOT(giveHelp()), CTRL+Key_H );
|
---|
107 |
|
---|
108 | connect( options, SIGNAL(activated(int)), this, SLOT(doOption(int)) );
|
---|
109 |
|
---|
110 | status = new QLabel(this);
|
---|
111 | status->setFrameStyle( QFrame::WinPanel | QFrame::Sunken );
|
---|
112 | status->setFixedHeight( fontMetrics().height() + 4 );
|
---|
113 |
|
---|
114 | setMouseTracking( TRUE );
|
---|
115 | }
|
---|
116 |
|
---|
117 | ImageViewer::~ImageViewer()
|
---|
118 | {
|
---|
119 | if ( alloc_context )
|
---|
120 | QColor::destroyAllocContext( alloc_context );
|
---|
121 | if ( other == this )
|
---|
122 | other = 0;
|
---|
123 | }
|
---|
124 |
|
---|
125 | /*
|
---|
126 | This function modifies the conversion_flags when an options menu item
|
---|
127 | is selected, then ensures all menu items are up to date, and reconverts
|
---|
128 | the image if possibly necessary.
|
---|
129 | */
|
---|
130 | void ImageViewer::doOption(int item)
|
---|
131 | {
|
---|
132 | if ( item == ss || item == cc ) {
|
---|
133 | // Toggle
|
---|
134 | bool newbool = !options->isItemChecked(item);
|
---|
135 | options->setItemChecked(item, newbool);
|
---|
136 | // And reconvert...
|
---|
137 | reconvertImage();
|
---|
138 | repaint(image.hasAlphaBuffer()); // show image in widget
|
---|
139 | return;
|
---|
140 | }
|
---|
141 |
|
---|
142 | if ( options->isItemChecked( item ) ) return; // They are all radio buttons
|
---|
143 |
|
---|
144 | int ocf = conversion_flags;
|
---|
145 |
|
---|
146 | if ( item == ac ) {
|
---|
147 | conversion_flags = ( conversion_flags & ~ColorMode_Mask ) | AutoColor;
|
---|
148 | } else if ( item == co ) {
|
---|
149 | conversion_flags = ( conversion_flags & ~ColorMode_Mask ) | ColorOnly;
|
---|
150 | } else if ( item == mo ) {
|
---|
151 | conversion_flags = ( conversion_flags & ~ColorMode_Mask ) | MonoOnly;
|
---|
152 | } else if ( item == fd ) {
|
---|
153 | conversion_flags = ( conversion_flags & ~Dither_Mask ) | DiffuseDither;
|
---|
154 | } else if ( item == bd ) {
|
---|
155 | conversion_flags = ( conversion_flags & ~Dither_Mask ) | OrderedDither;
|
---|
156 | } else if ( item == td ) {
|
---|
157 | conversion_flags = ( conversion_flags & ~Dither_Mask ) | ThresholdDither;
|
---|
158 | } else if ( item == ta ) {
|
---|
159 | conversion_flags = ( conversion_flags & ~AlphaDither_Mask ) | ThresholdAlphaDither;
|
---|
160 | } else if ( item == fa ) {
|
---|
161 | conversion_flags = ( conversion_flags & ~AlphaDither_Mask ) | DiffuseAlphaDither;
|
---|
162 | } else if ( item == ba ) {
|
---|
163 | conversion_flags = ( conversion_flags & ~AlphaDither_Mask ) | OrderedAlphaDither;
|
---|
164 | } else if ( item == ad ) {
|
---|
165 | conversion_flags = ( conversion_flags & ~DitherMode_Mask ) | PreferDither;
|
---|
166 | } else if ( item == dd ) {
|
---|
167 | conversion_flags = ( conversion_flags & ~DitherMode_Mask ) | AvoidDither;
|
---|
168 | }
|
---|
169 |
|
---|
170 | if ( ocf != conversion_flags ) {
|
---|
171 | setMenuItemFlags();
|
---|
172 | // And reconvert...
|
---|
173 | reconvertImage();
|
---|
174 | repaint(image.hasAlphaBuffer()); // show image in widget
|
---|
175 | }
|
---|
176 | }
|
---|
177 |
|
---|
178 | /*
|
---|
179 | Set the options menu to reflect the conversion_flags value.
|
---|
180 | */
|
---|
181 | void ImageViewer::setMenuItemFlags()
|
---|
182 | {
|
---|
183 | // File
|
---|
184 | bool valid_image = pm.size() != QSize( 0, 0 );
|
---|
185 | file->setItemEnabled( si, valid_image );
|
---|
186 | file->setItemEnabled( sp, valid_image );
|
---|
187 |
|
---|
188 | // Edit
|
---|
189 | edit->setItemEnabled( t1, image.depth() != 1 );
|
---|
190 | edit->setItemEnabled( t8, image.depth() != 8 );
|
---|
191 | edit->setItemEnabled( t32, image.depth() != 32 );
|
---|
192 |
|
---|
193 | // Options
|
---|
194 | bool may_need_color_dithering =
|
---|
195 | !valid_image
|
---|
196 | || image.depth() == 32 && QPixmap::defaultDepth() < 24;
|
---|
197 | bool may_need_dithering = may_need_color_dithering
|
---|
198 | || image.depth() > 1 && options->isItemChecked(mo)
|
---|
199 | || image.depth() > 1 && QPixmap::defaultDepth() == 1;
|
---|
200 | bool has_alpha_mask = !valid_image || image.hasAlphaBuffer();
|
---|
201 |
|
---|
202 | options->setItemEnabled( fd, may_need_dithering );
|
---|
203 | options->setItemEnabled( bd, may_need_dithering );
|
---|
204 | options->setItemEnabled( td, may_need_dithering );
|
---|
205 |
|
---|
206 | options->setItemEnabled( ta, has_alpha_mask );
|
---|
207 | options->setItemEnabled( fa, has_alpha_mask );
|
---|
208 | options->setItemEnabled( ba, has_alpha_mask );
|
---|
209 |
|
---|
210 | options->setItemEnabled( ad, may_need_color_dithering );
|
---|
211 | options->setItemEnabled( dd, may_need_color_dithering );
|
---|
212 |
|
---|
213 | options->setItemChecked( ac, (conversion_flags & ColorMode_Mask) == AutoColor );
|
---|
214 | options->setItemChecked( co, (conversion_flags & ColorMode_Mask) == ColorOnly );
|
---|
215 | options->setItemChecked( mo, (conversion_flags & ColorMode_Mask) == MonoOnly );
|
---|
216 | options->setItemChecked( fd, (conversion_flags & Dither_Mask) == DiffuseDither );
|
---|
217 | options->setItemChecked( bd, (conversion_flags & Dither_Mask) == OrderedDither );
|
---|
218 | options->setItemChecked( td, (conversion_flags & Dither_Mask) == ThresholdDither );
|
---|
219 | options->setItemChecked( ta, (conversion_flags & AlphaDither_Mask) == ThresholdAlphaDither );
|
---|
220 | options->setItemChecked( fa, (conversion_flags & AlphaDither_Mask) == DiffuseAlphaDither );
|
---|
221 | options->setItemChecked( ba, (conversion_flags & AlphaDither_Mask) == OrderedAlphaDither );
|
---|
222 | options->setItemChecked( ad, (conversion_flags & DitherMode_Mask) == PreferDither );
|
---|
223 | options->setItemChecked( dd, (conversion_flags & DitherMode_Mask) == AvoidDither );
|
---|
224 | }
|
---|
225 |
|
---|
226 | void ImageViewer::updateStatus()
|
---|
227 | {
|
---|
228 | if ( pm.size() == QSize( 0, 0 ) ) {
|
---|
229 | if ( !filename.isEmpty() )
|
---|
230 | status->setText("Could not load image");
|
---|
231 | else
|
---|
232 | status->setText("No image - select Open from File menu.");
|
---|
233 | } else {
|
---|
234 | QString message, moremsg;
|
---|
235 | message.sprintf("%dx%d", image.width(), image.height());
|
---|
236 | if ( pm.size() != pmScaled.size() ) {
|
---|
237 | moremsg.sprintf(" [%dx%d]", pmScaled.width(),
|
---|
238 | pmScaled.height());
|
---|
239 | message += moremsg;
|
---|
240 | }
|
---|
241 | moremsg.sprintf(", %d bits ", image.depth());
|
---|
242 | message += moremsg;
|
---|
243 | if (image.valid(pickx,picky)) {
|
---|
244 | moremsg.sprintf("(%d,%d)=#%0*x ",
|
---|
245 | pickx, picky,
|
---|
246 | image.hasAlphaBuffer() ? 8 : 6,
|
---|
247 | image.pixel(pickx,picky));
|
---|
248 | message += moremsg;
|
---|
249 | }
|
---|
250 | if ( image.numColors() > 0 ) {
|
---|
251 | if (image.valid(pickx,picky)) {
|
---|
252 | moremsg.sprintf(", %d/%d colors", image.pixelIndex(pickx,picky),
|
---|
253 | image.numColors());
|
---|
254 | } else {
|
---|
255 | moremsg.sprintf(", %d colors", image.numColors());
|
---|
256 | }
|
---|
257 | message += moremsg;
|
---|
258 | }
|
---|
259 | if ( image.hasAlphaBuffer() ) {
|
---|
260 | if ( image.depth() == 8 ) {
|
---|
261 | int i;
|
---|
262 | bool alpha[256];
|
---|
263 | int nalpha=0;
|
---|
264 |
|
---|
265 | for (i=0; i<256; i++)
|
---|
266 | alpha[i] = FALSE;
|
---|
267 |
|
---|
268 | for (i=0; i<image.numColors(); i++) {
|
---|
269 | int alevel = image.color(i) >> 24;
|
---|
270 | if (!alpha[alevel]) {
|
---|
271 | alpha[alevel] = TRUE;
|
---|
272 | nalpha++;
|
---|
273 | }
|
---|
274 | }
|
---|
275 | moremsg.sprintf(", %d alpha levels", nalpha);
|
---|
276 | } else {
|
---|
277 | // Too many pixels to bother counting.
|
---|
278 | moremsg = ", 8-bit alpha channel";
|
---|
279 | }
|
---|
280 | message += moremsg;
|
---|
281 | }
|
---|
282 | status->setText(message);
|
---|
283 | }
|
---|
284 | }
|
---|
285 |
|
---|
286 | /*
|
---|
287 | This function saves the image.
|
---|
288 | */
|
---|
289 | void ImageViewer::saveImage( int item )
|
---|
290 | {
|
---|
291 | const char* fmt = saveimage->text(item);
|
---|
292 | QString savefilename = QFileDialog::getSaveFileName(QString::null, QString::null,
|
---|
293 | this, filename);
|
---|
294 | if ( !savefilename.isEmpty() )
|
---|
295 | if ( !image.save( savefilename, fmt ) )
|
---|
296 | QMessageBox::warning( this, "Save failed", "Error saving file" );
|
---|
297 | }
|
---|
298 |
|
---|
299 | /*
|
---|
300 | This function saves the converted image.
|
---|
301 | */
|
---|
302 | void ImageViewer::savePixmap( int item )
|
---|
303 | {
|
---|
304 | const char* fmt = savepixmap->text(item);
|
---|
305 | QString savefilename = QFileDialog::getSaveFileName(QString::null,
|
---|
306 | QString::null, this, filename);
|
---|
307 | if ( !savefilename.isEmpty() )
|
---|
308 | if ( !pmScaled.save( savefilename, fmt ) )
|
---|
309 | QMessageBox::warning( this, "Save failed", "Error saving file" );
|
---|
310 | }
|
---|
311 |
|
---|
312 |
|
---|
313 | void ImageViewer::newWindow()
|
---|
314 | {
|
---|
315 | ImageViewer* that = new ImageViewer(0, "new window", WDestructiveClose);
|
---|
316 | that->options->setItemChecked( that->cc, useColorContext() );
|
---|
317 | that->show();
|
---|
318 | }
|
---|
319 |
|
---|
320 | /*
|
---|
321 | This function is the slot for processing the Open menu item.
|
---|
322 | */
|
---|
323 | void ImageViewer::openFile()
|
---|
324 | {
|
---|
325 | QString newfilename = QFileDialog::getOpenFileName( QString::null,
|
---|
326 | QString::null,
|
---|
327 | this );
|
---|
328 | if ( !newfilename.isEmpty() ) {
|
---|
329 | loadImage( newfilename ) ;
|
---|
330 | repaint(); // show image in widget
|
---|
331 | }
|
---|
332 | }
|
---|
333 |
|
---|
334 | /*
|
---|
335 | This function loads an image from a file and resizes the widget to
|
---|
336 | exactly fit the image size. If the file was not found or the image
|
---|
337 | format was unknown it will resize the widget to fit the errorText
|
---|
338 | message (see above) displayed in the current font.
|
---|
339 |
|
---|
340 | Returns TRUE if the image was successfully loaded.
|
---|
341 | */
|
---|
342 |
|
---|
343 | bool ImageViewer::loadImage( const QString& fileName )
|
---|
344 | {
|
---|
345 | filename = fileName;
|
---|
346 | bool ok = FALSE;
|
---|
347 | if ( !filename.isEmpty() ) {
|
---|
348 | QApplication::setOverrideCursor( waitCursor ); // this might take time
|
---|
349 | ok = image.load(filename, 0);
|
---|
350 | pickx = -1;
|
---|
351 | clickx = -1;
|
---|
352 | if ( ok )
|
---|
353 | ok = reconvertImage();
|
---|
354 | if ( ok ) {
|
---|
355 | setCaption( filename ); // set window caption
|
---|
356 | int w = pm.width();
|
---|
357 | int h = pm.height();
|
---|
358 |
|
---|
359 | const int reasonable_width = 128;
|
---|
360 | if ( w < reasonable_width ) {
|
---|
361 | // Integer scale up to something reasonable
|
---|
362 | int multiply = ( reasonable_width + w - 1 ) / w;
|
---|
363 | w *= multiply;
|
---|
364 | h *= multiply;
|
---|
365 | }
|
---|
366 |
|
---|
367 | h += menubar->heightForWidth(w) + status->height();
|
---|
368 | resize( w, h ); // we resize to fit image
|
---|
369 | } else {
|
---|
370 | pm.resize(0,0); // couldn't load image
|
---|
371 | update();
|
---|
372 | }
|
---|
373 | QApplication::restoreOverrideCursor(); // restore original cursor
|
---|
374 | }
|
---|
375 | updateStatus();
|
---|
376 | setMenuItemFlags();
|
---|
377 | return ok;
|
---|
378 | }
|
---|
379 |
|
---|
380 | bool ImageViewer::reconvertImage()
|
---|
381 | {
|
---|
382 | bool success = FALSE;
|
---|
383 |
|
---|
384 | if ( image.isNull() ) return FALSE;
|
---|
385 |
|
---|
386 | if ( alloc_context ) {
|
---|
387 | QColor::destroyAllocContext( alloc_context );
|
---|
388 | alloc_context = 0;
|
---|
389 | }
|
---|
390 | if ( useColorContext() ) {
|
---|
391 | alloc_context = QColor::enterAllocContext();
|
---|
392 | // Clear the image to hide flickering palette
|
---|
393 | QPainter painter(this);
|
---|
394 | painter.eraseRect(0, menubar->heightForWidth( width() ), width(), height());
|
---|
395 | }
|
---|
396 |
|
---|
397 | QApplication::setOverrideCursor( waitCursor ); // this might take time
|
---|
398 | if ( pm.convertFromImage(image, conversion_flags) )
|
---|
399 | {
|
---|
400 | pmScaled = QPixmap();
|
---|
401 | scale();
|
---|
402 | resize( width(), height() );
|
---|
403 | success = TRUE; // load successful
|
---|
404 | } else {
|
---|
405 | pm.resize(0,0); // couldn't load image
|
---|
406 | }
|
---|
407 | updateStatus();
|
---|
408 | setMenuItemFlags();
|
---|
409 | QApplication::restoreOverrideCursor(); // restore original cursor
|
---|
410 |
|
---|
411 | if ( useColorContext() )
|
---|
412 | QColor::leaveAllocContext();
|
---|
413 |
|
---|
414 | return success; // TRUE if loaded OK
|
---|
415 | }
|
---|
416 |
|
---|
417 | bool ImageViewer::smooth() const
|
---|
418 | {
|
---|
419 | return options->isItemChecked(ss);
|
---|
420 | }
|
---|
421 |
|
---|
422 | bool ImageViewer::useColorContext() const
|
---|
423 | {
|
---|
424 | return options->isItemChecked(cc);
|
---|
425 | }
|
---|
426 |
|
---|
427 | /*
|
---|
428 | This functions scales the pixmap in the member variable "pm" to fit the
|
---|
429 | widget size and puts the resulting pixmap in the member variable "pmScaled".
|
---|
430 | */
|
---|
431 |
|
---|
432 | void ImageViewer::scale()
|
---|
433 | {
|
---|
434 | int h = height() - menubar->heightForWidth( width() ) - status->height();
|
---|
435 |
|
---|
436 | if ( image.isNull() ) return;
|
---|
437 |
|
---|
438 | QApplication::setOverrideCursor( waitCursor ); // this might take time
|
---|
439 | if ( width() == pm.width() && h == pm.height() )
|
---|
440 | { // no need to scale if widget
|
---|
441 | pmScaled = pm; // size equals pixmap size
|
---|
442 | } else {
|
---|
443 | if (smooth()) {
|
---|
444 | pmScaled.convertFromImage(image.smoothScale(width(), h),
|
---|
445 | conversion_flags);
|
---|
446 | } else {
|
---|
447 | QWMatrix m; // transformation matrix
|
---|
448 | m.scale(((double)width())/pm.width(),// define scale factors
|
---|
449 | ((double)h)/pm.height());
|
---|
450 | pmScaled = pm.xForm( m ); // create scaled pixmap
|
---|
451 | }
|
---|
452 | }
|
---|
453 | QApplication::restoreOverrideCursor(); // restore original cursor
|
---|
454 | }
|
---|
455 |
|
---|
456 | /*
|
---|
457 | The resize event handler, if a valid pixmap was loaded it will call
|
---|
458 | scale() to fit the pixmap to the new widget size.
|
---|
459 | */
|
---|
460 |
|
---|
461 | void ImageViewer::resizeEvent( QResizeEvent * )
|
---|
462 | {
|
---|
463 | status->setGeometry(0, height() - status->height(),
|
---|
464 | width(), status->height());
|
---|
465 |
|
---|
466 | if ( pm.size() == QSize( 0, 0 ) ) // we couldn't load the image
|
---|
467 | return;
|
---|
468 |
|
---|
469 | int h = height() - menubar->heightForWidth( width() ) - status->height();
|
---|
470 | if ( width() != pmScaled.width() || h != pmScaled.height())
|
---|
471 | { // if new size,
|
---|
472 | scale(); // scale pmScaled to window
|
---|
473 | updateStatus();
|
---|
474 | }
|
---|
475 | if ( image.hasAlphaBuffer() )
|
---|
476 | erase();
|
---|
477 | }
|
---|
478 |
|
---|
479 | bool ImageViewer::convertEvent( QMouseEvent* e, int& x, int& y)
|
---|
480 | {
|
---|
481 | if ( pm.size() != QSize( 0, 0 ) ) {
|
---|
482 | int h = height() - menubar->heightForWidth( width() ) - status->height();
|
---|
483 | int nx = e->x() * image.width() / width();
|
---|
484 | int ny = (e->y()-menubar->heightForWidth( width() )) * image.height() / h;
|
---|
485 | if (nx != x || ny != y ) {
|
---|
486 | x = nx;
|
---|
487 | y = ny;
|
---|
488 | updateStatus();
|
---|
489 | return TRUE;
|
---|
490 | }
|
---|
491 | }
|
---|
492 | return FALSE;
|
---|
493 | }
|
---|
494 |
|
---|
495 | void ImageViewer::mousePressEvent( QMouseEvent *e )
|
---|
496 | {
|
---|
497 | may_be_other = convertEvent(e, clickx, clicky);
|
---|
498 | }
|
---|
499 |
|
---|
500 | void ImageViewer::mouseReleaseEvent( QMouseEvent * )
|
---|
501 | {
|
---|
502 | if ( may_be_other )
|
---|
503 | other = this;
|
---|
504 | }
|
---|
505 |
|
---|
506 | /*
|
---|
507 | Record the pixel position of interest.
|
---|
508 | */
|
---|
509 | void ImageViewer::mouseMoveEvent( QMouseEvent *e )
|
---|
510 | {
|
---|
511 | if (convertEvent(e,pickx,picky)) {
|
---|
512 | updateStatus();
|
---|
513 | if ((e->state()&LeftButton)) {
|
---|
514 | may_be_other = FALSE;
|
---|
515 | if ( clickx >= 0 && other) {
|
---|
516 | copyFrom(other);
|
---|
517 | }
|
---|
518 | }
|
---|
519 | }
|
---|
520 | }
|
---|
521 |
|
---|
522 | /*
|
---|
523 | Draws the portion of the scaled pixmap that needs to be updated or prints
|
---|
524 | an error message if no legal pixmap has been loaded.
|
---|
525 | */
|
---|
526 |
|
---|
527 | void ImageViewer::paintEvent( QPaintEvent *e )
|
---|
528 | {
|
---|
529 | if ( pm.size() != QSize( 0, 0 ) ) { // is an image loaded?
|
---|
530 | QPainter painter(this);
|
---|
531 | painter.setClipRect(e->rect());
|
---|
532 | painter.drawPixmap(0, menubar->heightForWidth( width() ), pmScaled);
|
---|
533 | }
|
---|
534 | }
|
---|
535 |
|
---|
536 |
|
---|
537 | /*
|
---|
538 | Explain anything that might be confusing.
|
---|
539 | */
|
---|
540 | void ImageViewer::giveHelp()
|
---|
541 | {
|
---|
542 | if (!helpmsg) {
|
---|
543 | QString helptext =
|
---|
544 | "<b>Usage:</b> <tt>showimg [-m] <i>filename ...</i></tt>"
|
---|
545 | "<blockquote>"
|
---|
546 | "<tt>-m</tt> - use <i>ManyColor</i> color spec"
|
---|
547 | "</blockquote>"
|
---|
548 | "<p>Supported input formats:"
|
---|
549 | "<blockquote>";
|
---|
550 | helptext += QImage::inputFormatList().join(", ");
|
---|
551 | helptext += "</blockquote>";
|
---|
552 |
|
---|
553 | helpmsg = new QMessageBox( "Help", helptext,
|
---|
554 | QMessageBox::Information, QMessageBox::Ok, 0, 0, 0, 0, FALSE );
|
---|
555 | }
|
---|
556 | helpmsg->show();
|
---|
557 | helpmsg->raise();
|
---|
558 | }
|
---|
559 |
|
---|
560 | void ImageViewer::copyFrom(ImageViewer* s)
|
---|
561 | {
|
---|
562 | if ( clickx >= 0 ) {
|
---|
563 | int dx = clickx;
|
---|
564 | int dy = clicky;
|
---|
565 | int sx = s->clickx;
|
---|
566 | int sy = s->clicky;
|
---|
567 | int sw = QABS(clickx - pickx)+1;
|
---|
568 | int sh = QABS(clicky - picky)+1;
|
---|
569 | if ( clickx > pickx ) {
|
---|
570 | dx = pickx;
|
---|
571 | sx -= sw-1;
|
---|
572 | }
|
---|
573 | if ( clicky > picky ) {
|
---|
574 | dy = picky;
|
---|
575 | sy -= sh-1;
|
---|
576 | }
|
---|
577 | bitBlt( &image, dx, dy, &s->image, sx, sy, sw, sh );
|
---|
578 | reconvertImage();
|
---|
579 | repaint( image.hasAlphaBuffer() );
|
---|
580 | }
|
---|
581 | }
|
---|
582 | ImageViewer* ImageViewer::other = 0;
|
---|
583 |
|
---|
584 | void ImageViewer::hFlip()
|
---|
585 | {
|
---|
586 | setImage(image.mirror(TRUE,FALSE));
|
---|
587 | }
|
---|
588 |
|
---|
589 | void ImageViewer::vFlip()
|
---|
590 | {
|
---|
591 | setImage(image.mirror(FALSE,TRUE));
|
---|
592 | }
|
---|
593 |
|
---|
594 | void ImageViewer::rot180()
|
---|
595 | {
|
---|
596 | setImage(image.mirror(TRUE,TRUE));
|
---|
597 | }
|
---|
598 |
|
---|
599 | void ImageViewer::copy()
|
---|
600 | {
|
---|
601 | #ifndef QT_NO_MIMECLIPBOARD
|
---|
602 | QApplication::clipboard()->setImage(image); // Less information loss
|
---|
603 | #endif
|
---|
604 | }
|
---|
605 |
|
---|
606 | void ImageViewer::paste()
|
---|
607 | {
|
---|
608 | #ifndef QT_NO_MIMECLIPBOARD
|
---|
609 | QImage p = QApplication::clipboard()->image();
|
---|
610 | if ( !p.isNull() ) {
|
---|
611 | filename = "pasted";
|
---|
612 | setImage(p);
|
---|
613 | }
|
---|
614 | #endif
|
---|
615 | }
|
---|
616 |
|
---|
617 | void ImageViewer::setImage(const QImage& newimage)
|
---|
618 | {
|
---|
619 | image = newimage;
|
---|
620 |
|
---|
621 | pickx = -1;
|
---|
622 | clickx = -1;
|
---|
623 | setCaption( filename ); // set window caption
|
---|
624 | int w = image.width();
|
---|
625 | int h = image.height();
|
---|
626 | if ( !w )
|
---|
627 | return;
|
---|
628 |
|
---|
629 | const int reasonable_width = 128;
|
---|
630 | if ( w < reasonable_width ) {
|
---|
631 | // Integer scale up to something reasonable
|
---|
632 | int multiply = ( reasonable_width + w - 1 ) / w;
|
---|
633 | w *= multiply;
|
---|
634 | h *= multiply;
|
---|
635 | }
|
---|
636 |
|
---|
637 | h += menubar->heightForWidth(w) + status->height();
|
---|
638 | resize( w, h ); // we resize to fit image
|
---|
639 |
|
---|
640 | reconvertImage();
|
---|
641 | repaint( image.hasAlphaBuffer() );
|
---|
642 |
|
---|
643 | updateStatus();
|
---|
644 | setMenuItemFlags();
|
---|
645 | }
|
---|
646 |
|
---|
647 | void ImageViewer::editText()
|
---|
648 | {
|
---|
649 | ImageTextEditor editor(image,this);
|
---|
650 | editor.exec();
|
---|
651 | }
|
---|
652 |
|
---|
653 | void ImageViewer::to1Bit()
|
---|
654 | {
|
---|
655 | toBitDepth(1);
|
---|
656 | }
|
---|
657 |
|
---|
658 | void ImageViewer::to8Bit()
|
---|
659 | {
|
---|
660 | toBitDepth(8);
|
---|
661 | }
|
---|
662 |
|
---|
663 | void ImageViewer::to32Bit()
|
---|
664 | {
|
---|
665 | toBitDepth(32);
|
---|
666 | }
|
---|
667 |
|
---|
668 | void ImageViewer::toBitDepth(int d)
|
---|
669 | {
|
---|
670 | image = image.convertDepth(d);
|
---|
671 | reconvertImage();
|
---|
672 | repaint( image.hasAlphaBuffer() );
|
---|
673 | }
|
---|