FreeCAD

Форк
0
/
BitmapFactory.cpp 
670 строк · 20.3 Кб
1
/***************************************************************************
2
 *   Copyright (c) 2004 Jürgen Riegel <juergen.riegel@web.de>              *
3
 *                                                                         *
4
 *   This file is part of the FreeCAD CAx development system.              *
5
 *                                                                         *
6
 *   This library is free software; you can redistribute it and/or         *
7
 *   modify it under the terms of the GNU Library General Public           *
8
 *   License as published by the Free Software Foundation; either          *
9
 *   version 2 of the License, or (at your option) any later version.      *
10
 *                                                                         *
11
 *   This library  is distributed in the hope that it will be useful,      *
12
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
13
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
14
 *   GNU Library General Public License for more details.                  *
15
 *                                                                         *
16
 *   You should have received a copy of the GNU Library General Public     *
17
 *   License along with this library; see the file COPYING.LIB. If not,    *
18
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
19
 *   Suite 330, Boston, MA  02111-1307, USA                                *
20
 *                                                                         *
21
 ***************************************************************************/
22

23

24
#include "PreCompiled.h"
25
#ifndef _PreComp_
26
# include <QApplication>
27
# include <QBitmap>
28
# include <QDir>
29
# include <QFile>
30
# include <QFileInfo>
31
# include <QMap>
32
# include <QImageReader>
33
# include <QPainter>
34
# include <QPalette>
35
# include <QString>
36
# include <QSvgRenderer>
37
# include <QStyleOption>
38
#endif
39

40
#include <string>
41
#include <Inventor/fields/SoSFImage.h>
42

43
#include <App/Application.h>
44
#include <Base/Console.h>
45
#include <Base/ConsoleObserver.h>
46

47
#include "BitmapFactory.h"
48

49
using namespace Gui;
50

51
/* XPM */
52
static const char *not_found[]={
53
"24 24 2 1",
54
"# c #000000",
55
". c #ffffff",
56
"........................",
57
"........................",
58
"...##..............##...",
59
"..####............####..",
60
"..#####..........#####..",
61
"..######........#####...",
62
"...######......######...",
63
"....######....######....",
64
".....######..######.....",
65
"......############......",
66
".......##########.......",
67
"........########........",
68
".........######.........",
69
"........########........",
70
".......##########.......",
71
"......############......",
72
".....######..######.....",
73
"....######....######....",
74
"..#######......######...",
75
".#######........######..",
76
".######..........#####..",
77
"..####.............##...",
78
"........................",
79
"........................"};
80

81
namespace Gui {
82
class BitmapFactoryInstP
83
{
84
public:
85
    QMap<std::string, const char**> xpmMap;
86
    QMap<std::string, QPixmap> xpmCache;
87
};
88
}
89

90
BitmapFactoryInst* BitmapFactoryInst::_pcSingleton = nullptr;
91

92
BitmapFactoryInst& BitmapFactoryInst::instance()
93
{
94
    if (!_pcSingleton)
95
    {
96
        _pcSingleton = new BitmapFactoryInst;
97
        std::map<std::string,std::string>::const_iterator it;
98
        it = App::GetApplication().Config().find("ProgramIcons");
99
        if (it != App::GetApplication().Config().end()) {
100
            QString home = QString::fromStdString(App::Application::getHomePath());
101
            QString path = QString::fromUtf8(it->second.c_str());
102
            if (QDir(path).isRelative()) {
103
                path = QFileInfo(QDir(home), path).absoluteFilePath();
104
            }
105
            _pcSingleton->addPath(path);
106
        }
107
        _pcSingleton->addPath(QString::fromLatin1("%1/icons").arg(QString::fromStdString(App::Application::getHomePath())));
108
        _pcSingleton->addPath(QString::fromLatin1("%1/icons").arg(QString::fromStdString(App::Application::getUserAppDataDir())));
109
        _pcSingleton->addPath(QLatin1String(":/icons/"));
110
        _pcSingleton->addPath(QLatin1String(":/Icons/"));
111
    }
112

113
    return *_pcSingleton;
114
}
115

116
void BitmapFactoryInst::destruct ()
117
{
118
    if (_pcSingleton)
119
    delete _pcSingleton;
120
    _pcSingleton = nullptr;
121
}
122

123
BitmapFactoryInst::BitmapFactoryInst()
124
{
125
    d = new BitmapFactoryInstP;
126
    restoreCustomPaths();
127
}
128

129
BitmapFactoryInst::~BitmapFactoryInst()
130
{
131
    delete d;
132
}
133

134
void BitmapFactoryInst::restoreCustomPaths()
135
{
136
    Base::Reference<ParameterGrp> group = App::GetApplication().GetParameterGroupByPath
137
        ("User parameter:BaseApp/Preferences/Bitmaps");
138
    std::vector<std::string> paths = group->GetASCIIs("CustomPath");
139
    for (auto & path : paths) {
140
        addPath(QString::fromUtf8(path.c_str()));
141
    }
142
}
143

144
void BitmapFactoryInst::addPath(const QString& path)
145
{
146
    QDir::addSearchPath(QString::fromLatin1("icons"), path);
147
}
148

149
void BitmapFactoryInst::removePath(const QString& path)
150
{
151
    QStringList iconPaths = QDir::searchPaths(QString::fromLatin1("icons"));
152
    int pos = iconPaths.indexOf(path);
153
    if (pos != -1) {
154
        iconPaths.removeAt(pos);
155
        QDir::setSearchPaths(QString::fromLatin1("icons"), iconPaths);
156
    }
157
}
158

159
QStringList BitmapFactoryInst::getPaths() const
160
{
161
    return QDir::searchPaths(QString::fromLatin1("icons"));
162
}
163

164
QStringList BitmapFactoryInst::findIconFiles() const
165
{
166
    QStringList files, filters;
167
    QList<QByteArray> formats = QImageReader::supportedImageFormats();
168
    for (QList<QByteArray>::iterator it = formats.begin(); it != formats.end(); ++it)
169
        filters << QString::fromLatin1("*.%1").arg(QString::fromLatin1(*it).toLower());
170

171
    QStringList paths = QDir::searchPaths(QString::fromLatin1("icons"));
172
    paths.removeDuplicates();
173
    for (QStringList::Iterator pt = paths.begin(); pt != paths.end(); ++pt) {
174
        QDir d(*pt);
175
        d.setNameFilters(filters);
176
        QFileInfoList fi = d.entryInfoList();
177
        for (QFileInfoList::iterator it = fi.begin(); it != fi.end(); ++it)
178
            files << it->absoluteFilePath();
179
    }
180

181
    files.removeDuplicates();
182
    return files;
183
}
184

185
void BitmapFactoryInst::addXPM(const char* name, const char** pXPM)
186
{
187
    d->xpmMap[name] = pXPM;
188
}
189

190
void BitmapFactoryInst::addPixmapToCache(const char* name, const QPixmap& icon)
191
{
192
    d->xpmCache[name] = icon;
193
}
194

195
bool BitmapFactoryInst::findPixmapInCache(const char* name, QPixmap& px) const
196
{
197
    QMap<std::string, QPixmap>::Iterator it = d->xpmCache.find(name);
198
    if (it != d->xpmCache.end()) {
199
        px = it.value();
200
        return true;
201
    }
202
    return false;
203
}
204

205
QIcon BitmapFactoryInst::iconFromTheme(const char* name, const QIcon& fallback)
206
{
207
    QString iconName = QString::fromUtf8(name);
208
    QIcon icon = QIcon::fromTheme(iconName, fallback);
209
    if (icon.isNull()) {
210
        QPixmap px = pixmap(name);
211
        if (!px.isNull())
212
            icon.addPixmap(px);
213
    }
214

215
    return icon;
216
}
217

218
bool BitmapFactoryInst::loadPixmap(const QString& filename, QPixmap& icon) const
219
{
220
    QFileInfo fi(filename);
221
    if (fi.exists()) {
222
        // first check if it's an SVG because Qt's qsvg4 module shouldn't be used therefore
223
        if (fi.suffix().toLower() == QLatin1String("svg")) {
224
            QFile svgFile(fi.filePath());
225
            if (svgFile.open(QFile::ReadOnly | QFile::Text)) {
226
                QByteArray content = svgFile.readAll();
227
                icon = pixmapFromSvg(content, QSize(64,64));
228
            }
229
        }
230
        else {
231
            // try with Qt plugins
232
            icon.load(fi.filePath());
233
        }
234
    }
235

236
    return !icon.isNull();
237
}
238

239
QPixmap BitmapFactoryInst::pixmap(const char* name) const
240
{
241
    if (!name || *name == '\0')
242
        return {};
243

244
    // as very first test check whether the pixmap is in the cache
245
    QMap<std::string, QPixmap>::Iterator it = d->xpmCache.find(name);
246
    if (it != d->xpmCache.end())
247
        return it.value();
248

249
    // now try to find it in the built-in XPM
250
    QPixmap icon;
251
    QMap<std::string,const char**>::Iterator It = d->xpmMap.find(name);
252
    if (It != d->xpmMap.end())
253
        icon = QPixmap(It.value());
254

255
    // Try whether an absolute path is given
256
    QString fn = QString::fromUtf8(name);
257
    if (icon.isNull())
258
        loadPixmap(fn, icon);
259

260
    // try to find it in the 'icons' search paths
261
    if (icon.isNull()) {
262
        QList<QByteArray> formats = QImageReader::supportedImageFormats();
263
        formats.prepend("SVG"); // check first for SVG to use special import mechanism
264

265
        QString fileName = QString::fromLatin1("icons:") + fn;
266
        if (!loadPixmap(fileName, icon)) {
267
            // Go through supported file formats
268
            for (QList<QByteArray>::iterator fm = formats.begin(); fm != formats.end(); ++fm) {
269
                QString path = QString::fromLatin1("%1.%2").arg(fileName,
270
                    QString::fromLatin1((*fm).toLower().constData()));
271
                if (loadPixmap(path, icon)) {
272
                    break;
273
                }
274
            }
275
        }
276
    }
277

278
    if (!icon.isNull()) {
279
        d->xpmCache[name] = icon;
280
        return icon;
281
    }
282

283
    Base::Console().Warning("Cannot find icon: %s\n", name);
284
    return QPixmap(not_found);
285
}
286

287
QPixmap BitmapFactoryInst::pixmapFromSvg(const char* name, const QSizeF& size,
288
                                         const ColorMap& colorMapping) const
289
{
290
    // If an absolute path is given
291
    QPixmap icon;
292
    QString iconPath;
293
    QString fn = QString::fromUtf8(name);
294
    if (QFile(fn).exists())
295
        iconPath = fn;
296

297
    // try to find it in the 'icons' search paths
298
    if (iconPath.isEmpty()) {
299
        QString fileName = QString::fromLatin1("icons:") + fn;
300
        QFileInfo fi(fileName);
301
        if (fi.exists()) {
302
            iconPath = fi.filePath();
303
        }
304
        else {
305
            fileName += QLatin1String(".svg");
306
            fi.setFile(fileName);
307
            if (fi.exists()) {
308
                iconPath = fi.filePath();
309
            }
310
        }
311
    }
312

313
    if (!iconPath.isEmpty()) {
314
        QFile file(iconPath);
315
        if (file.open(QFile::ReadOnly | QFile::Text)) {
316
            QByteArray content = file.readAll();
317
            icon = pixmapFromSvg(content, size, colorMapping);
318
        }
319
    }
320

321
    return icon;
322
}
323

324
QPixmap BitmapFactoryInst::pixmapFromSvg(const char* name, const QSizeF& size, qreal dpr,
325
                                         const ColorMap& colorMapping) const
326
{
327
    qreal width = size.width() * dpr;
328
    qreal height = size.height() * dpr;
329
    QPixmap px(pixmapFromSvg(name, QSizeF(width, height), colorMapping));
330
    px.setDevicePixelRatio(dpr);
331
    return px;
332
}
333

334
QPixmap BitmapFactoryInst::pixmapFromSvg(const QByteArray& originalContents, const QSizeF& size,
335
                                         const ColorMap& colorMapping) const
336
{
337
    QString stringContents = QString::fromUtf8(originalContents);
338
    for ( const auto &colorToColor : colorMapping ) {
339
        ulong fromColor = colorToColor.first;
340
        ulong toColor = colorToColor.second;
341
        QString fromColorString = QString::fromLatin1(":#%1;").arg(fromColor, 6, 16,  QChar::fromLatin1('0'));
342
        QString toColorString = QString::fromLatin1(":#%1;").arg(toColor, 6, 16,  QChar::fromLatin1('0'));
343
        stringContents = stringContents.replace(fromColorString, toColorString);
344
    }
345
    QByteArray contents = stringContents.toUtf8();
346

347
    QImage image(size.toSize(), QImage::Format_ARGB32_Premultiplied);
348
    image.fill(0x00000000);
349

350
    QPainter p(&image);
351
    QSvgRenderer svg;
352
    {
353
        // tmp. disable the report window to suppress some bothering warnings
354
        const Base::ILoggerBlocker blocker("ReportOutput", Base::ConsoleSingleton::MsgType_Wrn);
355
        svg.load(contents);
356
    }
357
    svg.render(&p);
358
    p.end();
359

360
    return QPixmap::fromImage(image);
361
}
362

363
QStringList BitmapFactoryInst::pixmapNames() const
364
{
365
    QStringList names;
366
    for (QMap<std::string,const char**>::Iterator It = d->xpmMap.begin(); It != d->xpmMap.end(); ++It)
367
        names << QString::fromUtf8(It.key().c_str());
368
    for (QMap<std::string, QPixmap>::Iterator It = d->xpmCache.begin(); It != d->xpmCache.end(); ++It) {
369
        QString item = QString::fromUtf8(It.key().c_str());
370
        if (!names.contains(item))
371
            names << item;
372
    }
373
    return names;
374
}
375

376
QPixmap BitmapFactoryInst::resize(int w, int h, const QPixmap& p, Qt::BGMode bgmode) const
377
{
378
    if (bgmode == Qt::TransparentMode) {
379
        if (p.width() == 0 || p.height() == 0)
380
            w = 1;
381

382
        QPixmap pix = p;
383
        int x = pix.width () > w ? 0 : (w - pix.width ())/2;
384
        int y = pix.height() > h ? 0 : (h - pix.height())/2;
385

386
        if (x == 0 && y == 0)
387
            return pix;
388

389
        QPixmap pm (w,h);
390
        QBitmap mask (w,h);
391
        mask.fill(Qt::color0);
392

393
        QBitmap bm = pix.mask();
394
        if (!bm.isNull())
395
        {
396
            QPainter painter(&mask);
397
            painter.drawPixmap(QPoint(x, y), bm, QRect(0, 0, pix.width(), pix.height()));
398
            pm.setMask(mask);
399
        }
400
        else
401
        {
402
            pm.setMask(mask);
403
            pm = fillRect(x, y, pix.width(), pix.height(), pm, Qt::OpaqueMode);
404
        }
405

406
        QPainter pt;
407
        pt.begin( &pm );
408
        pt.drawPixmap(x, y, pix);
409
        pt.end();
410
        return pm;
411
    } else { // Qt::OpaqueMode
412
        QPixmap pix = p;
413

414
        if (pix.width() == 0 || pix.height() == 0)
415
            return pix; // do not resize a null pixmap
416

417
        QPalette pal = qApp->palette();
418
        QColor dl = pal.color(QPalette::Disabled, QPalette::Light);
419
        QColor dt = pal.color(QPalette::Disabled, QPalette::Text);
420

421
        QPixmap pm(w,h);
422
        pm.fill(dl);
423

424
        QPainter pt;
425
        pt.begin( &pm );
426
        pt.setPen( dl );
427
        pt.drawPixmap(1, 1, pix);
428
        pt.setPen( dt );
429
        pt.drawPixmap(0, 0, pix);
430
        pt.end();
431
        return pm;
432
    }
433
}
434

435
QPixmap BitmapFactoryInst::fillRect(int x, int y, int w, int h, const QPixmap& p, Qt::BGMode bgmode) const
436
{
437
    QBitmap b = p.mask();
438
    if (b.isNull())
439
        return p; // sorry, but cannot do anything
440

441
    QPixmap pix = p;
442

443
    // modify the mask
444
    QPainter pt;
445
    pt.begin(&b);
446
    if (bgmode == Qt::OpaqueMode)
447
        pt.fillRect(x, y, w, h, Qt::color1); // make opaque
448
    else // Qt::TransparentMode
449
        pt.fillRect(x, y, w, h, Qt::color0); // make transparent
450
    pt.end();
451

452
    pix.setMask(b);
453

454
    return pix;
455
}
456

457
QPixmap BitmapFactoryInst::merge(const QPixmap& p1, const QPixmap& p2, bool vertical) const
458
{
459
    int width = 0;
460
    int height = 0;
461

462
    int x = 0;
463
    int y = 0;
464

465
    // get the size for the new pixmap
466
    if (vertical) {
467
        y = p1.height();
468
        width  = qMax( p1.width(), p2.width() );
469
        height = p1.height() + p2.height();
470
    } else {
471
        x = p1.width();
472
        width  = p1.width() + p2.width();
473
        height = qMax( p1.height(), p2.height() );
474
    }
475

476
    QPixmap res( width, height );
477
    QBitmap mask( width, height );
478
    QBitmap mask1 = p1.mask();
479
    QBitmap mask2 = p2.mask();
480
    mask.fill( Qt::color0 );
481

482
    auto* pt1 = new QPainter(&res);
483
    pt1->drawPixmap(0, 0, p1);
484
    pt1->drawPixmap(x, y, p2);
485
    delete pt1;
486

487
    auto* pt2 = new QPainter(&mask);
488
    pt2->drawPixmap(0, 0, mask1);
489
    pt2->drawPixmap(x, y, mask2);
490
    delete pt2;
491

492
    res.setMask(mask);
493
    return res;
494
}
495

496
QPixmap BitmapFactoryInst::merge(const QPixmap& p1, const QPixmap& p2, Position pos) const
497
{
498
    // does the similar as the method above except that this method does not resize the resulting pixmap
499
    int x = 0, y = 0;
500
    qreal dpr1 = p1.devicePixelRatio();
501
    qreal dpr2 = p2.devicePixelRatio();
502

503
    switch (pos)
504
    {
505
    case TopLeft:
506
        break;
507
    case TopRight:
508
        x = p1.width ()/dpr1 - p2.width ()/dpr2;
509
        break;
510
    case BottomLeft:
511
        y = p1.height()/dpr1 - p2.height()/dpr2;
512
        break;
513
    case BottomRight:
514
        x = p1.width ()/dpr1 - p2.width ()/dpr2;
515
        y = p1.height()/dpr1 - p2.height()/dpr2;
516
        break;
517
    }
518

519
    QPixmap p = p1;
520
    p = fillRect(x, y, p2.width(), p2.height(), p, Qt::OpaqueMode);
521

522
    QPainter pt;
523
    pt.begin( &p );
524
    pt.setPen(Qt::NoPen);
525
    pt.drawRect(x, y, p2.width(), p2.height());
526
    pt.drawPixmap(x, y, p2);
527
    pt.end();
528

529
    return p;
530
}
531

532
QPixmap BitmapFactoryInst::disabled(const QPixmap& p) const
533
{
534
    QStyleOption opt;
535
    opt.palette = QApplication::palette();
536
    return QApplication::style()->generatedIconPixmap(QIcon::Disabled, p, &opt);
537
}
538

539
void BitmapFactoryInst::convert(const QImage& p, SoSFImage& img) const
540
{
541
    SbVec2s size;
542
    size[0] = p.width();
543
    size[1] = p.height();
544

545
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
546
    int buffersize = static_cast<int>(p.sizeInBytes());
547
#else
548
    int buffersize = p.byteCount();
549
#endif
550
    int numcomponents = 0;
551
    QVector<QRgb> table = p.colorTable();
552
    if (!table.isEmpty()) {
553
        if (p.hasAlphaChannel()) {
554
            if (p.allGray())
555
                numcomponents = 2;
556
            else
557
                numcomponents = 4;
558
        }
559
        else {
560
            if (p.allGray())
561
                numcomponents = 1;
562
            else
563
                numcomponents = 3;
564
        }
565
    }
566
    else {
567
        numcomponents = buffersize / (size[0] * size[1]);
568
    }
569

570
    // allocate image data
571
    img.setValue(size, numcomponents, nullptr);
572

573
    unsigned char * bytes = img.startEditing(size, numcomponents);
574

575
    int width  = (int)size[0];
576
    int height = (int)size[1];
577

578
    for (int y = 0; y < height; y++)
579
    {
580
        unsigned char * line = &bytes[width*numcomponents*(height-(y+1))];
581
        for (int x = 0; x < width; x++)
582
        {
583
            QRgb rgb = p.pixel(x,y);
584
            switch (numcomponents)
585
            {
586
            default:
587
                break;
588
            case 1:
589
                line[0] = qGray( rgb );
590
                break;
591
            case 2:
592
                line[0] = qGray( rgb );
593
                line[1] = qAlpha( rgb );
594
                break;
595
            case 3:
596
                line[0] = qRed( rgb );
597
                line[1] = qGreen( rgb );
598
                line[2] = qBlue( rgb );
599
                break;
600
            case 4:
601
                line[0] = qRed( rgb );
602
                line[1] = qGreen( rgb );
603
                line[2] = qBlue( rgb );
604
                line[3] = qAlpha( rgb );
605
                break;
606
            }
607

608
            line += numcomponents;
609
        }
610
    }
611

612
    img.finishEditing();
613
}
614

615
void BitmapFactoryInst::convert(const SoSFImage& p, QImage& img) const
616
{
617
    SbVec2s size;
618
    int numcomponents;
619

620
    const unsigned char * bytes = p.getValue(size, numcomponents);
621
    if (!bytes)
622
        return;
623

624
    int width  = (int)size[0];
625
    int height = (int)size[1];
626

627
    img = QImage(width, height, QImage::Format_RGB32);
628
    QRgb * bits = (QRgb*) img.bits();
629

630
    for (int y = 0; y < height; y++)
631
    {
632
        const unsigned char * line = &bytes[width*numcomponents*(height-(y+1))];
633
        for (int x = 0; x < width; x++)
634
        {
635
            switch (numcomponents)
636
            {
637
            default:
638
            case 1:
639
                *bits++ = qRgb(line[0], line[0], line[0]);
640
                break;
641
            case 2:
642
                *bits++ = qRgba(line[0], line[0], line[0], line[1]);
643
                break;
644
            case 3:
645
                *bits++ = qRgb(line[0], line[1], line[2]);
646
                break;
647
            case 4:
648
                *bits++ = qRgba(line[0], line[1], line[2], line[3]);
649
                break;
650
            }
651

652
            line += numcomponents;
653
        }
654
    }
655
}
656

657
QIcon BitmapFactoryInst::mergePixmap (const QIcon &base, const QPixmap &px, Gui::BitmapFactoryInst::Position position)
658
{
659
    QIcon overlayedIcon;
660

661
    int w = QApplication::style()->pixelMetric(QStyle::PM_ListViewIconSize);
662

663
    overlayedIcon.addPixmap(Gui::BitmapFactory().merge(base.pixmap(w, w, QIcon::Normal, QIcon::Off),
664
                                                       px,position), QIcon::Normal, QIcon::Off);
665

666
    overlayedIcon.addPixmap(Gui::BitmapFactory().merge(base.pixmap(w, w, QIcon::Normal, QIcon::On ),
667
                                                       px,position), QIcon::Normal, QIcon::Off);
668

669
    return overlayedIcon;
670
}
671

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.