BitmapFactory.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (c) 2004 Jürgen Riegel <juergen.riegel@web.de>              *
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 
00024 #include "PreCompiled.h"
00025 #ifndef _PreComp_
00026 # include <QApplication>
00027 # include <QBitmap>
00028 # include <QDir>
00029 # include <QFile>
00030 # include <QFileInfo>
00031 # include <QMap>
00032 # include <QImageReader>
00033 # include <QPainter>
00034 # include <QPalette>
00035 # include <QSvgRenderer>
00036 # include <QStyleOption>
00037 # include <sstream>
00038 #endif
00039 
00040 #ifdef FC_OS_WIN32
00041 #define QTWEBKIT
00042 #endif
00043 
00044 #ifdef QTWEBKIT
00045 #include <QWebView>
00046 #include <QWebFrame>
00047 #endif
00048 
00049 #include <string>
00050 #include <Inventor/fields/SoSFImage.h>
00051 
00052 #include <Base/Console.h>
00053 #include <App/Application.h>
00054 
00055 #include "BitmapFactory.h"
00056 #include "Icons/images.cpp"
00057 #include "Icons/Feature.xpm"
00058 #include "Icons/Document.xpm"
00059 #include "Icons/BmpFactoryIcons.cpp"
00060 
00061 using namespace Gui;
00062 
00063 namespace Gui {
00064 class BitmapFactoryInstP
00065 {
00066 public:
00067     QMap<std::string, const char**> xpmMap;
00068     QMap<std::string, QPixmap> xpmCache;
00069     QStringList paths;
00070 };
00071 }
00072 
00073 BitmapFactoryInst* BitmapFactoryInst::_pcSingleton = NULL;
00074 
00075 BitmapFactoryInst& BitmapFactoryInst::instance(void)
00076 {
00077     if (_pcSingleton == NULL)
00078     {
00079         _pcSingleton = new BitmapFactoryInst;
00080         _pcSingleton->addPath(QLatin1String(":/icons/"));
00081         _pcSingleton->addPath(QLatin1String(":/Icons/"));
00082         _pcSingleton->addPath(QString::fromUtf8(App::GetApplication().GetHomePath()));
00083         _pcSingleton->addPath(QString::fromUtf8(App::GetApplication().Config()["UserAppData"].c_str()));
00084 
00085         RegisterIcons();
00086     }
00087 
00088     return *_pcSingleton;
00089 }
00090 
00091 void BitmapFactoryInst::destruct (void)
00092 {
00093     if (_pcSingleton != 0)
00094     delete _pcSingleton;
00095     _pcSingleton = 0;
00096 }
00097 
00098 BitmapFactoryInst::BitmapFactoryInst()
00099 {
00100     d = new BitmapFactoryInstP;
00101     restoreCustomPaths();
00102 }
00103 
00104 BitmapFactoryInst::~BitmapFactoryInst()
00105 {
00106     delete d;
00107 }
00108 
00109 void BitmapFactoryInst::addCustomPath(const QString& path)
00110 {
00111     Base::Reference<ParameterGrp> group = App::GetApplication().GetParameterGroupByPath
00112         ("User parameter:BaseApp/Preferences/Bitmaps");
00113     std::vector<std::string> paths = group->GetASCIIs("CustomPath");
00114     std::stringstream str;
00115     str << "CustomPath" << paths.size();
00116     group->SetASCII(str.str().c_str(), (const char*)path.toUtf8());
00117 }
00118 
00119 void BitmapFactoryInst::restoreCustomPaths()
00120 {
00121     Base::Reference<ParameterGrp> group = App::GetApplication().GetParameterGroupByPath
00122         ("User parameter:BaseApp/Preferences/Bitmaps");
00123     std::vector<std::string> paths = group->GetASCIIs("CustomPath");
00124     for (std::vector<std::string>::iterator it = paths.begin(); it != paths.end(); ++it) {
00125         addPath(QString::fromUtf8(it->c_str()));
00126     }
00127 }
00128 
00129 void BitmapFactoryInst::addPath(const QString& path)
00130 {
00131     d->paths.push_back(path);
00132 }
00133 
00134 void BitmapFactoryInst::removePath(const QString& path)
00135 {
00136     int pos = d->paths.indexOf(path);
00137     if (pos != -1) d->paths.removeAt(pos);
00138 }
00139 
00140 QStringList BitmapFactoryInst::findIconFiles() const
00141 {
00142     QStringList files, filters;
00143     QList<QByteArray> formats = QImageReader::supportedImageFormats();
00144     for (QList<QByteArray>::iterator it = formats.begin(); it != formats.end(); ++it)
00145         filters << QString::fromAscii("*.%1").arg(QString::fromAscii(*it).toLower());
00146 
00147     QStringList paths = d->paths;
00148 #if QT_VERSION >= 0x040500
00149     paths.removeDuplicates();
00150 #endif
00151     for (QStringList::ConstIterator pt = paths.begin(); pt != paths.end(); ++pt) {
00152         QDir d(*pt);
00153         d.setNameFilters(filters);
00154         QFileInfoList fi = d.entryInfoList();
00155         for (QFileInfoList::iterator it = fi.begin(); it != fi.end(); ++it)
00156             files << it->absoluteFilePath();
00157     }
00158 
00159     return files;
00160 }
00161 
00162 void BitmapFactoryInst::addXPM(const char* name, const char** pXPM)
00163 {
00164     d->xpmMap[name] = pXPM;
00165 }
00166 
00167 void BitmapFactoryInst::addPixmapToCache(const char* name, const QPixmap& icon)
00168 {
00169     d->xpmCache[name] = icon;
00170 }
00171 
00172 bool BitmapFactoryInst::findPixmapInCache(const char* name, QPixmap& px) const
00173 {
00174     QMap<std::string, QPixmap>::ConstIterator it = d->xpmCache.find(name);
00175     if (it != d->xpmCache.end()) {
00176         px = it.value();
00177         return true;
00178     }
00179     return false;
00180 }
00181 
00182 QPixmap BitmapFactoryInst::pixmap(const char* name) const
00183 {
00184     if (!name || *name == '\0')
00185         return QPixmap(px);
00186 
00187     // as very first test check whether the pixmap is in the cache
00188     QMap<std::string, QPixmap>::ConstIterator it = d->xpmCache.find(name);
00189     if (it != d->xpmCache.end())
00190         return it.value();
00191 
00192     // now try to find it in the built-in XPM
00193     QPixmap icon;
00194     QMap<std::string,const char**>::ConstIterator It = d->xpmMap.find(name);
00195     if (It != d->xpmMap.end())
00196         icon = QPixmap(It.value());
00197 
00198     // If an absolute path is given
00199     QString fn = QString::fromUtf8(name);
00200     if (icon.isNull() && QFile(fn).exists())
00201         icon.load(fn);
00202 
00203     // first check if it's an SVG because Qt's qsvg4 module shouldn't be used therefore
00204     if (icon.isNull()) {
00205         icon = pixmapFromSvg(name, QSize(24,24));
00206     }
00207 
00208     // try to find it in the given directories
00209     if (icon.isNull()) {
00210         bool found = false;
00211         QList<QByteArray> formats = QImageReader::supportedImageFormats();
00212         for (QStringList::ConstIterator pt = d->paths.begin(); pt != d->paths.end() && !found; ++pt) {
00213             QDir d(*pt);
00214             QString fileName = d.filePath(fn);
00215             if (QFile(fileName).exists()) {
00216                 icon.load(fileName);
00217                 found = true;
00218                 break;
00219             } else {
00220                 for (QList<QByteArray>::iterator fm = formats.begin(); fm != formats.end(); ++fm) {
00221                     QString path = QString::fromAscii("%1.%2").arg(fileName).
00222                         arg(QString::fromAscii((*fm).toLower().constData()));
00223                     if (QFile(path).exists()) {
00224                         icon.load(path);
00225                         found = true;
00226                         break;
00227                     }
00228                 }
00229             }
00230         }
00231     }
00232 
00233     if (!icon.isNull()) {
00234         d->xpmCache[name] = icon;
00235         return icon;
00236     }
00237 
00238     Base::Console().Warning("Cannot find icon: %s\n", name);
00239     return QPixmap(px);
00240 }
00241 
00242 QPixmap BitmapFactoryInst::pixmapFromSvg(const char* name, const QSize& size) const
00243 {
00244     // If an absolute path is given
00245     QPixmap icon;
00246     QString iconPath;
00247     QString fn = QString::fromUtf8(name);
00248     if (QFile(fn).exists())
00249         iconPath = fn;
00250 
00251     // try to find it in the given directories
00252     if (iconPath.isEmpty()) {
00253         for (QStringList::ConstIterator pt = d->paths.begin(); pt != d->paths.end(); ++pt) {
00254             QDir d(*pt);
00255             QString fileName = d.filePath(fn);
00256             if (QFile(fileName).exists()) {
00257                 iconPath = fileName;
00258                 break;
00259             } else {
00260                 fileName += QLatin1String(".svg");
00261                 if (QFile(fileName).exists()) {
00262                     iconPath = fileName;
00263                     break;
00264                 }
00265             }
00266         }
00267     }
00268 
00269     if (!iconPath.isEmpty()) {
00270         QFile file(iconPath);
00271         if (file.open(QFile::ReadOnly | QFile::Text)) {
00272             QByteArray content = file.readAll();
00273             icon = pixmapFromSvg(content, size);
00274         }
00275     }
00276 
00277     return icon;
00278 }
00279 
00280 QPixmap BitmapFactoryInst::pixmapFromSvg(const QByteArray& contents, const QSize& size) const
00281 {
00282 #ifdef QTWEBKIT
00283     QWebView webView;
00284     QPalette pal = webView.palette();
00285     pal.setColor(QPalette::Background, Qt::transparent);
00286     webView.setPalette(pal);
00287     webView.setContent(contents, QString::fromAscii("image/svg+xml"));
00288     QString node = QString::fromAscii("document.rootElement.nodeName");
00289     QString root = webView.page()->mainFrame()->evaluateJavaScript(node).toString();
00290     if (root.isEmpty() || root.compare(QLatin1String("svg"), Qt::CaseInsensitive)) {
00291         return QPixmap();
00292     }
00293 
00294     QString w = QString::fromAscii("document.rootElement.width.baseVal.value");
00295     QString h = QString::fromAscii("document.rootElement.height.baseVal.value");
00296     double ww = webView.page()->mainFrame()->evaluateJavaScript(w).toDouble();
00297     double hh = webView.page()->mainFrame()->evaluateJavaScript(h).toDouble();
00298     if (ww == 0.0 || hh == 0.0)
00299         return QPixmap();
00300 #endif
00301 
00302     QImage image(size, QImage::Format_ARGB32_Premultiplied);
00303     image.fill(0x00000000);
00304 
00305     QPainter p(&image);
00306 #ifdef QTWEBKIT
00307     qreal xs = size.isValid() ? size.width() / ww : 1.0;
00308     qreal ys = size.isValid() ? size.height() / hh : 1.0;
00309     p.scale(xs, ys);
00310 
00311     // the best quality
00312     p.setRenderHint(QPainter::Antialiasing);
00313     p.setRenderHint(QPainter::TextAntialiasing);
00314     p.setRenderHint(QPainter::SmoothPixmapTransform);
00315     p.setOpacity(0); // important to keep transparent background
00316     webView.page()->mainFrame()->render(&p);
00317 #else
00318     // tmp. disable the report window to suppress some bothering warnings
00319     Base::Console().SetEnabledMsgType("ReportOutput", ConsoleMsgType::MsgType_Wrn, false);
00320     QSvgRenderer svg(contents);
00321     Base::Console().SetEnabledMsgType("ReportOutput", ConsoleMsgType::MsgType_Wrn, true);
00322     svg.render(&p);
00323 #endif
00324     p.end();
00325 
00326     return QPixmap::fromImage(image);
00327 }
00328 
00329 QStringList BitmapFactoryInst::pixmapNames() const
00330 {
00331     QStringList names;
00332     for (QMap<std::string,const char**>::ConstIterator It = d->xpmMap.begin(); It != d->xpmMap.end(); ++It)
00333         names << QString::fromUtf8(It.key().c_str());
00334     for (QMap<std::string, QPixmap>::ConstIterator It = d->xpmCache.begin(); It != d->xpmCache.end(); ++It) {
00335         QString item = QString::fromUtf8(It.key().c_str());
00336         if (!names.contains(item))
00337             names << item;
00338     }
00339     return names;
00340 }
00341 
00342 QPixmap BitmapFactoryInst::resize(int w, int h, const QPixmap& p, Qt::BGMode bgmode) const
00343 {
00344     if (bgmode == Qt::TransparentMode) {
00345         if (p.width() == 0 || p.height() == 0)
00346             w = 1;
00347 
00348         QPixmap pix = p;
00349         int x = pix.width () > w ? 0 : (w - pix.width ())/2;
00350         int y = pix.height() > h ? 0 : (h - pix.height())/2;
00351 
00352         if (x == 0 && y == 0)
00353             return pix;
00354 
00355         QPixmap pm (w,h);
00356         QBitmap mask (w,h);
00357         mask.fill(Qt::color0);
00358 
00359         QBitmap bm = pix.mask();
00360         if (!bm.isNull())
00361         {
00362             QPainter painter(&mask);
00363             painter.drawPixmap(QPoint(x, y), bm, QRect(0, 0, pix.width(), pix.height()));
00364             pm.setMask(mask);
00365         }
00366         else
00367         {
00368             pm.setMask(mask);
00369             pm = fillRect(x, y, pix.width(), pix.height(), pm, Qt::OpaqueMode);
00370         }
00371 
00372         QPainter pt;
00373         pt.begin( &pm );
00374         pt.drawPixmap(x, y, pix);
00375         pt.end();
00376         return pm;
00377     } else { // Qt::OpaqueMode
00378         QPixmap pix = p;
00379 
00380         if (pix.width() == 0 || pix.height() == 0)
00381             return pix; // do not resize a null pixmap
00382 
00383         QPalette pal = qApp->palette();
00384         QColor dl = pal.color(QPalette::Disabled, QPalette::Light);
00385         QColor dt = pal.color(QPalette::Disabled, QPalette::Text);
00386 
00387         QPixmap pm = pix;
00388         pm = QPixmap(w,h);
00389         pm.fill(dl);
00390 
00391         QPainter pt;
00392         pt.begin( &pm );
00393         pt.setPen( dl );
00394         pt.drawPixmap(1, 1, pix);
00395         pt.setPen( dt );
00396         pt.drawPixmap(0, 0, pix);
00397         pt.end();
00398         return pm;
00399     }
00400 }
00401 
00402 QPixmap BitmapFactoryInst::fillRect(int x, int y, int w, int h, const QPixmap& p, Qt::BGMode bgmode) const
00403 {
00404     QBitmap b = p.mask();
00405     if (b.isNull())
00406         return p; // sorry, but cannot do anything
00407 
00408     QPixmap pix = p;
00409 
00410     // modify the mask
00411     QPainter pt;
00412     pt.begin(&b);
00413     if (bgmode == Qt::OpaqueMode)
00414         pt.fillRect(x, y, w, h, Qt::color1); // make opaque
00415     else // Qt::TransparentMode
00416         pt.fillRect(x, y, w, h, Qt::color0); // make transparent
00417     pt.end();
00418 
00419     pix.setMask(b);
00420 
00421     return pix;
00422 }
00423 
00424 QPixmap BitmapFactoryInst::merge(const QPixmap& p1, const QPixmap& p2, bool vertical) const
00425 {
00426     int width = 0;
00427     int height = 0;
00428 
00429     int x = 0;
00430     int y = 0;
00431 
00432     // get the size for the new pixmap
00433     if (vertical) {
00434         y = p1.height();
00435         width  = qMax( p1.width(), p2.width() );
00436         height = p1.height() + p2.height();
00437     } else {
00438         x = p1.width();
00439         width  = p1.width() + p2.width();
00440         height = qMax( p1.height(), p2.height() );
00441     }
00442 
00443     QPixmap res( width, height );
00444     QBitmap mask( width, height );
00445     QBitmap mask1 = p1.mask();
00446     QBitmap mask2 = p2.mask();
00447     mask.fill( Qt::color0 );
00448 
00449     QPainter* pt1 = new QPainter(&res);
00450     pt1->drawPixmap(0, 0, p1);
00451     pt1->drawPixmap(x, y, p2);
00452     delete pt1;
00453 
00454     QPainter* pt2 = new QPainter(&mask);
00455     pt2->drawPixmap(0, 0, mask1);
00456     pt2->drawPixmap(x, y, mask2);
00457     delete pt2;
00458 
00459     res.setMask(mask);
00460     return res;
00461 }
00462 
00463 QPixmap BitmapFactoryInst::merge(const QPixmap& p1, const QPixmap& p2, Position pos) const
00464 {
00465     // does the similar as the method above except that this method does not resize the resulting pixmap
00466     int x = 0, y = 0;
00467 
00468     switch (pos)
00469     {
00470     case Qt::TopLeftCorner:
00471         break;
00472     case Qt::TopRightCorner:
00473         x = p1.width () - p2.width ();
00474         break;
00475     case Qt::BottomLeftCorner:
00476         y = p1.height() - p2.height();
00477         break;
00478     case Qt::BottomRightCorner:
00479         x = p1.width () - p2.width ();
00480         y = p1.height() - p2.height();
00481         break;
00482     }
00483 
00484     QPixmap p = p1;
00485     p = fillRect(x, y, p2.width(), p2.height(), p, Qt::OpaqueMode);
00486 
00487     QPainter pt;
00488     pt.begin( &p );
00489     pt.setPen(Qt::NoPen);
00490     pt.drawRect(x, y, p2.width(), p2.height());
00491     pt.drawPixmap(x, y, p2);
00492     pt.end();
00493 
00494     return p;
00495 }
00496 
00497 QPixmap BitmapFactoryInst::disabled(const QPixmap& p) const
00498 {
00499     QStyleOption opt;
00500     opt.palette = QApplication::palette();
00501     return QApplication::style()->generatedIconPixmap(QIcon::Disabled, p, &opt);
00502 }
00503 
00504 void BitmapFactoryInst::convert(const QImage& p, SoSFImage& img) const
00505 {
00506     SbVec2s size;
00507     size[0] = p.width();
00508     size[1] = p.height();
00509 
00510     int buffersize = p.numBytes();
00511     int numcomponents = buffersize / ( size[0] * size[1] );
00512 
00513     // allocate image data
00514     img.setValue(size, numcomponents, NULL);
00515 
00516     unsigned char * bytes = img.startEditing(size, numcomponents);
00517 
00518     int width  = (int)size[0];
00519     int height = (int)size[1];
00520 
00521     for (int y = 0; y < height; y++) 
00522     {
00523         unsigned char * line = &bytes[width*numcomponents*(height-(y+1))];
00524         for (int x = 0; x < width; x++) 
00525         {
00526             QRgb rgb = p.pixel(x,y);
00527             switch (numcomponents) 
00528             {
00529             default:
00530                 break;
00531             case 1:
00532                 line[0] = qGray( rgb );
00533                 break;
00534             case 2:
00535                 line[0] = qGray( rgb );
00536                 line[1] = qAlpha( rgb );
00537                 break;
00538             case 3:
00539                 line[0] = qRed( rgb );
00540                 line[1] = qGreen( rgb );
00541                 line[2] = qBlue( rgb );
00542                 break;
00543             case 4:
00544                 line[0] = qRed( rgb );
00545                 line[1] = qGreen( rgb );
00546                 line[2] = qBlue( rgb );
00547                 line[3] = qAlpha( rgb );
00548                 break;
00549             }
00550 
00551             line += numcomponents;
00552         }
00553     }
00554 
00555     img.finishEditing();
00556 }
00557 
00558 void BitmapFactoryInst::convert(const SoSFImage& p, QImage& img) const
00559 {
00560     SbVec2s size;
00561     int numcomponents;
00562 
00563     const unsigned char * bytes = p.getValue(size, numcomponents);
00564 
00565     int width  = (int)size[0];
00566     int height = (int)size[1];
00567 
00568     img = QImage(width, height, QImage::Format_RGB32);
00569     QRgb * bits = (QRgb*) img.bits();
00570     
00571     for (int y = 0; y < height; y++) 
00572     {
00573         const unsigned char * line = &bytes[width*numcomponents*(height-(y+1))];
00574         for (int x = 0; x < width; x++) 
00575         {
00576             switch (numcomponents) 
00577             {
00578             default:
00579             case 1:
00580                 *bits++ = qRgb(line[0], line[0], line[0]);
00581                 break;
00582             case 2:
00583                 *bits++ = qRgba(line[0], line[0], line[0], line[1]);
00584                 break;
00585             case 3:
00586                 *bits++ = qRgb(line[0], line[1], line[2]);
00587                 break;
00588             case 4:
00589                 *bits++ = qRgba(line[0], line[1], line[2], line[3]);
00590                 break;
00591             }
00592 
00593             line += numcomponents;
00594         }
00595     }
00596 }
00597 

Generated on Wed Nov 23 18:59:58 2011 for FreeCAD by  doxygen 1.6.1