QGIS API Documentation  3.23.0-Master (7c4a6de034)
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  const QString fieldName = parameterAsString( parameters, QStringLiteral( "FIELD" ), context );
85  const 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  const 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  const 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  const QByteArray ba = feat.attribute( fieldIndex ).toByteArray();
123  if ( ba.isEmpty() )
124  continue;
125 
126  expressionContext.setFeature( feat );
127  const 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 
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
Class for parsing and evaluation of expressions (formerly called "search strings").
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
This class wraps a request for features to a vector layer (or directly its vector data provider).
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Sets flags that affect how features will be fetched.
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:56
QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
Definition: qgsfeature.cpp:320
bool isCanceled() const SIP_HOLDGIL
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:54
void setProgress(double progress)
Sets the current progress for the feedback object.
Definition: qgsfeedback.h:63
Contains information about the context in which a processing algorithm is executed.
Custom exception class for processing related exceptions.
Definition: qgsexception.h:83
@ FlagSkipGeometryValidityChecks
Invalid geometry checks should always be skipped. This flag can be useful for algorithms which always...
Base class for providing feedback from a processing algorithm.
virtual void pushInfo(const QString &info)
Pushes a general informational message from the algorithm.
virtual void reportError(const QString &error, bool fatalError=false)
Reports that the algorithm encountered an error while executing.
An expression parameter for processing algorithms.
An input feature source (such as vector layers) parameter for processing algorithms.
A vector layer or feature source field parameter for processing algorithms.
A folder destination parameter, for specifying the destination path for a folder created by the algor...
@ TypeVector
Tables (i.e. vector layers with or without geometry). When used for a sink this indicates the sink ha...
Definition: qgsprocessing.h:54