int main(int argc, char *argv[]) { const char *input, *source, *output; char *title; struct Cell_head cellhd; GDALDatasetH hDS; GDALRasterBandH hBand; struct GModule *module; struct { struct Option *input, *source, *output, *band, *title; } parm; struct { struct Flag *o, *f, *e, *r, *h, *v; } flag; int min_band, max_band, band; struct band_info info; int flip; struct Ref reference; G_gisinit(argv[0]); module = G_define_module(); G_add_keyword(_("raster")); G_add_keyword(_("import")); G_add_keyword(_("input")); G_add_keyword(_("external")); module->description = _("Links GDAL supported raster data as a pseudo GRASS raster map."); parm.input = G_define_standard_option(G_OPT_F_INPUT); parm.input->description = _("Name of raster file to be linked"); parm.input->required = NO; parm.input->guisection = _("Input"); parm.source = G_define_option(); parm.source->key = "source"; parm.source->description = _("Name of non-file GDAL data source"); parm.source->required = NO; parm.source->type = TYPE_STRING; parm.source->key_desc = "name"; parm.source->guisection = _("Input"); parm.output = G_define_standard_option(G_OPT_R_OUTPUT); parm.band = G_define_option(); parm.band->key = "band"; parm.band->type = TYPE_INTEGER; parm.band->required = NO; parm.band->description = _("Band to select (default: all)"); parm.band->guisection = _("Input"); parm.title = G_define_option(); parm.title->key = "title"; parm.title->key_desc = "phrase"; parm.title->type = TYPE_STRING; parm.title->required = NO; parm.title->description = _("Title for resultant raster map"); parm.title->guisection = _("Metadata"); flag.f = G_define_flag(); flag.f->key = 'f'; flag.f->description = _("List supported formats and exit"); flag.f->guisection = _("Print"); flag.f->suppress_required = YES; flag.o = G_define_flag(); flag.o->key = 'o'; flag.o->description = _("Override projection (use location's projection)"); flag.e = G_define_flag(); flag.e->key = 'e'; flag.e->description = _("Extend location extents based on new dataset"); flag.r = G_define_flag(); flag.r->key = 'r'; flag.r->description = _("Require exact range"); flag.h = G_define_flag(); flag.h->key = 'h'; flag.h->description = _("Flip horizontally"); flag.v = G_define_flag(); flag.v->key = 'v'; flag.v->description = _("Flip vertically"); if (G_parser(argc, argv)) exit(EXIT_FAILURE); GDALAllRegister(); if (flag.f->answer) { list_formats(); exit(EXIT_SUCCESS); } input = parm.input->answer; source = parm.source->answer; output = parm.output->answer; flip = 0; if (flag.h->answer) flip |= FLIP_H; if (flag.v->answer) flip |= FLIP_V; if (parm.title->answer) { title = G_store(parm.title->answer); G_strip(title); } else title = NULL; if (!input && !source) G_fatal_error(_("One of options <%s> or <%s> must be given"), parm.input->key, parm.source->key); if (input && source) G_fatal_error(_("Option <%s> and <%s> are mutually exclusive"), parm.input->key, parm.source->key); if (input && !G_is_absolute_path(input)) { char path[GPATH_MAX]; getcwd(path, sizeof(path)); strcat(path, "/"); strcat(path, input); input = G_store(path); } if (!input) input = source; hDS = GDALOpen(input, GA_ReadOnly); if (hDS == NULL) return 1; setup_window(&cellhd, hDS, &flip); check_projection(&cellhd, hDS, flag.o->answer); Rast_set_window(&cellhd); if (parm.band->answer) min_band = max_band = atoi(parm.band->answer); else min_band = 1, max_band = GDALGetRasterCount(hDS); G_verbose_message(_("Proceeding with import...")); if (max_band > min_band) { if (I_find_group(output) == 1) G_warning(_("Imagery group <%s> already exists and will be overwritten."), output); I_init_group_ref(&reference); } for (band = min_band; band <= max_band; band++) { char *output2, *title2 = NULL; G_message(_("Reading band %d of %d..."), band, GDALGetRasterCount( hDS )); hBand = GDALGetRasterBand(hDS, band); if (!hBand) G_fatal_error(_("Selected band (%d) does not exist"), band); if (max_band > min_band) { G_asprintf(&output2, "%s.%d", output, band); if (title) G_asprintf(&title2, "%s (band %d)", title, band); G_debug(1, "Adding raster map <%s> to group <%s>", output2, output); I_add_file_to_group_ref(output2, G_mapset(), &reference); } else { output2 = G_store(output); if (title) title2 = G_store(title); } query_band(hBand, output2, flag.r->answer, &cellhd, &info); create_map(input, band, output2, &cellhd, &info, title, flip); G_free(output2); G_free(title2); } if (flag.e->answer) update_default_window(&cellhd); /* Create the imagery group if multiple bands are imported */ if (max_band > min_band) { I_put_group_ref(output, &reference); I_put_group(output); G_message(_("Imagery group <%s> created"), output); } exit(EXIT_SUCCESS); }
bool QgsGrassRasterImport::import() { QgsDebugMsg( "entered" ); if ( !mPipe ) { setError( "Pipe is null." ); return false; } QgsRasterDataProvider * provider = mPipe->provider(); if ( !provider ) { setError( "Pipe has no provider." ); return false; } if ( !provider->isValid() ) { setError( "Provider is not valid." ); return false; } int redBand = 0; int greenBand = 0; int blueBand = 0; for ( int band = 1; band <= provider->bandCount(); band++ ) { QgsDebugMsg( QString( "band = %1" ).arg( band ) ); int colorInterpretation = provider->colorInterpretation( band ); if ( colorInterpretation == QgsRaster::RedBand ) { redBand = band; } else if ( colorInterpretation == QgsRaster::GreenBand ) { greenBand = band; } else if ( colorInterpretation == QgsRaster::BlueBand ) { blueBand = band; } QGis::DataType qgis_out_type = QGis::UnknownDataType; RASTER_MAP_TYPE data_type = -1; switch ( provider->dataType( band ) ) { case QGis::Byte: case QGis::UInt16: case QGis::Int16: case QGis::UInt32: case QGis::Int32: qgis_out_type = QGis::Int32; break; case QGis::Float32: qgis_out_type = QGis::Float32; break; case QGis::Float64: qgis_out_type = QGis::Float64; break; case QGis::ARGB32: case QGis::ARGB32_Premultiplied: qgis_out_type = QGis::Int32; // split to multiple bands? break; case QGis::CInt16: case QGis::CInt32: case QGis::CFloat32: case QGis::CFloat64: case QGis::UnknownDataType: setError( tr( "Data type %1 not supported" ).arg( provider->dataType( band ) ) ); return false; } QgsDebugMsg( QString( "data_type = %1" ).arg( data_type ) ); QString module = QgsGrass::qgisGrassModulePath() + "/qgis.r.in"; QStringList arguments; QString name = mGrassObject.name(); if ( provider->bandCount() > 1 ) { // raster.<band> to keep in sync with r.in.gdal name += QString( ".%1" ).arg( band ); } arguments.append( "output=" + name ); // get list of all output names QTemporaryFile gisrcFile; QProcess* process = 0; try { process = QgsGrass::startModule( mGrassObject.gisdbase(), mGrassObject.location(), mGrassObject.mapset(), module, arguments, gisrcFile ); } catch ( QgsGrass::Exception &e ) { setError( e.what() ); return false; } QDataStream outStream( process ); outStream << mExtent << ( qint32 )mXSize << ( qint32 )mYSize; outStream << ( qint32 )qgis_out_type; // calculate reasonable block size (5MB) int maximumTileHeight = 5000000 / mXSize; maximumTileHeight = std::max( 1, maximumTileHeight ); // smaller if reprojecting so that it can be canceled quickly if ( mPipe->projector() ) { maximumTileHeight = std::max( 1, 100000 / mXSize ); } QgsRasterIterator iter( mPipe->last() ); iter.setMaximumTileWidth( mXSize ); iter.setMaximumTileHeight( maximumTileHeight ); iter.startRasterRead( band, mXSize, mYSize, mExtent ); int iterLeft = 0; int iterTop = 0; int iterCols = 0; int iterRows = 0; QgsRasterBlock* block = 0; process->setReadChannel( QProcess::StandardOutput ); while ( iter.readNextRasterPart( band, iterCols, iterRows, &block, iterLeft, iterTop ) ) { for ( int row = 0; row < iterRows; row++ ) { if ( !block->convert( qgis_out_type ) ) { setError( tr( "Cannot convert block (%1) to data type %2" ).arg( block->toString() ).arg( qgis_out_type ) ); delete block; return false; } // prepare null values double noDataValue; if ( block->hasNoDataValue() ) { noDataValue = block->noDataValue(); } else { switch ( qgis_out_type ) { case QGis::Int32: noDataValue = -2147483648.0; break; case QGis::Float32: noDataValue = std::numeric_limits<float>::max() * -1.0; break; case QGis::Float64: noDataValue = std::numeric_limits<double>::max() * -1.0; break; default: // should not happen noDataValue = std::numeric_limits<double>::max() * -1.0; } for ( qgssize i = 0; i < ( qgssize )block->width()*block->height(); i++ ) { if ( block->isNoData( i ) ) { block->setValue( i, noDataValue ); } } } char * data = block->bits( row, 0 ); int size = iterCols * block->dataTypeSize(); QByteArray byteArray = QByteArray::fromRawData( data, size ); // does not copy data and does not take ownership if ( isCanceled() ) { outStream << true; // cancel module break; } outStream << false; // not canceled outStream << noDataValue; outStream << byteArray; // Without waitForBytesWritten() it does not finish ok on Windows (process timeout) process->waitForBytesWritten( -1 ); #ifndef Q_OS_WIN // wait until the row is written to allow quick cancel (don't send data to buffer) process->waitForReadyRead(); bool result; outStream >> result; #endif } delete block; if ( isCanceled() ) { outStream << true; // cancel module break; } } // TODO: send something back from module and read it here to close map correctly in module process->closeWriteChannel(); // TODO: best timeout? process->waitForFinished( 30000 ); QString stdoutString = process->readAllStandardOutput().data(); QString stderrString = process->readAllStandardError().data(); QString processResult = QString( "exitStatus=%1, exitCode=%2, error=%3, errorString=%4 stdout=%5, stderr=%6" ) .arg( process->exitStatus() ).arg( process->exitCode() ) .arg( process->error() ).arg( process->errorString() ) .arg( stdoutString.replace( "\n", ", " ) ).arg( stderrString.replace( "\n", ", " ) ); QgsDebugMsg( "processResult: " + processResult ); if ( process->exitStatus() != QProcess::NormalExit ) { setError( process->errorString() ); delete process; return false; } if ( process->exitCode() != 0 ) { setError( stderrString ); delete process; return false; } delete process; } QgsDebugMsg( QString( "redBand = %1 greenBand = %2 blueBand = %3" ).arg( redBand ).arg( greenBand ).arg( blueBand ) ); if ( redBand > 0 && greenBand > 0 && blueBand > 0 ) { // TODO: check if the group exists // I_find_group() QString name = mGrassObject.name(); G_TRY { QgsGrass::setMapset( mGrassObject.gisdbase(), mGrassObject.location(), mGrassObject.mapset() ); struct Ref ref; I_get_group_ref( name.toUtf8().data(), &ref ); QString redName = name + QString( ".%1" ).arg( redBand ); QString greenName = name + QString( ".%1" ).arg( greenBand ); QString blueName = name + QString( ".%1" ).arg( blueBand ); I_add_file_to_group_ref( redName.toUtf8().data(), mGrassObject.mapset().toUtf8().data(), &ref ); I_add_file_to_group_ref( greenName.toUtf8().data(), mGrassObject.mapset().toUtf8().data(), &ref ); I_add_file_to_group_ref( blueName.toUtf8().data(), mGrassObject.mapset().toUtf8().data(), &ref ); I_put_group_ref( name.toUtf8().data(), &ref ); } G_CATCH( QgsGrass::Exception &e ) { QgsDebugMsg( QString( "Cannot create group: %1" ).arg( e.what() ) ); }