SoFCOffscreenRenderer.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (c) 2005 Werner Mayer <wmayer[at]users.sourceforge.net>     *
00003  *                                                                         *
00004  *   This file is part of the FreeCAD CAx development system.              *
00005  *                                                                         *
00006  *   This library is free software; you can redistribute it and/or         *
00007  *   modify it under the terms of the GNU Library General Public           *
00008  *   License as published by the Free Software Foundation; either          *
00009  *   version 2 of the License, or (at your option) any later version.      *
00010  *                                                                         *
00011  *   This library  is distributed in the hope that it will be useful,      *
00012  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00013  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00014  *   GNU Library General Public License for more details.                  *
00015  *                                                                         *
00016  *   You should have received a copy of the GNU Library General Public     *
00017  *   License along with this library; see the file COPYING.LIB. If not,    *
00018  *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
00019  *   Suite 330, Boston, MA  02111-1307, USA                                *
00020  *                                                                         *
00021  ***************************************************************************/
00022 
00023 #include "PreCompiled.h"
00024 #ifndef _PreComp_
00025 # include <Inventor/fields/SoSFImage.h>
00026 # include <QBuffer>
00027 # include <QDateTime>
00028 # include <QFile>
00029 # include <QImageWriter>
00030 #endif
00031 
00032 //gcc
00033 # include <iomanip>
00034 # include <ios>
00035 # include <sstream>
00036 
00037 #include <Base/FileInfo.h>
00038 #include <Base/Exception.h>
00039 #include <Base/Console.h>
00040 #include <App/Application.h>
00041 
00042 #include "SoFCOffscreenRenderer.h"
00043 #include "BitmapFactory.h"
00044 
00045 using namespace Gui;
00046 using namespace std;
00047 
00048 
00049 void writeJPEGComment(const std::string&, QByteArray&);
00050 
00051 // ---------------------------------------------------------------
00052 
00053 SoFCOffscreenRenderer* SoFCOffscreenRenderer::inst = 0;
00054 
00055 
00056 SoFCOffscreenRenderer& SoFCOffscreenRenderer::instance()
00057 {
00058     if (inst==0)
00059         inst = new SoFCOffscreenRenderer(SbViewportRegion());
00060     return *inst;
00061 }
00062 
00063 SoFCOffscreenRenderer::SoFCOffscreenRenderer (const SbViewportRegion &viewportregion)
00064   : SoOffscreenRenderer(viewportregion)
00065 {
00066 }
00067 
00068 SoFCOffscreenRenderer::SoFCOffscreenRenderer (SoGLRenderAction *action)
00069   : SoOffscreenRenderer(action)
00070 {
00071 }
00072 
00073 SoFCOffscreenRenderer::~SoFCOffscreenRenderer()
00074 {
00075 }
00076 
00077 void SoFCOffscreenRenderer::writeToImage (QImage& img) const
00078 {
00079     const unsigned char * bytes = getBuffer();
00080     SbVec2s size = getViewportRegion().getViewportSizePixels();
00081     int numcomponents = (int) this->getComponents();
00082 
00083     SoSFImage image;
00084     image.setValue(size, numcomponents, bytes, SoSFImage::NO_COPY);
00085     BitmapFactory().convert(image, img);
00086 }
00087 
00088 void SoFCOffscreenRenderer::writeToImageFile (const char *filename, const char* comment) const
00089 {
00090     Base::FileInfo file(filename);
00091     if (file.hasExtension("JPG") || file.hasExtension("JPEG")) {
00092         QImage img;
00093         writeToImage(img);
00094 
00095         // writing comment in case of jpeg (Qt ignores setText() in case of jpeg)
00096         std::string com;
00097         if (strcmp(comment,"")==0)
00098             com = "Screenshot created by FreeCAD";
00099         else if (strcmp(comment,"$MIBA")==0)
00100             com = createMIBA();
00101         else
00102             com = comment;
00103 
00104         // write into memory
00105         QByteArray ba;
00106         QBuffer buffer(&ba);
00107         buffer.open(QIODevice::WriteOnly);
00108         img.save(&buffer, "JPG");
00109         writeJPEGComment(com, ba);
00110 
00111         QFile file(QString::fromUtf8(filename));
00112         if (file.open(QFile::WriteOnly)) {
00113             file.write(ba);
00114             file.close();
00115         }
00116         else {
00117             std::stringstream str;
00118             str << "Cannot open file '" << filename << "' for writing.";
00119             throw Base::Exception(str.str());
00120         }
00121     }
00122     else {
00123         // check for all QImage formats
00124         bool supported = false;
00125         QByteArray format;
00126         QList<QByteArray> qtformats = QImageWriter::supportedImageFormats();
00127         for (QList<QByteArray>::Iterator it = qtformats.begin(); it != qtformats.end(); ++it) {
00128             if (file.hasExtension((*it).data())) {
00129                 format = *it;
00130                 supported = true;
00131                 break;
00132             }
00133         }
00134 
00135         // Supported by Qt
00136         if (supported) {
00137             QImage img;
00138             writeToImage(img);
00139             // set keywords for PNG format
00140             if (file.hasExtension("PNG")) {
00141                 img.setText(QLatin1String("Title"), QString::fromUtf8(filename));
00142                 img.setText(QLatin1String("Author"), QLatin1String("FreeCAD (http://free-cad.sourceforge.net)"));
00143                 if (strcmp(comment,"")==0)
00144                     img.setText(QLatin1String("Description"), QLatin1String("Screenshot created by FreeCAD"));
00145                 else if (strcmp(comment,"$MIBA")==0)
00146                     img.setText(QLatin1String("Description"), QLatin1String(createMIBA().c_str()));
00147                 else 
00148                     img.setText(QLatin1String("Description"), QString::fromUtf8(comment));
00149                 img.setText(QLatin1String("Creation Time"), QDateTime::currentDateTime().toString());
00150                 img.setText(QLatin1String("Software"), 
00151                     QString::fromUtf8(App::GetApplication().getExecutableName()));
00152             }
00153 
00154             QFile f(QString::fromUtf8(filename));
00155             if (f.open(QFile::WriteOnly)) {
00156                 if (img.save(&f, format.data())) {
00157                     f.close();
00158                 }
00159                 else {
00160                     f.close();
00161                     std::stringstream str;
00162                     str << "Cannot save image to file '" << filename << "'.";
00163                     throw Base::Exception(str.str());
00164                 }
00165             }
00166             else {
00167                 std::stringstream str;
00168                 str << "Cannot open file '" << filename << "' for writing.";
00169                 throw Base::Exception(str.str());
00170             }
00171         }
00172         else if (isWriteSupported(file.extension().c_str())) {
00173             // Any format which is supported by Coin only
00174             if (!writeToFile(filename, file.extension().c_str()))
00175                 throw Base::FileException("Error writing image file", filename);
00176         }
00177         else if (file.hasExtension("EPS") || file.hasExtension("PS")) {
00178             // Any format which is supported by Coin only
00179 #ifdef FC_OS_WIN32
00180             FILE* fd = _wfopen(file.toStdWString().c_str(), L"w");
00181 #else
00182             FILE* fd = fopen(filename, "w");
00183 #endif
00184             bool ok = writeToPostScript(fd);
00185             fclose(fd);
00186             if (!ok)
00187                 throw Base::FileException("Error writing image file", filename);
00188         }
00189         else if (file.hasExtension("RGB") || file.hasExtension("SGI")) {
00190             // Any format which is supported by Coin only
00191 #ifdef FC_OS_WIN32
00192             FILE* fd = _wfopen(file.toStdWString().c_str(), L"w");
00193 #else
00194             FILE* fd = fopen(filename, "w");
00195 #endif
00196             bool ok = writeToRGB(fd);
00197             fclose(fd);
00198             if (!ok)
00199                 throw Base::FileException("Error writing image file", filename);
00200         }
00201     }
00202 }
00203 
00204 QStringList SoFCOffscreenRenderer::getWriteImageFiletypeInfo()
00205 {
00206     QStringList formats;
00207 
00208     // get all supported formats by Coin3D
00209     int num = getNumWriteFiletypes();
00210     for (int i=0; i < num; i++) {
00211 #if   (COIN_MAJOR_VERSION < 2) // Coin3D <= 1.x
00212         SbList<SbName> extlist;
00213 #elif (COIN_MAJOR_VERSION < 3) // Coin3D <= 2.x
00214 # if  (COIN_MINOR_VERSION < 3) // Coin3D <= 2.2.x
00215         SbList<SbName> extlist;
00216 # else                         // Coin3D >= 2.3.x
00217         SbPList extlist;
00218 # endif                        
00219 #else                          // Coin3D >= 3.x
00220         SbPList extlist;
00221 #endif
00222 
00223         SbString fullname, description;
00224         getWriteFiletypeInfo(i, extlist, fullname, description);
00225 
00226         for (int j=0; j < extlist.getLength(); j++) {
00227             QString ext = QLatin1String((const char*) extlist[j]);
00228             if (formats.indexOf(ext.toUpper()) == -1)
00229                 formats << ext.toUpper();
00230         }
00231     }
00232 
00233     // add now all further QImage formats
00234     QList<QByteArray> qtformats = QImageWriter::supportedImageFormats();
00235     for (QList<QByteArray>::Iterator it = qtformats.begin(); it != qtformats.end(); ++it) {
00236         // not supported? then append
00237         if (!isWriteSupported((*it).data()) && formats.indexOf(QLatin1String(*it)) == -1)
00238             formats << QLatin1String(*it);
00239     }
00240 
00241     // now add PostScript and SGI RGB
00242     if (formats.indexOf(QLatin1String("EPS")) == -1)
00243         formats << QLatin1String("EPS");
00244     else if (formats.indexOf(QLatin1String("SGI")) == -1)
00245         formats << QLatin1String("SGI");
00246 
00247     formats.sort();
00248 
00249     return formats;
00250 }
00251 
00252 std::string SoFCOffscreenRenderer::createMIBA() const
00253 {
00254     std::stringstream com;
00255 
00256     com << setw(7) << setfill(' ') << fixed;
00257     com << "<?xml version=\"1.0\" encoding=\"UTF-8\"?> \n" ;
00258     com << "<MIBA xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"http://juergen-riegel.net/Miba/Miba2.xsd\" Version=\"2\"> \n" ;
00259     com << " <View>\n"; 
00260     com << "  <Matrix \n"; 
00261     com << "     a11=\"" << _Matrix[0][0] <<"\" a12=\"" << _Matrix[1][0] <<"\" a13=\"" << _Matrix[2][0] <<"\" a14=\"" << _Matrix[3][0] << "\"\n";
00262     com << "     a21=\"" << _Matrix[0][1] <<"\" a22=\"" << _Matrix[1][1] <<"\" a23=\"" << _Matrix[2][1] <<"\" a24=\"" << _Matrix[3][1] << "\"\n";
00263     com << "     a31=\"" << _Matrix[0][2] <<"\" a32=\"" << _Matrix[1][2] <<"\" a33=\"" << _Matrix[2][2] <<"\" a34=\"" << _Matrix[3][2] << "\"\n";
00264     com << "     a41=\"" << _Matrix[0][3] <<"\" a42=\"" << _Matrix[1][3] <<"\" a43=\"" << _Matrix[2][3] <<"\" a44=\"" << _Matrix[3][3] << "\"\n";
00265     com << "   />\n" ; 
00266     com << " </View>\n" ; 
00267     com << " <Source>\n" ; 
00268     com << "  <Creator>Unknown</Creator>\n" ;  
00269     com << "  <CreationDate>2006-07-05T01:11:00</CreationDate>\n" ;  
00270     com << "  <CreatingSystem>FreeCAD 0.5</CreatingSystem>\n" ;
00271     com << "  <PartNumber>Unknown</PartNumber>\n";
00272     com << "  <Revision>1.0</Revision>\n";
00273     com << " </Source>\n" ;
00274     com << "</MIBA>\n" ;
00275 
00276     return com.str();
00277 }
00278 
00279 void writeJPEGComment(const std::string& comment, QByteArray& ba)
00280 {
00281     const unsigned char M_SOF0  = 0xc0;
00282     const unsigned char M_SOF1  = 0xc1;
00283     const unsigned char M_SOF2  = 0xc2;
00284     const unsigned char M_SOF3  = 0xc3;
00285     const unsigned char M_SOF5  = 0xc5;
00286     const unsigned char M_SOF6  = 0xc6;
00287     const unsigned char M_SOF7  = 0xc7;
00288     const unsigned char M_SOF9  = 0xc9;
00289     const unsigned char M_SOF10 = 0xcA;
00290     const unsigned char M_SOF11 = 0xcb;
00291     const unsigned char M_SOF13 = 0xcd;
00292     const unsigned char M_SOF14 = 0xce;
00293     const unsigned char M_SOF15 = 0xcf;
00294     const unsigned char M_SOI   = 0xd8;
00295     const unsigned char M_EOI   = 0xd9;
00296     const unsigned char M_COM   = 0xfe;
00297 
00298     union Byte {
00299         char c; unsigned char u;
00300     };
00301 
00302     if (comment.empty() || ba.length() < 2)
00303         return;
00304 
00305     // first marker
00306     Byte a,b;
00307     a.c = ba[0];
00308     b.c = ba[1];
00309     if (a.u == 0xff && b.u == M_SOI) {
00310         int index = 2;
00311         int len = ba.length();
00312         while (index < len) {
00313             // next marker
00314             a.c = ba[index++];
00315             while (a.u != 0xff && index < len) {
00316                 a.c = ba[index++];
00317             }
00318             do {
00319                 b.c = ba[index++];
00320             } while (b.u == 0xff && index < len);
00321             switch (b.u) {
00322                 case M_SOF0:
00323                 case M_SOF1:
00324                 case M_SOF2:
00325                 case M_SOF3:
00326                 case M_SOF5:
00327                 case M_SOF6:
00328                 case M_SOF7:
00329                 case M_SOF9:
00330                 case M_SOF10:
00331                 case M_SOF11:
00332                 case M_SOF13:
00333                 case M_SOF14:
00334                 case M_SOF15:
00335                 case M_EOI:
00336                     {
00337                         Byte a, b;
00338                         a.u = 0xff;
00339                         b.u = M_COM;
00340                         index -= 2; // insert comment before marker
00341                         ba.insert(index++, a.c);
00342                         ba.insert(index++, b.c);
00343                         int val = comment.size() + 2;
00344                         ba.insert(index++,(val >> 8) & 0xff);
00345                         ba.insert(index++,val & 0xff);
00346                         ba.insert(index, comment.c_str());
00347                         index = len; // finished
00348                     }   break;
00349                 case M_COM:
00350                 default:
00351                     {
00352                         Byte a, b;
00353                         a.c = ba[index++];
00354                         b.c = ba[index++];
00355                         int off = ((unsigned int)a.u << 8) + (unsigned int)b.u;
00356                         index += off;
00357                         index -= 2; // next marker
00358                     }   break;
00359             }
00360         }
00361     }
00362 }

Generated on Wed Nov 23 19:00:40 2011 for FreeCAD by  doxygen 1.6.1