<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet href="https://blog.geothings.ch/feed_style.xsl" type="text/xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <tabi:metadata xmlns:tabi="https://github.com/welpo/tabi">
        <tabi:base_url>https://blog.geothings.ch</tabi:base_url>
        <tabi:separator>
            •
        </tabi:separator>
        <tabi:about_feeds>
            This is a web feed, also known as an Atom feed. Subscribe by copying the URL from the address bar into your newsreader. Visit About Feeds to learn more and get started. It's free.
        </tabi:about_feeds>
        <tabi:visit_the_site>
            Visit website
        </tabi:visit_the_site>
        <tabi:recent_posts>
            Recent posts
        </tabi:recent_posts>
        <tabi:last_updated_on>
            Updated on $DATE
        </tabi:last_updated_on>
        <tabi:default_theme></tabi:default_theme>
        <tabi:post_listing_date>date</tabi:post_listing_date>
        <tabi:current_section>gdal</tabi:current_section>
    </tabi:metadata><link rel="extra-stylesheet" href="https://blog.geothings.ch/skins/mint.css?h=504215cf6bc10586b487" /><title>geothings - gdal</title>
        <subtitle>spatial data | open source | oversharing</subtitle>
    <link href="https://blog.geothings.ch/tags/gdal/atom.xml" rel="self" type="application/atom+xml"/>
    <link href="https://blog.geothings.ch/tags/gdal/" rel="alternate" type="text/html"/>
    <generator uri="https://www.getzola.org/">Zola</generator><updated>2024-03-08T00:00:00+00:00</updated><id>https://blog.geothings.ch/tags/gdal/atom.xml</id><entry xml:lang="en">
        <title>Opening and writing raster dataset with GDAL Rust</title>
        <published>2024-03-08T00:00:00+00:00</published>
        <updated>2024-03-08T00:00:00+00:00</updated>
        <author>
            <name>jujube</name>
        </author>
        <link rel="alternate" href="https://blog.geothings.ch/blog/rust-gdal/" type="text/html"/>
        <id>https://blog.geothings.ch/blog/rust-gdal/</id>
        
            <content type="html">&lt;p&gt;I’ve been trying to learn Rust lately. For some reason there is something that I find very appealing in this language. From all I could read, it’s very efficient in resources and memory, it’s fast, and it doesn’t let you mess around with memory. Regarding performances, it places itself next to C and C++, and when looking into the world of language performances, I learned that Python was kind of slow, around 100x slower according to some benchmarks. Obviously this value in itself doesn’t mean much, and many more aspects of a language must be taken account when choosing one for the task, but this information kind of planted its seed. It might be because I have a problem with inefficient and overly complicated process, but I find the idea to work with a system language very elegant.&lt;/p&gt;
&lt;p&gt;But we’re not here to talk about the Rust language in itself. We’ll see how to read and write raster data using the Rust binding for GDAL. Also, this is about how I tried to compare the Rust and Python bindings for GDAL and how I learned that it doesn’t change a thing in terms of performance.&lt;/p&gt;
&lt;h2 id=&quot;wait-what&quot;&gt;Wait what?&lt;/h2&gt;
&lt;p&gt;Well I started by thinking “Oh I can’t wait to see how faster GDAL in Rust is compared to Python”. So I started by reading a raster file and print some basic information. I use a band from a &lt;a rel=&quot;external&quot; href=&quot;https://browser.dataspace.copernicus.eu/&quot;&gt;Sentinel-2 image&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;how-to-open-a-raster-file&quot;&gt;How to open a raster file?&lt;/h3&gt;
&lt;p&gt;Let’s do it. We’ll be working with the GDAL crate from &lt;a rel=&quot;external&quot; href=&quot;https://crates.io/crates/gdal&quot;&gt;crates.io&lt;/a&gt; (&lt;code&gt;cargo add gdal&lt;/code&gt;) and the GDAL package prom &lt;a rel=&quot;external&quot; href=&quot;https://pypi.org/project/GDAL/&quot;&gt;PyPi&lt;/a&gt; (&lt;code&gt;pip install GDAL&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;In Rust:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;use&lt;/span&gt;&lt;span class=&quot;z-10&quot;&gt; gdal&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;z-10 z-i&quot;&gt;Dataset&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;// Open dataset&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;let&lt;/span&gt;&lt;span&gt; ds&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-10 z-i&quot;&gt; Dataset&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;IMG.jp2&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;unwrap&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;This raster has &lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;{}&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; bands.&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span&gt; ds&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;raster_count&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;());&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;// Read band&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;let&lt;/span&gt;&lt;span&gt; band&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span&gt; ds&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;rasterband&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-14&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;unwrap&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;// Print statistics&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;if let&lt;/span&gt;&lt;span class=&quot;z-10 z-i&quot;&gt; Some&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span&gt;stats&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span&gt; band&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;get_statistics&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-11&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-11&quot;&gt; true&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;unwrap&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;    println!&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;        &amp;quot;[ STATS ] =  Minimum=&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;{}&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;, Maximum=&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;{}&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;, Mean=&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;{}&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;, StdDev=&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;{}&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        stats&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span&gt;min&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span&gt; stats&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span&gt;max&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span&gt; stats&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span&gt;mean&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span&gt; stats&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span&gt;std_dev&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4&quot;&gt;    );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4&quot;&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;admonition warning&quot;&gt;
&lt;div class=&quot;admonition-icon admonition-icon-warning&quot;&gt;&lt;/div&gt;
&lt;div class=&quot;admonition-content&quot;&gt;
&lt;strong class=&quot;admonition-title&quot;&gt;WARNING&lt;/strong&gt;
&lt;p&gt;I’m using a lot of .unwrap(), which in very short will cause the code to panic if a problem occurs, this is for a quick and dirty test. Within a “production” environment you would handle errors and stuff.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;And in Python:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;from&lt;/span&gt;&lt;span&gt; osgeo&lt;/span&gt;&lt;span class=&quot;z-9&quot;&gt; import&lt;/span&gt;&lt;span&gt; gdal&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;gdal&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;UseExceptions&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;# Open dataset&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;dataset&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span&gt; gdal&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;Open&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;#39;IMG.jp2&amp;#39;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;nband&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span&gt; dataset&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span&gt;RasterCount&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-14 z-i&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-7 z-i&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;#39;This raster contains &lt;/span&gt;&lt;span class=&quot;z-16&quot;&gt;{&lt;/span&gt;&lt;span&gt;nband&lt;/span&gt;&lt;span class=&quot;z-16&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; bands.&amp;#39;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;# Read band&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;srcband&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span&gt; dataset&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;GetRasterBand&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-14&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;# Print statistics&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;stats&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span&gt; srcband&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;GetStatistics&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-14&quot;&gt; True&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-14&quot;&gt; True&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt; )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-14 z-i&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-7 z-i&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;#39;[ STATS ] =  Minimum=%.3f, Maximum=%.3f, Mean=%.3f, StdDev=%.3f&amp;#39;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-1&quot;&gt;    %&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;z-12 z-i&quot;&gt; stats&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;z-14 z-i&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;z-12 z-i&quot;&gt; stats&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;z-14 z-i&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;z-12 z-i&quot;&gt; stats&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;z-14 z-i&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;z-12 z-i&quot;&gt; stats&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;z-14 z-i&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;] ))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;File opened and information read. We can compare their runtime.&lt;/p&gt;
&lt;h3 id=&quot;comparing-performances&quot;&gt;Comparing performances&lt;/h3&gt;
&lt;p&gt;Building the Rust program, then running and timing these two codes multiple times, we get results like follows:&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Rust&lt;/th&gt;&lt;th&gt;Python&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;real    &lt;strong&gt;0m0.072s&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;real    &lt;strong&gt;0m0.156s&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;user    0m0.154s&lt;/td&gt;&lt;td&gt;user    0m0.752s&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;sys     0m0.275s&lt;/td&gt;&lt;td&gt;sys     0m1.689s&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;div class=&quot;admonition warning&quot;&gt;
&lt;div class=&quot;admonition-icon admonition-icon-warning&quot;&gt;&lt;/div&gt;
&lt;div class=&quot;admonition-content&quot;&gt;
&lt;strong class=&quot;admonition-title&quot;&gt;WARNING&lt;/strong&gt;
&lt;p&gt;This is a naive approach on testing and comparing performances, not a full-fledged benchmark.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Twice as fast without any processing or multi-threading, at that point I though “Oh it’s gonna be good”.&lt;/p&gt;
&lt;h2 id=&quot;let-s-add-some-writing-then&quot;&gt;Let’s add some writing then&lt;/h2&gt;
&lt;p&gt;It’s only the start, we’ll now read the data in our raster dataset and, since my source is in .jp2, write it in a new raster dataset in the GeoTiff format.&lt;/p&gt;
&lt;h3 id=&quot;how-to-write-a-raster-dataset-with-gdal-bindings&quot;&gt;How to write a raster dataset with GDAL bindings?&lt;/h3&gt;
&lt;p&gt;We will be using the Create() approach rather than the CreateCopy() (see the nuance in the &lt;a rel=&quot;external&quot; href=&quot;https://gdal.org/tutorials/raster_api_tut.html#using-createcopy&quot;&gt;doc&lt;/a&gt;). Geospatialized rasters come with series of metadata and overviews. The CreateCopy() automatically takes those from the source dataset and copy them into the destination. While this obviously simplifies the work if we don’t need to bring any change to these information, using Create() helps to better understand the structure of a raster. Also I have a quite important performance difference between the two and I’ve found Create() more efficient for my use case.&lt;/p&gt;
&lt;p&gt;So the code now becomes as follow.&lt;/p&gt;
&lt;p&gt;In Rust:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;use&lt;/span&gt;&lt;span class=&quot;z-10&quot;&gt; gdal&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;z-10 z-i&quot;&gt;Dataset&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-10 z-i&quot;&gt; DriverManager&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;// Open dataset&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;let&lt;/span&gt;&lt;span&gt; ds&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-10 z-i&quot;&gt; Dataset&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;IMG.jp2&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;unwrap&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;This raster has &lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;{}&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; bands.&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span&gt; ds&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;raster_count&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;());&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;// Get source dataset metadata&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;let&lt;/span&gt;&lt;span&gt; projection&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span&gt; ds&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;projection&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;let&lt;/span&gt;&lt;span&gt; spatial_ref&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span&gt; ds&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;spatial_ref&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;unwrap&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;let&lt;/span&gt;&lt;span&gt; geo_transform&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span&gt; ds&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;geo_transform&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;unwrap&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt; (&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span&gt; y&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span&gt; ds&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;raster_size&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;// Read band&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;let&lt;/span&gt;&lt;span&gt; band&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span&gt; ds&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;rasterband&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-14&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;unwrap&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;// Get GeoTiff driver  &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;let&lt;/span&gt;&lt;span&gt; d&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-10 z-i&quot;&gt; DriverManager&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;get_driver_by_name&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;GTiff&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;unwrap&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;// Create the destination dataset as mutable with 1 band&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;let mut&lt;/span&gt;&lt;span&gt; dst_ds&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span&gt; d&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;create_with_band_type&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-9&quot;&gt;u16&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span&gt; _&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;IMG_as_tiff.gtiff&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    x&lt;/span&gt;&lt;span class=&quot;z-9&quot;&gt; as isize&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span&gt; y&lt;/span&gt;&lt;span class=&quot;z-9&quot;&gt; as isize&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-14&quot;&gt; 1&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;unwrap&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;// Set metadata from source dataset&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;dst_ds&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;set_geo_transform&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;geo_transform&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;unwrap&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;dst_ds&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;set_projection&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;projection&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;unwrap&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;dst_ds&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;set_spatial_ref&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;spatial_ref&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;unwrap&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;// Get the destination band as mutable&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;let mut&lt;/span&gt;&lt;span&gt; dst_band&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span&gt; dst_ds&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;rasterband&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-14&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;unwrap&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;// Read the source data as Buffer&amp;lt;u16&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;let&lt;/span&gt;&lt;span&gt; buf&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span&gt; band&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;read_as&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-9&quot;&gt;u16&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;z-14&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-14&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;), (&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span&gt; y&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;), (&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span&gt; y&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;),&lt;/span&gt;&lt;span class=&quot;z-10 z-i&quot;&gt; None&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;unwrap&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;// Write the data in the destination band&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;dst_band&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;z-14&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-14&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;), (&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span&gt; y&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;),&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span&gt;buf&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;unwrap&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;// Close dataset for good conscience&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ds&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;close&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;unwrap&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;dst_ds&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;close&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;unwrap&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And in Python:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;# Open dataset&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ds&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span&gt; gdal&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;Open&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;#39;IMG.jp2&amp;#39;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;nband&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span&gt; ds&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span&gt;RasterCount&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-14 z-i&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-7 z-i&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;#39;This raster has &lt;/span&gt;&lt;span class=&quot;z-16&quot;&gt;{&lt;/span&gt;&lt;span&gt;nband&lt;/span&gt;&lt;span class=&quot;z-16&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; bands.&amp;#39;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;# Get dataset metadata&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;srcprojection&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span&gt; ds&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;GetProjection&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;srcspatialref&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span&gt; ds&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;GetSpatialRef&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;srcgeotransform&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span&gt; ds&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;GetGeoTransform&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span&gt;xsize&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span&gt; ysize&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt; (&lt;/span&gt;&lt;span&gt;ds&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span&gt;RasterXSize&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span&gt; ds&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span&gt;RasterYSize&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;# Get GeoTiff driver&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fileformat&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; &amp;quot;GTiff&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;driver&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span&gt; gdal&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;GetDriverByName&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span&gt;fileformat&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;# Create the destination dataset with 1 band&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;dst_ds&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span&gt; driver&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;Create&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;#39;IMG_as_tiff.gtiff&amp;#39;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-12 z-i&quot;&gt; xsize&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span&gt;xsize&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-12 z-i&quot;&gt; ysize&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span&gt;ysize&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-12 z-i&quot;&gt;                    bands&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span&gt;nband&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-12 z-i&quot;&gt; eType&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span&gt;gdal&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span&gt;GDT_UInt16&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;# Set metadata from source dataset&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;dst_ds&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;SetProjection&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span&gt;srcprojection&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;dst_ds&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;SetGeoTransform&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span&gt;srcgeotransform&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;dst_ds&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;SetSpatialRef&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span&gt;srcspatialref&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;# Get the destination band&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;srcband&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span&gt; ds&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;GetRasterBand&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-14&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;# Read the source data as Array&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;srcdata&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span&gt; srcband&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;ReadAsArray&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;# Write the data in the destination band&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;dst_ds&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;GetRasterBand&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-14&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;WriteArray&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span&gt;srcdata&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;# Close dataset for good conscience&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ds&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-14&quot;&gt; None&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;dst_ds&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-14&quot;&gt; None&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Both codes should create a new raster file that resembles our source, but in GeoTiff. And that’s it, you can convert a raster file into any format. We’re just scratching the surface, you can subset data, reproject, transpose it if you want etc.&lt;/p&gt;
&lt;h3 id=&quot;but-let-s-compare-performances-again&quot;&gt;But let’s compare performances again&lt;/h3&gt;
&lt;p&gt;Now as “la cerise sur le gâteau”, let’s see how powerful Rust can be.&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Rust&lt;/th&gt;&lt;th&gt;Python&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;real    &lt;strong&gt;0m1.024s&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;real    &lt;strong&gt;0m1.133s&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;user    0m17.150s&lt;/td&gt;&lt;td&gt;user    0m17.335s&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;sys     0m1.629s&lt;/td&gt;&lt;td&gt;sys     0m2.089s&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Wait let me rerun.&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Rust&lt;/th&gt;&lt;th&gt;Python&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;real    &lt;strong&gt;0m1.053s&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;real    &lt;strong&gt;0m1.141s&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;user    0m17.076s&lt;/td&gt;&lt;td&gt;user    0m17.324s&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;sys     0m1.608s&lt;/td&gt;&lt;td&gt;sys     0m2.134s&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Hmm.&lt;/p&gt;
&lt;h2 id=&quot;wait-what-bis&quot;&gt;Wait what? (bis)&lt;/h2&gt;
&lt;p&gt;Well that’s not what I expected.&lt;/p&gt;
&lt;p&gt;In the process I forgot something important, we are working with &lt;strong&gt;bindings&lt;/strong&gt;. Asking &lt;a rel=&quot;external&quot; href=&quot;https://en.wikipedia.org/wiki/Language_binding&quot;&gt;Wikipedia&lt;/a&gt; what a binding is:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In programming and software design, binding is an application programming interface (API) that provides glue code specifically made to allow a programming language to use a foreign library or operating system service (one that is not native to that language).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So from my understanding, working with Rust or Python or any other language bindings is just working with the API that let us call the underlying code, for GDAL written in C and C++. Thus the overhead that we generate is only the interaction with the library, not during the process itself, since it’s running C/C++ code. The difference that we observe is probably the same that we were observing when we just opened a file.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;GDAL raster processing is &lt;strong&gt;very&lt;/strong&gt; similar in Rust and Python. When working with its bindings, it doesn’t change much which language you use &lt;strong&gt;to perform the GDAL operations in themself&lt;/strong&gt;, since in any case you’re running C/C++ code from your program. But everything that is around need to be considered when choosing the right tool. If your program needs multi-threading then you’l probably chose Rust, if you need quick development without much optimization then Python might be a best fit. But it’s comfortable to see that the GDAL processing time won’t change significantly.&lt;/p&gt;
&lt;p&gt;I’m not at all trying to say that Rust is not worth it, I’m excited to go further into it and work on projects, but it remains a tool and there should be no injunction to use it if it doesn’t bring much to the table for your use case.&lt;/p&gt;
&lt;p&gt;Also it’s totally possible that I totally misunderstood something and that those comparisons are meaningless, happy to learn more about it.&lt;/p&gt;
</content>
        <summary type="html">Some first tries at using the GDAL/OGR binding in Rust 🦀</summary>
        </entry><entry xml:lang="en">
        <title>PMTiles exploration</title>
        <published>2024-02-02T00:00:00+00:00</published>
        <updated>2024-02-02T00:00:00+00:00</updated>
        <author>
            <name>jujube</name>
        </author>
        <link rel="alternate" href="https://blog.geothings.ch/blog/pmtiles-introduction/" type="text/html"/>
        <id>https://blog.geothings.ch/blog/pmtiles-introduction/</id>
        
            <content type="html">&lt;p&gt;It’s a technology that I came across rather recently. Tile generation when maintaining a geographic oriented website can be a hassle: it can take time, generates a lot of files, and can be a critical process. PMTiles might have the potential to facilitate some of this work and we’ll try to see how.&lt;/p&gt;
&lt;h2 id=&quot;what-are-pmtiles&quot;&gt;What are PMTiles?&lt;/h2&gt;
&lt;p&gt;In itself, PMTiles is a specification for building single-file tile pyramids. It’s open source and part of a larger project called &lt;a rel=&quot;external&quot; href=&quot;https://protomaps.com/&quot;&gt;Protomaps&lt;/a&gt;, and it aims at mapping the World, just that. The major difference with the kind of tiles that I know is that they are embedded as a single file, like the MBTile format, which make the interaction very intuitive, I mean we all get the idea of what a file is. But what does it bring compared to MBTiles? Well from the Protomaps website:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A MBTiles file needs to be accessed as a SQLite database on disk, so requires a running server and disk storage for cloud hosting. &lt;strong&gt;PMTiles is designed to be cloud-native&lt;/strong&gt; and readable in fine-grained parts from remote storage like Amazon S3.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It aims at simplifying the manipulation of tiles in a cloud native approach, for worldwide coverage.&lt;/p&gt;
&lt;h2 id=&quot;how-to-create-pmtiles&quot;&gt;How to create PMTiles?&lt;/h2&gt;
&lt;p&gt;The &lt;a rel=&quot;external&quot; href=&quot;https://docs.protomaps.com/pmtiles/create&quot;&gt;Protomaps website&lt;/a&gt; gives us some tools to create these tiles. Let’s try some possibilities.&lt;/p&gt;
&lt;h3 id=&quot;generate-pmtiles-using-gdal&quot;&gt;Generate PMTiles using GDAL&lt;/h3&gt;
&lt;p&gt;Our &lt;a rel=&quot;external&quot; href=&quot;https://www.geothings.ch/posts/gdal-appreciation/&quot;&gt;Swiss Army Knife&lt;/a&gt; is back, starting version 3.8.0 GDAL has native support for PMTiles, so let’s try that.&lt;/p&gt;
&lt;p&gt;First check the GDAL version you’re using, you’ll want 3.8.0 or higher:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;gdalinfo&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; --version&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;--&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; GDAL 3.8.3, released 2024/01/04&lt;/span&gt;&lt;span&gt; (debug&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; build&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let’s start from an OSM &lt;code&gt;.pbf&lt;/code&gt; file (see &lt;a rel=&quot;external&quot; href=&quot;https://www.geothings.ch/posts/vector-tiles-with-martin/#downloading-some-data&quot;&gt;Serving vector tiles with Martin&lt;/a&gt;). To convert this file into a PMTiles file you can enter:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;ogr2ogr&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; -f PMTiles out.pmtiles switzerland-latest.osm.pbf&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The process might take some time if you’re working on a large dataset. By default the MAXZOOM is 5, which is rather low, so the run shouldn’t take to long, but if you start to increase the parameter to around 15, which allows to represent data from much closer, processing time increases.&lt;/p&gt;
&lt;p&gt;But once the command is done, well that’s it!&lt;/p&gt;
&lt;p&gt;Alternatively we can use &lt;a rel=&quot;external&quot; href=&quot;https://github.com/felt/tippecanoe&quot;&gt;tippecanoe&lt;/a&gt; to achieve the same result.&lt;/p&gt;
&lt;h3 id=&quot;generate-pmtiles-using-tippecanoe&quot;&gt;Generate PMTiles using tippecanoe&lt;/h3&gt;
&lt;div class=&quot;admonition warning&quot;&gt;
&lt;div class=&quot;admonition-icon admonition-icon-warning&quot;&gt;&lt;/div&gt;
&lt;div class=&quot;admonition-content&quot;&gt;
&lt;strong class=&quot;admonition-title&quot;&gt;WARNING&lt;/strong&gt;
&lt;p&gt;Under construction&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&quot;visualize-pmtiles&quot;&gt;Visualize PMTiles&lt;/h2&gt;
&lt;p&gt;The easiest way is to go to the &lt;a rel=&quot;external&quot; href=&quot;https://protomaps.github.io/PMTiles/&quot;&gt;PMTiles Viewer Page&lt;/a&gt; and upload your newly created PMTiles file.&lt;/p&gt;
&lt;p&gt;Obviously you can add it to your custom project. The easiest way of doing is by using the Leaflet plugin &lt;a rel=&quot;external&quot; href=&quot;https://github.com/protomaps/protomaps-leaflet&quot;&gt;protomaps-leaflet&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Starting from complete scratch you can create an &lt;code&gt;.html&lt;/code&gt; file with the following content:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;html&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;&amp;lt;!DOCTYPE&lt;/span&gt;&lt;span class=&quot;z-10&quot;&gt; html&lt;/span&gt;&lt;span class=&quot;z-9&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;head&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-1&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;meta&lt;/span&gt;&lt;span class=&quot;z-10&quot;&gt; charset&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;utf-8&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; /&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-1&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;meta&lt;/span&gt;&lt;span class=&quot;z-10&quot;&gt; name&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;viewport&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-10&quot;&gt; content&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;width=device-width, initial-scale=1&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-1&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;link&lt;/span&gt;&lt;span class=&quot;z-10&quot;&gt; rel&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;stylesheet&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-10&quot;&gt; href&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;https://unpkg.com/leaflet@1.7.1/dist/leaflet.css&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; /&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-1&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;z-10&quot;&gt; src&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;https://unpkg.com/leaflet@1.7.1/dist/leaflet.js&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-1&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;z-10&quot;&gt; src&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;https://unpkg.com/protomaps-leaflet@latest/dist/protomaps-leaflet.min.js&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-1&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;        body&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4&quot;&gt;        #&lt;/span&gt;&lt;span class=&quot;z-10&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;            height&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-14&quot;&gt; 100&lt;/span&gt;&lt;span class=&quot;z-9&quot;&gt;vh&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;            margin&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-14&quot;&gt; 0&lt;/span&gt;&lt;span class=&quot;z-9&quot;&gt;px&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-1&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;head&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-1&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;h2&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;Hey I&amp;#39;m a custom page&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;h2&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-1&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;Let&amp;#39;s add some Leaflet and PMTiles.&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-1&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;z-10&quot;&gt; id&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;map&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-1&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;        let&lt;/span&gt;&lt;span&gt; PAINT_RULES&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4&quot;&gt;            {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                dataLayer&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; &amp;quot;multipolygons&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-4 z-i&quot;&gt; //here we render only one layer, check your layers names &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                symbolizer&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; new&lt;/span&gt;&lt;span&gt; protomapsL&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;PolygonSymbolizer&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;{&lt;/span&gt;&lt;span&gt; fill&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; &amp;quot;steelblue&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt; }&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        ]&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;        const&lt;/span&gt;&lt;span&gt; map&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-14&quot;&gt; L&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;map&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;#39;map&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;setView&lt;/span&gt;&lt;span&gt;([&lt;/span&gt;&lt;span class=&quot;z-14&quot;&gt;46.5&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-14&quot;&gt; 6.6&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-14&quot;&gt; 13&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;z-4 z-i&quot;&gt; //chose a view that suits you&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;        var&lt;/span&gt;&lt;span&gt; osm&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-14&quot;&gt; L&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;tileLayer&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;#39;https://tile.openstreetmap.org/{z}/{x}/{y}.png&amp;#39;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;, {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            maxZoom&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-14&quot;&gt; 19&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            attribution&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; &amp;#39;&amp;amp;copy; &amp;lt;a href=&amp;quot;http://www.openstreetmap.org/copyright&amp;quot;&amp;gt;OpenStreetMap&amp;lt;/a&amp;gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4&quot;&gt;        }&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;addTo&lt;/span&gt;&lt;span&gt;(map)&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;        var&lt;/span&gt;&lt;span&gt; layer&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span&gt; protomapsL&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;leafletLayer&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4&quot;&gt;            {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                url&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; &amp;#39;http://127.0.0.1:8080/your_pmtile_file.pmtiles&amp;#39;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                paint_rules&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span&gt; PAINT_RULES&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4&quot;&gt;            }&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;addTo&lt;/span&gt;&lt;span&gt;(map)&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-1&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-1&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For testing purposes you might have to serve you PMTiles through http. To do so you can do as the Protomaps website suggests:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;npm&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; install -g http-server&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;# Then from the folder containing your PMTiles.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;http-server&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; . --cors&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Open your &lt;code&gt;.html&lt;/code&gt; file on the browser of your choice and you should see the map with your PMTiles displayed.&lt;/p&gt;
&lt;h2 id=&quot;when-should-pmtiles-be-used&quot;&gt;When should PMTiles be used?&lt;/h2&gt;
&lt;p&gt;Again, the documentation on &lt;a rel=&quot;external&quot; href=&quot;https://protomaps.com/faq&quot;&gt;Protomaps website&lt;/a&gt; is quite complete and gives us some insights.&lt;/p&gt;
&lt;h3 id=&quot;cloud-hosting&quot;&gt;Cloud hosting&lt;/h3&gt;
&lt;p&gt;PMTiles are stored as a single file, and compression is so efficient that the size is ridiculous compared to classic png tiles. Number of requests necessary is drastically reduced and thus the cost of operation as well.&lt;/p&gt;
&lt;h3 id=&quot;static-data&quot;&gt;Static data&lt;/h3&gt;
&lt;p&gt;PMTiles don’t support localized updates so each time you’ll need to apply an update, the whole file needs to be rewritten. If your data don’t change that much PMTiles are a wise choice, but If you need to have a more dynamic rendering the documentation recommends PostGIS with the &lt;a rel=&quot;external&quot; href=&quot;https://postgis.net/docs/ST_AsMVT.html&quot;&gt;ST_As_MVT()&lt;/a&gt; function.&lt;/p&gt;
&lt;h3 id=&quot;simplicity&quot;&gt;Simplicity&lt;/h3&gt;
&lt;p&gt;Here it’s more like a feeling about the philosophy of the specification. You have a single file, accessible without introduced complexity, directly from a library like Leaflet, which itself has &lt;em&gt;simplicity&lt;/em&gt; as one of its core objectives. It looks like one of those project that allows you to make complicated-looking things so easily. I guess it’s a sign of a good project.&lt;/p&gt;
&lt;h2 id=&quot;final-words&quot;&gt;Final words&lt;/h2&gt;
&lt;p&gt;Well it was rather easy to discover. I mean we create a file, we basically load it within a project and we’re good to go. Obviously there are some customizations to do with styling and labels etc. But once you have the starting point and your tools, it takes minutes to create what you desire.&lt;/p&gt;
&lt;p&gt;Here we’re just scratching the surface, remains to explore filtering, styling etc. But the concept in itself and the unreasonable performance of the compression make it very interesting if you’re in the situation where PMTiles could give you an advantage; the file created for OSM data Switzerland, with zooms from 0 to 14, is around 1GB, it costs pennies to upload and host on cloud services.&lt;/p&gt;
&lt;p&gt;It’s a project to support and look for, I guess?&lt;/p&gt;
</content>
        <summary type="html">Messing around with something I never used, have some pmtiles.</summary>
        </entry><entry xml:lang="en">
        <title>A little bit of GDAL/OGR appreciation</title>
        <published>2024-01-19T00:00:00+00:00</published>
        <updated>2024-01-19T00:00:00+00:00</updated>
        <author>
            <name>jujube</name>
        </author>
        <link rel="alternate" href="https://blog.geothings.ch/blog/gdal-appreciation/" type="text/html"/>
        <id>https://blog.geothings.ch/blog/gdal-appreciation/</id>
        
            <content type="html">&lt;p&gt;If there had to be one single tool to work with spatial data, I think GDAL/OGR would be the first name to come to mind. Its usages range from raster to vector, it can be used as command line, imported as a library in many languages through bindings developed by the community, many applications provide UI to parameterize and run GDAL etc. Its versatility makes it an amazing tool to work with spatial data in a lot of different contexts, but it’s sometimes underestimated or even misunderstood.&lt;/p&gt;
&lt;p&gt;We will quickly introduce GDAL/OGR, then give some examples of usage to help for some quick starts.&lt;/p&gt;
&lt;h2 id=&quot;what-is-gdal-ogr&quot;&gt;What is GDAL/OGR?&lt;/h2&gt;
&lt;p&gt;GDAL/OGR (&lt;strong&gt;G&lt;/strong&gt;eospatial &lt;strong&gt;D&lt;/strong&gt;ata &lt;strong&gt;A&lt;/strong&gt;bstraction &lt;strong&gt;L&lt;/strong&gt;ibrary/&lt;strong&gt;O&lt;/strong&gt;pen&lt;strong&gt;G&lt;/strong&gt;IS Simple Features &lt;strong&gt;R&lt;/strong&gt;eference Implementation) is a library for working with raster and vector geospatial data formats, coded mainly in C++, C and Python. The first release dates from 2000, and the project has now more than &lt;a rel=&quot;external&quot; href=&quot;https://github.com/OSGeo/gdal/graphs/contributors&quot;&gt;450 contributors&lt;/a&gt; at the time of writing. This is a very active project with regular releases.&lt;/p&gt;
&lt;p&gt;The project is composed of two parts: the raster processing library GDAL and the feature processing library OGR, both merged during the release of GDAL 2.0. When working with raster data you will use programs prefixed with &lt;em&gt;gdal&lt;/em&gt; (gdal_translate, gdalwarp etc.) while vector data will use &lt;em&gt;ogr&lt;/em&gt; prefixed scripts (ogrinfo, ogr2ogr etc.). When talking aboutt &lt;em&gt;GDAL&lt;/em&gt;, both libraries are included, and we’ll do the same from here.&lt;/p&gt;
&lt;p&gt;As its name suggests, GDAL abstracts data in order to standardize its way of interacting with it. The driver creates the interface between the data source and the tools, allowing to focus on the logic of the process rather than how to read or write the data. This makes it a very extensible project; including a new format of data source requires to write a new driver, nothing more. You could see that the list of supported formats is quite something, either &lt;a rel=&quot;external&quot; href=&quot;https://gdal.org/drivers/raster/index.html#&quot;&gt;raster&lt;/a&gt; or &lt;a rel=&quot;external&quot; href=&quot;https://gdal.org/drivers/vector/index.html&quot;&gt;vector&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;GDAL describes itself as a translator, meaning that data come from a source and goes to its destination. Translations can occur at different moment during the process, during reading or by the script called. These translations can occur on multiple axis as well, we could for example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Extract a subset of source data depending on a region of interest.&lt;/li&gt;
&lt;li&gt;Extract a subset of source data based on an attribute.&lt;/li&gt;
&lt;li&gt;Reproject data into a different coordinate system.&lt;/li&gt;
&lt;li&gt;Merge a series of data files into a single one.&lt;/li&gt;
&lt;li&gt;etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.geothings.ch/blog/gdal-appreciation/gdal.jpeg&quot; alt=&quot;gdal-appreciation&quot; /&gt;
&lt;em&gt;Source unknown, if it’s your image and you want to be cited please leave a comment&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;As an open source project with a permissive MIT license, GDAL is used by many projects, open source or proprietary, to process geospatial data. If you’ve used QGIS, ArcGIS, FME or PostGIS, you’ve used GDAL under the hood.&lt;/p&gt;
&lt;h2 id=&quot;why-would-i-use-it&quot;&gt;Why would I use it?&lt;/h2&gt;
&lt;p&gt;Weirdly, even though GDAL is basically everywhere there is geospatial data to be moved, it’s not so much acknowledged by GIS people, or at least it’s not really used on its own. If you read this, you definitely use GDAL, but maybe without noticing.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Ok but why would I complicate my life with some command lines when the same tool is being used by a software that provides me a user interface easier to use?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;While it’s much intuitive to explore geospatial data through a user interface such as QGIS, where you can interactively load your data, chose the process you want to apply, its parameters, and visualize the results, things get a bit more complicated once you’ve done the exploratory part and want to reapply your newly defined process to new data. Repeating operations becomes quickly tedious and error-prone. You could use a tool such as the &lt;a rel=&quot;external&quot; href=&quot;https://docs.qgis.org/3.28/en/docs/user_manual/processing/modeler.html&quot;&gt;Model Designer&lt;/a&gt; from QGIS (amazing little tool, check it if you repeat a lot of operations in QGIS), but how do you schedule your process to be started when you’re not able to launch it manually?&lt;/p&gt;
&lt;p&gt;If you use a heavy client ETL such as FME, try once to compare the difference in speed between a simple table transfer done by launching a FME workspace (using a command line) and a simple &lt;em&gt;ogr2ogr&lt;/em&gt; command, there is at least an order of magnitude of difference.&lt;/p&gt;
&lt;p&gt;It’s about using a tool designed for a purpose as efficiently as possible.&lt;/p&gt;
&lt;h2 id=&quot;how-to-install&quot;&gt;How to install?&lt;/h2&gt;
&lt;p&gt;We’ll assume you have no installation of GDAL yet, but just to make sure you can try:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;gdalinfo&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; --version&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which gives:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;GDAL 3.4.1, released 2021/12/27&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If it’s not installed you can refer to the installation instructions from &lt;a rel=&quot;external&quot; href=&quot;https://gdal.org/download.html#&quot;&gt;GDAL website&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For example, I’m working on Ubuntu 22.04, for which the GDAL package is the &lt;a rel=&quot;external&quot; href=&quot;https://launchpad.net/ubuntu/+source/gdal&quot;&gt;3.4.1&lt;/a&gt;. The latest version can be installed by downloading the latest release, but I usually stick with the provided version for my platform, unless I need a specific update.&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;apt&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; update&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;apt&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; install gdal-bin&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And you should be good!&lt;/p&gt;
&lt;div class=&quot;admonition warning&quot;&gt;
&lt;div class=&quot;admonition-icon admonition-icon-warning&quot;&gt;&lt;/div&gt;
&lt;div class=&quot;admonition-content&quot;&gt;
&lt;strong class=&quot;admonition-title&quot;&gt;WARNING&lt;/strong&gt;
&lt;p&gt;You might already have GDAL installed through another software like QGIS, be careful during the installation, multiple installations might interfere and create warnings or errors. On Windows you can use the &lt;em&gt;OSGeo Shell&lt;/em&gt; to access any tool from the OSGeo ecosystem.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&quot;and-how-do-we-use-it&quot;&gt;And how do we use it?&lt;/h2&gt;
&lt;p&gt;It’s easy, you just need to be comfortable with command lines. If you’ve mostly worked with user interfaces it might look scary, but it really is not complicated.&lt;/p&gt;
&lt;h3 id=&quot;access-metadata&quot;&gt;Access metadata&lt;/h3&gt;
&lt;p&gt;The first thing we usually do with data is to have some information about it. Let’s try to see the metadata of a random .jpeg:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;gdalinfo&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; gdal.jpeg&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Driver: JPEG/JPEG JFIF&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Files: gdal.jpeg&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Size is 711, 882&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Metadata:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  EXIF_Orientation=1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Image Structure Metadata:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  COMPRESSION=JPEG&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  INTERLEAVE=PIXEL&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  SOURCE_COLOR_SPACE=YCbCr&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Corner Coordinates:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Upper Left  (    0.0,    0.0)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Lower Left  (    0.0,  882.0)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Upper Right (  711.0,    0.0)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Lower Right (  711.0,  882.0)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Center      (  355.5,  441.0)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Band 1 Block=711x1 Type=Byte, ColorInterp=Red&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Overviews: 356x441, 178x221&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Image Structure Metadata:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    COMPRESSION=JPEG&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Band 2 Block=711x1 Type=Byte, ColorInterp=Green&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Overviews: 356x441, 178x221&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Image Structure Metadata:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    COMPRESSION=JPEG&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Band 3 Block=711x1 Type=Byte, ColorInterp=Blue&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Overviews: 356x441, 178x221&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Image Structure Metadata:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    COMPRESSION=JPEG&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Easy right? And it’s not even georeferenced, it’s a .jpeg, a driver exists, it opens.&lt;/p&gt;
&lt;p&gt;We can try the same with some vector data. We’ll have a look at what is going on in one of the PostgreSQL database hosted on my computer.&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;ogrinfo&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; -ro PG:dbname=osm_suisse&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;INFO: Open of `PG:dbname=osm_suisse&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      using driver `PostgreSQL&amp;#39; successful.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1: planet_osm_line (Line String)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2: planet_osm_polygon&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;3: planet_osm_roads (Line String)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;4: planet_osm_point (Point)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;5: natural_polygons&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And as we can see I have 5 layers in my database. Notice how we used the &lt;em&gt;ogrinfo&lt;/em&gt; command for questioning vector data. Here &lt;em&gt;ogrinfo&lt;/em&gt; (like &lt;em&gt;gdalinfo&lt;/em&gt;) requires a dataset source as input, the syntax will depend on each driver, make sure to have a look at the &lt;a rel=&quot;external&quot; href=&quot;https://gdal.org/drivers/vector/index.html&quot;&gt;documentation&lt;/a&gt;. For a PostgreSQL connection, the line could have looked like:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;ogrinfo&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; -ro PG:&amp;quot;dbname=&amp;#39;osm_suisse&amp;#39; host=&amp;#39;localhost&amp;#39; port=&amp;#39;5432&amp;#39; user=&amp;#39;x&amp;#39; password=&amp;#39;y&amp;#39;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can extend the information that we want to see for each layer by adding the &lt;code&gt;-al&lt;/code&gt; flag to the line. The option &lt;code&gt;-so&lt;/code&gt; will summarize the output.&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;ogrinfo&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; -ro -so -al PG:dbname=osm_suisse&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;INFO: Open of `PG:dbname=osm_suisse&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      using driver `PostgreSQL&amp;#39; successful.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Layer name: planet_osm_line&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Geometry: Line String&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Feature Count: 2137192&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Extent: (626211.331305, 5706647.213604) - (1253686.695428, 6117386.570796)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Layer SRS WKT:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PROJCRS[&amp;quot;WGS 84 / Pseudo-Mercator&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    BASEGEOGCRS[&amp;quot;WGS 84&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        ENSEMBLE[&amp;quot;World Geodetic System 1984 ensemble&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            MEMBER[&amp;quot;World Geodetic System 1984 (Transit)&amp;quot;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            MEMBER[&amp;quot;World Geodetic System 1984 (G730)&amp;quot;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            MEMBER[&amp;quot;World Geodetic System 1984 (G873)&amp;quot;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            MEMBER[&amp;quot;World Geodetic System 1984 (G1150)&amp;quot;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            MEMBER[&amp;quot;World Geodetic System 1984 (G1674)&amp;quot;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            MEMBER[&amp;quot;World Geodetic System 1984 (G1762)&amp;quot;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            MEMBER[&amp;quot;World Geodetic System 1984 (G2139)&amp;quot;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            ELLIPSOID[&amp;quot;WGS 84&amp;quot;,6378137,298.257223563,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                LENGTHUNIT[&amp;quot;metre&amp;quot;,1]],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            ENSEMBLEACCURACY[2.0]],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        PRIMEM[&amp;quot;Greenwich&amp;quot;,0,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            ANGLEUNIT[&amp;quot;degree&amp;quot;,0.0174532925199433]],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        ID[&amp;quot;EPSG&amp;quot;,4326]],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    CONVERSION[&amp;quot;Popular Visualisation Pseudo-Mercator&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        METHOD[&amp;quot;Popular Visualisation Pseudo Mercator&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            ID[&amp;quot;EPSG&amp;quot;,1024]],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        PARAMETER[&amp;quot;Latitude of natural origin&amp;quot;,0,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            ANGLEUNIT[&amp;quot;degree&amp;quot;,0.0174532925199433],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            ID[&amp;quot;EPSG&amp;quot;,8801]],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        PARAMETER[&amp;quot;Longitude of natural origin&amp;quot;,0,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            ANGLEUNIT[&amp;quot;degree&amp;quot;,0.0174532925199433],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            ID[&amp;quot;EPSG&amp;quot;,8802]],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        PARAMETER[&amp;quot;False easting&amp;quot;,0,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            LENGTHUNIT[&amp;quot;metre&amp;quot;,1],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            ID[&amp;quot;EPSG&amp;quot;,8806]],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        PARAMETER[&amp;quot;False northing&amp;quot;,0,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            LENGTHUNIT[&amp;quot;metre&amp;quot;,1],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            ID[&amp;quot;EPSG&amp;quot;,8807]]],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    CS[Cartesian,2],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        AXIS[&amp;quot;easting (X)&amp;quot;,east,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            ORDER[1],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            LENGTHUNIT[&amp;quot;metre&amp;quot;,1]],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        AXIS[&amp;quot;northing (Y)&amp;quot;,north,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            ORDER[2],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            LENGTHUNIT[&amp;quot;metre&amp;quot;,1]],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    USAGE[&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        SCOPE[&amp;quot;Web mapping and visualisation.&amp;quot;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        AREA[&amp;quot;World between 85.06°S and 85.06°N.&amp;quot;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        BBOX[-85.06,-180,85.06,180]],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ID[&amp;quot;EPSG&amp;quot;,3857]]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Data axis to CRS axis mapping: 1,2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Geometry Column = way&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;osm_id: Integer64 (0.0)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;access: String (0.0)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;addr:housename: String (0.0)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;addr:housenumber: String (0.0)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[...]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And now we have the full detail of our layers; name, type, feature count, etc.&lt;/p&gt;
&lt;h3 id=&quot;basic-translations&quot;&gt;Basic translations&lt;/h3&gt;
&lt;p&gt;Now that we know what were working, with we can try to move some things around. Let’s start by exporting our vector data into a geopackage.&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;ogr2ogr&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; -f GPKG exported_data.gpkg &amp;quot;PG:dbname=osm_suisse tables=planet_osm_point&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here we’re exporting the table &lt;em&gt;planet_osm_point&lt;/em&gt; into the &lt;em&gt;exported_data.gpkg&lt;/em&gt; geopackage. The format can be recognized by the extension of the output file, but it’s safer to ensure the format by passing the argument &lt;code&gt;-f&lt;/code&gt;. Again, each driver documentation will have its driver name to be used.&lt;/p&gt;
&lt;h3 id=&quot;add-a-filter&quot;&gt;Add a filter&lt;/h3&gt;
&lt;p&gt;We can export a subset of our data, based on an attribute for example. Let’s say we want to export the points where the attribute &lt;em&gt;addr:housenumber&lt;/em&gt; is not null, and we want to save it in another table in our newly created geopackage. We’d do something like:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;ogr2ogr&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; -update -f GPKG -where &amp;#39;&amp;quot;addr:housenumber&amp;quot; is not null&amp;#39; -nln only_housenumbers exported_data.gpkg &amp;quot;PG:dbname=osm_suisse tables=planet_osm_point&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We want to update our dataset (our geopackage) and not create a new one, so we use the &lt;code&gt;-update&lt;/code&gt; option. The syntax of the &lt;code&gt;-where&lt;/code&gt; parameter is a bit convoluted here since there is a special character in the column name, but with a simple name you’d just need a pair of quotes &lt;code&gt;-where &quot;housenumber&quot; is not null&quot;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Let’s have a look at our geopackage:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;ogrinfo&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; -ro -al -so exported_data.gpkg&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;INFO: Open of `exported_data.gpkg&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      using driver `GPKG&amp;#39; successful.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Layer name: planet_osm_point&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Geometry: Point&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Feature Count: 2146246&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Extent: (626415.435591, 5736097.599850) - (1189428.532375, 6117386.570796)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Layer SRS WKT:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PROJCRS[&amp;quot;WGS 84 / Pseudo-Mercator&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    BASEGEOGCRS[&amp;quot;WGS 84&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        ENSEMBLE[&amp;quot;World Geodetic System 1984 ensemble&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            MEMBER[&amp;quot;World Geodetic System 1984 (Transit)&amp;quot;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            MEMBER[&amp;quot;World Geodetic System 1984 (G730)&amp;quot;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            MEMBER[&amp;quot;World Geodetic System 1984 (G873)&amp;quot;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            MEMBER[&amp;quot;World Geodetic System 1984 (G1150)&amp;quot;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[...]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Layer name: only_housenumbers&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Geometry: Point&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Feature Count: 366561&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Extent: (663719.309401, 5751784.044673) - (1167785.106794, 6072459.331387)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Layer SRS WKT:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PROJCRS[&amp;quot;WGS 84 / Pseudo-Mercator&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    BASEGEOGCRS[&amp;quot;WGS 84&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        ENSEMBLE[&amp;quot;World Geodetic System 1984 ensemble&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            MEMBER[&amp;quot;World Geodetic System 1984 (Transit)&amp;quot;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            MEMBER[&amp;quot;World Geodetic System 1984 (G730)&amp;quot;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            MEMBER[&amp;quot;World Geodetic System 1984 (G873)&amp;quot;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            MEMBER[&amp;quot;World Geodetic System 1984 (G1150)&amp;quot;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            MEMBER[&amp;quot;World Geodetic System 1984 (G1674)&amp;quot;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[...]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The new layer has been added to the geopackage. Has the query been respected?&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;ogrinfo&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; -ro -al -so -sql &amp;#39;select * from only_housenumbers where &amp;quot;addr:housenumber&amp;quot; is null&amp;#39; exported_data.gpkg&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;INFO: Open of `exported_data.gpkg&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      using driver `GPKG&amp;#39; successful.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Layer name: SELECT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Geometry: Point&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Feature Count: 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Layer SRS WKT:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PROJCRS[&amp;quot;WGS 84 / Pseudo-Mercator&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[...]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Yes! No data without &lt;em&gt;addr:housenumber&lt;/em&gt;.&lt;/p&gt;
&lt;div class=&quot;admonition tip&quot;&gt;
&lt;div class=&quot;admonition-icon admonition-icon-tip&quot;&gt;&lt;/div&gt;
&lt;div class=&quot;admonition-content&quot;&gt;
&lt;strong class=&quot;admonition-title&quot;&gt;TIP&lt;/strong&gt;
&lt;p&gt;The &lt;code&gt;-sql&lt;/code&gt; option is another way of filtering data, it allows you to pass a sql query in any of the sql flavor supported by the driver, you can even save your queries in a text file and pass the file to the &lt;code&gt;-sql&lt;/code&gt; parameter as &lt;code&gt;-sql @path/to/my_file&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id=&quot;geometric-operations&quot;&gt;Geometric operations?&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;-sql&lt;/code&gt; parameter can also be used to apply transformations to the data. We’ll request the same points, but this time we’ll create a buffer around them.&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;ogr2ogr&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; -update -f GPKG -sql &amp;#39;select ST_Buffer(way, 50) from planet_osm_point where &amp;quot;addr:housenumber&amp;quot; is not null&amp;#39; -nln buffered_only_housenumbers exported_data.gpkg &amp;quot;PG:dbname=osm_suisse tables=planet_osm_point&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And that’s it, we have our buffer around the points of interest. Here GDAL makes use of the internal capabilities of PostgreSQL and PostGIS by passing directly the request to the database, but the same command using the &lt;em&gt;only_housenumbers&lt;/em&gt; layer from our geopackage would also be valid.&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;ogr2ogr&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; -update -f GPKG -sql &amp;quot;select ST_Buffer(way, 50) from only_housenumbers&amp;quot; -nln buffered_only_housenumbers exported_data.gpkg exported_data.gpkg&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;admonition tip&quot;&gt;
&lt;div class=&quot;admonition-icon admonition-icon-tip&quot;&gt;&lt;/div&gt;
&lt;div class=&quot;admonition-content&quot;&gt;
&lt;strong class=&quot;admonition-title&quot;&gt;TIP&lt;/strong&gt;
&lt;p&gt;In the case of PostgreSQL/PostGIS you can write the &lt;code&gt;-sql&lt;/code&gt; parameter like you would write your queries directly into the database. They are passed directly to the database by GDAL.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This should give you a small idea of the things you can do with GDAL and how to start experimenting.&lt;/p&gt;
&lt;h2 id=&quot;final-words&quot;&gt;Final words&lt;/h2&gt;
&lt;p&gt;Well that was a lot more than expected. But GDAL really is a very strong and important tool. Diving into the details of all the available options, both for the command AND the drivers, is not a small task, but understanding how to navigate around and find the information that you need to process your data as you wish can go a long way. Manual and repeated tasks can be replaced to help to focus on more pertinent work, process time can be (by experience) reduced drastically depending on the tools you’re initially using. And if you’re working on data hosted on a server without graphic interface, well you have a tool to get the info you need!&lt;/p&gt;
&lt;p&gt;Obviously GDAL alone can’t do everything and has its imperfections; I’ve really struggled with installations in the past (Python binding might have bested me at some point), and the number of parameters is a bit overwhelming. But once you have it working it does the job, and really well.&lt;/p&gt;
&lt;p&gt;If you can, use GDAL.&lt;/p&gt;
</content>
        <summary type="html">To one of the OGs of geographical information, it&#39;s everywhere and you should knwo about it.</summary>
        </entry>
</feed>
