Skip to content

Commit e80c31e

Browse files
committed
[FEATURE][processing] New algorithm for extracting binary blobs from fields
Allows users to extract binary fields to files. The filename is set via a data defined expression, so can be taken from a column value or a more complex expression.
1 parent 5c27b7d commit e80c31e

File tree

4 files changed

+217
-0
lines changed

4 files changed

+217
-0
lines changed

src/analysis/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ SET(QGIS_ANALYSIS_SRCS
4141
processing/qgsalgorithmexplodehstore.cpp
4242
processing/qgsalgorithmextendlines.cpp
4343
processing/qgsalgorithmextenttolayer.cpp
44+
processing/qgsalgorithmextractbinary.cpp
4445
processing/qgsalgorithmextractbyattribute.cpp
4546
processing/qgsalgorithmextractbyexpression.cpp
4647
processing/qgsalgorithmextractbyextent.cpp
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
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+
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." );
36+
}
37+
38+
QString QgsExtractBinaryFieldAlgorithm::shortDescription() const
39+
{
40+
return QObject::tr( "This algorithm extracts contents from a binary field, saving them to individual files." );
41+
}
42+
43+
QStringList QgsExtractBinaryFieldAlgorithm::tags() const
44+
{
45+
return QObject::tr( "blob,binaries,save,file,contents,field,column" ).split( ',' );
46+
}
47+
48+
QString QgsExtractBinaryFieldAlgorithm::group() const
49+
{
50+
return QObject::tr( "Vector table" );
51+
}
52+
53+
QString QgsExtractBinaryFieldAlgorithm::groupId() const
54+
{
55+
return QStringLiteral( "vectortable" );
56+
}
57+
58+
QgsExtractBinaryFieldAlgorithm *QgsExtractBinaryFieldAlgorithm::createInstance() const
59+
{
60+
return new QgsExtractBinaryFieldAlgorithm();
61+
}
62+
63+
void QgsExtractBinaryFieldAlgorithm::initAlgorithm( const QVariantMap & )
64+
{
65+
addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ),
66+
QObject::tr( "Input layer" ), QList< int>() << QgsProcessing::TypeVector ) );
67+
68+
addParameter( new QgsProcessingParameterField( QStringLiteral( "FIELD" ), QObject::tr( "Binary field" ), QVariant(),
69+
QStringLiteral( "INPUT" ), QgsProcessingParameterField::Any ) );
70+
71+
std::unique_ptr< QgsProcessingParameterString > fileNameParam = qgis::make_unique< QgsProcessingParameterString >( QStringLiteral( "FILENAME" ), QObject::tr( "File name" ) );
72+
fileNameParam->setIsDynamic( true );
73+
fileNameParam->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "Filename" ), QObject::tr( "File name" ), QgsPropertyDefinition::String ) );
74+
fileNameParam->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) );
75+
addParameter( fileNameParam.release() );
76+
77+
addParameter( new QgsProcessingParameterFolderDestination( QStringLiteral( "FOLDER" ), QObject::tr( "Destination folder" ) ) );
78+
}
79+
80+
QVariantMap QgsExtractBinaryFieldAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
81+
{
82+
std::unique_ptr< QgsProcessingFeatureSource > input( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
83+
if ( !input )
84+
throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) );
85+
86+
QString fieldName = parameterAsString( parameters, QStringLiteral( "FIELD" ), context );
87+
int fieldIndex = input->fields().lookupField( fieldName );
88+
if ( fieldIndex < 0 )
89+
throw QgsProcessingException( QObject::tr( "Invalid binary field" ) );
90+
91+
const QString folder = parameterAsString( parameters, QStringLiteral( "FOLDER" ), context );
92+
if ( !QFileInfo::exists( folder ) )
93+
throw QgsProcessingException( QObject::tr( "Destination folder %1 does not exist" ).arg( folder ) );
94+
95+
QDir dir( folder );
96+
const QString filename = parameterAsString( parameters, QStringLiteral( "FILENAME" ), context );
97+
bool dynamicFilename = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "FILENAME" ) );
98+
QgsExpressionContext expressionContext = createExpressionContext( parameters, context, input.get() );
99+
QgsProperty filenameProperty;
100+
101+
QSet< QString > fields;
102+
fields.insert( fieldName );
103+
QgsFeatureRequest request;
104+
if ( dynamicFilename )
105+
{
106+
filenameProperty = parameters.value( QStringLiteral( "FILENAME" ) ).value< QgsProperty >();
107+
filenameProperty.prepare( expressionContext );
108+
fields.unite( filenameProperty.referencedFields() );
109+
}
110+
request.setSubsetOfAttributes( fields, input->fields() ).setFlags( QgsFeatureRequest::NoGeometry );
111+
QgsFeatureIterator features = input->getFeatures( request, QgsProcessingFeatureSource::FlagSkipGeometryValidityChecks );
112+
double step = input->featureCount() > 0 ? 100.0 / input->featureCount() : 1;
113+
int i = 0;
114+
QgsFeature feat;
115+
while ( features.nextFeature( feat ) )
116+
{
117+
i++;
118+
if ( feedback->isCanceled() )
119+
{
120+
break;
121+
}
122+
123+
feedback->setProgress( i * step );
124+
125+
QByteArray ba = feat.attribute( fieldIndex ).toByteArray();
126+
if ( ba.isEmpty() )
127+
continue;
128+
129+
QString name = filename;
130+
if ( dynamicFilename )
131+
{
132+
expressionContext.setFeature( feat );
133+
name = filenameProperty.valueAsString( expressionContext, name );
134+
}
135+
136+
const QString path = dir.filePath( name );
137+
QFile file( path );
138+
if ( !file.open( QIODevice::WriteOnly | QFile::Truncate ) )
139+
{
140+
feedback->reportError( QObject::tr( "Could not open %1 for writing" ).arg( path ) );
141+
}
142+
else
143+
{
144+
file.write( ba );
145+
file.close();
146+
feedback->pushInfo( QObject::tr( "Extracted %1" ).arg( path ) );
147+
}
148+
}
149+
150+
QVariantMap outputs;
151+
outputs.insert( QStringLiteral( "FOLDER" ), folder );
152+
return outputs;
153+
}
154+
155+
156+
///@endcond
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/***************************************************************************
2+
qgsalgorithmextractbinary.h
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+
#ifndef QGSALGORITHMEXTRACTBINARY_H
19+
#define QGSALGORITHMEXTRACTBINARY_H
20+
21+
#define SIP_NO_FILE
22+
23+
#include "qgis.h"
24+
#include "qgsprocessingalgorithm.h"
25+
26+
///@cond PRIVATE
27+
28+
/**
29+
* Native extract binary field algorithm.
30+
*/
31+
class QgsExtractBinaryFieldAlgorithm : public QgsProcessingAlgorithm
32+
{
33+
34+
public:
35+
36+
QgsExtractBinaryFieldAlgorithm() = default;
37+
QString name() const override;
38+
QString displayName() const override;
39+
QStringList tags() const override;
40+
QString group() const override;
41+
QString groupId() const override;
42+
QString shortHelpString() const override;
43+
QString shortDescription() const override;
44+
void initAlgorithm( const QVariantMap &configuration = QVariantMap() ) override;
45+
QgsExtractBinaryFieldAlgorithm *createInstance() const override SIP_FACTORY;
46+
47+
protected:
48+
49+
QVariantMap processAlgorithm( const QVariantMap &parameters,
50+
QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
51+
52+
};
53+
54+
///@endcond PRIVATE
55+
56+
#endif // QGSALGORITHMEXTRACTBINARY_H
57+
58+

src/analysis/processing/qgsnativealgorithms.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include "qgsalgorithmexplodehstore.h"
3737
#include "qgsalgorithmextendlines.h"
3838
#include "qgsalgorithmextenttolayer.h"
39+
#include "qgsalgorithmextractbinary.h"
3940
#include "qgsalgorithmextractbyattribute.h"
4041
#include "qgsalgorithmextractbyexpression.h"
4142
#include "qgsalgorithmextractbyextent.h"
@@ -163,6 +164,7 @@ void QgsNativeAlgorithms::loadAlgorithms()
163164
addAlgorithm( new QgsExplodeHstoreAlgorithm() );
164165
addAlgorithm( new QgsExtendLinesAlgorithm() );
165166
addAlgorithm( new QgsExtentToLayerAlgorithm() );
167+
addAlgorithm( new QgsExtractBinaryFieldAlgorithm() );
166168
addAlgorithm( new QgsExtractByAttributeAlgorithm() );
167169
addAlgorithm( new QgsExtractByExpressionAlgorithm() );
168170
addAlgorithm( new QgsExtractByExtentAlgorithm() );

0 commit comments

Comments
 (0)