mirror of
https://github.com/google/sandboxed-api.git
synced 2024-03-22 13:11:30 +08:00
Merge pull request #64 from bohdanty:gdal_sandbox
PiperOrigin-RevId: 337856019 Change-Id: Ib1d9c5614f02da4df8d624f006f31ea09bb5c560
This commit is contained in:
commit
cba334a9d1
2
.gitmodules
vendored
2
.gitmodules
vendored
|
@ -12,7 +12,7 @@
|
|||
url = https://bitbucket.org/jpommier/pffft/src/master/
|
||||
[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/
|
||||
[submodule "oss-internship-2020/curl/curl_wrapper/curl"]
|
||||
path = oss-internship-2020/curl/curl_wrapper/curl
|
||||
url = git@github.com:curl/curl.git
|
||||
|
|
141
oss-internship-2020/gdal/raster_to_gtiff/CMakeLists.txt
Normal file
141
oss-internship-2020/gdal/raster_to_gtiff/CMakeLists.txt
Normal file
|
@ -0,0 +1,141 @@
|
|||
# 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.12)
|
||||
|
||||
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")
|
||||
set(ENABLE_TESTS OFF CACHE BOOL "Enable GDAL sandbox tests")
|
||||
set(GDAL_HEADER_PREFIX "/usr/local/include" CACHE PATH "Prefix of the path to gdal.h")
|
||||
set(LIBGDAL_PREFIX "${CMAKE_CURRENT_SOURCE_DIR}/lib" CACHE PATH "Prefix of the path to libgdal.a")
|
||||
set(LIBPROJ_PREFIX "${CMAKE_CURRENT_SOURCE_DIR}/lib" CACHE PATH "Prefix of the path to libproj.a")
|
||||
|
||||
add_subdirectory("${SAPI_ROOT}"
|
||||
"${CMAKE_BINARY_DIR}/sandboxed-api-build"
|
||||
EXCLUDE_FROM_ALL)
|
||||
|
||||
add_library(libgdal STATIC IMPORTED)
|
||||
set_property(TARGET libgdal PROPERTY IMPORTED_LOCATION
|
||||
"${LIBGDAL_PREFIX}/libgdal.a")
|
||||
|
||||
add_library(libproj STATIC IMPORTED)
|
||||
set_property(TARGET libproj PROPERTY IMPORTED_LOCATION
|
||||
"${LIBPROJ_PREFIX}/libproj.a")
|
||||
|
||||
target_link_libraries(libgdal INTERFACE
|
||||
crypto
|
||||
expat
|
||||
jpeg
|
||||
libproj
|
||||
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_HEADER_PREFIX}/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_library(utils STATIC
|
||||
utils.h utils.cc
|
||||
)
|
||||
|
||||
target_link_libraries(utils PUBLIC
|
||||
sapi::sapi
|
||||
sandbox2::temp_file
|
||||
sandbox2::fileops
|
||||
sandbox2::util
|
||||
sandbox2::file_base
|
||||
)
|
||||
|
||||
add_library(gtiff_converter STATIC
|
||||
gtiff_converter.h gtiff_converter.cc
|
||||
)
|
||||
|
||||
target_link_libraries(gtiff_converter PUBLIC
|
||||
data_retriever
|
||||
gdal_sapi
|
||||
sapi::sapi
|
||||
)
|
||||
|
||||
add_executable(raster_to_gtiff
|
||||
raster_to_gtiff.cc
|
||||
)
|
||||
|
||||
target_link_libraries(raster_to_gtiff
|
||||
data_retriever
|
||||
utils
|
||||
gtiff_converter
|
||||
)
|
||||
|
||||
if (ENABLE_TESTS)
|
||||
include(GoogleTest)
|
||||
enable_testing()
|
||||
|
||||
add_executable(tests tests.cc)
|
||||
target_link_libraries(tests PRIVATE
|
||||
data_retriever
|
||||
gtiff_converter
|
||||
utils
|
||||
gtest
|
||||
gtest_main
|
||||
sandbox2::testing
|
||||
sandbox2::file_base
|
||||
)
|
||||
|
||||
gtest_discover_tests(tests PROPERTIES
|
||||
ENVIRONMENT "TEST_TMPDIR=/tmp/"
|
||||
ENVIRONMENT "TEST_SRCDIR=${PROJECT_SOURCE_DIR}"
|
||||
)
|
||||
|
||||
endif()
|
101
oss-internship-2020/gdal/raster_to_gtiff/README.md
Normal file
101
oss-internship-2020/gdal/raster_to_gtiff/README.md
Normal file
|
@ -0,0 +1,101 @@
|
|||
# GDAL Raster to GeoTIFF Workflow Sandbox
|
||||
This repository is an example of how Sandboxed API can be used with GDAL C Raster API to implement the creation of the GeoTIFF dataset inside the sandbox.
|
||||
|
||||
## Workflow details
|
||||
Implemented workflow consists of a few steps:
|
||||
1. Register needed drivers inside the sandbox
|
||||
2. Get specific driver by name (GTiff)
|
||||
3. Map output file inside the sandbox and create a GeoTIFF dataset backed by this file
|
||||
4. Set affine transformation coefficients if needed
|
||||
5. Set projection reference string if needed
|
||||
6. Write raster bands data to the dataset using RasterIO
|
||||
1. Set No data value if needed
|
||||
7. Clean up data and close the dataset
|
||||
|
||||
## Implementation details
|
||||
This project consists of a CMake file that shows how you can connect Sandboxed API and GDAL, a raster data parser using unsandboxed GDAL to generate sample input for the sandboxed workflow, sample sandbox policy that could work with GeoTIFF files without any violations, command-line utility that uses sandboxed GDAL to implement the workflow and GoogleTest unit tests to compare raster data of original datasets with the raster data of datasets that have been created inside the sandbox.
|
||||
|
||||
## Build GDAL sandbox
|
||||
Because GDAL doesn't use CMake or Bazel it's required to have a static build of libgdal and libproj. Moreover, proj.db file path is required to be able to map it inside the sandbox and use it internally for some of the projections.
|
||||
|
||||
### Build GDAL and PROJ from sources
|
||||
To get the latest version of both GDAL and PROJ you will need to build them from sources. To make a clean installation you can use the build folder as an installation path, with this approach you won't affect any system files and will be able to easily delete everything later.
|
||||
First, you will need to build PROJ, which is used internally in the GDAL. You can't use the libproj-dev package because it contains an outdated version, while GDAL requires a more recent one.
|
||||
To [install PROJ from sources](https://proj.org/install.html#compilation-and-installation-from-source-code) you can do the following:
|
||||
```
|
||||
mkdir build && cd build
|
||||
wget https://download.osgeo.org/proj/proj-7.1.1.tar.gz
|
||||
tar xvzf proj-7.1.1.tar.gz
|
||||
mkdir proj_build
|
||||
cd proj-7.1.1
|
||||
./configure --prefix=/path/to/build/proj_build
|
||||
make -j8
|
||||
make install
|
||||
make check
|
||||
```
|
||||
The static version of libproj will be available at `proj_build/lib/libproj.a`.
|
||||
Then, you can start [GDAL installation](https://trac.osgeo.org/gdal/wiki/BuildingOnUnix):
|
||||
```
|
||||
cd build
|
||||
git clone https://github.com/OSGeo/gdal
|
||||
mkdir gdal_build
|
||||
cd gdal/gdal
|
||||
./configure --prefix=/path/to/build/gdal_build --with-proj=/path/to/build/proj_build
|
||||
make -j8
|
||||
make install
|
||||
```
|
||||
To verify that everything is installed correctly you can run gdalinfo utility.
|
||||
```
|
||||
cd ../../gdal_build/bin/
|
||||
./gdalinfo --version
|
||||
```
|
||||
The static version of libgdal will be available at `gdal_build/lib/libgdal.a`.
|
||||
You will need to specify paths to those static libraries as the CMake arguments to build the project. Also, the Sandboxed API generator needs `gdal.h` header, which is located at `build/gdal/gdal/gcore/gdal.h`.
|
||||
|
||||
### Build sandboxed GDAL
|
||||
To build the examples from this repository you can use CMake in the following way:
|
||||
```
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -G Ninja -DSAPI_ROOT=/path/to/sapi
|
||||
```
|
||||
This build expects `lib/` folder with both `libgdal.a` and `libproj.a` to be present near the source files.
|
||||
Also, you need to have `gdal.h` header so Sandboxed API generator could parse it, the default expected path to it is `/usr/local/include`.
|
||||
Finally, you could enable tests with the `-DENABLE_TESTS=ON` option for the CMake.
|
||||
You can specify those paths as a CMake argument, so the complete example looks like this:
|
||||
```
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -G Ninja -DSAPI_ROOT=/path/to/sapi \
|
||||
-DGDAL_HEADER_PREFIX=/path/to/gdal/header \
|
||||
-DLIBGDAL_PREFIX=/path/to/libgdal_static_build \
|
||||
-DLIBPROJ_PREFIX=/path/to/libproj_static_build \
|
||||
-DENABLE_TESTS=ON
|
||||
```
|
||||
After CMake build is completed, you can run `ninja` to build the executables.
|
||||
|
||||
## Examples
|
||||
PROJ uses `proj.db` database to work correctly with different transformations and you will need to map it to the sandbox manually to be able to retrieve it in the restricted environment. After the installation you can find `proj.db` in `/path/to/proj/share/proj/proj.db`.
|
||||
|
||||
You can use environment variables to set path to proj:
|
||||
```
|
||||
export PROJ_DB_PATH=/path/to/proj.db
|
||||
```
|
||||
The code will check this variable and if it represents a valid file it will be mounted inside the sandbox.
|
||||
Alternatively, if there is no such environment variable program will try to use the default path `/usr/local/share/proj/proj.db`.
|
||||
There is a simple command-line utility that takes path to the GeoTIFF file and absolute path to the output file as arguments, parses raster data from the input file and, re-creates the same GeoTIFF file (except some metadata) inside the sandbox.
|
||||
|
||||
You can run it in the following way:
|
||||
```
|
||||
./raster_to_gtiff path/to/input.tif /absolute/path/to/output.tif
|
||||
```
|
||||
After that, you can compare both files using the `gdalinfo` utility.
|
||||
Also, there are unit tests that automatically convert a few files and then compare input and output raster data to make sure that they are equal.
|
||||
To run tests your CMake build must use `-DENABLE_TESTS=ON`, then you can run tests using `ctest`.
|
||||
Note that it will also run Sandboxed API related tests. To run tests manually you will need to specify a few environmental variables and then run `tests` executable.
|
||||
```
|
||||
export TEST_TMPDIR=/tmp/
|
||||
export TEST_SRCDIR=/path/to/project/source
|
||||
```
|
||||
|
||||
All test data is from [osgeo samples](http://download.osgeo.org/geotiff/samples/).
|
66
oss-internship-2020/gdal/raster_to_gtiff/gdal_sandbox.h
Normal file
66
oss-internship-2020/gdal/raster_to_gtiff/gdal_sandbox.h
Normal file
|
@ -0,0 +1,66 @@
|
|||
// 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 RASTER_TO_GTIFF_GDAL_SANDBOX_H_
|
||||
#define RASTER_TO_GTIFF_GDAL_SANDBOX_H_
|
||||
|
||||
#include <syscall.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "gdal_sapi.sapi.h" // NOLINT(build/include)
|
||||
|
||||
namespace gdal::sandbox {
|
||||
|
||||
class GdalSapiSandbox : public GdalSandbox {
|
||||
public:
|
||||
GdalSapiSandbox(std::string out_directory_path, std::string proj_db_path,
|
||||
time_t time_limit = 0)
|
||||
: out_directory_path_(std::move(out_directory_path)),
|
||||
proj_db_path_(std::move(proj_db_path)) {
|
||||
SetWallTimeLimit(time_limit).IgnoreError();
|
||||
}
|
||||
|
||||
private:
|
||||
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()
|
||||
})
|
||||
.AddFile(proj_db_path_) // proj.db is required for some projections
|
||||
.AddDirectory(out_directory_path_, /*is_ro=*/false)
|
||||
.BuildOrDie();
|
||||
}
|
||||
|
||||
std::string out_directory_path_;
|
||||
std::string proj_db_path_;
|
||||
};
|
||||
|
||||
} // namespace gdal::sandbox
|
||||
|
||||
#endif // RASTER_TO_GTIFF_GDAL_SANDBOX_H_
|
97
oss-internship-2020/gdal/raster_to_gtiff/get_raster_data.cc
Normal file
97
oss-internship-2020/gdal/raster_to_gtiff/get_raster_data.cc
Normal file
|
@ -0,0 +1,97 @@
|
|||
// 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" // NOLINT(build/include)
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "gdal.h" // NOLINT(build/include)
|
||||
|
||||
namespace gdal::sandbox::parser {
|
||||
|
||||
namespace {
|
||||
|
||||
inline constexpr int kGeoTransformSize = 6;
|
||||
|
||||
} // 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));
|
||||
|
||||
std::vector<int32_t> band_raster_data(width * height);
|
||||
|
||||
// GDALRasterIO with GF_Write 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);
|
||||
|
||||
GDALClose(dataset);
|
||||
|
||||
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::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 RASTER_TO_GTIFF_GET_RASTER_DATA_H_
|
||||
#define RASTER_TO_GTIFF_GET_RASTER_DATA_H_
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace gdal::sandbox::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 GDALColorInterp enum
|
||||
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::parser
|
||||
|
||||
#endif // RASTER_TO_GTIFF_GET_RASTER_DATA_H_
|
133
oss-internship-2020/gdal/raster_to_gtiff/gtiff_converter.cc
Normal file
133
oss-internship-2020/gdal/raster_to_gtiff/gtiff_converter.cc
Normal file
|
@ -0,0 +1,133 @@
|
|||
// 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 "gtiff_converter.h" // NOLINT(build/include)
|
||||
|
||||
#include "sandboxed_api/sandbox2/util/fileops.h"
|
||||
|
||||
namespace gdal::sandbox {
|
||||
|
||||
namespace {
|
||||
|
||||
inline constexpr absl::string_view kDriverName = "GTiff";
|
||||
|
||||
} // namespace
|
||||
|
||||
RasterToGTiffProcessor::RasterToGTiffProcessor(std::string out_file_full_path,
|
||||
std::string proj_db_path,
|
||||
parser::RasterDataset data,
|
||||
int retry_count)
|
||||
: sapi::Transaction(std::make_unique<GdalSapiSandbox>(
|
||||
sandbox2::file_util::fileops::StripBasename(out_file_full_path),
|
||||
std::move(proj_db_path))),
|
||||
out_file_full_path_(std::move(out_file_full_path)),
|
||||
data_(std::move(data)) {
|
||||
set_retry_count(retry_count);
|
||||
SetTimeLimit(absl::InfiniteDuration());
|
||||
}
|
||||
|
||||
absl::Status RasterToGTiffProcessor::Main() {
|
||||
GdalApi api(sandbox());
|
||||
SAPI_RETURN_IF_ERROR(api.GDALAllRegister());
|
||||
|
||||
sapi::v::CStr driver_name_ptr(kDriverName);
|
||||
|
||||
SAPI_ASSIGN_OR_RETURN(absl::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());
|
||||
|
||||
sapi::v::ConstCStr out_file_full_path_ptr(out_file_full_path_.c_str());
|
||||
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(
|
||||
absl::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());
|
||||
|
||||
int current_band = 1;
|
||||
for (auto& band_data : data_.bands) {
|
||||
SAPI_ASSIGN_OR_RETURN(absl::StatusOr<GDALRasterBandH> band,
|
||||
api.GDALGetRasterBand(&dataset_ptr, current_band));
|
||||
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(band_data.data.data(),
|
||||
band_data.data.size());
|
||||
|
||||
SAPI_ASSIGN_OR_RETURN(
|
||||
absl::StatusOr<CPLErr> result,
|
||||
api.GDALRasterIO(&band_ptr, GF_Write, 0, 0, band_data.width,
|
||||
band_data.height, data_array.PtrBefore(),
|
||||
band_data.width, band_data.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>(band_data.color_interp)));
|
||||
|
||||
TRANSACTION_FAIL_IF_NOT(result.value() == CPLErr::CE_None,
|
||||
"Error setting color interpretation");
|
||||
|
||||
if (band_data.no_data_value.has_value()) {
|
||||
SAPI_ASSIGN_OR_RETURN(result, api.GDALSetRasterNoDataValue(
|
||||
&band_ptr, band_data.no_data_value.value()));
|
||||
|
||||
TRANSACTION_FAIL_IF_NOT(result.value() == CPLErr::CE_None,
|
||||
"Error setting no data value for the band");
|
||||
}
|
||||
|
||||
++current_band;
|
||||
}
|
||||
|
||||
if (data_.wkt_projection.length() > 0) {
|
||||
sapi::v::ConstCStr wkt_projection_ptr(data_.wkt_projection.c_str());
|
||||
SAPI_ASSIGN_OR_RETURN(
|
||||
absl::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(
|
||||
absl::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 gdal::sandbox
|
41
oss-internship-2020/gdal/raster_to_gtiff/gtiff_converter.h
Normal file
41
oss-internship-2020/gdal/raster_to_gtiff/gtiff_converter.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
// 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 RASTER_TO_GTIFF_GTIFF_CONVERTER_H_
|
||||
#define RASTER_TO_GTIFF_GTIFF_CONVERTER_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "gdal_sandbox.h" // NOLINT(build/include)
|
||||
#include "get_raster_data.h" // NOLINT(build/include)
|
||||
#include "sandboxed_api/transaction.h"
|
||||
|
||||
namespace gdal::sandbox {
|
||||
|
||||
class RasterToGTiffProcessor : public sapi::Transaction {
|
||||
public:
|
||||
RasterToGTiffProcessor(std::string out_file_full_path,
|
||||
std::string proj_db_path, parser::RasterDataset data,
|
||||
int retry_count = 0);
|
||||
|
||||
private:
|
||||
absl::Status Main() final;
|
||||
|
||||
const std::string out_file_full_path_;
|
||||
parser::RasterDataset data_;
|
||||
};
|
||||
|
||||
} // namespace gdal::sandbox
|
||||
|
||||
#endif // RASTER_TO_GTIFF_GTIFF_CONVERTER_H_
|
73
oss-internship-2020/gdal/raster_to_gtiff/raster_to_gtiff.cc
Normal file
73
oss-internship-2020/gdal/raster_to_gtiff/raster_to_gtiff.cc
Normal file
|
@ -0,0 +1,73 @@
|
|||
// 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 <cstdlib>
|
||||
#include <iostream>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
#include "get_raster_data.h" // NOLINT(build/include)
|
||||
#include "gtiff_converter.h" // NOLINT(build/include)
|
||||
#include "sandboxed_api/sandbox2/util/fileops.h"
|
||||
#include "sandboxed_api/sandbox2/util/path.h"
|
||||
#include "utils.h" // NOLINT(build/include)
|
||||
|
||||
namespace {
|
||||
|
||||
absl::Status SaveToGTiff(gdal::sandbox::parser::RasterDataset bands_data,
|
||||
std::string out_file) {
|
||||
std::optional<std::string> proj_db_path =
|
||||
gdal::sandbox::utils::FindProjDbPath();
|
||||
|
||||
if (proj_db_path == std::nullopt) {
|
||||
return absl::FailedPreconditionError("Specified proj.db does not exist");
|
||||
}
|
||||
|
||||
gdal::sandbox::RasterToGTiffProcessor processor(
|
||||
std::move(out_file), std::move(proj_db_path.value()),
|
||||
std::move(bands_data));
|
||||
|
||||
return processor.Run();
|
||||
}
|
||||
|
||||
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) {
|
||||
if (argc < 3 || !sandbox2::file::IsAbsolutePath(argv[2])) {
|
||||
Usage();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
std::string input_data_path = std::string(argv[1]);
|
||||
std::string output_data_path = std::string(argv[2]);
|
||||
|
||||
if (absl::Status status = gdal::sandbox::SaveToGTiff(
|
||||
gdal::sandbox::parser::GetRasterBandsFromFile(
|
||||
std::move(input_data_path)),
|
||||
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/SP27GTIF.tif
vendored
Normal file
BIN
oss-internship-2020/gdal/raster_to_gtiff/testdata/SP27GTIF.tif
vendored
Normal file
Binary file not shown.
BIN
oss-internship-2020/gdal/raster_to_gtiff/testdata/cea.tif
vendored
Normal file
BIN
oss-internship-2020/gdal/raster_to_gtiff/testdata/cea.tif
vendored
Normal file
Binary file not shown.
74
oss-internship-2020/gdal/raster_to_gtiff/tests.cc
Normal file
74
oss-internship-2020/gdal/raster_to_gtiff/tests.cc
Normal file
|
@ -0,0 +1,74 @@
|
|||
// 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 <optional>
|
||||
#include <string>
|
||||
|
||||
#include "gdal_sandbox.h" // NOLINT(build/include)
|
||||
#include "get_raster_data.h" // NOLINT(build/include)
|
||||
#include "gtiff_converter.h" // NOLINT(build/include)
|
||||
#include "gtest/gtest.h"
|
||||
#include "sandboxed_api/sandbox2/testing.h"
|
||||
#include "sandboxed_api/sandbox2/util/fileops.h"
|
||||
#include "sandboxed_api/sandbox2/util/path.h"
|
||||
#include "utils.h" // NOLINT(build/include)
|
||||
|
||||
namespace {
|
||||
|
||||
inline constexpr absl::string_view kTempFilePrefix = "temp_data";
|
||||
inline constexpr absl::string_view kFirstTestDataPath = "testdata/cea.tif";
|
||||
inline constexpr absl::string_view kSecondTestDataPath =
|
||||
"testdata/SP27GTIF.tif";
|
||||
|
||||
} // namespace
|
||||
|
||||
class TestGTiffProcessor : public testing::TestWithParam<absl::string_view> {
|
||||
public:
|
||||
TestGTiffProcessor() : tempfile_(sandbox2::GetTestTempPath()) {}
|
||||
|
||||
protected:
|
||||
const gdal::sandbox::utils::TempFile tempfile_;
|
||||
};
|
||||
|
||||
TEST_P(TestGTiffProcessor, TestProcessorOnGTiffData) {
|
||||
std::string file_path = gdal::sandbox::utils::GetTestDataPath(GetParam());
|
||||
|
||||
ASSERT_TRUE(sandbox2::file_util::fileops::Exists(file_path, false))
|
||||
<< "Error finding input dataset";
|
||||
|
||||
ASSERT_TRUE(tempfile_.HasValue()) << "Error creating temporary output file";
|
||||
|
||||
gdal::sandbox::parser::RasterDataset original_bands_data =
|
||||
gdal::sandbox::parser::GetRasterBandsFromFile(file_path);
|
||||
|
||||
std::optional<std::string> proj_db_path =
|
||||
gdal::sandbox::utils::FindProjDbPath();
|
||||
ASSERT_TRUE(proj_db_path != std::nullopt)
|
||||
<< "Specified proj.db does not exist";
|
||||
|
||||
gdal::sandbox::RasterToGTiffProcessor processor(
|
||||
tempfile_.GetPath(), std::move(proj_db_path.value()),
|
||||
original_bands_data);
|
||||
|
||||
ASSERT_EQ(processor.Run(), absl::OkStatus())
|
||||
<< "Error creating new GTiff dataset inside sandbox";
|
||||
|
||||
ASSERT_EQ(original_bands_data,
|
||||
gdal::sandbox::parser::GetRasterBandsFromFile(tempfile_.GetPath()))
|
||||
<< "New dataset doesn't match the original one";
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(GDALTests, TestGTiffProcessor,
|
||||
::testing::Values(kFirstTestDataPath,
|
||||
kSecondTestDataPath));
|
77
oss-internship-2020/gdal/raster_to_gtiff/utils.cc
Normal file
77
oss-internship-2020/gdal/raster_to_gtiff/utils.cc
Normal file
|
@ -0,0 +1,77 @@
|
|||
// 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 "utils.h" // NOLINT(build/include)
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include "sandboxed_api/sandbox2/util/fileops.h"
|
||||
#include "sandboxed_api/sandbox2/util/path.h"
|
||||
#include "sandboxed_api/sandbox2/util/temp_file.h"
|
||||
|
||||
namespace gdal::sandbox::utils {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr char kProjDbEnvVariableName[] = "PROJ_DB_PATH";
|
||||
inline constexpr absl::string_view kDefaultProjDbPath =
|
||||
"/usr/local/share/proj/proj.db";
|
||||
|
||||
} // namespace
|
||||
|
||||
TempFile::TempFile(absl::string_view prefix) {
|
||||
auto file_data = sandbox2::CreateNamedTempFile(prefix);
|
||||
|
||||
if (file_data.ok()) {
|
||||
file_data_ = std::move(file_data.value());
|
||||
}
|
||||
}
|
||||
|
||||
TempFile::~TempFile() {
|
||||
if (HasValue()) {
|
||||
unlink(file_data_.value().first.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
bool TempFile::HasValue() const { return file_data_.has_value(); }
|
||||
|
||||
int TempFile::GetFd() const { return file_data_.value().second; }
|
||||
|
||||
std::string TempFile::GetPath() const { return file_data_.value().first; }
|
||||
|
||||
std::optional<std::string> FindProjDbPath() {
|
||||
std::string proj_db_path(kDefaultProjDbPath);
|
||||
|
||||
if (const char* proj_db_env_var = std::getenv(kProjDbEnvVariableName);
|
||||
proj_db_env_var != nullptr) {
|
||||
proj_db_path = proj_db_env_var;
|
||||
}
|
||||
|
||||
if (!sandbox2::file_util::fileops::Exists(proj_db_path, false)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return proj_db_path;
|
||||
}
|
||||
|
||||
std::string GetTestDataPath(absl::string_view testdata_path) {
|
||||
const char* test_srcdir = std::getenv("TEST_SRCDIR");
|
||||
|
||||
return sandbox2::file::JoinPath(test_srcdir == nullptr
|
||||
? sandbox2::file_util::fileops::GetCWD()
|
||||
: test_srcdir,
|
||||
testdata_path);
|
||||
}
|
||||
|
||||
} // namespace gdal::sandbox::utils
|
52
oss-internship-2020/gdal/raster_to_gtiff/utils.h
Normal file
52
oss-internship-2020/gdal/raster_to_gtiff/utils.h
Normal file
|
@ -0,0 +1,52 @@
|
|||
// 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 RASTER_TO_GTIFF_UTILS_H_
|
||||
#define RASTER_TO_GTIFF_UTILS_H_
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
|
||||
namespace gdal::sandbox::utils {
|
||||
|
||||
// RAII wrapper that creates temporary file and automatically unlinks it
|
||||
class TempFile {
|
||||
public:
|
||||
explicit TempFile(absl::string_view prefix);
|
||||
TempFile(const TempFile&) = delete;
|
||||
TempFile& operator=(const TempFile&) = delete;
|
||||
TempFile(TempFile&&) = delete;
|
||||
TempFile& operator=(TempFile&&) = delete;
|
||||
~TempFile();
|
||||
|
||||
bool HasValue() const;
|
||||
int GetFd() const;
|
||||
std::string GetPath() const;
|
||||
|
||||
private:
|
||||
std::optional<std::pair<std::string, int>> file_data_ = std::nullopt;
|
||||
};
|
||||
|
||||
// Helper function to retrieve potential proj.db path from environment variable
|
||||
std::optional<std::string> FindProjDbPath();
|
||||
|
||||
// Tries to get test folder path from the TEST_SRCDIR environment variable and
|
||||
// uses CWD path otherwise to join it with the testdata_path
|
||||
std::string GetTestDataPath(absl::string_view testdata_path);
|
||||
|
||||
} // namespace gdal::sandbox::utils
|
||||
|
||||
#endif // RASTER_TO_GTIFF_UTILS_H_
|
Loading…
Reference in New Issue
Block a user