Branch data Line data Source code
1 : : /*************************************************************************** 2 : : qgsalgorithmextractbinary.cpp 3 : : ----------------------------------- 4 : : begin : November 2018 5 : : copyright : (C) 2018 by Nyall Dawson 6 : : email : nyall dot dawson at gmail dot com 7 : : ***************************************************************************/ 8 : : 9 : : /*************************************************************************** 10 : : * * 11 : : * This program is free software; you can redistribute it and/or modify * 12 : : * it under the terms of the GNU General Public License as published by * 13 : : * the Free Software Foundation; either version 2 of the License, or * 14 : : * (at your option) any later version. * 15 : : * * 16 : : ***************************************************************************/ 17 : : 18 : : #include "qgsalgorithmextractbinary.h" 19 : : #include "qgsfeaturerequest.h" 20 : : 21 : : ///@cond PRIVATE 22 : : 23 : 0 : QString QgsExtractBinaryFieldAlgorithm::name() const 24 : : { 25 : 0 : return QStringLiteral( "extractbinary" ); 26 : : } 27 : : 28 : 0 : QString QgsExtractBinaryFieldAlgorithm::displayName() const 29 : : { 30 : 0 : return QObject::tr( "Extract binary field" ); 31 : : } 32 : : 33 : 0 : QString QgsExtractBinaryFieldAlgorithm::shortHelpString() const 34 : : { 35 : 0 : return QObject::tr( "This algorithm extracts contents from a binary field, saving them to individual files.\n\n" 36 : : "Filenames can be generated using values taken from " 37 : : "an attribute in the source table or based on a more complex expression." ); 38 : : } 39 : : 40 : 0 : QString QgsExtractBinaryFieldAlgorithm::shortDescription() const 41 : : { 42 : 0 : return QObject::tr( "This algorithm extracts contents from a binary field, saving them to individual files." ); 43 : : } 44 : : 45 : 0 : QStringList QgsExtractBinaryFieldAlgorithm::tags() const 46 : : { 47 : 0 : return QObject::tr( "blob,binaries,save,file,contents,field,column" ).split( ',' ); 48 : 0 : } 49 : : 50 : 0 : QString QgsExtractBinaryFieldAlgorithm::group() const 51 : : { 52 : 0 : return QObject::tr( "Vector table" ); 53 : : } 54 : : 55 : 0 : QString QgsExtractBinaryFieldAlgorithm::groupId() const 56 : : { 57 : 0 : return QStringLiteral( "vectortable" ); 58 : : } 59 : : 60 : 0 : QgsExtractBinaryFieldAlgorithm *QgsExtractBinaryFieldAlgorithm::createInstance() const 61 : : { 62 : 0 : return new QgsExtractBinaryFieldAlgorithm(); 63 : : } 64 : : 65 : 0 : void QgsExtractBinaryFieldAlgorithm::initAlgorithm( const QVariantMap & ) 66 : : { 67 : 0 : addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), 68 : 0 : QObject::tr( "Input layer" ), QList< int>() << QgsProcessing::TypeVector ) ); 69 : : 70 : 0 : addParameter( new QgsProcessingParameterField( QStringLiteral( "FIELD" ), QObject::tr( "Binary field" ), QVariant(), 71 : 0 : QStringLiteral( "INPUT" ), QgsProcessingParameterField::Any ) ); 72 : : 73 : 0 : addParameter( new QgsProcessingParameterExpression( QStringLiteral( "FILENAME" ), QObject::tr( "File name" ), QVariant(), QStringLiteral( "INPUT" ) ) ); 74 : : 75 : 0 : addParameter( new QgsProcessingParameterFolderDestination( QStringLiteral( "FOLDER" ), QObject::tr( "Destination folder" ) ) ); 76 : 0 : } 77 : : 78 : 0 : QVariantMap QgsExtractBinaryFieldAlgorithm::processAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) 79 : : { 80 : 0 : std::unique_ptr< QgsProcessingFeatureSource > input( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) ); 81 : 0 : if ( !input ) 82 : 0 : throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) ); 83 : : 84 : 0 : QString fieldName = parameterAsString( parameters, QStringLiteral( "FIELD" ), context ); 85 : 0 : int fieldIndex = input->fields().lookupField( fieldName ); 86 : 0 : if ( fieldIndex < 0 ) 87 : 0 : throw QgsProcessingException( QObject::tr( "Invalid binary field" ) ); 88 : : 89 : 0 : const QString folder = parameterAsString( parameters, QStringLiteral( "FOLDER" ), context ); 90 : 0 : if ( !QFileInfo::exists( folder ) ) 91 : 0 : throw QgsProcessingException( QObject::tr( "Destination folder %1 does not exist" ).arg( folder ) ); 92 : : 93 : 0 : QDir dir( folder ); 94 : 0 : const QString filenameExpressionString = parameterAsString( parameters, QStringLiteral( "FILENAME" ), context ); 95 : 0 : QgsExpressionContext expressionContext = createExpressionContext( parameters, context, input.get() ); 96 : : 97 : 0 : QSet< QString > fields; 98 : 0 : fields.insert( fieldName ); 99 : 0 : QgsFeatureRequest request; 100 : : 101 : 0 : QgsExpression filenameExpression( filenameExpressionString ); 102 : 0 : filenameExpression.prepare( &expressionContext ); 103 : 0 : fields.unite( filenameExpression.referencedColumns() ); 104 : 0 : request.setSubsetOfAttributes( fields, input->fields() ); 105 : 0 : if ( !filenameExpression.needsGeometry() ) 106 : 0 : request.setFlags( QgsFeatureRequest::NoGeometry ); 107 : : 108 : 0 : QgsFeatureIterator features = input->getFeatures( request, QgsProcessingFeatureSource::FlagSkipGeometryValidityChecks ); 109 : 0 : double step = input->featureCount() > 0 ? 100.0 / input->featureCount() : 1; 110 : 0 : int i = 0; 111 : 0 : QgsFeature feat; 112 : 0 : while ( features.nextFeature( feat ) ) 113 : : { 114 : 0 : i++; 115 : 0 : if ( feedback->isCanceled() ) 116 : : { 117 : 0 : break; 118 : : } 119 : : 120 : 0 : feedback->setProgress( i * step ); 121 : : 122 : 0 : QByteArray ba = feat.attribute( fieldIndex ).toByteArray(); 123 : 0 : if ( ba.isEmpty() ) 124 : 0 : continue; 125 : : 126 : 0 : expressionContext.setFeature( feat ); 127 : 0 : QString name = filenameExpression.evaluate( &expressionContext ).toString(); 128 : 0 : if ( filenameExpression.hasEvalError() ) 129 : : { 130 : 0 : feedback->reportError( QObject::tr( "Error evaluating filename: %1" ).arg( filenameExpression.evalErrorString() ) ); 131 : 0 : continue; 132 : : } 133 : : 134 : 0 : const QString path = dir.filePath( name ); 135 : 0 : QFile file( path ); 136 : 0 : if ( !file.open( QIODevice::WriteOnly | QFile::Truncate ) ) 137 : : { 138 : 0 : feedback->reportError( QObject::tr( "Could not open %1 for writing" ).arg( path ) ); 139 : 0 : } 140 : : else 141 : : { 142 : 0 : file.write( ba ); 143 : 0 : file.close(); 144 : 0 : feedback->pushInfo( QObject::tr( "Extracted %1" ).arg( path ) ); 145 : : } 146 : 0 : } 147 : : 148 : 0 : QVariantMap outputs; 149 : 0 : outputs.insert( QStringLiteral( "FOLDER" ), folder ); 150 : 0 : return outputs; 151 : 0 : } 152 : : 153 : : 154 : : ///@endcond