Sitemap
Rahul Bhat

Rahul Bhat

Tech Project Lead - Data Scientist at United Nations

How to Extract ECW Files for Free Using Docker: Skip the $$$$ Proprietary Software

7 min readDec 4, 2025

--

The Problem: Expensive and Incompatible ECW Extraction Tools

If you work with geospatial data, you’ve probably encountered ECW (Enhanced Compressed Wavelets) files. They’re great for compressing satellite imagery and aerial photos, but extracting them is a nightmare.

Here’s why:

Proprietary Software Costs: The official ECW SDK from Hexagon Geospatial comes with hefty licensing fees. We’re talking hundreds to thousands of dollars depending on your use case. For small projects, research, or individual developers, this isn’t feasible.

Compatibility Issues: Popular GIS software like QGIS and ArcGIS can struggle with ECW support across different operating systems. ArcGIS on Linux? Forget about it. QGIS with full ECW support on Windows? Hit or miss depending on your build version.

Platform Limitations: Traditional extraction methods lock you into specific operating systems or require complex library installations that break between different system versions.

Time-Consuming Setup: Installing ECW libraries directly on your system means dealing with dependency hell — conflicting versions, missing packages, and hours of troubleshooting.

Sound familiar? I hit all these walls recently on a Chile drone imagery project. That’s when Docker came to the rescue.

Press enter or click to view image in full size
Skip proprietary software costs. Extract ECW files free using Docker on any operating system.

The Solution: Free, Cross-Platform ECW Extraction with Docker

Here’s the good news: Docker lets you extract ECW files for free using GDAL (Geospatial Data Abstraction Library) without any proprietary software or costly licenses.

Even better? It works on Linux, Windows (WSL2), and macOS — all with the same setup.

Why This Approach is Better

Completely free — No licensing fees
Cross-platform — Works on Linux, Windows (via WSL2), and Mac
No library conflicts — Everything runs in an isolated container
Reproducible — Same results on every machine
Scalable — Process hundreds of files automatically
No bloatware — Just what you need, nothing extra

Getting Started: System Requirements

For this method, you’ll need:

Linux: Ubuntu 20.04+ (or any modern Linux distro) Windows: Windows 10/11 with WSL2 enabled + Docker Desktop macOS: Docker Desktop for Mac General: Python 3.8+, at least 2GB disk space, sudo/admin access

Installation Guide

For Linux (Ubuntu/Debian)

First, update your system:

sudo apt update
sudo apt upgrade -y

sudo apt install -y \
curl \
wget \
git \
python3 \
python3-pip \
python3-venv

Install Docker:

sudo apt remove -y docker docker-engine docker.io containerd runc

sudo apt install -y \
ca-certificates \
gnupg \
lsb-release

sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Verify Docker works:

sudo docker --version
sudo docker run hello-world

Optional — avoid using sudo with every docker command:

sudo usermod -aG docker $USER
newgrp docker
docker run hello-world

For Windows (via WSL2)

  1. Enable WSL2:
  • Open PowerShell as Administrator
  • Run: wsl --install
  • Restart your computer
  • Install a Linux distribution (Ubuntu 20.04 recommended) from Microsoft Store

2. Install Docker Desktop for Windows:

3. Verify in WSL2 terminal:

docker --version
docker run hello-world

For macOS

  1. Install Docker Desktop for Mac:

2. Verify installation:

docker --version 
docker run hello-world

Setting Up Your Project

Create your project directory structure:

mkdir -p ~/ecw_extraction
cd ~/ecw_extraction

mkdir -p extracted # Your ECW files go here
mkdir -p converted_images # Converted files will be saved here
mkdir -p scripts # Processing scripts
mkdir -p logs # Log files

Pulling the GDAL Docker Image with ECW Support

docker pull geodata/gdal

Verify ECW support is available:

docker run --rm geodata/gdal gdalinfo --formats | grep -i ECW

You should see:

ECW -raster- (rw+): ERDAS Compressed Wavelets (SDK 5.5)
JP2ECW -raster,vector- (rw+v): ERDAS JPEG2000 (SDK 5.5)

Perfect!

Preparing Your ECW Files

Copy your ECW files to the extracted directory:

cp /path/to/your/*.ecw extracted/
cp /path/to/your/*.eww extracted/ # World files (optional)
cp /path/to/your/*.prj extracted/ # Projection files (optional)

Verify:

ls -lh extracted/

Test Run: Manual Extraction

Before automating, let’s test one file manually.

Get Rahul Bhat’s stories in your inbox

Join Medium for free to get updates from this writer.

Get information about your ECW file:

docker run --rm \
-v $(pwd)/extracted:/input \
geodata/gdal \
gdalinfo /input/ortofoto.ecw

Replace ortofoto.ecw with your actual filename. You'll see detailed info like size, coordinate system, and pixel dimensions.

Now convert it to GeoTIFF (a standard, widely-compatible format):

docker run --rm \
-v $(pwd)/extracted:/input \
-v $(pwd)/converted_images:/output \
geodata/gdal \
gdal_translate \
-of GTiff \
/input/ortofoto.ecw \
/output/ortofoto.tif

Check the result:

ls -lh converted_images/

See the .tif file? You're ready for batch processing! ✅

Automate with Python: Batch Processing Script

Create scripts/extract_ecw_direct.py:

#!/usr/bin/env python3
"""
ECW Extraction using Docker with direct file access
Works on Linux, Windows (WSL2), and macOS
"""

import subprocess
import os
import sys
from pathlib import Path
import logging
# Configure logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
class ECWExtractor:
def __init__(self, input_dir="extracted", output_dir="converted_images"):
self.input_dir = Path(input_dir)
self.output_dir = Path(output_dir)
self.output_dir.mkdir(parents=True, exist_ok=True)

logger.info(f"ECW Extractor initialized:")
logger.info(f" Input directory: {self.input_dir}")
logger.info(f" Output directory: {self.output_dir}")

def extract_ecw_to_geotiff(self, ecw_file, output_format="GTiff"):
"""Extract ECW to GeoTIFF using Docker"""

ecw_path = self.input_dir / ecw_file
if not ecw_path.exists():
logger.error(f"ECW file not found: {ecw_path}")
return False

output_file = ecw_path.stem + ".tif"
output_path = self.output_dir / output_file

logger.info(f"Converting {ecw_file} to {output_file}...")

cmd = [
"docker", "run", "--rm",
"-v", f"{self.input_dir.absolute()}:/input",
"-v", f"{self.output_dir.absolute()}:/output",
"geodata/gdal",
"gdal_translate",
"-of", output_format,
"/input/" + ecw_file,
"/output/" + output_file
]

try:
result = subprocess.run(cmd, capture_output=True, text=True, timeout=300)

if result.returncode == 0:
logger.info(f"✓ Successfully converted {ecw_file}")
logger.info(f" Output: {output_path}")
return True
else:
logger.error(f"✗ Conversion failed for {ecw_file}")
logger.error(f" Error: {result.stderr}")
return False

except subprocess.TimeoutExpired:
logger.error(f"✗ Conversion timed out for {ecw_file}")
return False
except Exception as e:
logger.error(f"✗ Error converting {ecw_file}: {e}")
return False

def get_ecw_info(self, ecw_file):
"""Get detailed information about ECW file"""

ecw_path = self.input_dir / ecw_file
if not ecw_path.exists():
logger.error(f"ECW file not found: {ecw_path}")
return None

logger.info(f"Getting information for {ecw_file}...")

cmd = [
"docker", "run", "--rm",
"-v", f"{self.input_dir.absolute()}:/input",
"geodata/gdal",
"gdalinfo",
"/input/" + ecw_file
]

try:
result = subprocess.run(cmd, capture_output=True, text=True, timeout=60)

if result.returncode == 0:
logger.info(f"✓ Successfully retrieved info for {ecw_file}")
return result.stdout
else:
logger.error(f"✗ Failed to get info for {ecw_file}")
return None

except Exception as e:
logger.error(f"✗ Error getting info for {ecw_file}: {e}")
return None

def process_all_ecw_files(self):
"""Process all ECW files in the input directory"""

ecw_files = list(self.input_dir.glob("*.ecw"))
if not ecw_files:
logger.error("No ECW files found in input directory")
return False

logger.info(f"Found {len(ecw_files)} ECW files to process")

success_count = 0
for ecw_file in ecw_files:
logger.info(f"\nProcessing {ecw_file.name}...")

info = self.get_ecw_info(ecw_file.name)
if info:
info_file = self.output_dir / f"{ecw_file.stem}_info.txt"
with open(info_file, 'w') as f:
f.write(info)
logger.info(f" Info saved to: {info_file}")

if self.extract_ecw_to_geotiff(ecw_file.name):
success_count += 1

logger.info(f"\nProcessing complete: {success_count}/{len(ecw_files)} files converted successfully")
return success_count > 0
def main():
"""Main function"""
logger.info("=" * 80)
logger.info("ECW EXTRACTION USING DOCKER")
logger.info("=" * 80)

extractor = ECWExtractor()
success = extractor.process_all_ecw_files()

if success:
logger.info("\n✓ ECW extraction completed successfully!")
logger.info(f"Check output directory: {extractor.output_dir}")
else:
logger.error("\n✗ ECW extraction failed!")
sys.exit(1)
if __name__ == "__main__":
main()

Make it executable:

chmod +x scripts/extract_ecw_direct.py

Run it:

python3 scripts/extract_ecw_direct.py

The script will process all ECW files in your extracted/ directory and save GeoTIFF conversions to converted_images/.

Verify Your Results

Create scripts/verify_extraction.py:

#!/usr/bin/env python3
"""
Verify extracted files and validate conversion quality
"""

import subprocess
from pathlib import Path
import logging
import sys

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

class ExtractionVerifier:
def __init__(self, output_dir="converted_images"):
self.output_dir = Path(output_dir)

def verify_geotiff(self, tif_file):
"""Verify GeoTIFF file"""

tif_path = self.output_dir / tif_file
if not tif_path.exists():
logger.error(f"GeoTIFF file not found: {tif_path}")
return False

logger.info(f"Verifying {tif_file}...")

cmd = [
"docker", "run", "--rm",
"-v", f"{self.output_dir.absolute()}:/data",
"geodata/gdal",
"gdalinfo",
"/data/" + tif_file
]

try:
result = subprocess.run(cmd, capture_output=True, text=True, timeout=60)

if result.returncode == 0:
logger.info(f" ✓ {tif_file} is valid")

info = result.stdout
lines = info.split('\n')

for line in lines:
if 'Size is' in line:
logger.info(f" Size: {line.split('Size is')[1].strip()}")
elif 'Coordinate System is' in line:
logger.info(f" CRS: {line.split('Coordinate System is')[1].strip()}")

return True
else:
logger.error(f" ✗ {tif_file} is invalid: {result.stderr}")
return False

except Exception as e:
logger.error(f" ✗ Error verifying {tif_file}: {e}")
return False

def verify_all_files(self):
"""Verify all extracted files"""

tif_files = list(self.output_dir.glob("*.tif"))

if not tif_files:
logger.error("No GeoTIFF files found for verification")
return False

logger.info(f"Found {len(tif_files)} GeoTIFF files to verify")

valid_count = 0
for tif_file in tif_files:
if self.verify_geotiff(tif_file.name):
valid_count += 1

logger.info(f"\nVerification complete: {valid_count}/{len(tif_files)} files are valid")
return valid_count > 0

def main():
"""Main function"""
logger.info("=" * 80)
logger.info("ECW EXTRACTION VERIFICATION")
logger.info("=" * 80)

verifier = ExtractionVerifier()
success = verifier.verify_all_files()

if success:
logger.info("\n✓ Verification completed successfully!")
else:
logger.error("\n✗ Verification failed!")
sys.exit(1)

if __name__ == "__main__":
chmod +x scripts/verify_extraction.py  ### Permissions
python3 scripts/verify_extraction.py

Troubleshooting

Can’t run docker on Windows? Make sure WSL2 is fully installed and Docker Desktop has WSL2 backend enabled in settings.

Permission denied on Linux?

sudo usermod -aG docker $USER
newgrp docker

ECW format not found?

docker run --rm geodata/gdal gdalinfo --formats | grep ECW

If empty, try: docker pull osgeo/gdal:ubuntu-small-latest

Out of disk space?

df -h
docker system prune -a

Why This Matters

Let me be real about what you’re getting here:

Instead of:

  • Paying hundreds/thousands for licenses
  • Struggling with OS-specific software
  • Hours of library installation headaches
  • Vendor lock-in to proprietary tools

You get:

  • Zero licensing costs
  • Same workflow on Linux, Windows, and Mac
  • Reproducible results every time
  • Scalable batch processing
  • Open-source sustainability

On my Chile drone imagery project, this saved us from buying expensive proprietary software. We process 50+ ECW files monthly without a single licensing fee.

What’s Next?

After extraction, you can:

  • Import GeoTIFF files into QGIS (free, open-source GIS)
  • Run machine learning models for image analysis
  • Create orthomosaics for research
  • Share files freely without licensing restrictions

Start extracting your ECW files for free today. No credit card, no licensing fees, no compatibility nightmares. Just Docker, GDAL, and clean GeoTIFF files.

--

--

Written by Rahul Bhat

Tech Project Lead - Data Scientist at United Nations