From 051798328c529cf6a3b5d8e1f391894b38359726 Mon Sep 17 00:00:00 2001 From: Alexander Marek Date: Fri, 12 Jun 2026 13:39:48 +0200 Subject: [PATCH] TileGenerator stores scale factor of tiles (in relation to original svg dimensions) in dimensions.json --- Svg.Tests.Win/DeepZoom/TileGeneratorTests.cs | 33 ++++++++++++++++++++ Svg/DeepZoom/TileGenerator.cs | 12 ++++--- Svg/Svg.csproj | 4 ++- 3 files changed, 44 insertions(+), 5 deletions(-) diff --git a/Svg.Tests.Win/DeepZoom/TileGeneratorTests.cs b/Svg.Tests.Win/DeepZoom/TileGeneratorTests.cs index 13e50c3fc..10c9bf424 100644 --- a/Svg.Tests.Win/DeepZoom/TileGeneratorTests.cs +++ b/Svg.Tests.Win/DeepZoom/TileGeneratorTests.cs @@ -412,9 +412,42 @@ public async Task GenerateTilesFromSvgAsync_ProducesExpectedZoomLevels() var dims = System.Text.Json.JsonDocument.Parse(dimsJson).RootElement; Assert.AreEqual(pyramidW, dims.GetProperty("width").GetInt32(), "dimensions.json width mismatch."); Assert.AreEqual(pyramidH, dims.GetProperty("height").GetInt32(), "dimensions.json height mismatch."); + Assert.IsTrue(dims.TryGetProperty("scaleX", out _), "dimensions.json missing scaleX."); + Assert.IsTrue(dims.TryGetProperty("scaleY", out _), "dimensions.json missing scaleY."); #endif } +#if !NETFRAMEWORK + [Test] + public async Task GenerateTilesFromSvgAsync_WritesScaleFactorsToDimensionsJson() + { + // Arrange — render the SVG into a pyramid 10× wider than the document so scaleX ≈ 10. + // Consumers (RenderOnPlanOptionsProvider) use these to re-map plan-item coordinates + // from the original SVG coordinate system into pyramid space and back. + var file = Path.Combine(TestContext.CurrentContext.WorkDirectory, "Assets\\plan_iss.svg"); + var doc = SvgDocument.Open(file); + var docSize = doc.GetDimensions(); + int targetWidth = (int)Math.Ceiling(docSize.Width * 10); + int pyramidH = (int)Math.Ceiling(targetWidth * docSize.Height / docSize.Width); + float expectedScaleX = targetWidth / docSize.Width; + float expectedScaleY = pyramidH / docSize.Height; + + var tiles = new ConcurrentDictionary(); + + // Act + await new TileGenerator().GenerateTilesAsync(doc, targetWidth, CreateMemoryStreamProvider(tiles)); + + // Assert + Assert.IsTrue(tiles.ContainsKey("/dimensions.json"), "dimensions.json missing."); + var dimsJson = System.Text.Encoding.UTF8.GetString(tiles["/dimensions.json"].ToArray()); + var dims = System.Text.Json.JsonDocument.Parse(dimsJson).RootElement; + Assert.AreEqual(expectedScaleX, (float)dims.GetProperty("scaleX").GetDouble(), 0.0001f, + "dimensions.json scaleX mismatch."); + Assert.AreEqual(expectedScaleY, (float)dims.GetProperty("scaleY").GetDouble(), 0.0001f, + "dimensions.json scaleY mismatch."); + } +#endif + [Test] public async Task GenerateTilesFromSvgAsync_TilesMatchCurrentPipeline_WithinTolerance() { diff --git a/Svg/DeepZoom/TileGenerator.cs b/Svg/DeepZoom/TileGenerator.cs index 060a6229f..b81619b9d 100644 --- a/Svg/DeepZoom/TileGenerator.cs +++ b/Svg/DeepZoom/TileGenerator.cs @@ -3,6 +3,7 @@ using Svg.Platform; using System; using System.Collections.Generic; +using System.Globalization; using System.IO; using System.Threading; using System.Threading.Tasks; @@ -102,7 +103,7 @@ await GenerateZ0TilesScanlineAsync(codec, originalWidth, originalHeight, kvp.Value.Dispose(); } pending.Clear(); - await WriteMetadataAsync(originalWidth, originalHeight, tileOutputStreamProvider); + await WriteMetadataAsync(originalWidth, originalHeight, 1.0, 1.0, tileOutputStreamProvider); } private async Task GenerateZ0TilesSubsetAsync( @@ -431,7 +432,7 @@ await TryCascadeAsync(0, tx, ty, pending, pendingLock, levelTilesX, levelTilesY, kvp.Value.Dispose(); } pending.Clear(); - await WriteMetadataAsync(pyramidW, pyramidH, tileOutputStreamProvider); + await WriteMetadataAsync(pyramidW, pyramidH, scaleX, scaleY, tileOutputStreamProvider); } private async Task WriteTileAndStorePendingAsync( @@ -566,10 +567,13 @@ private static async Task WriteEncodedTileAsync( } private static async Task WriteMetadataAsync( - int width, int height, + int width, int height, double scaleX, double scaleY, Func> streamProvider) { - var json = System.Text.Encoding.UTF8.GetBytes($"{{\"width\":{width},\"height\":{height}}}"); + var sx = scaleX.ToString("R", CultureInfo.InvariantCulture); + var sy = scaleY.ToString("R", CultureInfo.InvariantCulture); + var json = System.Text.Encoding.UTF8.GetBytes( + $"{{\"width\":{width},\"height\":{height},\"scaleX\":{sx},\"scaleY\":{sy}}}"); using var outStream = await streamProvider("", "dimensions.json"); await outStream.WriteAsync(json, 0, json.Length); } diff --git a/Svg/Svg.csproj b/Svg/Svg.csproj index a9b01bbdf..c030dc414 100644 --- a/Svg/Svg.csproj +++ b/Svg/Svg.csproj @@ -3,10 +3,12 @@ netstandard2.0;net48;net10.0 PackageReference - 3.2.0-optiq01 + 3.2.0-optiq02 gentledpp,zepr Opti-Q GmbH + #3.2.0-optiq02 + TileGenerator stores scale factor in dimensions.json (relative to svg dimensions) #3.2.0-optiq01 Moved to avalonia 12 #3.1.4-optiq01