mirror of
https://github.com/google/sandboxed-api.git
synced 2024-03-22 13:11:30 +08:00
Raster to GTiff workflow implementation
Implemented simple GTiff file parser to test sandboxed part of code on a real data, added unit tests. Need to improve the CMake file to make it work without specifying the absolute paths to libraries.
This commit is contained in:
parent
0b1951ea4c
commit
b06d020f32
2
.gitmodules
vendored
2
.gitmodules
vendored
|
@ -9,4 +9,4 @@
|
|||
url = https://github.com/curl/curl
|
||||
[submodule "oss-internship-2020/gdal/gdal"]
|
||||
path = oss-internship-2020/gdal/gdal
|
||||
url = https://github.com/OSGeo/gdal/tree/master/gdal
|
||||
url = https://github.com/OSGeo/gdal/
|
||||
|
|
103
oss-internship-2020/gdal/raster_to_gtiff/CMakeLists.txt
Normal file
103
oss-internship-2020/gdal/raster_to_gtiff/CMakeLists.txt
Normal file
|
@ -0,0 +1,103 @@
|
|||
# Copyright 2020 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
project(GDALSandbox CXX C)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED True)
|
||||
|
||||
set(SAPI_ROOT "" CACHE PATH "Path to the Sandboxed API source tree")
|
||||
# cmake .. -G Ninja -DSAPI_ROOT=$HOME/sapi_root
|
||||
|
||||
set(SAPI_ENABLE_EXAMPLES OFF CACHE BOOL "")
|
||||
set(SAPI_ENABLE_TESTS OFF CACHE BOOL "")
|
||||
add_subdirectory("${SAPI_ROOT}"
|
||||
"${CMAKE_BINARY_DIR}/sandboxed-api-build"
|
||||
# Omit this to have the full Sandboxed API in IDE
|
||||
EXCLUDE_FROM_ALL)
|
||||
|
||||
add_library(libgdal STATIC IMPORTED)
|
||||
set_property(TARGET libgdal PROPERTY IMPORTED_LOCATION
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/lib/libgdal.a")
|
||||
|
||||
|
||||
# TODO: Build PROJ statically and link it as gdal
|
||||
# TODO: Use environment variables to specify path prefix to libproj and gdal header
|
||||
# TODO: Add environment variable to enable tests
|
||||
|
||||
target_link_libraries(libgdal INTERFACE
|
||||
crypto expat jpeg
|
||||
/usr/local/lib/libproj.so
|
||||
sqlite3 tiff z pthread m rt dl curl)
|
||||
|
||||
add_sapi_library(gdal_sapi
|
||||
FUNCTIONS
|
||||
GDALOpen
|
||||
GDALAllRegister
|
||||
GDALGetDatasetDriver
|
||||
GDALCreate
|
||||
GDALGetDriverByName
|
||||
GDALGetRasterBand
|
||||
GDALSetRasterColorInterpretation
|
||||
GDALSetProjection
|
||||
GDALSetGeoTransform
|
||||
GDALSetRasterNoDataValue
|
||||
GDALRasterIO
|
||||
GDALClose
|
||||
|
||||
INPUTS "../gdal/gdal/gcore/gdal.h"
|
||||
LIBRARY libgdal
|
||||
LIBRARY_NAME gdal
|
||||
|
||||
NAMESPACE "gdal::sandbox"
|
||||
)
|
||||
|
||||
target_include_directories(gdal_sapi INTERFACE
|
||||
"${PROJECT_BINARY_DIR}"
|
||||
)
|
||||
|
||||
add_library(data_retriever STATIC
|
||||
get_raster_data.h get_raster_data.cc
|
||||
)
|
||||
|
||||
target_link_libraries(data_retriever
|
||||
libgdal
|
||||
)
|
||||
|
||||
add_executable(raster_to_gtiff
|
||||
raster_to_gtiff.cc
|
||||
)
|
||||
|
||||
target_link_libraries(raster_to_gtiff
|
||||
data_retriever
|
||||
gdal_sapi
|
||||
sapi::sapi
|
||||
)
|
||||
|
||||
find_package(GTest REQUIRED)
|
||||
include_directories(${GTEST_INCLUDE_DIRS})
|
||||
|
||||
add_executable(tests tests.cc)
|
||||
target_link_libraries(tests
|
||||
PRIVATE
|
||||
gdal_sapi
|
||||
data_retriever
|
||||
sapi::sapi
|
||||
sandbox2::temp_file
|
||||
sandbox2::fileops
|
||||
${GTEST_LIBRARIES}
|
||||
${GTEST_MAIN_LIBRARIES}
|
||||
)
|
0
oss-internship-2020/gdal/raster_to_gtiff/README.md
Normal file
0
oss-internship-2020/gdal/raster_to_gtiff/README.md
Normal file
67
oss-internship-2020/gdal/raster_to_gtiff/gdal_sandbox.h
Normal file
67
oss-internship-2020/gdal/raster_to_gtiff/gdal_sandbox.h
Normal file
|
@ -0,0 +1,67 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef GDAL_SANDBOX_H_
|
||||
#define GDAL_SANDBOX_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <syscall.h>
|
||||
|
||||
#include "gdal_sapi.sapi.h"
|
||||
#include "sandboxed_api/sandbox2/util/fileops.h"
|
||||
|
||||
namespace gdal::sandbox {
|
||||
|
||||
class GdalSapiSandbox : public gdalSandbox {
|
||||
public:
|
||||
GdalSapiSandbox(std::string path)
|
||||
: gdalSandbox(),
|
||||
path_(std::move(path))
|
||||
{}
|
||||
|
||||
std::unique_ptr<sandbox2::Policy> ModifyPolicy(
|
||||
sandbox2::PolicyBuilder*) override {
|
||||
|
||||
return sandbox2::PolicyBuilder()
|
||||
.AllowDynamicStartup()
|
||||
.AllowRead()
|
||||
.AllowSystemMalloc()
|
||||
.AllowWrite()
|
||||
.AllowExit()
|
||||
.AllowOpen()
|
||||
.AllowSyscalls({
|
||||
__NR_futex,
|
||||
__NR_getdents64, // DriverRegisterAll()
|
||||
__NR_lseek, // GDALCreate()
|
||||
__NR_getpid, // GDALCreate()
|
||||
__NR_sysinfo, // VSI_TIFFOpen_common()
|
||||
__NR_prlimit64, // CPLGetUsablePhysicalRAM()
|
||||
__NR_ftruncate, // GTiffDataset::FillEmptyTiles()
|
||||
__NR_unlink, // GDALDriver::Delete()
|
||||
})
|
||||
// TODO: Deal with proj.db so you don't need to specify exact path ih the policy
|
||||
.AddFile("/usr/local/share/proj/proj.db") // proj.db is required
|
||||
.AddDirectory("/usr/local/lib") // To add libproj.so.19.1.1
|
||||
.AddDirectory(path_, /*is_ro=*/false)
|
||||
.BuildOrDie();
|
||||
}
|
||||
|
||||
private:
|
||||
std::string path_;
|
||||
};
|
||||
|
||||
} // namespace gdal::sandbox
|
||||
|
||||
#endif // GDAL_SANDBOX_H_
|
128
oss-internship-2020/gdal/raster_to_gtiff/get_raster_data.cc
Normal file
128
oss-internship-2020/gdal/raster_to_gtiff/get_raster_data.cc
Normal file
|
@ -0,0 +1,128 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "get_raster_data.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
|
||||
#include "gdal.h"
|
||||
|
||||
namespace gdal::sandbox::tests::parser {
|
||||
|
||||
namespace {
|
||||
|
||||
inline constexpr int kGeoTransformSize = 6;
|
||||
|
||||
void PrintInformationAboutDataset(GDALDatasetH dataset, GDALDriverH driver) {
|
||||
double adfGeoTransform[6];
|
||||
printf("Driver: %s/%s\n",
|
||||
GDALGetDriverShortName(driver),
|
||||
GDALGetDriverLongName(driver));
|
||||
printf("Size is %dx%dx%d\n",
|
||||
GDALGetRasterXSize(dataset),
|
||||
GDALGetRasterYSize(dataset),
|
||||
GDALGetRasterCount(dataset) );
|
||||
if(GDALGetProjectionRef(dataset) != NULL )
|
||||
printf("Projection is `%s'\n", GDALGetProjectionRef(dataset));
|
||||
if(GDALGetGeoTransform(dataset, adfGeoTransform) == CE_None)
|
||||
{
|
||||
printf("Origin = (%.6f,%.6f)\n",
|
||||
adfGeoTransform[0], adfGeoTransform[3]);
|
||||
printf("Pixel Size = (%.6f,%.6f)\n",
|
||||
adfGeoTransform[1], adfGeoTransform[5]);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
RasterDataset GetRasterBandsFromFile(const std::string& filename) {
|
||||
GDALAllRegister();
|
||||
GDALDatasetH dataset = GDALOpen(filename.data(), GA_ReadOnly);
|
||||
GDALDriverH driver = GDALGetDatasetDriver(dataset);
|
||||
|
||||
RasterDataset result_dataset = {
|
||||
GDALGetRasterXSize(dataset),
|
||||
GDALGetRasterYSize(dataset)
|
||||
};
|
||||
|
||||
if (GDALGetProjectionRef(dataset) != nullptr) {
|
||||
result_dataset.wkt_projection = std::string(GDALGetProjectionRef(dataset));
|
||||
}
|
||||
|
||||
std::vector<double> geo_transform(kGeoTransformSize, 0.0);
|
||||
|
||||
if (GDALGetGeoTransform(dataset, geo_transform.data()) == CE_None) {
|
||||
result_dataset.geo_transform = std::move(geo_transform);
|
||||
}
|
||||
|
||||
int bands_count = GDALGetRasterCount(dataset);
|
||||
|
||||
std::vector<RasterBandData> bands_data;
|
||||
bands_data.reserve(bands_count);
|
||||
|
||||
for (int i = 1; i <= bands_count; ++i) {
|
||||
GDALRasterBandH band = GDALGetRasterBand(dataset, i);
|
||||
int width = GDALGetRasterBandXSize(band);
|
||||
int height = GDALGetRasterBandYSize(band);
|
||||
|
||||
std::unique_ptr<int> no_data_result = nullptr;
|
||||
double no_data_value = GDALGetRasterNoDataValue(band, no_data_result.get());
|
||||
std::optional<double> no_data_value_holder =
|
||||
no_data_result.get() == nullptr ? std::nullopt
|
||||
: std::make_optional<double>(no_data_value);
|
||||
|
||||
int data_type = static_cast<int>(GDALGetRasterDataType(band));
|
||||
int color_interp = static_cast<int>(GDALGetRasterColorInterpretation(band));
|
||||
|
||||
// Use std::variant or void* and reinterpet casts for the runtime template deduction
|
||||
std::vector<int> band_raster_data;
|
||||
band_raster_data.resize(width * height);
|
||||
|
||||
// GDALRasterIO with GF_Read should use the same type (GDT_Int32)
|
||||
GDALRasterIO(band, GF_Read, 0, 0, width, height, band_raster_data.data(),
|
||||
width, height, GDT_Int32, 0, 0);
|
||||
|
||||
bands_data.push_back(
|
||||
{
|
||||
width,
|
||||
height,
|
||||
std::move(band_raster_data),
|
||||
data_type,
|
||||
color_interp,
|
||||
std::move(no_data_value_holder)
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
result_dataset.bands = std::move(bands_data);
|
||||
|
||||
return result_dataset;
|
||||
}
|
||||
|
||||
bool operator==(const RasterBandData& lhs, const RasterBandData& rhs) {
|
||||
return lhs.width == rhs.width && lhs.height == rhs.height
|
||||
&& lhs.data == rhs.data && lhs.data_type == rhs.data_type
|
||||
&& lhs.color_interp == rhs.color_interp
|
||||
&& lhs.no_data_value == rhs.no_data_value;
|
||||
}
|
||||
|
||||
bool operator==(const RasterDataset& lhs, const RasterDataset& rhs) {
|
||||
return lhs.width == rhs.width && lhs.height == rhs.height
|
||||
&& lhs.bands == rhs.bands
|
||||
&& lhs.wkt_projection == rhs.wkt_projection
|
||||
&& lhs.geo_transform == rhs.geo_transform;
|
||||
}
|
||||
|
||||
} // namespace gdal::sandbox::tests:parser
|
47
oss-internship-2020/gdal/raster_to_gtiff/get_raster_data.h
Normal file
47
oss-internship-2020/gdal/raster_to_gtiff/get_raster_data.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef GET_RASTER_DATA_H_
|
||||
#define GET_RASTER_DATA_H_
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace gdal::sandbox::tests::parser {
|
||||
|
||||
struct RasterBandData {
|
||||
int width;
|
||||
int height;
|
||||
std::vector<int> data;
|
||||
int data_type; // Corresponds to the GDALDataType enum
|
||||
int color_interp; // Corresponds to the
|
||||
std::optional<double> no_data_value;
|
||||
};
|
||||
|
||||
struct RasterDataset {
|
||||
int width;
|
||||
int height;
|
||||
std::vector<RasterBandData> bands;
|
||||
std::string wkt_projection; // OpenGIS WKT format
|
||||
std::vector<double> geo_transform;
|
||||
};
|
||||
|
||||
RasterDataset GetRasterBandsFromFile(const std::string& filename);
|
||||
bool operator==(const RasterBandData& lhs, const RasterBandData& rhs);
|
||||
bool operator==(const RasterDataset& lhs, const RasterDataset& rhs);
|
||||
|
||||
} // namespace gdal::sandbox::tests::parser
|
||||
|
||||
#endif // GET_RASTER_DATA_H
|
166
oss-internship-2020/gdal/raster_to_gtiff/raster_to_gtiff.cc
Normal file
166
oss-internship-2020/gdal/raster_to_gtiff/raster_to_gtiff.cc
Normal file
|
@ -0,0 +1,166 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <filesystem>
|
||||
|
||||
#include "sandboxed_api/sandbox2/util/fileops.h"
|
||||
|
||||
#include "gdal_sandbox.h"
|
||||
#include "get_raster_data.h"
|
||||
|
||||
namespace {
|
||||
|
||||
#define SAPI_FAIL_IF_NOT(x, y) \
|
||||
if (!(x)) { \
|
||||
return absl::FailedPreconditionError(y); \
|
||||
}
|
||||
|
||||
inline constexpr absl::string_view kDriverName = "GTiff";
|
||||
|
||||
absl::Status SaveToGTiff(gdal::sandbox::tests::parser::RasterDataset bands_data,
|
||||
std::string out_file) {
|
||||
using namespace gdal::sandbox;
|
||||
|
||||
std::string output_data_folder = "";
|
||||
|
||||
if (!sandbox2::file_util::fileops::RemoveLastPathComponent(out_file,
|
||||
&output_data_folder)) {
|
||||
return absl::FailedPreconditionError("Error getting output file directory");
|
||||
}
|
||||
|
||||
GdalSapiSandbox sandbox(output_data_folder);
|
||||
SAPI_RETURN_IF_ERROR(sandbox.Init());
|
||||
gdalApi api(&sandbox);
|
||||
SAPI_RETURN_IF_ERROR(api.GDALAllRegister());
|
||||
|
||||
sapi::v::ConstCStr driver_name_ptr(kDriverName.data());
|
||||
|
||||
SAPI_ASSIGN_OR_RETURN(sapi::StatusOr<GDALDriverH> driver,
|
||||
api.GDALGetDriverByName(driver_name_ptr.PtrBefore()));
|
||||
|
||||
SAPI_FAIL_IF_NOT(driver.value() != nullptr,
|
||||
"Error getting GTiff driver");
|
||||
sapi::v::RemotePtr driver_ptr(driver.value());
|
||||
|
||||
sapi::v::ConstCStr out_file_full_path_ptr(out_file.data());
|
||||
sapi::v::NullPtr create_options;
|
||||
|
||||
GDALDataType type = bands_data.bands.size() > 0 ?
|
||||
static_cast<GDALDataType>(bands_data.bands[0].data_type)
|
||||
: GDALDataType::GDT_Unknown;
|
||||
|
||||
SAPI_ASSIGN_OR_RETURN(sapi::StatusOr<GDALDatasetH> dataset,
|
||||
api.GDALCreate(&driver_ptr, out_file_full_path_ptr.PtrBefore(),
|
||||
bands_data.width, bands_data.height, bands_data.bands.size(), type,
|
||||
&create_options));
|
||||
|
||||
SAPI_FAIL_IF_NOT(dataset.value(),
|
||||
"Error creating dataset");
|
||||
sapi::v::RemotePtr dataset_ptr(dataset.value());
|
||||
|
||||
for (int i = 0; i < bands_data.bands.size(); ++i) {
|
||||
SAPI_ASSIGN_OR_RETURN(sapi::StatusOr<GDALRasterBandH> band,
|
||||
api.GDALGetRasterBand(&dataset_ptr, i + 1));
|
||||
SAPI_FAIL_IF_NOT(band.value() != nullptr,
|
||||
"Error getting band from dataset");
|
||||
sapi::v::RemotePtr band_ptr(band.value());
|
||||
|
||||
sapi::v::Array<int> data_array(bands_data.bands[i].data.data(),
|
||||
bands_data.bands[i].data.size());
|
||||
|
||||
SAPI_ASSIGN_OR_RETURN(sapi::StatusOr<CPLErr> result,
|
||||
api.GDALRasterIO(&band_ptr, GF_Write, 0, 0,
|
||||
bands_data.bands[i].width, bands_data.bands[i].height,
|
||||
data_array.PtrBefore(), bands_data.bands[i].width,
|
||||
bands_data.bands[i].height, GDALDataType::GDT_Int32, 0, 0));
|
||||
|
||||
SAPI_FAIL_IF_NOT(result.value() == CPLErr::CE_None,
|
||||
"Error writing band to dataset");
|
||||
|
||||
SAPI_ASSIGN_OR_RETURN(result, api.GDALSetRasterColorInterpretation(
|
||||
&band_ptr, static_cast<GDALColorInterp>(
|
||||
bands_data.bands[i].color_interp)));
|
||||
|
||||
SAPI_FAIL_IF_NOT(result.value() == CPLErr::CE_None,
|
||||
"Error setting color interpretation");
|
||||
|
||||
if (bands_data.bands[i].no_data_value.has_value()) {
|
||||
SAPI_ASSIGN_OR_RETURN(result,
|
||||
api.GDALSetRasterNoDataValue(&band_ptr,
|
||||
bands_data.bands[i].no_data_value.value()));
|
||||
|
||||
SAPI_FAIL_IF_NOT(result.value() == CPLErr::CE_None,
|
||||
"Error setting no data value for the band");
|
||||
}
|
||||
}
|
||||
|
||||
if (bands_data.wkt_projection.length() > 0) {
|
||||
sapi::v::ConstCStr wkt_projection_ptr(bands_data.wkt_projection.data());
|
||||
SAPI_ASSIGN_OR_RETURN(sapi::StatusOr<CPLErr> result,
|
||||
api.GDALSetProjection(&dataset_ptr, wkt_projection_ptr.PtrBefore()));
|
||||
SAPI_FAIL_IF_NOT(result.value() == CPLErr::CE_None,
|
||||
"Error setting wkt projection");
|
||||
}
|
||||
|
||||
if (bands_data.geo_transform.size() > 0) {
|
||||
sapi::v::Array<double> geo_transform_ptr(bands_data.geo_transform.data(),
|
||||
bands_data.geo_transform.size());
|
||||
SAPI_ASSIGN_OR_RETURN(sapi::StatusOr<CPLErr> result,
|
||||
api.GDALSetGeoTransform(&dataset_ptr, geo_transform_ptr.PtrBefore()));
|
||||
|
||||
SAPI_FAIL_IF_NOT(result.value() == CPLErr::CE_None,
|
||||
"Error setting geo transform");
|
||||
}
|
||||
|
||||
SAPI_RETURN_IF_ERROR(api.GDALClose(&dataset_ptr));
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
void Usage() {
|
||||
std::cerr << "Example application that converts raster data to GTiff"
|
||||
" format inside the sandbox. Usage:\n"
|
||||
"raster_to_gtiff input_filename output_filename\n"
|
||||
"output_filename must be absolute" << std::endl;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
using namespace gdal::sandbox;
|
||||
|
||||
if (argc < 3
|
||||
|| !std::filesystem::path(std::string(argv[2])).is_absolute()) {
|
||||
Usage();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
std::string input_data_path = std::string(argv[1]);
|
||||
std::string output_data_path = std::string(argv[2]);
|
||||
|
||||
tests::parser::RasterDataset bands_data
|
||||
= tests::parser::GetRasterBandsFromFile(std::move(input_data_path));
|
||||
|
||||
if (absl::Status status =
|
||||
SaveToGTiff(std::move(bands_data), std::move(output_data_path));
|
||||
!status.ok()) {
|
||||
std::cerr << status.ToString() << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
BIN
oss-internship-2020/gdal/raster_to_gtiff/testdata/earth_map.tif
vendored
Normal file
BIN
oss-internship-2020/gdal/raster_to_gtiff/testdata/earth_map.tif
vendored
Normal file
Binary file not shown.
BIN
oss-internship-2020/gdal/raster_to_gtiff/testdata/map.tif
vendored
Normal file
BIN
oss-internship-2020/gdal/raster_to_gtiff/testdata/map.tif
vendored
Normal file
Binary file not shown.
BIN
oss-internship-2020/gdal/raster_to_gtiff/testdata/map_large.tif
vendored
Normal file
BIN
oss-internship-2020/gdal/raster_to_gtiff/testdata/map_large.tif
vendored
Normal file
Binary file not shown.
224
oss-internship-2020/gdal/raster_to_gtiff/tests.cc
Normal file
224
oss-internship-2020/gdal/raster_to_gtiff/tests.cc
Normal file
|
@ -0,0 +1,224 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <iostream>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "sandboxed_api/transaction.h"
|
||||
#include "sandboxed_api/sandbox2/util/temp_file.h"
|
||||
#include "sandboxed_api/sandbox2/util/fileops.h"
|
||||
|
||||
#include "gdal_sandbox.h"
|
||||
#include "get_raster_data.h"
|
||||
|
||||
namespace gdal::sandbox::tests {
|
||||
namespace {
|
||||
|
||||
inline constexpr absl::string_view kDriverName = "GTiff";
|
||||
inline constexpr absl::string_view kTempFilePrefix = "temp_data";
|
||||
inline constexpr absl::string_view kFirstTestDataPath =
|
||||
"../testdata/map.tif";
|
||||
inline constexpr absl::string_view kSecondTestDataPath =
|
||||
"../testdata/map_large.tif";
|
||||
inline constexpr absl::string_view kThirdTestDataPath =
|
||||
"../testdata/earth_map.tif";
|
||||
|
||||
// RAII wrapper that creates temporary file and automatically unlinks it
|
||||
class TempFile {
|
||||
public:
|
||||
explicit TempFile(absl::string_view prefix)
|
||||
{
|
||||
auto file_data = sandbox2::CreateNamedTempFile(prefix);
|
||||
|
||||
if (file_data.ok()) {
|
||||
file_data_ = std::move(file_data.value());
|
||||
}
|
||||
}
|
||||
|
||||
~TempFile() {
|
||||
if (file_data_.has_value()) {
|
||||
unlink(file_data_.value().first.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
bool HasValue() const {
|
||||
return file_data_.has_value();
|
||||
}
|
||||
|
||||
int GetFd() const {
|
||||
return file_data_.value().second;
|
||||
}
|
||||
|
||||
std::string GetPath() const {
|
||||
return file_data_.value().first;
|
||||
}
|
||||
|
||||
private:
|
||||
std::optional<std::pair<std::string, int>> file_data_ = std::nullopt;
|
||||
};
|
||||
|
||||
// Wrapper around raster to GTiff workflow
|
||||
class RasterToGTiffProcessor : public sapi::Transaction {
|
||||
public:
|
||||
explicit RasterToGTiffProcessor(std::string out_filename,
|
||||
std::string out_path,
|
||||
parser::RasterDataset data,
|
||||
int retry_count = 0)
|
||||
: sapi::Transaction(std::make_unique<GdalSapiSandbox>(out_path)),
|
||||
out_filename_(std::move(out_filename)),
|
||||
out_path_(std::move(out_path)),
|
||||
data_(std::move(data))
|
||||
{
|
||||
set_retry_count(retry_count);
|
||||
SetTimeLimit(absl::InfiniteDuration());
|
||||
}
|
||||
|
||||
private:
|
||||
absl::Status Main() final;
|
||||
|
||||
const std::string out_filename_;
|
||||
const std::string out_path_;
|
||||
parser::RasterDataset data_;
|
||||
};
|
||||
|
||||
absl::Status RasterToGTiffProcessor::Main() {
|
||||
gdalApi api(sandbox());
|
||||
SAPI_RETURN_IF_ERROR(api.GDALAllRegister());
|
||||
|
||||
sapi::v::ConstCStr driver_name_ptr(kDriverName.data());
|
||||
|
||||
SAPI_ASSIGN_OR_RETURN(sapi::StatusOr<GDALDriverH> driver,
|
||||
api.GDALGetDriverByName(driver_name_ptr.PtrBefore()));
|
||||
|
||||
TRANSACTION_FAIL_IF_NOT(driver.value() != nullptr,
|
||||
"Error getting GTiff driver");
|
||||
sapi::v::RemotePtr driver_ptr(driver.value());
|
||||
|
||||
std::string out_file_full_path = absl::StrCat(out_path_, "/", out_filename_);
|
||||
sapi::v::ConstCStr out_file_full_path_ptr(out_file_full_path.data());
|
||||
sapi::v::NullPtr create_options;
|
||||
|
||||
GDALDataType type = data_.bands.size() > 0 ?
|
||||
static_cast<GDALDataType>(data_.bands[0].data_type)
|
||||
: GDALDataType::GDT_Unknown;
|
||||
|
||||
SAPI_ASSIGN_OR_RETURN(sapi::StatusOr<GDALDatasetH> dataset,
|
||||
api.GDALCreate(&driver_ptr, out_file_full_path_ptr.PtrBefore(),
|
||||
data_.width, data_.height, data_.bands.size(), type,
|
||||
&create_options));
|
||||
|
||||
TRANSACTION_FAIL_IF_NOT(dataset.value(),
|
||||
"Error creating dataset");
|
||||
sapi::v::RemotePtr dataset_ptr(dataset.value());
|
||||
|
||||
for (int i = 0; i < data_.bands.size(); ++i) {
|
||||
SAPI_ASSIGN_OR_RETURN(sapi::StatusOr<GDALRasterBandH> band,
|
||||
api.GDALGetRasterBand(&dataset_ptr, i + 1));
|
||||
TRANSACTION_FAIL_IF_NOT(band.value() != nullptr,
|
||||
"Error getting band from dataset");
|
||||
sapi::v::RemotePtr band_ptr(band.value());
|
||||
|
||||
sapi::v::Array<int> data_array(data_.bands[i].data.data(),
|
||||
data_.bands[i].data.size());
|
||||
|
||||
SAPI_ASSIGN_OR_RETURN(sapi::StatusOr<CPLErr> result,
|
||||
api.GDALRasterIO(&band_ptr, GF_Write, 0, 0,
|
||||
data_.bands[i].width, data_.bands[i].height, data_array.PtrBefore(),
|
||||
data_.bands[i].width, data_.bands[i].height, GDT_Int32, 0, 0));
|
||||
|
||||
TRANSACTION_FAIL_IF_NOT(result.value() == CPLErr::CE_None,
|
||||
"Error writing band to dataset");
|
||||
|
||||
SAPI_ASSIGN_OR_RETURN(result, api.GDALSetRasterColorInterpretation(
|
||||
&band_ptr, static_cast<GDALColorInterp>(
|
||||
data_.bands[i].color_interp)));
|
||||
|
||||
TRANSACTION_FAIL_IF_NOT(result.value() == CPLErr::CE_None,
|
||||
"Error setting color interpretation");
|
||||
|
||||
if (data_.bands[i].no_data_value.has_value()) {
|
||||
SAPI_ASSIGN_OR_RETURN(result,
|
||||
api.GDALSetRasterNoDataValue(&band_ptr,
|
||||
data_.bands[i].no_data_value.value()));
|
||||
|
||||
TRANSACTION_FAIL_IF_NOT(result.value() == CPLErr::CE_None,
|
||||
"Error setting no data value for the band");
|
||||
}
|
||||
}
|
||||
|
||||
if (data_.wkt_projection.length() > 0) {
|
||||
sapi::v::ConstCStr wkt_projection_ptr(data_.wkt_projection.data());
|
||||
SAPI_ASSIGN_OR_RETURN(sapi::StatusOr<CPLErr> result,
|
||||
api.GDALSetProjection(&dataset_ptr, wkt_projection_ptr.PtrBefore()));
|
||||
TRANSACTION_FAIL_IF_NOT(result.value() == CPLErr::CE_None,
|
||||
"Error setting wkt projection");
|
||||
}
|
||||
|
||||
if (data_.geo_transform.size() > 0) {
|
||||
sapi::v::Array<double> geo_transform_ptr(data_.geo_transform.data(),
|
||||
data_.geo_transform.size());
|
||||
SAPI_ASSIGN_OR_RETURN(sapi::StatusOr<CPLErr> result,
|
||||
api.GDALSetGeoTransform(&dataset_ptr, geo_transform_ptr.PtrBefore()));
|
||||
|
||||
TRANSACTION_FAIL_IF_NOT(result.value() == CPLErr::CE_None,
|
||||
"Error setting geo transform");
|
||||
}
|
||||
|
||||
SAPI_RETURN_IF_ERROR(api.GDALClose(&dataset_ptr));
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
class TestGTiffProcessor : public testing::TestWithParam<absl::string_view> {
|
||||
public:
|
||||
TestGTiffProcessor()
|
||||
: tempfile_(kTempFilePrefix)
|
||||
{}
|
||||
|
||||
protected:
|
||||
const TempFile tempfile_;
|
||||
};
|
||||
|
||||
TEST_P(TestGTiffProcessor, TestProcessorOnGTiffData) {
|
||||
std::string filename = std::string(GetParam());
|
||||
|
||||
ASSERT_TRUE(tempfile_.HasValue())
|
||||
<< "Error creating temporary output file";
|
||||
|
||||
parser::RasterDataset original_bands_data =
|
||||
parser::GetRasterBandsFromFile(filename);
|
||||
|
||||
RasterToGTiffProcessor processor(tempfile_.GetPath(),
|
||||
sandbox2::file_util::fileops::GetCWD(), original_bands_data);
|
||||
ASSERT_EQ(processor.Run(), absl::OkStatus())
|
||||
<< "Error creating new GTiff dataset inside sandbox";
|
||||
|
||||
ASSERT_EQ(original_bands_data,
|
||||
parser::GetRasterBandsFromFile(tempfile_.GetPath()))
|
||||
<< "New dataset doesn't match the original one";
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
GDALTests,
|
||||
TestGTiffProcessor,
|
||||
::testing::Values(kFirstTestDataPath,
|
||||
kSecondTestDataPath,
|
||||
kThirdTestDataPath)
|
||||
);
|
||||
|
||||
} // namespace gdal::sandbox::tests
|
Loading…
Reference in New Issue
Block a user