23 #include "qglviewer.h"
25 #ifndef NO_VECTORIAL_RENDER
26 # include "ui_VRenderInterface.h"
27 # include "VRender/VRender.h"
30 #include "ui_ImageInterface.h"
33 # include <QImageWriter>
35 #include <qfileinfo.h>
36 #include <qfiledialog.h>
37 #include <qmessagebox.h>
38 #include <qapplication.h>
40 #include <qinputdialog.h>
41 #include <qprogressdialog.h>
48 static QString formats;
50 static QMap<QString, QString> Qtformat;
52 static QMap<QString, QString> FDFormatString;
54 static QMap<QString, QString> extension;
60 snapshotFileName_ = QFileInfo(name).absoluteFilePath();
64 const QString& QGLViewer::snapshotFilename()
const
66 qWarning(
"snapshotFilename is deprecated. Use snapshotFileName() (uppercase N) instead.");
67 return snapshotFileName();
80 QStringList list = formats.split(
";;", QString::SkipEmptyParts);
81 int current = list.indexOf(FDFormatString[snapshotFormat()]);
82 QString format = QInputDialog::getItem(
this,
"Snapshot format",
"Select a snapshot format", list, current,
false, &ok);
84 setSnapshotFormat(Qtformat[format]);
91 void QGLViewer::initializeSnapshotFormats()
93 QList<QByteArray> list = QImageWriter::supportedImageFormats();
94 QStringList formatList;
95 for (
int i=0; i < list.size(); ++i)
96 formatList << QString(list.at(i).toUpper());
102 #ifndef NO_VECTORIAL_RENDER
106 formatList +=
"XFIG";
111 QStringList QtText, MenuText, Ext;
112 QtText +=
"JPEG"; MenuText +=
"JPEG (*.jpg)"; Ext +=
"jpg";
113 QtText +=
"PNG"; MenuText +=
"PNG (*.png)"; Ext +=
"png";
114 QtText +=
"EPS"; MenuText +=
"Encapsulated Postscript (*.eps)"; Ext +=
"eps";
115 QtText +=
"PS"; MenuText +=
"Postscript (*.ps)"; Ext +=
"ps";
116 QtText +=
"PPM"; MenuText +=
"24bit RGB Bitmap (*.ppm)"; Ext +=
"ppm";
117 QtText +=
"BMP"; MenuText +=
"Windows Bitmap (*.bmp)"; Ext +=
"bmp";
118 QtText +=
"XFIG"; MenuText +=
"XFig (*.fig)"; Ext +=
"fig";
120 QStringList::iterator itText = QtText.begin();
121 QStringList::iterator itMenu = MenuText.begin();
122 QStringList::iterator itExt = Ext.begin();
124 while (itText != QtText.end())
127 if (formatList.contains((*itText)))
130 if (formats.isEmpty())
131 setSnapshotFormat(*itText);
134 formats += (*itMenu);
135 Qtformat[(*itMenu)] = (*itText);
136 FDFormatString[(*itText)] = (*itMenu);
137 extension[(*itText)] = (*itExt);
147 static bool checkFileName(QString& fileName, QWidget* widget,
const QString& snapshotFormat)
149 if (fileName.isEmpty())
153 QFileInfo info(fileName);
155 if (info.suffix().isEmpty())
158 if (fileName.right(1) !=
".")
160 fileName += extension[snapshotFormat];
161 info.setFile(fileName);
163 else if (info.suffix() != extension[snapshotFormat])
166 QString modifiedName = info.absolutePath() +
'/' + info.baseName() +
"." + extension[snapshotFormat];
167 QFileInfo modifInfo(modifiedName);
168 int i=(QMessageBox::warning(widget,
"Wrong extension",
169 info.fileName()+
" has a wrong extension.\nSave as "+modifInfo.fileName()+
" instead ?",
172 QMessageBox::Cancel));
173 if (i==QMessageBox::Cancel)
176 if (i==QMessageBox::Yes)
178 fileName = modifiedName;
179 info.setFile(fileName);
186 #ifndef NO_VECTORIAL_RENDER
188 void drawVectorial(
void* param)
197 static void showProgressDialog(QGLWidget* parent);
198 static void updateProgress(
float progress,
const QString& stepString);
199 static void hideProgressDialog();
202 static QProgressDialog* progressDialog;
205 QProgressDialog* ProgressDialog::progressDialog = NULL;
207 void ProgressDialog::showProgressDialog(QGLWidget* parent)
209 progressDialog =
new QProgressDialog(parent);
210 progressDialog->setWindowTitle(
"Image rendering progress");
211 progressDialog->setMinimumSize(300, 40);
212 progressDialog->setCancelButton(NULL);
213 progressDialog->show();
216 void ProgressDialog::updateProgress(
float progress,
const QString& stepString)
218 progressDialog->setValue(
int(progress*100));
219 QString message(stepString);
220 if (message.length() > 33)
221 message = message.left(17) +
"..." + message.right(12);
222 progressDialog->setLabelText(message);
223 progressDialog->update();
224 qApp->processEvents();
227 void ProgressDialog::hideProgressDialog()
229 progressDialog->close();
230 delete progressDialog;
231 progressDialog = NULL;
234 class VRenderInterface:
public QDialog,
public Ui::VRenderInterface
236 public: VRenderInterface(QWidget *parent) : QDialog(parent) { setupUi(
this); }
243 static int saveVectorialSnapshot(
const QString& fileName, QGLWidget* widget,
const QString& snapshotFormat)
245 static VRenderInterface* VRinterface = NULL;
248 VRinterface =
new VRenderInterface(widget);
252 if (snapshotFormat ==
"XFIG")
254 VRinterface->tightenBBox->setEnabled(
false);
255 VRinterface->colorBackground->setEnabled(
false);
259 VRinterface->tightenBBox->setEnabled(
true);
260 VRinterface->colorBackground->setEnabled(
true);
263 if (VRinterface->exec() == QDialog::Rejected)
267 vparams.setFilename(fileName);
269 if (snapshotFormat ==
"EPS") vparams.setFormat(vrender::VRenderParams::EPS);
270 if (snapshotFormat ==
"PS") vparams.setFormat(vrender::VRenderParams::PS);
271 if (snapshotFormat ==
"XFIG") vparams.setFormat(vrender::VRenderParams::XFIG);
273 vparams.setOption(vrender::VRenderParams::CullHiddenFaces, !(VRinterface->includeHidden->isChecked()));
274 vparams.setOption(vrender::VRenderParams::OptimizeBackFaceCulling, VRinterface->cullBackFaces->isChecked());
275 vparams.setOption(vrender::VRenderParams::RenderBlackAndWhite, VRinterface->blackAndWhite->isChecked());
276 vparams.setOption(vrender::VRenderParams::AddBackground, VRinterface->colorBackground->isChecked());
277 vparams.setOption(vrender::VRenderParams::TightenBoundingBox, VRinterface->tightenBBox->isChecked());
279 switch (VRinterface->sortMethod->currentIndex())
281 case 0: vparams.setSortMethod(vrender::VRenderParams::NoSorting);
break;
282 case 1: vparams.setSortMethod(vrender::VRenderParams::BSPSort);
break;
283 case 2: vparams.setSortMethod(vrender::VRenderParams::TopologicalSort);
break;
284 case 3: vparams.setSortMethod(vrender::VRenderParams::AdvancedTopologicalSort);
break;
286 qWarning(
"VRenderInterface::saveVectorialSnapshot: Unknown SortMethod");
289 vparams.setProgressFunction(&ProgressDialog::updateProgress);
290 ProgressDialog::showProgressDialog(widget);
291 widget->makeCurrent();
293 vrender::VectorialRender(drawVectorial, (
void*) widget, vparams);
294 ProgressDialog::hideProgressDialog();
295 widget->setCursor(QCursor(Qt::ArrowCursor));
300 #endif // NO_VECTORIAL_RENDER
303 class ImageInterface:
public QDialog,
public Ui::ImageInterface
305 public: ImageInterface(QWidget *parent) : QDialog(parent) { setupUi(
this); }
311 bool QGLViewer::saveImageSnapshot(
const QString& fileName)
313 static ImageInterface* imageInterface = NULL;
316 imageInterface =
new ImageInterface(
this);
318 imageInterface->imgWidth->setValue(width());
319 imageInterface->imgHeight->setValue(height());
321 imageInterface->imgQuality->setValue(snapshotQuality());
323 if (imageInterface->exec() == QDialog::Rejected)
327 qApp->processEvents();
329 setSnapshotQuality(imageInterface->imgQuality->value());
331 QColor previousBGColor = backgroundColor();
332 if (imageInterface->whiteBackground->isChecked())
333 setBackgroundColor(Qt::white);
335 QSize finalSize(imageInterface->imgWidth->value(), imageInterface->imgHeight->value());
337 double oversampling = imageInterface->oversampling->value();
338 QSize subSize(
int(this->width()/oversampling),
int(this->height()/oversampling));
340 double aspectRatio = width() /
static_cast<double>(height());
341 double newAspectRatio = finalSize.width() /
static_cast<double>(finalSize.height());
343 double zNear = camera()->zNear();
344 double zFar = camera()->zFar();
347 bool expand = imageInterface->expandFrustum->isChecked();
348 if (camera()->type() == qglviewer::Camera::PERSPECTIVE)
349 if ((expand && (newAspectRatio>aspectRatio)) || (!expand && (newAspectRatio<aspectRatio)))
351 yMin = zNear * tan(camera()->fieldOfView() / 2.0);
352 xMin = newAspectRatio * yMin;
356 xMin = zNear * tan(camera()->fieldOfView() / 2.0) * aspectRatio;
357 yMin = xMin / newAspectRatio;
361 camera()->getOrthoWidthHeight(xMin, yMin);
362 if ((expand && (newAspectRatio>aspectRatio)) || (!expand && (newAspectRatio<aspectRatio)))
363 xMin = newAspectRatio * yMin;
365 yMin = xMin / newAspectRatio;
368 QImage image(finalSize.width(), finalSize.height(), QImage::Format_ARGB32);
372 QMessageBox::warning(
this,
"Image saving error",
373 "Unable to create resulting image",
374 QMessageBox::Ok, QMessageBox::NoButton);
381 double scaleX = subSize.width() /
static_cast<double>(finalSize.width());
382 double scaleY = subSize.height() /
static_cast<double>(finalSize.height());
384 double deltaX = 2.0 * xMin * scaleX;
385 double deltaY = 2.0 * yMin * scaleY;
387 int nbX = finalSize.width() / subSize.width();
388 int nbY = finalSize.height() / subSize.height();
391 if (nbX * subSize.width() < finalSize.width())
393 if (nbY * subSize.height() < finalSize.height())
400 tileRegion_ =
new TileRegion();
401 double tileXMin, tileWidth, tileYMin, tileHeight;
402 if ((expand && (newAspectRatio>aspectRatio)) || (!expand && (newAspectRatio<aspectRatio)))
404 double tileTotalWidth = newAspectRatio * height();
405 tileXMin = (width() - tileTotalWidth) / 2.0;
406 tileWidth = tileTotalWidth * scaleX;
408 tileHeight = height() * scaleY;
409 tileRegion_->textScale = 1.0 / scaleY;
413 double tileTotalHeight = width() / newAspectRatio;
414 tileYMin = (height() - tileTotalHeight) / 2.0;
415 tileHeight = tileTotalHeight * scaleY;
417 tileWidth = width() * scaleX;
418 tileRegion_->textScale = 1.0 / scaleX;
422 for (
int i=0; i<nbX; i++)
423 for (
int j=0; j<nbY; j++)
428 glMatrixMode(GL_PROJECTION);
430 if (camera()->type() == qglviewer::Camera::PERSPECTIVE)
431 glFrustum(-xMin + i*deltaX, -xMin + (i+1)*deltaX, yMin - (j+1)*deltaY, yMin - j*deltaY, zNear, zFar);
433 glOrtho(-xMin + i*deltaX, -xMin + (i+1)*deltaX, yMin - (j+1)*deltaY, yMin - j*deltaY, zNear, zFar);
434 glMatrixMode(GL_MODELVIEW);
436 tileRegion_->xMin = tileXMin + i * tileWidth;
437 tileRegion_->xMax = tileXMin + (i+1) * tileWidth;
438 tileRegion_->yMin = tileYMin + j * tileHeight;
439 tileRegion_->yMax = tileYMin + (j+1) * tileHeight;
447 QImage snapshot = grabFrameBuffer(
true);
454 QImage subImage = snapshot.scaled(subSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
457 for (
int ii=0; ii<subSize.width(); ii++)
459 int fi = i*subSize.width() + ii;
460 if (fi == image.width())
462 for (
int jj=0; jj<subSize.height(); jj++)
464 int fj = j*subSize.height() + jj;
465 if (fj == image.height())
467 image.setPixel(fi, fj, subImage.pixel(ii,jj));
473 bool saveOK = image.save(fileName, snapshotFormat().toLatin1().constData(), snapshotQuality());
481 if (imageInterface->whiteBackground->isChecked())
482 setBackgroundColor(previousBGColor);
540 if (snapshotFileName().isEmpty() || !automatic)
543 QString selectedFormat = FDFormatString[snapshotFormat()];
544 fileName = QFileDialog::getSaveFileName(
this,
"Choose a file name to save under", snapshotFileName(), formats, &selectedFormat,
545 overwrite?QFileDialog::DontConfirmOverwrite:QFileDialog::Options(0));
546 setSnapshotFormat(Qtformat[selectedFormat]);
548 if (checkFileName(fileName,
this, snapshotFormat()))
549 setSnapshotFileName(fileName);
554 QFileInfo fileInfo(snapshotFileName());
556 if ((automatic) && (snapshotCounter() >= 0))
559 const QString baseName = fileInfo.baseName();
561 count.sprintf(
"%.04d", snapshotCounter_++);
563 suffix = fileInfo.suffix();
564 if (suffix.isEmpty())
565 suffix = extension[snapshotFormat()];
566 fileInfo.setFile(fileInfo.absolutePath()+
'/' + baseName +
'-' + count +
'.' + suffix);
569 while (fileInfo.exists())
571 count.sprintf(
"%.04d", snapshotCounter_++);
572 fileInfo.setFile(fileInfo.absolutePath() +
'/' +baseName +
'-' + count +
'.' + fileInfo.suffix());
577 #ifndef NO_VECTORIAL_RENDER
578 if ( (snapshotFormat() ==
"EPS") || (snapshotFormat() ==
"PS") || (snapshotFormat() ==
"XFIG") )
580 saveOK = (saveVectorialSnapshot(fileInfo.filePath(),
this, snapshotFormat()) <= 0);
585 QImage snapshot = frameBufferSnapshot();
586 saveOK = snapshot.save(fileInfo.filePath(), snapshotFormat().toLatin1().constData(), snapshotQuality());
589 saveOK = saveImageSnapshot(fileInfo.filePath());
592 QMessageBox::warning(
this,
"Snapshot problem",
"Unable to save snapshot in\n"+fileInfo.filePath());
595 QImage QGLViewer::frameBufferSnapshot()
604 return grabFrameBuffer(
true);
620 const QString previousName = snapshotFileName();
621 const int previousCounter = snapshotCounter();
622 setSnapshotFileName(fileName);
623 setSnapshotCounter(-1);
624 saveSnapshot(
true, overwrite);
625 setSnapshotFileName(previousName);
626 setSnapshotCounter(previousCounter);
635 QClipboard *cb = QApplication::clipboard();
636 cb->setImage(frameBufferSnapshot());
bool openSnapshotFormatDialog()
Opens a dialog that displays the different available snapshot formats.
void saveSnapshot(bool automatic=true, bool overwrite=false)
Saves a snapshot of the current image displayed by the widget.
void setSnapshotFileName(const QString &name)
Sets snapshotFileName().
A versatile 3D OpenGL viewer based on QGLWidget.
void snapshotToClipboard()
Takes a snapshot of the current display and pastes it to the clipboard.