<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" version="2.0">
  <channel>
    <title>topic Re: Loading local XYZ Tiles in .NET Maps SDK Questions</title>
    <link>https://community.esri.com/t5/net-maps-sdk-questions/loading-local-xyz-tiles/m-p/1247400#M11591</link>
    <description>&lt;P&gt;Did you mean to add the backslash in the tile template? It should just be forward slashes. Also the doc states you need to use the level row and column parameter instead of x y z.&amp;nbsp; That might be why. (If you load the layer, you should get a load error telling you exactly this) Also you don't need the subdomain overload, since you don't have a subdomain in the template uri.&lt;BR /&gt;So you'd have something like:&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;LI-CODE lang="csharp"&gt;private readonly string _templateUri = "file:///C:/Users/Zach/Desktop/DEM/XYZ2/{level}/{col}/{row}.png";   &lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;This made it work for me. You can also instead implement a custom ImageTiledLayer, which gives you full control of how the image bytes are loaded. It is more work, but gives a lot better control. Example:&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;LI-CODE lang="csharp"&gt;using Esri.ArcGISRuntime.ArcGISServices;
using Esri.ArcGISRuntime.Geometry;
using Esri.ArcGISRuntime.Mapping;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;

namespace CustomTileLayerSample
{
    public class LocalTiledLayer : ImageTiledLayer
    {
        private readonly string _templateUri = "C:\\Users\\Zach\\Desktop\\DEM\\XYZ2\\{0}\\{1}\\{2}.png";

        public LocalTiledLayer() : base(CreateTileInfo(), new Envelope(-2.003750722959434E7, -1.997186888040859E7, 2.003750722959434E7, 1.9971868880408563E7, SpatialReferences.WebMercator))
        {
        }

        private static TileInfo CreateTileInfo()
        {
            List&amp;lt;LevelOfDetail&amp;gt; levels = new List&amp;lt;LevelOfDetail&amp;gt;();
            var resolution = 156543.03392800014;
            var scale = 5.91657527591555E8;
            int levelCount = 24;
            for (int i = 0; i &amp;lt; levelCount; i++)
            {
                levels.Add(new LevelOfDetail(i, resolution, scale));
                resolution /= 2; scale/=2;
            }
            return new TileInfo(96, TileImageFormat.Png32, levels, new MapPoint(-2.0037508342787E7, 2.0037508342787E7, SpatialReferences.WebMercator), SpatialReferences.WebMercator, 256, 256);
        }

        protected override async Task&amp;lt;ImageTileData&amp;gt; GetTileDataAsync(int level, int row, int column, CancellationToken cancellationToken)
        {
            var file = string.Format(_templateUri, level, row, column);
            if (File.Exists(file))
            {
                var bytes = await File.ReadAllBytesAsync(file).ConfigureAwait(false);
                return new ImageTileData(level, row, column, bytes, "image/png");
            }
            return new ImageTileData(level, row, column, new byte[] { }, "image/png");
        }
    }
}&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;You could even take this a step further and generate tiles on the fly:&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;LI-CODE lang="csharp"&gt;        protected override Task&amp;lt;ImageTileData&amp;gt; GetTileDataAsync(int level, int row, int column, CancellationToken cancellationToken)
        {
            return Task.Run(() =&amp;gt;
            {
                using var pen = new System.Drawing.Pen(System.Drawing.Color.Black);
                using var font = new System.Drawing.Font("Times New Roman", 12);
                using var image = new System.Drawing.Bitmap(256, 256);
                using var g = Graphics.FromImage(image);
                g.DrawString($"{level}/{row}/{column}", font, System.Drawing.Brushes.Black, new PointF(100, 122));
                g.DrawLine(pen, 0, 0, 255, 0);
                g.DrawLine(pen, 0, 0, 0, 255);
                using var filestream = new MemoryStream();
                image.Save(filestream, System.Drawing.Imaging.ImageFormat.Png);
                return new ImageTileData(level, row, column, filestream.ToArray(), "image/png");
            });
        }&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
    <pubDate>Wed, 11 Jan 2023 19:39:28 GMT</pubDate>
    <dc:creator>dotMorten_esri</dc:creator>
    <dc:date>2023-01-11T19:39:28Z</dc:date>
    <item>
      <title>Loading local XYZ Tiles</title>
      <link>https://community.esri.com/t5/net-maps-sdk-questions/loading-local-xyz-tiles/m-p/1246916#M11589</link>
      <description>&lt;P&gt;Hello, I am attempting to load a local XYZ tiles to my map. I feel like the relevant example is this so I have followed this&amp;nbsp; is&amp;nbsp;&lt;A href="https://developers.arcgis.com/net/wpf/sample-code/web-tiled-layer/" target="_blank"&gt;https://developers.arcgis.com/net/wpf/sample-code/web-tiled-layer/&lt;/A&gt;&amp;nbsp;but instead of a Url I am pointing to a local folder on my PC.&lt;/P&gt;&lt;LI-CODE lang="csharp"&gt;private readonly string _templateUri = "file:///C:\\Users/Zach/Desktop/DEM/XYZ2/{z}/{x}/{y}.png";   

        // List of subdomains for use when constructing the web tiled layer
        private readonly List&amp;lt;string&amp;gt; _tiledLayerSubdomains = new List&amp;lt;string&amp;gt; { "12" };

        
        


        public mapviewTest()
        {
            InitializeComponent();
            Initialize();
        }

        private void Initialize()
        {
            // Create the layer from the URL and the subdomain list
            WebTiledLayer myBaseLayer = new WebTiledLayer(_templateUri, _tiledLayerSubdomains);

            // Create a basemap from the layer
            Basemap layerBasemap = new Basemap(myBaseLayer);

            // Create a map to hold the basemap
            Map myMap = new Map(layerBasemap);

            // Add the map to the map view
            MyMapView.Map = myMap;
        }&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;The main folder has a Subfolder named "12" then in that folder several other folders with numbers which is where the actual PNG images live.&lt;/P&gt;&lt;P&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="ZachRuiz_0-1673373521642.png" style="width: 400px;"&gt;&lt;img src="https://community.esri.com/t5/image/serverpage/image-id/60098i163F4F3BAF6E00E2/image-size/medium?v=v2&amp;amp;px=400" role="button" title="ZachRuiz_0-1673373521642.png" alt="ZachRuiz_0-1673373521642.png" /&gt;&lt;/span&gt;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="ZachRuiz_1-1673373581699.png" style="width: 400px;"&gt;&lt;img src="https://community.esri.com/t5/image/serverpage/image-id/60100iB57EE9F21D68593E/image-size/medium?v=v2&amp;amp;px=400" role="button" title="ZachRuiz_1-1673373581699.png" alt="ZachRuiz_1-1673373581699.png" /&gt;&lt;/span&gt;&lt;/P&gt;&lt;P&gt;Am I going about this the correct way?&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Tue, 10 Jan 2023 18:00:15 GMT</pubDate>
      <guid>https://community.esri.com/t5/net-maps-sdk-questions/loading-local-xyz-tiles/m-p/1246916#M11589</guid>
      <dc:creator>ZachRuiz</dc:creator>
      <dc:date>2023-01-10T18:00:15Z</dc:date>
    </item>
    <item>
      <title>Re: Loading local XYZ Tiles</title>
      <link>https://community.esri.com/t5/net-maps-sdk-questions/loading-local-xyz-tiles/m-p/1247400#M11591</link>
      <description>&lt;P&gt;Did you mean to add the backslash in the tile template? It should just be forward slashes. Also the doc states you need to use the level row and column parameter instead of x y z.&amp;nbsp; That might be why. (If you load the layer, you should get a load error telling you exactly this) Also you don't need the subdomain overload, since you don't have a subdomain in the template uri.&lt;BR /&gt;So you'd have something like:&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;LI-CODE lang="csharp"&gt;private readonly string _templateUri = "file:///C:/Users/Zach/Desktop/DEM/XYZ2/{level}/{col}/{row}.png";   &lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;This made it work for me. You can also instead implement a custom ImageTiledLayer, which gives you full control of how the image bytes are loaded. It is more work, but gives a lot better control. Example:&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;LI-CODE lang="csharp"&gt;using Esri.ArcGISRuntime.ArcGISServices;
using Esri.ArcGISRuntime.Geometry;
using Esri.ArcGISRuntime.Mapping;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;

namespace CustomTileLayerSample
{
    public class LocalTiledLayer : ImageTiledLayer
    {
        private readonly string _templateUri = "C:\\Users\\Zach\\Desktop\\DEM\\XYZ2\\{0}\\{1}\\{2}.png";

        public LocalTiledLayer() : base(CreateTileInfo(), new Envelope(-2.003750722959434E7, -1.997186888040859E7, 2.003750722959434E7, 1.9971868880408563E7, SpatialReferences.WebMercator))
        {
        }

        private static TileInfo CreateTileInfo()
        {
            List&amp;lt;LevelOfDetail&amp;gt; levels = new List&amp;lt;LevelOfDetail&amp;gt;();
            var resolution = 156543.03392800014;
            var scale = 5.91657527591555E8;
            int levelCount = 24;
            for (int i = 0; i &amp;lt; levelCount; i++)
            {
                levels.Add(new LevelOfDetail(i, resolution, scale));
                resolution /= 2; scale/=2;
            }
            return new TileInfo(96, TileImageFormat.Png32, levels, new MapPoint(-2.0037508342787E7, 2.0037508342787E7, SpatialReferences.WebMercator), SpatialReferences.WebMercator, 256, 256);
        }

        protected override async Task&amp;lt;ImageTileData&amp;gt; GetTileDataAsync(int level, int row, int column, CancellationToken cancellationToken)
        {
            var file = string.Format(_templateUri, level, row, column);
            if (File.Exists(file))
            {
                var bytes = await File.ReadAllBytesAsync(file).ConfigureAwait(false);
                return new ImageTileData(level, row, column, bytes, "image/png");
            }
            return new ImageTileData(level, row, column, new byte[] { }, "image/png");
        }
    }
}&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;You could even take this a step further and generate tiles on the fly:&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;LI-CODE lang="csharp"&gt;        protected override Task&amp;lt;ImageTileData&amp;gt; GetTileDataAsync(int level, int row, int column, CancellationToken cancellationToken)
        {
            return Task.Run(() =&amp;gt;
            {
                using var pen = new System.Drawing.Pen(System.Drawing.Color.Black);
                using var font = new System.Drawing.Font("Times New Roman", 12);
                using var image = new System.Drawing.Bitmap(256, 256);
                using var g = Graphics.FromImage(image);
                g.DrawString($"{level}/{row}/{column}", font, System.Drawing.Brushes.Black, new PointF(100, 122));
                g.DrawLine(pen, 0, 0, 255, 0);
                g.DrawLine(pen, 0, 0, 0, 255);
                using var filestream = new MemoryStream();
                image.Save(filestream, System.Drawing.Imaging.ImageFormat.Png);
                return new ImageTileData(level, row, column, filestream.ToArray(), "image/png");
            });
        }&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Wed, 11 Jan 2023 19:39:28 GMT</pubDate>
      <guid>https://community.esri.com/t5/net-maps-sdk-questions/loading-local-xyz-tiles/m-p/1247400#M11591</guid>
      <dc:creator>dotMorten_esri</dc:creator>
      <dc:date>2023-01-11T19:39:28Z</dc:date>
    </item>
  </channel>
</rss>

