QGIS API Documentation  3.8.0-Zanzibar (11aff65)
qgsalgorithmextractbinary.cpp
Go to the documentation of this file.
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 
19 #include "qgsfeaturerequest.h"
20 
22 
23 QString QgsExtractBinaryFieldAlgorithm::name() const
24 {
25  return QStringLiteral( "extractbinary" );
26 }
27 
28 QString QgsExtractBinaryFieldAlgorithm::displayName() const
29 {
30  return QObject::tr( "Extract binary field" );
31 }
32 
33 QString QgsExtractBinaryFieldAlgorithm::shortHelpString() const
34 {
35  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 QString QgsExtractBinaryFieldAlgorithm::shortDescription() const
41 {
42  return QObject::tr( "This algorithm extracts contents from a binary field, saving them to individual files." );
43 }
44 
45 QStringList QgsExtractBinaryFieldAlgorithm::tags() const
46 {
47  return QObject::tr( "blob,binaries,save,file,contents,field,column" ).split( ',' );
48 }
49 
50 QString QgsExtractBinaryFieldAlgorithm::group() const
51 {
52  return QObject::tr( "Vector table" );
53 }
54 
55 QString QgsExtractBinaryFieldAlgorithm::groupId() const
56 {
57  return QStringLiteral( "vectortable" );
58 }
59 
60 QgsExtractBinaryFieldAlgorithm *QgsExtractBinaryFieldAlgorithm::createInstance() const
61 {
62  return new QgsExtractBinaryFieldAlgorithm();
63 }
64 
65 void QgsExtractBinaryFieldAlgorithm::initAlgorithm( const QVariantMap & )
66 {
67  addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ),
68  QObject::tr( "Input layer" ), QList< int>() << QgsProcessing::TypeVector ) );
69 
70  addParameter( new QgsProcessingParameterField( QStringLiteral( "FIELD" ), QObject::tr( "Binary field" ), QVariant(),
71  QStringLiteral( "INPUT" ), QgsProcessingParameterField::Any ) );
72 
73  addParameter( new QgsProcessingParameterExpression( QStringLiteral( "FILENAME" ), QObject::tr( "File name" ), QVariant(), QStringLiteral( "INPUT" ) ) );
74 
75  addParameter( new QgsProcessingParameterFolderDestination( QStringLiteral( "FOLDER" ), QObject::tr( "Destination folder" ) ) );
76 }
77 
78 QVariantMap QgsExtractBinaryFieldAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
79 {
80  std::unique_ptr< QgsProcessingFeatureSource > input( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
81  if ( !input )
82  throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) );
83 
84  QString fieldName = parameterAsString( parameters, QStringLiteral( "FIELD" ), context );
85  int fieldIndex = input->fields().lookupField( fieldName );
86  if ( fieldIndex < 0 )
87  throw QgsProcessingException( QObject::tr( "Invalid binary field" ) );
88 
89  const QString folder = parameterAsString( parameters, QStringLiteral( "FOLDER" ), context );
90  if ( !QFileInfo::exists( folder ) )
91  throw QgsProcessingException( QObject::tr( "Destination folder %1 does not exist" ).arg( folder ) );
92 
93  QDir dir( folder );
94  const QString filenameExpressionString = parameterAsString( parameters, QStringLiteral( "FILENAME" ), context );
95  QgsExpressionContext expressionContext = createExpressionContext( parameters, context, input.get() );
96 
97  QSet< QString > fields;
98  fields.insert( fieldName );
99  QgsFeatureRequest request;
100 
101  QgsExpression filenameExpression( filenameExpressionString );
102  filenameExpression.prepare( &expressionContext );
103  fields.unite( filenameExpression.referencedColumns() );
104  request.setSubsetOfAttributes( fields, input->fields() );
105  if ( !filenameExpression.needsGeometry() )
107 
108  QgsFeatureIterator features = input->getFeatures( request, QgsProcessingFeatureSource::FlagSkipGeometryValidityChecks );
109  double step = input->featureCount() > 0 ? 100.0 / input->featureCount() : 1;
110  int i = 0;
111  QgsFeature feat;
112  while ( features.nextFeature( feat ) )
113  {
114  i++;
115  if ( feedback->isCanceled() )
116  {
117  break;
118  }
119 
120  feedback->setProgress( i * step );
121 
122  QByteArray ba = feat.attribute( fieldIndex ).toByteArray();
123  if ( ba.isEmpty() )
124  continue;
125 
126  expressionContext.setFeature( feat );
127  QString name = filenameExpression.evaluate( &expressionContext ).toString();
128  if ( filenameExpression.hasEvalError() )
129  {
130  feedback->reportError( QObject::tr( "Error evaluating filename: %1" ).arg( filenameExpression.evalErrorString() ) );
131  continue;
132  }
133 
134  const QString path = dir.filePath( name );
135  QFile file( path );
136  if ( !file.open( QIODevice::WriteOnly | QFile::Truncate ) )
137  {
138  feedback->reportError( QObject::tr( "Could not open %1 for writing" ).arg( path ) );
139  }
140  else
141  {
142  file.write( ba );
143  file.close();
144  feedback->pushInfo( QObject::tr( "Extracted %1" ).arg( path ) );
145  }
146  }
147 
148  QVariantMap outputs;
149  outputs.insert( QStringLiteral( "FOLDER" ), folder );
150  return outputs;
151 }
152 
153 
Class for parsing and evaluation of expressions (formerly called "search strings").
Wrapper for iterator of features from vector data provider or vector layer.
Base class for providing feedback from a processing algorithm.
Invalid geometry checks should always be skipped. This flag can be useful for algorithms which always...
A vector layer or feature source field parameter for processing algorithms.
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
An expression parameter for processing algorithms.
void setProgress(double progress)
Sets the current progress for the feedback object.
Definition: qgsfeedback.h:63
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:55
virtual void pushInfo(const QString &info)
Pushes a general informational message from the algorithm.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
This class wraps a request for features to a vector layer (or directly its vector data provider)...
Custom exception class for processing related exceptions.
Definition: qgsexception.h:82
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:54
An input feature source (such as vector layers) parameter for processing algorithms.
A folder destination parameter, for specifying the destination path for a folder created by the algor...
Tables (i.e. vector layers with or without geometry). When used for a sink this indicates the sink ha...
Definition: qgsprocessing.h:53
virtual void reportError(const QString &error, bool fatalError=false)
Reports that the algorithm encountered an error while executing.
bool nextFeature(QgsFeature &f)
Geometry is not required. It may still be returned if e.g. required for a filter condition.
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
Definition: qgsfeature.cpp:262
Contains information about the context in which a processing algorithm is executed.
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Sets flags that affect how features will be fetched.