<?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>rust</tabi:current_section>
    </tabi:metadata><link rel="extra-stylesheet" href="https://blog.geothings.ch/skins/mint.css?h=504215cf6bc10586b487" /><title>geothings - rust</title>
        <subtitle>spatial data | open source | oversharing</subtitle>
    <link href="https://blog.geothings.ch/tags/rust/atom.xml" rel="self" type="application/atom+xml"/>
    <link href="https://blog.geothings.ch/tags/rust/" 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/rust/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>Serving vector tiles with Martin</title>
        <published>2023-12-20T00:00:00+00:00</published>
        <updated>2023-12-20T00:00:00+00:00</updated>
        <author>
            <name>jujube</name>
        </author>
        <link rel="alternate" href="https://blog.geothings.ch/blog/vector-tiles-with-martin/" type="text/html"/>
        <id>https://blog.geothings.ch/blog/vector-tiles-with-martin/</id>
        
            <content type="html">&lt;p&gt;There are some amazing tools out there, and they are getting build fast. I haven’t had the opportunity to work with vector tiles during my day-to-day jobs, but I wanted to explore what it is and how to set some things up, just for the fun of it. We’ll see here how to start using &lt;a rel=&quot;external&quot; href=&quot;https://github.com/maplibre/martin&quot;&gt;Martin&lt;/a&gt;, a vector tile server built in Rust serving PostGIS data.&lt;/p&gt;
&lt;h2 id=&quot;vector-tiles&quot;&gt;Vector tiles&lt;/h2&gt;
&lt;p&gt;The standard has been set by &lt;a rel=&quot;external&quot; href=&quot;https://www.mapbox.com/&quot;&gt;Mapbox&lt;/a&gt;. In the same manner a WMTS serves raster tiles, vector tiles allow for the visualization of large volumes of data over the web, but as their name suggests, they are vectors.&lt;/p&gt;
&lt;p&gt;It comes with some advantages compared to raster formats:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It’s significantly lighter, about 20 to 50% of its raster equivalent according to &lt;a rel=&quot;external&quot; href=&quot;https://documentation.maptiler.com/hc/en-us/articles/4411234458385-Raster-vs-Vector-Map-Tiles-What-Is-the-Difference-Between-the-Two-Data-Types-&quot;&gt;MapTiler&lt;/a&gt;. Vector data are series of points and each pixel of the map doesn’t have to have information declared; a rectangle polygon covering thousands of square kilometers can still be defined with 4 points.&lt;/li&gt;
&lt;li&gt;It is stylized dynamically. While raster tiles need to be generated with their style embedded, vector tiles style can just be modified on the fly, without going through the laborious process of tiles generation that can take easily several hours/days.&lt;/li&gt;
&lt;li&gt;It’s fast. Moving through a vector tile map feels smooth, there is no apparent tile loading.&lt;/li&gt;
&lt;li&gt;What you request is what you get. You directly query the tiles, not some sort of other service along your tiles.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;It’s an amazing standard to visualize spatial data in a web map. Obviously it’s not suitable for all kinds of data, you have to have discrete data that make sense to be visualized as vector; I doubt that raw satellites images as vector tiles are a good idea.&lt;/p&gt;
&lt;h2 id=&quot;installing-postgresql-and-postgis&quot;&gt;Installing PostgreSQL and PostGIS&lt;/h2&gt;
&lt;p&gt;First thing first, we need to store data somewhere. Martin is designed to be used with PostGIS, PMTiles and MBTiles, we’ll explore the PostGIS alternative.&lt;/p&gt;
&lt;p&gt;The following commands were used on an Ubuntu distribution.&lt;/p&gt;
&lt;p&gt;Let’s start by installing PostgreSQL:&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; install postgresql&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then the PostGIS extension:&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; install postgis&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We’ll already set things up in the database by creating a dedicated user, creating a database and creating the PostGIS extension in there. From psql, create a user:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;sql&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;create user&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt; martin_usr&lt;/span&gt;&lt;span class=&quot;z-9&quot;&gt; with password&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; &amp;#39;my_password&amp;#39;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Create a database:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;sql&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;create database&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt; martin_db&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Go to your new database (&lt;code&gt;\c martin_db&lt;/code&gt;) and create the extension:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;sql&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;create&lt;/span&gt;&lt;span&gt; extension postgis;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We won’t cover here the more extensive tuning of the database. You should be set on the database side for this example.&lt;/p&gt;
&lt;h2 id=&quot;downloading-some-data&quot;&gt;Downloading some data&lt;/h2&gt;
&lt;p&gt;Obviously you’ll want some data to serve as vector tiles. In a production environment you’ll probably want to serve your own data, so this step would probably not be necessary. For the example we don’t have any data yet, so we’ll use some from osm through &lt;a rel=&quot;external&quot; href=&quot;https://download.geofabrik.de/&quot;&gt;GeoFabrik&lt;/a&gt;. Since I’m in Switzerland, let’s download data over the country:&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;curl&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; https://download.geofabrik.de/europe/switzerland-latest.osm.pbf -O&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We are using &lt;code&gt;osm2pgsql&lt;/code&gt; to import data into the database, so the &lt;code&gt;.pbf&lt;/code&gt; format is ideal.&lt;/p&gt;
&lt;p&gt;You can then load your data (&lt;code&gt;apt install osm2pgsql&lt;/code&gt; if you don’t have the tool):&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;osm2pgsql&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; -d martin_db -U martin_usr switzerland-latest.osm.pbf&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We now have osm data over a whole country, easy right?&lt;/p&gt;
&lt;h2 id=&quot;now-install-martin&quot;&gt;Now install Martin&lt;/h2&gt;
&lt;p&gt;Here comes the best part, the vector tile server itself. There are multiple ways to start working with Martin, we’ll use rust and its package manager &lt;a rel=&quot;external&quot; href=&quot;https://doc.rust-lang.org/book/ch01-03-hello-cargo.html&quot;&gt;cargo&lt;/a&gt;. If you don’t want to install those on your server you might prefer the &lt;a rel=&quot;external&quot; href=&quot;https://maplibre.org/martin/run-with-docker.html&quot;&gt;Docker installation&lt;/a&gt;, or simply using binaries.&lt;/p&gt;
&lt;p&gt;As said earlier, Martin is build in rust, and it’s accessible as a crate using cargo. You can first &lt;a rel=&quot;external&quot; href=&quot;https://www.rust-lang.org/tools/install&quot;&gt;install rust&lt;/a&gt;:&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;curl&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; --proto &amp;#39;=https&amp;#39; --tlsv1.2 -sSf https://sh.rustup.rs&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; |&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt; sh&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then install Martin:&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;cargo&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; install martin&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;martin&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; --help&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And that’s it! Martin’s here.&lt;/p&gt;
&lt;h2 id=&quot;can-t-be-that-simple-right&quot;&gt;Can’t be that simple right?&lt;/h2&gt;
&lt;p&gt;Finally, you can run your new server:&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;martin&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; &amp;quot;postgresql://martin_usr:my_password@localhost:5432/martin_db&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Martin can discover geometric tables in the database from the given url, so by default everything is served. So yes it can be that simple! Obviously environment variables need to be set, passwords hidden etc. But you have an idea of the process.&lt;/p&gt;
&lt;p&gt;You can try by yourself reading the catalog:&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;curl&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; http://0.0.0.0:3000/catalog&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; |&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt; json_pp&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;json&quot;&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;   &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;fonts&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;&amp;quot; : {},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4&quot;&gt;   &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;sprites&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;&amp;quot; : {},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4&quot;&gt;   &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;tiles&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;&amp;quot; : {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4&quot;&gt;      &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;planet_osm_line&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;&amp;quot; : {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4&quot;&gt;         &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;content_type&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;&amp;quot; :&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; &amp;quot;application/x-protobuf&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 class=&quot;z-4&quot;&gt;         &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;&amp;quot; :&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; &amp;quot;public.planet_osm_line.way&amp;quot;&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;      &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;planet_osm_point&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;&amp;quot; : {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4&quot;&gt;         &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;content_type&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;&amp;quot; :&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; &amp;quot;application/x-protobuf&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 class=&quot;z-4&quot;&gt;         &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;&amp;quot; :&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; &amp;quot;public.planet_osm_point.way&amp;quot;&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;      &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;planet_osm_polygon&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;&amp;quot; : {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4&quot;&gt;         &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;content_type&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;&amp;quot; :&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; &amp;quot;application/x-protobuf&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 class=&quot;z-4&quot;&gt;         &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;&amp;quot; :&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; &amp;quot;public.planet_osm_polygon.way&amp;quot;&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;      &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;planet_osm_roads&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;&amp;quot; : {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4&quot;&gt;         &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;content_type&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;&amp;quot; :&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; &amp;quot;application/x-protobuf&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 class=&quot;z-4&quot;&gt;         &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;&amp;quot; :&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; &amp;quot;public.planet_osm_roads.way&amp;quot;&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;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;h2 id=&quot;visualize-data-using-qgis&quot;&gt;Visualize data using QGIS&lt;/h2&gt;
&lt;p&gt;Once the server is running we can easily visualize our data in a client. Starting QGIS 3.14,&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Layer&lt;/em&gt; &amp;gt; &lt;em&gt;Add Layer&lt;/em&gt; &amp;gt; &lt;em&gt;Add Vector Tile Layer&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And enter the url then &lt;em&gt;OK&lt;/em&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;http://localhost:3000/planet_osm_line,planet_osm_point,planet_osm_polygon/{z}/{x}/{y}&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.geothings.ch/blog/vector-tiles-with-martin/add-vector-tiles.png&quot; alt=&quot;add-vector-tiles&quot; /&gt;&lt;/p&gt;
&lt;p&gt;You should see a rather absurd amount of data.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.geothings.ch/blog/vector-tiles-with-martin/visualization.png&quot; alt=&quot;visualization&quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;to-conclude&quot;&gt;To conclude&lt;/h2&gt;
&lt;p&gt;Here is how to get started with Martin, a rust vector tile server. It’s just the start, we don’t cover here the creation of symbology and more in depth configurations and optimization, but it gives an idea of how easy and powerful such a tool can be.&lt;/p&gt;
</content>
        <summary type="html">Vector tiles seems nice, let&#39;s see who&#39;s Martin.</summary>
        </entry>
</feed>
