Created
May 2, 2025 19:16
-
-
Save ThingEngineer/343b2406273c3e51ee145656aa974ace to your computer and use it in GitHub Desktop.
Convert GeoPackage to MBTiles with specified zoom levels
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# gpkg2mbtiles.sh - Convert GeoPackage to MBTiles with specified zoom levels | |
# | |
# Usage: ./gpkg2mbtiles.sh -Z <min_zoom> -z <max_zoom> <input_file> | |
# Example: ./gpkg2mbtiles.sh -Z 14 -z 17 wa-parcels | |
# | |
# Created by: Josh Campbell - ThingEngineer | |
# Date: 2025-05-01 | |
# ANSI color codes | |
RED='\033[0;31m' | |
GREEN='\033[0;32m' | |
YELLOW='\033[0;33m' | |
BLUE='\033[0;34m' | |
PURPLE='\033[0;35m' | |
NC='\033[0m' # No Color | |
# Function to format seconds to minutes:seconds | |
format_time() { | |
local seconds=$1 | |
local minutes=$((seconds / 60)) | |
local remaining_seconds=$((seconds % 60)) | |
printf "%d:%02d" $minutes $remaining_seconds | |
} | |
# Function to print separator | |
print_separator() { | |
echo -e "\n${BLUE}=====================================================================================================${NC}\n" | |
} | |
# Function to print command and then execute it | |
run_command() { | |
local cmd="$1" | |
echo -e "${GREEN}Running command:${NC} ${cmd}" | |
eval $cmd | |
if [ $? -ne 0 ]; then | |
echo -e "\n${RED}Error executing command:${NC} ${cmd}" | |
exit 1 | |
fi | |
} | |
# Check if required arguments are provided | |
if [ "$#" -lt 3 ]; then | |
echo -e "${RED}Usage: $0 -Z <min_zoom> -z <max_zoom> <input_file>${NC}" | |
echo -e "${YELLOW}Example: $0 -Z 14 -z 17 wa-parcels${NC}" | |
exit 1 | |
fi | |
# Parse arguments | |
min_zoom="" | |
max_zoom="" | |
while getopts "Z:z:" opt; do | |
case $opt in | |
Z) | |
min_zoom=$OPTARG | |
;; | |
z) | |
max_zoom=$OPTARG | |
;; | |
\?) | |
echo -e "${RED}Invalid option: -$OPTARG${NC}" >&2 | |
exit 1 | |
;; | |
:) | |
echo -e "${RED}Option -$OPTARG requires an argument.${NC}" >&2 | |
exit 1 | |
;; | |
esac | |
done | |
# Get the input file (last argument) | |
shift $((OPTIND-1)) | |
if [ "$#" -ne 1 ]; then | |
echo -e "${RED}Please provide an input file name (without extension).${NC}" | |
exit 1 | |
fi | |
input_file="$1" | |
# Check if input file exists | |
if [ ! -f "${input_file}.gpkg" ]; then | |
echo -e "${RED}Input file ${input_file}.gpkg not found.${NC}" | |
exit 1 | |
fi | |
# Validate zoom levels | |
if [[ ! $min_zoom =~ ^[0-9]+$ ]] || [[ ! $max_zoom =~ ^[0-9]+$ ]]; then | |
echo -e "${RED}Zoom levels must be positive integers.${NC}" | |
exit 1 | |
fi | |
if [ "$min_zoom" -gt "$max_zoom" ]; then | |
echo -e "${RED}Minimum zoom level (-Z) cannot be greater than maximum zoom level (-z).${NC}" | |
exit 1 | |
fi | |
# Define output files | |
reprojected_file="${input_file}-reprojected.gpkg" | |
valid_file="${input_file}-valid.gpkg" | |
fgb_file="${input_file}.fgb" | |
mbtiles_file="${input_file}-${min_zoom}-${max_zoom}.mbtiles" | |
# Start timer | |
start_time=$(date +%s) | |
last_time=$start_time | |
echo -e "${YELLOW}Starting GeoPackage to MBTiles conversion workflow for ${input_file}.gpkg${NC}" | |
echo -e "${YELLOW}Min zoom: ${min_zoom}, Max zoom: ${max_zoom}${NC}" | |
print_separator | |
# Step 1: Check the input GPKG file | |
echo -e "${PURPLE}Step 1: Checking input GeoPackage file...${NC}" | |
run_command "ogrinfo -al -so ${input_file}.gpkg" | |
step_time=$(date +%s) | |
elapsed_seconds=$((step_time - last_time)) | |
formatted_time=$(format_time $elapsed_seconds) | |
echo -e "${YELLOW}Time elapsed: ${formatted_time}${NC}" | |
last_time=$step_time | |
print_separator | |
# Step 2: Reproject the GPKG file if needed | |
echo -e "${PURPLE}Step 2: Reprojecting GeoPackage to EPSG:4326...${NC}" | |
run_command "ogr2ogr -f \"GPKG\" -t_srs EPSG:4326 ${reprojected_file} ${input_file}.gpkg" | |
step_time=$(date +%s) | |
elapsed_seconds=$((step_time - last_time)) | |
formatted_time=$(format_time $elapsed_seconds) | |
echo -e "${YELLOW}Time elapsed: ${formatted_time}${NC}" | |
last_time=$step_time | |
print_separator | |
# Step 3: Check the reprojected GPKG file | |
echo -e "${PURPLE}Step 3: Checking reprojected GeoPackage file...${NC}" | |
run_command "ogrinfo -al -so ${reprojected_file}" | |
step_time=$(date +%s) | |
elapsed_seconds=$((step_time - last_time)) | |
formatted_time=$(format_time $elapsed_seconds) | |
echo -e "${YELLOW}Time elapsed: ${formatted_time}${NC}" | |
last_time=$step_time | |
print_separator | |
# Step 4: Validate geometries | |
echo -e "${PURPLE}Step 4: Validating geometries...${NC}" | |
run_command "ogr2ogr -f \"GPKG\" ${valid_file} ${reprojected_file} -makevalid" | |
step_time=$(date +%s) | |
elapsed_seconds=$((step_time - last_time)) | |
formatted_time=$(format_time $elapsed_seconds) | |
echo -e "${YELLOW}Time elapsed: ${formatted_time}${NC}" | |
last_time=$step_time | |
print_separator | |
# Step 5: Check the validated GPKG file | |
echo -e "${PURPLE}Step 5: Checking validated GeoPackage file...${NC}" | |
run_command "ogrinfo -al -so ${valid_file}" | |
step_time=$(date +%s) | |
elapsed_seconds=$((step_time - last_time)) | |
formatted_time=$(format_time $elapsed_seconds) | |
echo -e "${YELLOW}Time elapsed: ${formatted_time}${NC}" | |
last_time=$step_time | |
print_separator | |
# Step 6: Convert the GPKG to FlatGeoBuf | |
echo -e "${PURPLE}Step 6: Converting to FlatGeobuf format...${NC}" | |
run_command "ogr2ogr -f \"FlatGeobuf\" ${fgb_file} ${valid_file}" | |
step_time=$(date +%s) | |
elapsed_seconds=$((step_time - last_time)) | |
formatted_time=$(format_time $elapsed_seconds) | |
echo -e "${YELLOW}Time elapsed: ${formatted_time}${NC}" | |
last_time=$step_time | |
print_separator | |
# Step 7: Check the FGB file | |
echo -e "${PURPLE}Step 7: Checking FlatGeobuf file...${NC}" | |
run_command "ogrinfo -al -so ${fgb_file}" | |
step_time=$(date +%s) | |
elapsed_seconds=$((step_time - last_time)) | |
formatted_time=$(format_time $elapsed_seconds) | |
echo -e "${YELLOW}Time elapsed: ${formatted_time}${NC}" | |
last_time=$step_time | |
print_separator | |
# Step 8: Convert to MBTiles using Tippecanoe | |
echo -e "${PURPLE}Step 8: Converting to MBTiles using Tippecanoe...${NC}" | |
tippecanoe_cmd="tippecanoe -o ${mbtiles_file} -f -Z${min_zoom} -z${max_zoom} --read-parallel --hilbert --simplify-only-low-zooms --maximum-zoom=${max_zoom} --minimum-zoom=${min_zoom} ${fgb_file}" | |
run_command "$tippecanoe_cmd" | |
step_time=$(date +%s) | |
elapsed_seconds=$((step_time - last_time)) | |
formatted_time=$(format_time $elapsed_seconds) | |
echo -e "${YELLOW}Time elapsed: ${formatted_time}${NC}" | |
last_time=$step_time | |
print_separator | |
# Step 9: Check the MBTiles file | |
echo -e "${PURPLE}Step 9: Checking MBTiles file...${NC}" | |
run_command "ogrinfo -al -so -q ${mbtiles_file}" | |
step_time=$(date +%s) | |
elapsed_seconds=$((step_time - last_time)) | |
formatted_time=$(format_time $elapsed_seconds) | |
echo -e "${YELLOW}Time elapsed: ${formatted_time}${NC}" | |
print_separator | |
# Calculate total time | |
end_time=$(date +%s) | |
total_time=$((end_time - start_time)) | |
formatted_total_time=$(format_time $total_time) | |
echo -e "${GREEN}Conversion completed successfully!${NC}" | |
echo -e "${GREEN}Total time: ${formatted_total_time}${NC}" | |
echo -e "${GREEN}Output file: ${mbtiles_file}${NC}" | |
# Prompt to copy file via SCP | |
read -p "Copy the MBTiles file to the tile server? (y/n): " copy_response | |
if [[ "$copy_response" =~ ^[Yy]$ ]]; then | |
scp_cmd="scp ${mbtiles_file} [email protected]://home/docker/tileserver-gl-docker-compose/data" | |
echo -e "${GREEN}Running command:${NC} ${scp_cmd}" | |
eval $scp_cmd | |
if [ $? -eq 0 ]; then | |
echo -e "${GREEN}File copied successfully!${NC}" | |
else | |
echo -e "${RED}Error copying file.${NC}" | |
fi | |
fi | |
echo -e "${GREEN}Script completed.${NC}" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
System Prerequisites and Dependencies for
gpkg2mbtiles.sh
The following system prerequisites and dependencies are required to ensure the successful execution of the
gpkg2mbtiles.sh
script, which converts GeoPackage (.gpkg
) files to MBTiles (.mbtiles
) format.1. System Requirements
2. Software Dependencies
The following software tools must be installed and available in the system's
PATH
:2.1. GDAL (Geospatial Data Abstraction Library)
ogrinfo
,ogr2ogr
ogrinfo
: To inspect GeoPackage, FlatGeobuf, and MBTiles files for metadata and errors.ogr2ogr
: To reproject GeoPackage files to the EPSG:4326 coordinate system, validate geometries, and convert between formats.sudo apt-get install gdal-bin
brew install gdal
2.2. Tippecanoe
tippecanoe
--hilbert
and--read-parallel
)2.3. OpenSSH Client
scp
sudo apt-get install openssh-client
3. Additional Requirements
3.1. Network Access
scp
), ensure:[email protected]
).3.2. File Permissions
3.3. Input File
.gpkg
) file.4. Optional Tools
These tools are not required but can enhance the workflow:
4.1.
time
Command5. Environment Configuration
5.1. Add Tools to PATH
Ensure all required tools (
ogrinfo
,ogr2ogr
,tippecanoe
,scp
) are in the system'sPATH
. You can check this by running:5.2. Test Environment
Run the following commands to verify dependencies:
6. Troubleshooting
6.1. Missing Dependencies
If a command is not found, ensure the corresponding software is installed and available in the system's
PATH
.6.2. Permission Issues
Ensure the input file and output directory have the appropriate read/write permissions.
6.3. Tippecanoe Memory Usage
Generating MBTiles for large datasets may require significant memory. Monitor system resources during execution.
7. Example Environment Setup
Below is an example of setting up the required dependencies on an Ubuntu system:
By ensuring these prerequisites and dependencies are met, the
gpkg2mbtiles.sh
script will execute seamlessly.