QgsDiagramFactory* QgsSVGDiagramFactoryWidget::createFactory() { QString filePath = mPictureLineEdit->text(); if ( filePath.isEmpty() ) { return 0; } QFile svgFile( filePath ); if ( !svgFile.exists() ) { return 0; } //open file and read binary array if ( !svgFile.open( QIODevice::ReadOnly ) ) { return 0; } QByteArray svgData = svgFile.readAll(); QgsSVGDiagramFactory* factory = new QgsSVGDiagramFactory(); if ( !factory->setSVGData( svgData, filePath ) ) { delete factory; return 0; } return factory; }
void QgsSvgCache::replaceParamsAndCacheSvg( QgsSvgCacheEntry* entry ) { if ( !entry ) { return; } QFile svgFile( entry->file ); if ( !svgFile.open( QIODevice::ReadOnly ) ) { return; } QDomDocument svgDoc; if ( !svgDoc.setContent( &svgFile ) ) { return; } //replace fill color, outline color, outline with in all nodes QDomElement docElem = svgDoc.documentElement(); replaceElemParams( docElem, entry->fill, entry->outline, entry->outlineWidth ); entry->svgContent = svgDoc.toByteArray(); mTotalSize += entry->svgContent.size(); }
QIcon IconProducer::buildIcon(QString pathToSvgFile) { QFile svgFile(pathToSvgFile); svgFile.open(QIODevice::ReadOnly); QByteArray svg = svgFile.readAll(); QSvgRenderer render(svg); QPixmap pixmap(render.defaultSize()); pixmap.fill(QColor(0,0,0,0)); QPainter painter(&pixmap); render.render(&painter); return QIcon(pixmap); }
void QgsSvgCache::containsParams( const QString& path, bool& hasFillParam, QColor& defaultFillColor, bool& hasOutlineParam, QColor& defaultOutlineColor, bool& hasOutlineWidthParam, double& defaultOutlineWidth ) const { defaultFillColor = QColor( Qt::black ); defaultOutlineColor = QColor( Qt::black ); defaultOutlineWidth = 1.0; QFile svgFile( path ); if ( !svgFile.open( QIODevice::ReadOnly ) ) { return; } QDomDocument svgDoc; if ( !svgDoc.setContent( &svgFile ) ) { return; } QDomElement docElem = svgDoc.documentElement(); containsElemParams( docElem, hasFillParam, defaultFillColor, hasOutlineParam, defaultOutlineColor, hasOutlineWidthParam, defaultOutlineWidth ); }
QByteArray QgsSvgCache::getImageData( const QString &path ) const { // is it a path to local file? QFile svgFile( path ); if ( svgFile.exists() ) { if ( svgFile.open( QIODevice::ReadOnly ) ) { return svgFile.readAll(); } else { return QByteArray(); } } // maybe it's a url... if ( !path.contains( "://" ) ) // otherwise short, relative SVG paths might be considered URLs { return QByteArray(); } QUrl svgUrl( path ); if ( !svgUrl.isValid() ) { return QByteArray(); } // check whether it's a url pointing to a local file if ( svgUrl.scheme().compare( "file", Qt::CaseInsensitive ) == 0 ) { svgFile.setFileName( svgUrl.toLocalFile() ); if ( svgFile.exists() ) { if ( svgFile.open( QIODevice::ReadOnly ) ) { return svgFile.readAll(); } } // not found... return QByteArray(); } // the url points to a remote resource, download it! QNetworkReply *reply = 0; // The following code blocks until the file is downloaded... // TODO: use signals to get reply finished notification, in this moment // it's executed while rendering. while ( 1 ) { QgsDebugMsg( QString( "get svg: %1" ).arg( svgUrl.toString() ) ); QNetworkRequest request( svgUrl ); request.setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache ); request.setAttribute( QNetworkRequest::CacheSaveControlAttribute, true ); reply = QgsNetworkAccessManager::instance()->get( request ); connect( reply, SIGNAL( downloadProgress( qint64, qint64 ) ), this, SLOT( downloadProgress( qint64, qint64 ) ) ); //emit statusChanged( tr( "Downloading svg." ) ); // wait until the image download finished // TODO: connect to the reply->finished() signal while ( !reply->isFinished() ) { QCoreApplication::processEvents( QEventLoop::ExcludeUserInputEvents, 500 ); } if ( reply->error() != QNetworkReply::NoError ) { QgsMessageLog::logMessage( tr( "SVG request failed [error: %1 - url: %2]" ).arg( reply->errorString() ).arg( reply->url().toString() ), tr( "SVG" ) ); reply->deleteLater(); return QByteArray(); } QVariant redirect = reply->attribute( QNetworkRequest::RedirectionTargetAttribute ); if ( redirect.isNull() ) { // neither network error nor redirection // TODO: cache the image break; } // do a new request to the redirect url svgUrl = redirect.toUrl(); reply->deleteLater(); } QVariant status = reply->attribute( QNetworkRequest::HttpStatusCodeAttribute ); if ( !status.isNull() && status.toInt() >= 400 ) { QVariant phrase = reply->attribute( QNetworkRequest::HttpReasonPhraseAttribute ); QgsMessageLog::logMessage( tr( "SVG request error [status: %1 - reason phrase: %2]" ).arg( status.toInt() ).arg( phrase.toString() ), tr( "SVG" ) ); reply->deleteLater(); return QByteArray(); } QString contentType = reply->header( QNetworkRequest::ContentTypeHeader ).toString(); QgsDebugMsg( "contentType: " + contentType ); if ( !contentType.startsWith( "image/svg+xml", Qt::CaseInsensitive ) ) { reply->deleteLater(); return QByteArray(); } // read the image data QByteArray ba = reply->readAll(); reply->deleteLater(); return ba; }
void TestQgsProject::testPathResolverSvg() { QString dataDir( TEST_DATA_DIR ); //defined in CmakeLists.txt QString layerPath = dataDir + "/points.shp"; QVERIFY( QgsSymbolLayerUtils::svgSymbolNameToPath( QString(), QgsPathResolver() ).isEmpty() ); QVERIFY( QgsSymbolLayerUtils::svgSymbolPathToName( QString(), QgsPathResolver() ).isEmpty() ); // build a project with 3 layers, each having a simple renderer with SVG marker // - existing SVG file in project dir // - existing SVG file in QGIS dir // - non-exsiting SVG file QTemporaryDir dir; QVERIFY( dir.isValid() ); // on mac the returned path was not canonical and the resolver failed to convert paths properly QString dirPath = QFileInfo( dir.path() ).canonicalFilePath(); QString projectFilename = dirPath + "/project.qgs"; QString ourSvgPath = dirPath + "/valid.svg"; QString invalidSvgPath = dirPath + "/invalid.svg"; QFile svgFile( ourSvgPath ); QVERIFY( svgFile.open( QIODevice::WriteOnly ) ); svgFile.write( "<svg/>" ); // not a proper SVG, but good enough for this case svgFile.close(); QVERIFY( QFileInfo::exists( ourSvgPath ) ); // should exist now QString librarySvgPath = QgsSymbolLayerUtils::svgSymbolNameToPath( QStringLiteral( "transport/transport_airport.svg" ), QgsPathResolver() ); QCOMPARE( QgsSymbolLayerUtils::svgSymbolPathToName( librarySvgPath, QgsPathResolver() ), QStringLiteral( "transport/transport_airport.svg" ) ); QgsVectorLayer *layer1 = new QgsVectorLayer( layerPath, QStringLiteral( "points 1" ), QStringLiteral( "ogr" ) ); _useRendererWithSvgSymbol( layer1, ourSvgPath ); QgsVectorLayer *layer2 = new QgsVectorLayer( layerPath, QStringLiteral( "points 2" ), QStringLiteral( "ogr" ) ); _useRendererWithSvgSymbol( layer2, invalidSvgPath ); QgsVectorLayer *layer3 = new QgsVectorLayer( layerPath, QStringLiteral( "points 3" ), QStringLiteral( "ogr" ) ); _useRendererWithSvgSymbol( layer3, librarySvgPath ); QVERIFY( layer1->isValid() ); QgsProject project; project.addMapLayers( QList<QgsMapLayer *>() << layer1 << layer2 << layer3 ); project.write( projectFilename ); // make sure the path resolver works with relative paths (enabled by default) QCOMPARE( project.pathResolver().readPath( "./a.txt" ), dirPath + "/a.txt" ); QCOMPARE( project.pathResolver().writePath( dirPath + "/a.txt" ), QString( "./a.txt" ) ); // check that the saved paths are relative // key = layer name, value = svg path QHash<QString, QString> projectFileSvgPaths = _parseSvgPathsForLayers( projectFilename ); QCOMPARE( projectFileSvgPaths.count(), 3 ); QCOMPARE( projectFileSvgPaths["points 1"], QString( "./valid.svg" ) ); // relative path to project QCOMPARE( projectFileSvgPaths["points 2"], invalidSvgPath ); // full path to non-existent file (not sure why - but that's how it works now) QCOMPARE( projectFileSvgPaths["points 3"], QString( "transport/transport_airport.svg" ) ); // relative path to library // load project again, check that the paths are absolute QgsProject projectLoaded; projectLoaded.read( projectFilename ); QString svg1 = _getLayerSvgMarkerPath( projectLoaded, QStringLiteral( "points 1" ) ); QString svg2 = _getLayerSvgMarkerPath( projectLoaded, QStringLiteral( "points 2" ) ); QString svg3 = _getLayerSvgMarkerPath( projectLoaded, QStringLiteral( "points 3" ) ); QCOMPARE( svg1, ourSvgPath ); QCOMPARE( svg2, invalidSvgPath ); QCOMPARE( svg3, librarySvgPath ); // // now let's use these layers in embedded in another project... // QList<QDomNode> brokenNodes; QgsProject projectMaster; QVERIFY( projectMaster.createEmbeddedLayer( layer1->id(), projectFilename, brokenNodes ) ); QVERIFY( projectMaster.createEmbeddedLayer( layer2->id(), projectFilename, brokenNodes ) ); QVERIFY( projectMaster.createEmbeddedLayer( layer3->id(), projectFilename, brokenNodes ) ); QString svg1x = _getLayerSvgMarkerPath( projectMaster, QStringLiteral( "points 1" ) ); QString svg2x = _getLayerSvgMarkerPath( projectLoaded, QStringLiteral( "points 2" ) ); QString svg3x = _getLayerSvgMarkerPath( projectLoaded, QStringLiteral( "points 3" ) ); QCOMPARE( svg1x, ourSvgPath ); QCOMPARE( svg2x, invalidSvgPath ); QCOMPARE( svg3x, librarySvgPath ); }
bool KGameTheme::load(const QString &fileName) { if (fileName.isEmpty()) { qDebug() << "Refusing to load theme with no name"; return false; } QString filePath = QStandardPaths::locate( QStandardPaths::DataLocation, fileName, QStandardPaths::LocateFile ); qDebug() << "Attempting to load .desktop at" << filePath; if (filePath.isEmpty()) { return false; } // verify if it is a valid file first and if we can open it QFile themefile(filePath); if (!themefile.open(QIODevice::ReadOnly)) { qDebug() << "Could not open .desktop theme file" << filePath; return false; } d->prefix = QFileInfo(themefile).absolutePath() + '/'; themefile.close(); KConfig themeconfig(filePath, KConfig::SimpleConfig); if (!themeconfig.hasGroup(d->themeGroup)) { qDebug() << "Config group" << d->themeGroup << "does not exist in" << filePath; return false; } KConfigGroup group = themeconfig.group(d->themeGroup); //Copy the whole entryMap, so we can inherit generic properties as well, reducing the need to subclass for simple implementations d->themeproperties = group.entryMap(); //Version control int themeversion = group.readEntry("VersionFormat", 0); //Format is increased when we have incompatible changes, meaning that older clients are not able to use the remaining information safely if (themeversion > kThemeVersionFormat) { return false; } QString graphName = group.readEntry("FileName"); //d->graphics = KStandardDirs::locate("appdata", graphName); d->graphics = d->prefix + graphName; if (d->graphics.isEmpty()) return false; // let's see if svg file exists and can be opened QFile svgFile(d->graphics); if (!svgFile.open(QIODevice::ReadOnly)) { qDebug() << "Could not open file" << d->graphics; return false; } QString previewName = group.readEntry("Preview"); //QString graphicsPath = KStandardDirs::locate("appdata", previewName); QString graphicsPath = d->prefix + previewName; d->preview = QPixmap(graphicsPath); d->fileName = fileName; d->fullPath = filePath; d->loaded = true; return true; }
QByteArray QgsSvgCache::getImageData( const QString &path ) const { // is it a path to local file? QFile svgFile( path ); if ( svgFile.exists() ) { if ( svgFile.open( QIODevice::ReadOnly ) ) { return svgFile.readAll(); } else { return mMissingSvg; } } // maybe it's an embedded base64 string if ( path.startsWith( QLatin1String( "base64:" ), Qt::CaseInsensitive ) ) { QByteArray base64 = path.mid( 7 ).toLocal8Bit(); // strip 'base64:' prefix return QByteArray::fromBase64( base64, QByteArray::OmitTrailingEquals ); } // maybe it's a url... if ( !path.contains( QLatin1String( "://" ) ) ) // otherwise short, relative SVG paths might be considered URLs { return mMissingSvg; } QUrl svgUrl( path ); if ( !svgUrl.isValid() ) { return mMissingSvg; } // check whether it's a url pointing to a local file if ( svgUrl.scheme().compare( QLatin1String( "file" ), Qt::CaseInsensitive ) == 0 ) { svgFile.setFileName( svgUrl.toLocalFile() ); if ( svgFile.exists() ) { if ( svgFile.open( QIODevice::ReadOnly ) ) { return svgFile.readAll(); } } // not found... return mMissingSvg; } QMutexLocker locker( &mMutex ); // already a request in progress for this url if ( mPendingRemoteUrls.contains( path ) ) return mFetchingSvg; if ( mRemoteContentCache.contains( path ) ) { // already fetched this content - phew. Just return what we already got. return *mRemoteContentCache[ path ]; } mPendingRemoteUrls.insert( path ); //fire up task to fetch image in background QNetworkRequest request( svgUrl ); request.setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache ); request.setAttribute( QNetworkRequest::CacheSaveControlAttribute, true ); QgsNetworkContentFetcherTask *task = new QgsNetworkContentFetcherTask( request ); connect( task, &QgsNetworkContentFetcherTask::fetched, this, [this, task, path] { QMutexLocker locker( &mMutex ); QNetworkReply *reply = task->reply(); if ( !reply ) { // canceled QMetaObject::invokeMethod( const_cast< QgsSvgCache * >( this ), "onRemoteSvgFetched", Qt::QueuedConnection, Q_ARG( QString, path ), Q_ARG( bool, false ) ); return; } if ( reply->error() != QNetworkReply::NoError ) { QgsMessageLog::logMessage( tr( "SVG request failed [error: %1 - url: %2]" ).arg( reply->errorString(), path ), tr( "SVG" ) ); return; } bool ok = true; QVariant status = reply->attribute( QNetworkRequest::HttpStatusCodeAttribute ); if ( !status.isNull() && status.toInt() >= 400 ) { QVariant phrase = reply->attribute( QNetworkRequest::HttpReasonPhraseAttribute ); QgsMessageLog::logMessage( tr( "SVG request error [status: %1 - reason phrase: %2] for %3" ).arg( status.toInt() ).arg( phrase.toString(), path ), tr( "SVG" ) ); mRemoteContentCache.insert( path, new QByteArray( mMissingSvg ) ); ok = false; } // we accept both real SVG mime types AND plain text types - because some sites // (notably github) serve up svgs as raw text QString contentType = reply->header( QNetworkRequest::ContentTypeHeader ).toString(); if ( !contentType.startsWith( QLatin1String( "image/svg+xml" ), Qt::CaseInsensitive ) && !contentType.startsWith( QLatin1String( "text/plain" ), Qt::CaseInsensitive ) ) { QgsMessageLog::logMessage( tr( "Unexpected MIME type %1 received for %2" ).arg( contentType, path ), tr( "SVG" ) ); mRemoteContentCache.insert( path, new QByteArray( mMissingSvg ) ); ok = false; } if ( ok ) { // read the image data mRemoteContentCache.insert( path, new QByteArray( reply->readAll() ) ); } QMetaObject::invokeMethod( const_cast< QgsSvgCache * >( this ), "onRemoteSvgFetched", Qt::QueuedConnection, Q_ARG( QString, path ), Q_ARG( bool, true ) ); } );