SoFCOffscreenRenderer.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
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
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
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
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
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
00136 if (supported) {
00137 QImage img;
00138 writeToImage(img);
00139
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
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
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
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
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
00234 QList<QByteArray> qtformats = QImageWriter::supportedImageFormats();
00235 for (QList<QByteArray>::Iterator it = qtformats.begin(); it != qtformats.end(); ++it) {
00236
00237 if (!isWriteSupported((*it).data()) && formats.indexOf(QLatin1String(*it)) == -1)
00238 formats << QLatin1String(*it);
00239 }
00240
00241
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
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
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;
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;
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;
00358 } break;
00359 }
00360 }
00361 }
00362 }