1 /**************************************************************************** 2 * MeshLab o o * 3 * An extendible mesh processor o o * 4 * _ O _ * 5 * Copyright(C) 2005, 2009 \/)\/ * 6 * Visual Computing Lab /\/| * 7 * ISTI - Italian National Research Council | * 8 * \ * 9 * All rights reserved. * 10 * * 11 * This program is free software; you can redistribute it and/or modify * 12 * it under the terms of the GNU General Public License as published by * 13 * the Free Software Foundation; either version 2 of the License, or * 14 * (at your option) any later version. * 15 * * 16 * This program is distributed in the hope that it will be useful, * 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 19 * GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * 20 * for more details. * 21 * * 22 ****************************************************************************/ 23 24 #include "maskImageWidget.h" 25 #include "maskRenderWidget.h" 26 #include "fillImage.h" 27 #include <QtGui/QPen> 28 #include <QtGui/QBrush> 29 #include <QtGui/QPolygon> 30 #include <QtGui/QPixmap> 31 #include <QtGui/QImage> 32 #include <QtGui/QPainter> 33 #include <QtGui/QPalette> 34 #include <QtGui/QMouseEvent> 35 #include <QtGui/QPaintEvent> 36 #include <QtGui/QApplication> 37 #include <QtGui/QMessageBox> 38 #include <QtGui/QAction> 39 #include <QtGui/QVBoxLayout> 40 #include <QtGui/QToolBar> 41 #include <QtGui/QSpinBox> 42 #include <QtGui/QFileDialog> 43 #include <QtGui/QDesktopWidget> 44 45 #include <stack> 46 #include <cmath> 47 #include <sstream> 48 #include <cassert> 49 #include <iostream> 50 51 #ifdef WIN32 52 #undef min 53 #undef max 54 #endif 55 56 57 namespace ui 58 { 59 60 struct maskImageWidget::Impl 61 { 62 enum DrawMode { Pen, Eraser } mode_; 63 64 maskRenderWidget *render_area_; 65 int threshold_gradient_, threshold_fixed_; 66 int realwidth_, realheight_; 67 Impl(); 68 }; 69 70 Impl()71 maskImageWidget::Impl::Impl() 72 { 73 mode_ = Pen; 74 threshold_gradient_ = 100; 75 threshold_fixed_ = 30; 76 } 77 78 maskImageWidget(const QImage & image,QWidget * parent)79 maskImageWidget::maskImageWidget(const QImage& image, QWidget *parent) : QDialog(parent), pimpl_(new Impl) 80 { 81 init(image); 82 } 83 84 ~maskImageWidget()85 maskImageWidget::~maskImageWidget() throw() 86 { 87 delete pimpl_; 88 } 89 getMask() const90 QImage maskImageWidget::getMask() const 91 { 92 return pimpl_->render_area_->getMask(pimpl_->realwidth_, pimpl_->realheight_); 93 } 94 loadMask(const QString & filename)95 void maskImageWidget::loadMask(const QString& filename) 96 { 97 pimpl_->render_area_->load(filename); 98 } 99 init(const QImage & image)100 void maskImageWidget::init(const QImage& image) 101 { 102 setWindowTitle(tr("Mask Editor")); 103 104 QPixmap load("coral_open32x32.png"); 105 QPixmap save("coral_save32x32.png"); 106 QPixmap undo("coral_undo32x32.png"); 107 QPixmap redo("coral_redo32x32.png"); 108 QPixmap pen("coral_pencil32x32.png"); 109 QPixmap eraser("coral_eraser32x32.png"); 110 111 QAction *canvasloadmask = new QAction(this); 112 canvasloadmask->setIcon(load); 113 canvasloadmask->setText(tr("&Load Mask")); 114 QAction *canvassavemask = new QAction(this); 115 canvassavemask->setIcon(QIcon(save)); 116 canvassavemask->setText(tr("&Save Mask")); 117 QAction *canvasundo = new QAction(this); 118 canvasundo->setIcon(QIcon(undo)); 119 canvasundo->setText(tr("&Undo")); 120 canvasundo->setShortcut(QKeySequence("Ctrl+Z")); 121 QAction *canvasredo = new QAction(this); 122 canvasredo->setIcon(QIcon(redo)); 123 canvasredo->setText(tr("&Redo")); 124 canvasredo->setShortcut(QKeySequence("Ctrl+Shift+Z")); 125 QAction *canvasclear = new QAction(tr("&Clear"), this); 126 canvasclear->setShortcut(QKeySequence("Ctrl+C")); 127 128 QAction *canvaspen = new QAction(this); 129 canvaspen->setIcon(QIcon(pen)); 130 canvaspen->setText(tr("&Pen")); 131 QAction *canvaseraser = new QAction(this); 132 canvaseraser->setIcon(QIcon(eraser)); 133 canvaseraser->setText(tr("&Eraser")); 134 135 QActionGroup *actions(new QActionGroup(this)); 136 actions->addAction(canvaspen); 137 actions->addAction(canvaseraser); 138 canvaspen->setCheckable(true); 139 canvaseraser->setCheckable(true); 140 canvaspen->setChecked(true); 141 actions->setExclusive(true); 142 143 QAction *canvasOK = new QAction(this); 144 canvasOK->setText("OK"); 145 QAction *canvasCancel = new QAction(this); 146 canvasCancel->setText("Cancel"); 147 148 QBoxLayout *layout(new QVBoxLayout(this)); 149 150 // We don't want a real-size image. We will downscale it! 151 QImage image_to_use = image; 152 pimpl_->realwidth_ = image.width(); 153 pimpl_->realheight_ = image.height(); 154 qDebug("maskImageWidget::Init real wxh %i x%i",pimpl_->realwidth_,pimpl_->realheight_); 155 QDesktopWidget *desktop(QApplication::desktop()); 156 if (image.width() > (desktop->width() * .8) || 157 image.height() > (desktop->height() * .8)) 158 { 159 int width(desktop->width()), height(desktop->height()); 160 image_to_use = image.scaled((int)std::floor(width * .75), 161 (int)std::floor(height * .75), Qt::KeepAspectRatio); 162 } 163 pimpl_->render_area_ = new maskRenderWidget(image_to_use, this); 164 165 QToolBar *canvas_toolbar(new QToolBar(this)); 166 canvas_toolbar->addSeparator(); 167 canvas_toolbar->addAction(canvasloadmask); 168 canvas_toolbar->addAction(canvassavemask); 169 canvas_toolbar->addSeparator(); 170 171 canvas_toolbar->addAction(canvasundo); 172 canvas_toolbar->addAction(canvasredo); 173 canvas_toolbar->addSeparator(); 174 175 QSpinBox *pen_width(new QSpinBox(canvas_toolbar)); 176 pen_width->setToolTip(tr("Pen Width")); 177 pen_width->setRange(0, 80); 178 pen_width->setSingleStep(2); 179 pen_width->setValue(16); 180 connect(pen_width, SIGNAL(valueChanged(int)), SLOT(setCanvasPenWidth(int))); 181 canvas_toolbar->addWidget(pen_width); 182 canvas_toolbar->addAction(canvaspen); 183 canvas_toolbar->addAction(canvaseraser); 184 canvas_toolbar->addSeparator(); 185 186 QSpinBox *gradient(new QSpinBox(canvas_toolbar)); 187 gradient->setToolTip("Gradient Threshold"); 188 gradient->setRange(0, 255); 189 gradient->setValue(pimpl_->threshold_gradient_); 190 connect(gradient, SIGNAL(valueChanged(int)), SLOT(setGradientThreshold(int))); 191 192 QSpinBox *fixed(new QSpinBox(canvas_toolbar)); 193 fixed->setToolTip("Fixed Threshold"); 194 fixed->setRange(0, 255); 195 fixed->setValue(pimpl_->threshold_fixed_); 196 connect(fixed, SIGNAL(valueChanged(int)), SLOT(setFixedThreshold(int))); 197 198 canvas_toolbar->addWidget(gradient); 199 canvas_toolbar->addWidget(fixed); 200 canvas_toolbar->addSeparator(); 201 202 canvas_toolbar->addAction(canvasOK); 203 canvas_toolbar->addAction(canvasCancel); 204 205 layout->addWidget(canvas_toolbar); 206 layout->addWidget(pimpl_->render_area_); 207 layout->setSizeConstraint(QLayout::SetFixedSize); 208 209 connect(canvasloadmask, SIGNAL(activated()), SLOT(loadMask())); 210 connect(canvassavemask, SIGNAL(activated()), SLOT(saveMask())); 211 connect(canvasundo, SIGNAL(activated()), pimpl_->render_area_, SLOT(undo())); 212 connect(canvasredo, SIGNAL(activated()), pimpl_->render_area_, SLOT(redo())); 213 connect(canvasclear, SIGNAL(activated()), pimpl_->render_area_, SLOT(clear())); 214 connect(canvaspen, SIGNAL(activated()), SLOT(setCanvasPen())); 215 connect(canvaseraser, SIGNAL(activated()), SLOT(setCanvasEraser())); 216 217 connect(pimpl_->render_area_, SIGNAL(pointSelected(const QPoint &)), SLOT(automaticMask(const QPoint &))); 218 219 connect(canvasOK, SIGNAL(activated()), SLOT(accept())); 220 connect(canvasCancel, SIGNAL(activated()), SLOT(reject())); 221 } 222 setCanvasPenWidth(int width)223 void maskImageWidget::setCanvasPenWidth(int width) 224 { 225 QPen pen(pimpl_->render_area_->pen()); 226 pen.setWidth(width); 227 pimpl_->render_area_->setPen(pen); 228 } 229 230 setCanvasPen()231 void maskImageWidget::setCanvasPen() 232 { 233 QPen pen(pimpl_->render_area_->pen()); 234 pen.setColor(QColor(Qt::black)); 235 pen.setJoinStyle(Qt::RoundJoin); 236 pimpl_->render_area_->setPen(pen); 237 } 238 239 setCanvasEraser()240 void maskImageWidget::setCanvasEraser() 241 { 242 QPen pen(pimpl_->render_area_->pen()); 243 pen.setColor(QColor(Qt::transparent)); 244 pen.setJoinStyle(Qt::RoundJoin); 245 pimpl_->render_area_->setPen(pen); 246 } 247 248 setGradientThreshold(int threshold_gradient)249 void maskImageWidget::setGradientThreshold(int threshold_gradient) 250 { 251 pimpl_->threshold_gradient_ = threshold_gradient; 252 } 253 254 setFixedThreshold(int threshold_fixed)255 void maskImageWidget::setFixedThreshold(int threshold_fixed) 256 { 257 pimpl_->threshold_fixed_ = threshold_fixed; 258 } 259 loadMask()260 void maskImageWidget::loadMask() 261 { 262 try 263 { 264 QString filename(QFileDialog::getOpenFileName(this, QString("Open mask file"), QString(), QString("*.png"))); 265 if (QString::null != filename) 266 pimpl_->render_area_->load(filename); 267 } 268 catch (std::exception &e) 269 { 270 QMessageBox::warning(this, tr("Problem"), e.what()); 271 } 272 } 273 274 namespace 275 { check_extension(QString & filename,const QString & ext)276 bool check_extension(QString &filename, const QString &ext) 277 { 278 bool ret(false); 279 if (ext != filename.section('.', -1)) 280 { 281 int index(filename.lastIndexOf('.')); 282 if (-1 == index) 283 { 284 filename += '.'; 285 index += filename.size(); 286 } 287 filename.replace(index + 1, ext.size(), ext); 288 filename.resize(index + 1 + ext.size()); 289 ret = true; 290 } 291 return ret; 292 } 293 }; 294 saveMask()295 void maskImageWidget::saveMask() 296 { 297 try 298 { 299 QString filename(QFileDialog::getSaveFileName(this, QString("Save mask file"), QString(), QString("*.png"))); 300 if (QString::null != filename) 301 { 302 check_extension(filename, QString("png")); 303 pimpl_->render_area_->save(filename, pimpl_->realwidth_, pimpl_->realheight_); 304 } 305 } 306 catch (std::exception &e) 307 { 308 QMessageBox::warning(this, tr("Epoch 3D Webservice"), e.what()); 309 } 310 } 311 312 automaticMask(const QPoint & p)313 void maskImageWidget::automaticMask(const QPoint &p) 314 { 315 QImage image = (pimpl_->render_area_->palette().base().texture()).toImage(); 316 QImage out; 317 fillImage fi; 318 fi.Compute(image, p.x(), p.y(), pimpl_->threshold_gradient_, pimpl_->threshold_fixed_, out); 319 320 const size_t width(image.width()), height(image.height()); 321 QImage temp(pimpl_->render_area_->alphaMask()); 322 for (size_t i = 0; i < width; ++i) 323 { 324 for (size_t j = 0; j < height; ++j) 325 { 326 if (out.pixelIndex(i, j) > 0) 327 temp.setPixel(i, j, QColor(Qt::black).rgba()); 328 } 329 } 330 //temp.save("temp.jpg","jpg"); 331 pimpl_->render_area_->setAlphaMask(temp); 332 } 333 }; 334