saveSnapshot.cpp
Go to the documentation of this file.
00001 /****************************************************************************
00002 
00003  Copyright (C) 2002-2013 Gilles Debunne. All rights reserved.
00004 
00005  This file is part of the QGLViewer library version 2.4.0.
00006 
00007  http://www.libqglviewer.com - contact@libqglviewer.com
00008 
00009  This file may be used under the terms of the GNU General Public License 
00010  versions 2.0 or 3.0 as published by the Free Software Foundation and
00011  appearing in the LICENSE file included in the packaging of this file.
00012  In addition, as a special exception, Gilles Debunne gives you certain 
00013  additional rights, described in the file GPL_EXCEPTION in this package.
00014 
00015  libQGLViewer uses dual licensing. Commercial/proprietary software must
00016  purchase a libQGLViewer Commercial License.
00017 
00018  This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00019  WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00020 
00021 *****************************************************************************/
00022 
00023 #include "qglviewer.h"
00024 
00025 #ifndef NO_VECTORIAL_RENDER
00026 # if QT_VERSION >= 0x040000
00027 #  include "ui_VRenderInterface.h"
00028 # else
00029 #  include <qcheckbox.h>
00030 #  include <qcombobox.h>
00031 #  include "VRenderInterface.Qt3.h"
00032 # endif
00033 # include "VRender/VRender.h"
00034 #endif
00035 
00036 #if QT_VERSION >= 0x040000
00037 # include "ui_ImageInterface.h"
00038 #else
00039 # include <qspinbox.h>
00040 # include <qcheckbox.h>
00041 # include "ImageInterface.Qt3.h"
00042 #endif
00043 
00044 // Output format list
00045 #if QT_VERSION < 0x040000
00046 # include <qimage.h>
00047 #else
00048 # include <QImageWriter>
00049 #endif
00050 
00051 #include <qfileinfo.h>
00052 #include <qfiledialog.h>
00053 #include <qmessagebox.h>
00054 #include <qapplication.h>
00055 #include <qmap.h>
00056 #include <qinputdialog.h>
00057 #include <qprogressdialog.h>
00058 #include <qcursor.h>
00059 
00060 using namespace std;
00061 
00063 // List of available output file formats, formatted for QFileDialog.
00064 static QString formats;
00065 // Converts QFileDialog resulting format to Qt snapshotFormat.
00066 static QMap<QString, QString> Qtformat;
00067 // Converts Qt snapshotFormat to QFileDialog menu string.
00068 static QMap<QString, QString> FDFormatString;
00069 // Converts snapshotFormat to file extension
00070 static QMap<QString, QString> extension;
00071 
00072 
00074 void QGLViewer::setSnapshotFileName(const QString& name)
00075 {
00076 #if QT_VERSION >= 0x040000
00077   snapshotFileName_ = QFileInfo(name).absoluteFilePath();
00078 #else
00079   snapshotFileName_ = QFileInfo(name).absFilePath();
00080 #endif
00081 }
00082 
00083 #ifndef DOXYGEN
00084 const QString& QGLViewer::snapshotFilename() const
00085 {
00086   qWarning("snapshotFilename is deprecated. Use snapshotFileName() (uppercase N) instead.");
00087   return snapshotFileName();
00088 }
00089 #endif
00090 
00091 
00097 bool QGLViewer::openSnapshotFormatDialog()
00098 {
00099   bool ok = false;
00100 #if QT_VERSION >= 0x040000
00101   QStringList list = formats.split(";;", QString::SkipEmptyParts);
00102   int current = list.indexOf(FDFormatString[snapshotFormat()]);
00103   QString format = QInputDialog::getItem(this, "Snapshot format", "Select a snapshot format", list, current, false, &ok);
00104 #else
00105   QStringList list = QStringList::split(";;", formats);
00106   int current = list.findIndex(FDFormatString[snapshotFormat()]);
00107   QString format = QInputDialog::getItem("Snapshot format", "Select a snapshot format", list, current, false, &ok, this);
00108 #endif
00109   if (ok)
00110     setSnapshotFormat(Qtformat[format]);
00111   return ok;
00112 }
00113 
00114 
00115 // Finds all available Qt output formats, so that they can be available in
00116 // saveSnapshot dialog. Initialize snapshotFormat() to the first one.
00117 void QGLViewer::initializeSnapshotFormats()
00118 {
00119 #if QT_VERSION >= 0x040000
00120   QList<QByteArray> list = QImageWriter::supportedImageFormats();
00121   QStringList formatList;
00122   for (int i=0; i < list.size(); ++i)
00123     formatList << QString(list.at(i).toUpper());
00124 #else
00125   QStringList formatList = QImage::outputFormatList();
00126 #endif
00127   //        qWarning("Available image formats: ");
00128   //        QStringList::Iterator it = formatList.begin();
00129   //        while( it != formatList.end() )
00130   //          qWarning((*it++).);  QT4 change this. qWarning no longer accepts QString
00131 
00132 #ifndef NO_VECTORIAL_RENDER
00133   // We add the 3 vectorial formats to the list
00134   formatList += "EPS";
00135   formatList += "PS";
00136   formatList += "XFIG";
00137 #endif
00138 
00139   // Check that the interesting formats are available and add them in "formats"
00140   // Unused formats: XPM XBM PBM PGM
00141   QStringList QtText, MenuText, Ext;
00142   QtText += "JPEG";     MenuText += "JPEG (*.jpg)";             Ext += "jpg";
00143   QtText += "PNG";      MenuText += "PNG (*.png)";              Ext += "png";
00144   QtText += "EPS";      MenuText += "Encapsulated Postscript (*.eps)";  Ext += "eps";
00145   QtText += "PS";       MenuText += "Postscript (*.ps)";        Ext += "ps";
00146   QtText += "PPM";      MenuText += "24bit RGB Bitmap (*.ppm)"; Ext += "ppm";
00147   QtText += "BMP";      MenuText += "Windows Bitmap (*.bmp)";   Ext += "bmp";
00148   QtText += "XFIG";     MenuText += "XFig (*.fig)";             Ext += "fig";
00149 
00150 #if QT_VERSION < 0x030000
00151   QStringList::Iterator itText = QtText.begin();
00152   QStringList::Iterator itMenu = MenuText.begin();
00153   QStringList::Iterator itExt  = Ext.begin();
00154 #else
00155   QStringList::iterator itText = QtText.begin();
00156   QStringList::iterator itMenu = MenuText.begin();
00157   QStringList::iterator itExt  = Ext.begin();
00158 #endif
00159   while (itText != QtText.end())
00160     {
00161       //QMessageBox::information(this, "Snapshot ", "Trying format\n"+(*itText));
00162       if (formatList.contains((*itText)))
00163         {
00164           //QMessageBox::information(this, "Snapshot ", "Recognized format\n"+(*itText));
00165           if (formats.isEmpty())
00166             setSnapshotFormat(*itText);
00167           else
00168             formats += ";;";
00169           formats += (*itMenu);
00170           Qtformat[(*itMenu)]  = (*itText);
00171           FDFormatString[(*itText)]  = (*itMenu);
00172           extension[(*itText)] = (*itExt);
00173         }
00174       // Synchronize parsing
00175       itText++;
00176       itMenu++;
00177       itExt++;
00178     }
00179 }
00180 
00181 // Returns false if the user refused to use the fileName
00182 static bool checkFileName(QString& fileName, QWidget* widget, const QString& snapshotFormat)
00183 {
00184   if (fileName.isEmpty())
00185     return false;
00186 
00187   // Check that extension has been provided
00188   QFileInfo info(fileName);
00189 
00190 #if QT_VERSION >= 0x040000
00191   if (info.suffix().isEmpty())
00192 #else
00193   if (info.extension(false).isEmpty())
00194 #endif
00195     {
00196       // No extension given. Silently add one
00197       if (fileName.right(1) != ".")
00198         fileName += ".";
00199       fileName += extension[snapshotFormat];
00200       info.setFile(fileName);
00201     }
00202 #if QT_VERSION >= 0x040000
00203   else if (info.suffix() != extension[snapshotFormat])
00204 #else
00205   else if (info.extension(false) != extension[snapshotFormat])
00206 #endif
00207     {
00208       // Extension is not appropriate. Propose a modification
00209 #if QT_VERSION >= 0x040000
00210       QString modifiedName = info.absolutePath() + '/' + info.baseName() + "." + extension[snapshotFormat];
00211 #else
00212 # if QT_VERSION >= 0x030000
00213       QString modifiedName = info.dirPath() + '/' + info.baseName(true) + '.' + extension[snapshotFormat];
00214 # else
00215       QString modifiedName = info.dirPath() + '/' + info.baseName() + '.' + extension[snapshotFormat];
00216 # endif
00217 #endif
00218       QFileInfo modifInfo(modifiedName);
00219       int i=(QMessageBox::warning(widget,"Wrong extension",
00220                                   info.fileName()+" has a wrong extension.\nSave as "+modifInfo.fileName()+" instead ?",
00221                                   QMessageBox::Yes,
00222                                   QMessageBox::No,
00223                                   QMessageBox::Cancel));
00224       if (i==QMessageBox::Cancel)
00225         return false;
00226 
00227       if (i==QMessageBox::Yes)
00228         {
00229           fileName = modifiedName;
00230           info.setFile(fileName);
00231         }
00232     }
00233 
00234   return true;
00235 }
00236 
00237 #ifndef NO_VECTORIAL_RENDER
00238 // static void drawVectorial(void* param)
00239 void drawVectorial(void* param)
00240 {
00241   ( (QGLViewer*) param )->drawVectorial();
00242 }
00243 
00244 #ifndef DOXYGEN
00245 class ProgressDialog
00246 {
00247 public:
00248   static void showProgressDialog(QGLWidget* parent);
00249   static void updateProgress(float progress, const QString& stepString);
00250   static void hideProgressDialog();
00251 
00252 private:
00253   static QProgressDialog* progressDialog;
00254 };
00255 
00256 QProgressDialog* ProgressDialog::progressDialog = NULL;
00257 
00258 void ProgressDialog::showProgressDialog(QGLWidget* parent)
00259 {
00260   progressDialog = new QProgressDialog(parent);
00261 #if QT_VERSION >= 0x040000
00262   progressDialog->setWindowTitle("Image rendering progress");
00263 #else
00264   progressDialog->setCaption("Image rendering progress");
00265 #endif
00266   progressDialog->setMinimumSize(300, 40);
00267   progressDialog->setCancelButton(NULL);
00268   progressDialog->show();
00269 }
00270 
00271 void ProgressDialog::updateProgress(float progress, const QString& stepString)
00272 {
00273 #if QT_VERSION >= 0x040000
00274   progressDialog->setValue(int(progress*100));
00275 #else
00276   progressDialog->setProgress(int(progress*100));
00277 #endif
00278   QString message(stepString);
00279   if (message.length() > 33)
00280     message = message.left(17) + "..." + message.right(12);
00281   progressDialog->setLabelText(message);
00282   progressDialog->update();
00283   qApp->processEvents();
00284 }
00285 
00286 void ProgressDialog::hideProgressDialog()
00287 {
00288   progressDialog->close();
00289   delete progressDialog;
00290   progressDialog = NULL;
00291 }
00292 
00293 #if QT_VERSION >= 0x040000
00294 class VRenderInterface: public QDialog, public Ui::VRenderInterface
00295 {
00296  public: VRenderInterface(QWidget *parent) : QDialog(parent) { setupUi(this); }
00297 };
00298 #endif
00299 
00300 #endif
00301 
00302 // Pops-up a vectorial output option dialog box and save to fileName
00303 // Returns -1 in case of Cancel, 0 for success and (todo) error code in case of problem.
00304 static int saveVectorialSnapshot(const QString& fileName, QGLWidget* widget, const QString& snapshotFormat)
00305 {
00306   static VRenderInterface* VRinterface = NULL;
00307 
00308   if (!VRinterface)
00309 #if QT_VERSION >= 0x030000
00310     VRinterface = new VRenderInterface(widget);
00311 #else
00312     VRinterface = new VRenderInterface(widget, "", true); // Make the dialog modal
00313 #endif
00314 
00315   
00316   // Configure interface according to selected snapshotFormat
00317   if (snapshotFormat == "XFIG")
00318     {
00319       VRinterface->tightenBBox->setEnabled(false);
00320       VRinterface->colorBackground->setEnabled(false);
00321     }
00322   else
00323     {
00324       VRinterface->tightenBBox->setEnabled(true);
00325       VRinterface->colorBackground->setEnabled(true);
00326     }
00327 
00328   if (VRinterface->exec() == QDialog::Rejected)
00329     return -1;
00330 
00331   vrender::VRenderParams vparams;
00332   vparams.setFilename(fileName);
00333 
00334   if (snapshotFormat == "EPS")  vparams.setFormat(vrender::VRenderParams::EPS);
00335   if (snapshotFormat == "PS")   vparams.setFormat(vrender::VRenderParams::PS);
00336   if (snapshotFormat == "XFIG") vparams.setFormat(vrender::VRenderParams::XFIG);
00337 
00338   vparams.setOption(vrender::VRenderParams::CullHiddenFaces, !(VRinterface->includeHidden->isChecked()));
00339   vparams.setOption(vrender::VRenderParams::OptimizeBackFaceCulling, VRinterface->cullBackFaces->isChecked());
00340   vparams.setOption(vrender::VRenderParams::RenderBlackAndWhite, VRinterface->blackAndWhite->isChecked());
00341   vparams.setOption(vrender::VRenderParams::AddBackground, VRinterface->colorBackground->isChecked());
00342   vparams.setOption(vrender::VRenderParams::TightenBoundingBox, VRinterface->tightenBBox->isChecked());
00343 
00344 #if QT_VERSION >= 0x040000
00345   switch (VRinterface->sortMethod->currentIndex())
00346 #else
00347   switch (VRinterface->sortMethod->currentItem())
00348 #endif
00349     {
00350     case 0: vparams.setSortMethod(vrender::VRenderParams::NoSorting);           break;
00351     case 1: vparams.setSortMethod(vrender::VRenderParams::BSPSort);             break;
00352     case 2: vparams.setSortMethod(vrender::VRenderParams::TopologicalSort);     break;
00353     case 3: vparams.setSortMethod(vrender::VRenderParams::AdvancedTopologicalSort);     break;
00354     default:
00355       qWarning("VRenderInterface::saveVectorialSnapshot: Unknown SortMethod");
00356     }
00357 
00358   vparams.setProgressFunction(&ProgressDialog::updateProgress);
00359   ProgressDialog::showProgressDialog(widget);
00360   widget->makeCurrent();
00361   widget->raise();
00362   vrender::VectorialRender(drawVectorial, (void*) widget, vparams);
00363   ProgressDialog::hideProgressDialog();
00364 #if QT_VERSION < 0x030000
00365   widget->setCursor(Qt::arrowCursor);
00366 #else
00367   widget->setCursor(QCursor(Qt::ArrowCursor));
00368 #endif
00369 
00370   // Should return vparams.error(), but this is currently not set.
00371   return 0;
00372 }
00373 #endif // NO_VECTORIAL_RENDER
00374 
00375 
00376 #if QT_VERSION >= 0x040000
00377 class ImageInterface: public QDialog, public Ui::ImageInterface
00378 {
00379  public: ImageInterface(QWidget *parent) : QDialog(parent) { setupUi(this); }
00380 };
00381 #endif
00382 
00383 
00384 // Pops-up an image settings dialog box and save to fileName.
00385 // Returns false in case of problem.
00386 bool QGLViewer::saveImageSnapshot(const QString& fileName)
00387 {
00388   static ImageInterface* imageInterface = NULL;
00389 
00390   if (!imageInterface)
00391 #if QT_VERSION >= 0x030000
00392     imageInterface = new ImageInterface(this);
00393 #else
00394     imageInterface = new ImageInterface(this, "", true);  // Make the dialog modal
00395 #endif
00396 
00397   // 1 means never set : use current window size as default
00398   if ((imageInterface->imgWidth->value() == 1) && (imageInterface->imgHeight->value() == 1))
00399     {
00400       imageInterface->imgWidth->setValue(width());
00401       imageInterface->imgHeight->setValue(height());
00402     }
00403 
00404   imageInterface->imgQuality->setValue(snapshotQuality());
00405 
00406   if (imageInterface->exec() == QDialog::Rejected)
00407     return true;
00408 
00409   // Hide closed dialog
00410   qApp->processEvents();
00411   
00412   setSnapshotQuality(imageInterface->imgQuality->value());
00413   
00414   QColor previousBGColor = backgroundColor();
00415   if (imageInterface->whiteBackground->isChecked())
00416     setBackgroundColor(Qt::white);
00417 
00418   QSize finalSize(imageInterface->imgWidth->value(), imageInterface->imgHeight->value());
00419 
00420   double oversampling = imageInterface->oversampling->value();
00421   QSize subSize(int(this->width()/oversampling), int(this->height()/oversampling));
00422 
00423   double aspectRatio = width() / static_cast<double>(height());
00424   double newAspectRatio = finalSize.width() / static_cast<double>(finalSize.height());
00425 
00426   double zNear = camera()->zNear();
00427   double zFar = camera()->zFar();
00428 
00429   double xMin, yMin;
00430   bool expand = imageInterface->expandFrustum->isChecked();
00431   if (camera()->type() == qglviewer::Camera::PERSPECTIVE)
00432     if ((expand && (newAspectRatio>aspectRatio)) || (!expand && (newAspectRatio<aspectRatio)))
00433       {
00434         yMin = zNear * tan(camera()->fieldOfView() / 2.0);
00435         xMin = newAspectRatio * yMin;
00436       }
00437     else
00438       {
00439         xMin = zNear * tan(camera()->fieldOfView() / 2.0) * aspectRatio;
00440         yMin = xMin / newAspectRatio;
00441       }
00442   else
00443     {
00444       camera()->getOrthoWidthHeight(xMin, yMin);
00445       if ((expand && (newAspectRatio>aspectRatio)) || (!expand && (newAspectRatio<aspectRatio)))
00446         xMin = newAspectRatio * yMin;
00447       else
00448         yMin = xMin / newAspectRatio;
00449     }
00450   
00451 #if QT_VERSION >= 0x040000
00452   QImage image(finalSize.width(), finalSize.height(), QImage::Format_ARGB32);
00453 #else
00454   QImage image(finalSize.width(), finalSize.height(), 32);
00455 #endif
00456 
00457   if (image.isNull())
00458     {
00459       QMessageBox::warning(this, "Image saving error",
00460                            "Unable to create resulting image",
00461                            QMessageBox::Ok, QMessageBox::NoButton);
00462       return false;
00463     }
00464 
00465   // ProgressDialog disabled since it interfers with the screen grabing mecanism on some platforms. Too bad.
00466   // ProgressDialog::showProgressDialog(this);
00467 
00468   double scaleX = subSize.width() / static_cast<double>(finalSize.width());
00469   double scaleY = subSize.height() / static_cast<double>(finalSize.height());
00470 
00471   double deltaX = 2.0 * xMin * scaleX;
00472   double deltaY = 2.0 * yMin * scaleY;
00473 
00474   int nbX = finalSize.width() / subSize.width();
00475   int nbY = finalSize.height() / subSize.height();
00476 
00477   // Extra subimage on the right/bottom border(s) if needed
00478   if (nbX * subSize.width() < finalSize.width())
00479     nbX++;
00480   if (nbY * subSize.height() < finalSize.height())
00481     nbY++;
00482 
00483   makeCurrent();
00484 
00485   // tileRegion_ is used by startScreenCoordinatesSystem to appropriately set the local
00486   // coordinate system when tiling
00487   tileRegion_ = new TileRegion();
00488   double tileXMin, tileWidth, tileYMin, tileHeight;
00489   if ((expand && (newAspectRatio>aspectRatio)) || (!expand && (newAspectRatio<aspectRatio)))
00490     {
00491       double tileTotalWidth = newAspectRatio * height();
00492       tileXMin = (width() - tileTotalWidth) / 2.0;
00493       tileWidth = tileTotalWidth * scaleX;
00494       tileYMin = 0.0;
00495       tileHeight = height() * scaleY;
00496       tileRegion_->textScale = 1.0 / scaleY;
00497     }
00498   else
00499     {
00500       double tileTotalHeight = width() / newAspectRatio;
00501       tileYMin = (height() - tileTotalHeight) / 2.0;
00502       tileHeight = tileTotalHeight * scaleY;
00503       tileXMin = 0.0;
00504       tileWidth = width() * scaleX;
00505       tileRegion_->textScale = 1.0 / scaleX;
00506     }
00507 
00508   int count=0;
00509   for (int i=0; i<nbX; i++)
00510     for (int j=0; j<nbY; j++)
00511       {
00512         preDraw();
00513 
00514         // Change projection matrix
00515         glMatrixMode(GL_PROJECTION);
00516         glLoadIdentity();
00517         if (camera()->type() == qglviewer::Camera::PERSPECTIVE)
00518           glFrustum(-xMin + i*deltaX, -xMin + (i+1)*deltaX, yMin - (j+1)*deltaY, yMin - j*deltaY, zNear, zFar);
00519         else
00520           glOrtho(-xMin + i*deltaX, -xMin + (i+1)*deltaX, yMin - (j+1)*deltaY, yMin - j*deltaY, zNear, zFar);
00521         glMatrixMode(GL_MODELVIEW);
00522 
00523         tileRegion_->xMin = tileXMin + i * tileWidth;
00524         tileRegion_->xMax = tileXMin + (i+1) * tileWidth;
00525         tileRegion_->yMin = tileYMin + j * tileHeight;
00526         tileRegion_->yMax = tileYMin + (j+1) * tileHeight;
00527 
00528         draw();
00529         postDraw();
00530 
00531         // ProgressDialog::hideProgressDialog();
00532         // qApp->processEvents();
00533 
00534         QImage snapshot = grabFrameBuffer(true);
00535 
00536         // ProgressDialog::showProgressDialog(this);
00537         // ProgressDialog::updateProgress(count / (float)(nbX*nbY),
00538         // "Generating image ["+QString::number(count)+"/"+QString::number(nbX*nbY)+"]");
00539         // qApp->processEvents();
00540 
00541 #if QT_VERSION >= 0x040000
00542         QImage subImage = snapshot.scaled(subSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
00543 #else
00544 # if QT_VERSION >= 0x030000
00545         QImage subImage = snapshot.scale(subSize, QImage::ScaleFree);
00546 # else
00547         QImage subImage = snapshot.smoothScale(subSize.width(), subSize.height());
00548 # endif
00549 #endif
00550 
00551         // Copy subImage in image
00552         for (int ii=0; ii<subSize.width(); ii++)
00553           {
00554             int fi = i*subSize.width() + ii;
00555             if (fi == image.width())
00556               break;
00557             for (int jj=0; jj<subSize.height(); jj++)
00558               {
00559                 int fj = j*subSize.height() + jj;
00560                 if (fj == image.height())
00561                   break;
00562                 image.setPixel(fi, fj, subImage.pixel(ii,jj));
00563               }
00564           }
00565         count++;
00566       }
00567   
00568 #if QT_VERSION >= 0x040000
00569   bool saveOK = image.save(fileName, snapshotFormat().toLatin1().constData(), snapshotQuality());
00570 #else
00571   bool saveOK = image.save(fileName, snapshotFormat(), snapshotQuality());
00572 #endif
00573 
00574   // ProgressDialog::hideProgressDialog();
00575 
00576   // #if QT_VERSION < 0x030000
00577   // setCursor(Qt::arrowCursor);
00578   // #else
00579   // setCursor(QCursor(Qt::ArrowCursor));
00580   // #endif
00581 
00582   delete tileRegion_;
00583   tileRegion_ = NULL;
00584 
00585   if (imageInterface->whiteBackground->isChecked())
00586     setBackgroundColor(previousBGColor);
00587 
00588   return saveOK;
00589 }
00590 
00591 
00641 void QGLViewer::saveSnapshot(bool automatic, bool overwrite)
00642 {
00643   // Ask for file name
00644   if (snapshotFileName().isEmpty() || !automatic)
00645     {
00646       QString fileName;
00647 #if QT_VERSION < 0x030000
00648       if (openSnapshotFormatDialog())
00649         fileName = QFileDialog::getSaveFileName(snapshotFileName(), FDFormatString[snapshotFormat()]+";;All files (*.*)", this, "Save dialog");
00650       else
00651         return;
00652 #else
00653       QString selectedFormat = FDFormatString[snapshotFormat()];
00654 # if QT_VERSION >= 0x040000
00655       fileName = QFileDialog::getSaveFileName(this, "Choose a file name to save under", snapshotFileName(), formats, &selectedFormat,
00656                                               overwrite?QFileDialog::DontConfirmOverwrite:QFlag(0));
00657 # else
00658       fileName = QFileDialog::getSaveFileName(snapshotFileName(), formats, this,
00659                                               "Save Snapshot dialog", "Choose a file name to save under", &selectedFormat);
00660 # endif
00661       setSnapshotFormat(Qtformat[selectedFormat]);
00662 #endif
00663 
00664       if (checkFileName(fileName, this, snapshotFormat()))
00665         setSnapshotFileName(fileName);
00666       else
00667         return;
00668     }
00669 
00670   QFileInfo fileInfo(snapshotFileName());
00671 
00672   if ((automatic) && (snapshotCounter() >= 0))
00673     {
00674       // In automatic mode, names have a number appended
00675       const QString baseName = fileInfo.baseName();
00676       QString count;
00677       count.sprintf("%.04d", snapshotCounter_++);
00678       QString suffix;
00679 #if QT_VERSION >= 0x040000
00680       suffix = fileInfo.suffix();
00681       if (suffix.isEmpty())
00682         suffix = extension[snapshotFormat()];
00683       fileInfo.setFile(fileInfo.absolutePath()+ '/' + baseName + '-' + count + '.' + suffix);
00684 #else      
00685       suffix = fileInfo.extension();
00686       if (suffix.isEmpty())
00687         suffix = extension[snapshotFormat()];
00688       fileInfo.setFile(fileInfo.dirPath()+ '/' + baseName + '-' + count + '.' + suffix);
00689 #endif
00690 
00691       if (!overwrite)
00692         while (fileInfo.exists())
00693           {
00694             count.sprintf("%.04d", snapshotCounter_++);
00695 #if QT_VERSION >= 0x040000
00696             fileInfo.setFile(fileInfo.absolutePath() + '/' +baseName + '-' + count + '.' + fileInfo.suffix());
00697 #else
00698             fileInfo.setFile(fileInfo.dirPath() + '/' + baseName + '-' + count + '.' + fileInfo.extension());
00699 #endif
00700           }
00701     }
00702 
00703 #if QT_VERSION < 0x040000
00704   if ((fileInfo.exists()) && (!overwrite) &&
00705       (QMessageBox::warning(this,"Overwrite file ?",
00706                             "File "+fileInfo.fileName()+" already exists.\nOverwrite ?",
00707                             QMessageBox::Yes,
00708                             QMessageBox::Cancel) == QMessageBox::Cancel))
00709       return;
00710 #endif
00711   
00712   bool saveOK;
00713 #ifndef NO_VECTORIAL_RENDER
00714   if ( (snapshotFormat() == "EPS") || (snapshotFormat() == "PS") || (snapshotFormat() == "XFIG") )
00715       // Vectorial snapshot. -1 means cancel, 0 is ok, >0 (should be) an error
00716       saveOK = (saveVectorialSnapshot(fileInfo.filePath(), this, snapshotFormat()) <= 0);
00717   else
00718 #endif
00719     if (automatic)
00720         {
00721       QImage snapshot = frameBufferSnapshot();
00722 #if QT_VERSION >= 0x040000
00723     saveOK = snapshot.save(fileInfo.filePath(), snapshotFormat().toLatin1().constData(), snapshotQuality());
00724 #else
00725     saveOK = snapshot.save(fileInfo.filePath(), snapshotFormat(), snapshotQuality());
00726 #endif
00727         }
00728         else
00729           saveOK = saveImageSnapshot(fileInfo.filePath());
00730 
00731   if (!saveOK)
00732     QMessageBox::warning(this, "Snapshot problem", "Unable to save snapshot in\n"+fileInfo.filePath());
00733 }
00734 
00735 QImage QGLViewer::frameBufferSnapshot()
00736 {
00737       // Viewer must be on top of other windows.
00738       makeCurrent();
00739       raise();
00740       // Hack: Qt has problems if the frame buffer is grabbed after QFileDialog is displayed.
00741       // We grab the frame buffer before, even if it might be not necessary (vectorial rendering).
00742       // The problem could not be reproduced on a simple example to submit a Qt bug.
00743       // However, only grabs the backgroundImage in the eponym example. May come from the driver.
00744       return grabFrameBuffer(true);
00745 }
00746 
00758 void QGLViewer::saveSnapshot(const QString& fileName, bool overwrite)
00759 {
00760   const QString previousName = snapshotFileName();
00761   const int previousCounter = snapshotCounter();
00762   setSnapshotFileName(fileName);
00763   setSnapshotCounter(-1);
00764   saveSnapshot(true, overwrite);
00765   setSnapshotFileName(previousName);
00766   setSnapshotCounter(previousCounter);
00767 }
00768 
00773 void QGLViewer::snapshotToClipboard()
00774 {
00775         QClipboard *cb = QApplication::clipboard();
00776         cb->setImage(frameBufferSnapshot()); 
00777 }
00778 
00779 #if QT_VERSION < 0x030000
00780 // This code is largely inspired from Qt's method available in version 3
00781 // Copyright Trolltech AS
00782 QImage QGLViewer::grabFrameBuffer(bool withAlpha)
00783 {
00784   makeCurrent();
00785   QImage res;
00786   int w = width();
00787   int h = height();
00788   if (format().rgba())
00789   {
00790         res = QImage(w, h, 32);
00791         glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, res.bits());
00792         if (QImage::systemByteOrder() == QImage::BigEndian)
00793         {
00794           // OpenGL gives RGBA; Qt wants ARGB
00795           uint *p = (uint*)res.bits();
00796           uint *end = p + w*h;
00797           if (withAlpha && format().alpha())
00798           {
00799                 while (p < end)
00800                 {
00801                   uint a = *p << 24;
00802                   *p = (*p >> 8) | a;
00803                   p++;
00804                 }
00805           }
00806           else
00807           {
00808                 while (p < end)
00809                   *p++ >>= 8;
00810           }
00811         }
00812         else
00813         {
00814           // OpenGL gives ABGR (i.e. RGBA backwards); Qt wants ARGB
00815           res = res.swapRGB();
00816         }
00817         res.setAlphaBuffer(withAlpha && format().alpha());
00818   }
00819   else
00820   {
00821 #if defined (Q_OS_WIN) || defined (Q_WS_WIN)
00822         res = QImage(w, h, 8);
00823         glReadPixels(0, 0, w, h, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, res.bits());
00824         //int palSize = 0;
00825         //const QRgb* pal = QColor::palette(&palSize);
00826         //if (pal && palSize)
00827         //{
00828         //  res.setNumColors(palSize);
00829         //  for (int i = 0; i < palSize; i++)
00830         //      res.setColor(i, pal[i]);
00831         //}
00832 #endif
00833   }
00834 
00835   return res.mirror();
00836 }
00837 
00838 #endif // QT_VERSION < 0x030000


octovis
Author(s): Kai M. Wurm , Armin Hornung
autogenerated on Thu Feb 11 2016 23:51:20