mirror of
https://github.com/ClemensFischer/XAML-Map-Control.git
synced 2025-12-06 07:12:04 +01:00
Removed MapImages library
This commit is contained in:
parent
135473b799
commit
b04ed4eebe
|
|
@ -1,204 +0,0 @@
|
||||||
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
|
||||||
// © 2022 Clemens Fischer
|
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
|
||||||
|
|
||||||
using MapControl.Projections;
|
|
||||||
using System;
|
|
||||||
using System.Globalization;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
#if WINUI
|
|
||||||
using Windows.Foundation;
|
|
||||||
using Microsoft.UI.Xaml;
|
|
||||||
using Microsoft.UI.Xaml.Controls;
|
|
||||||
using Microsoft.UI.Xaml.Media;
|
|
||||||
using Microsoft.UI.Xaml.Media.Imaging;
|
|
||||||
#elif UWP
|
|
||||||
using Windows.Foundation;
|
|
||||||
using Windows.UI.Xaml;
|
|
||||||
using Windows.UI.Xaml.Controls;
|
|
||||||
using Windows.UI.Xaml.Media;
|
|
||||||
using Windows.UI.Xaml.Media.Imaging;
|
|
||||||
#else
|
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Controls;
|
|
||||||
using System.Windows.Media;
|
|
||||||
using System.Windows.Media.Imaging;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace MapControl.Images
|
|
||||||
{
|
|
||||||
public partial class GeoImage
|
|
||||||
{
|
|
||||||
private const string PixelScaleQuery = "/ifd/{ushort=33550}";
|
|
||||||
private const string TiePointQuery = "/ifd/{ushort=33922}";
|
|
||||||
private const string TransformQuery = "/ifd/{ushort=34264}";
|
|
||||||
private const string NoDataQuery = "/ifd/{ushort=42113}";
|
|
||||||
|
|
||||||
public static readonly DependencyProperty PathProperty = DependencyProperty.RegisterAttached(
|
|
||||||
"Path", typeof(string), typeof(GeoImage), new PropertyMetadata(null, PathPropertyChanged));
|
|
||||||
|
|
||||||
public BitmapSource Bitmap { get; }
|
|
||||||
public Matrix Transform { get; }
|
|
||||||
public MapProjection Projection { get; }
|
|
||||||
public BoundingBox BoundingBox { get; }
|
|
||||||
public double Rotation { get; }
|
|
||||||
|
|
||||||
public GeoImage(BitmapSource bitmap, Matrix transform, MapProjection projection)
|
|
||||||
{
|
|
||||||
Bitmap = bitmap;
|
|
||||||
Transform = transform;
|
|
||||||
Projection = projection;
|
|
||||||
|
|
||||||
if (transform.M12 != 0 || transform.M21 != 0)
|
|
||||||
{
|
|
||||||
Rotation = (Math.Atan2(transform.M12, transform.M11) + Math.Atan2(transform.M21, -transform.M22)) * 90d / Math.PI;
|
|
||||||
|
|
||||||
// effective unrotated transform
|
|
||||||
transform.M11 = Math.Sqrt(transform.M11 * transform.M11 + transform.M12 * transform.M12);
|
|
||||||
transform.M22 = -Math.Sqrt(transform.M22 * transform.M22 + transform.M21 * transform.M21);
|
|
||||||
transform.M12 = 0;
|
|
||||||
transform.M21 = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
var rect = new Rect(
|
|
||||||
transform.Transform(new Point()),
|
|
||||||
transform.Transform(new Point(bitmap.PixelWidth, bitmap.PixelHeight)));
|
|
||||||
|
|
||||||
BoundingBox = projection != null
|
|
||||||
? projection.RectToBoundingBox(rect)
|
|
||||||
: new BoundingBox
|
|
||||||
{
|
|
||||||
West = rect.X,
|
|
||||||
East = rect.X + rect.Width,
|
|
||||||
South = rect.Y,
|
|
||||||
North = rect.Y + rect.Height
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string GetPath(Image image)
|
|
||||||
{
|
|
||||||
return (string)image.GetValue(PathProperty);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void SetPath(Image image, string path)
|
|
||||||
{
|
|
||||||
image.SetValue(PathProperty, path);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Task<GeoImage> ReadImage(string imageFilePath)
|
|
||||||
{
|
|
||||||
var ext = Path.GetExtension(imageFilePath);
|
|
||||||
if (ext.Length < 4)
|
|
||||||
{
|
|
||||||
throw new ArgumentException("Invalid image file path extension, must have at least three characters.");
|
|
||||||
}
|
|
||||||
|
|
||||||
var dir = Path.GetDirectoryName(imageFilePath);
|
|
||||||
var file = Path.GetFileNameWithoutExtension(imageFilePath);
|
|
||||||
var worldFilePath = Path.Combine(dir, file + ext.Remove(2, 1) + "w");
|
|
||||||
|
|
||||||
if (File.Exists(worldFilePath))
|
|
||||||
{
|
|
||||||
return ReadImage(imageFilePath, worldFilePath, Path.Combine(dir, file + ".prj"));
|
|
||||||
}
|
|
||||||
|
|
||||||
return ReadGeoTiff(imageFilePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task<GeoImage> ReadImage(string imageFilePath, string worldFilePath, string projFilePath = null)
|
|
||||||
{
|
|
||||||
var transform = ReadWorldFile(worldFilePath);
|
|
||||||
|
|
||||||
var projection = (projFilePath != null && File.Exists(projFilePath))
|
|
||||||
? ReadProjectionFile(projFilePath)
|
|
||||||
: null;
|
|
||||||
|
|
||||||
var bitmap = (BitmapSource)await ImageLoader.LoadImageAsync(imageFilePath);
|
|
||||||
|
|
||||||
return new GeoImage(bitmap, transform, projection);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Matrix ReadWorldFile(string path)
|
|
||||||
{
|
|
||||||
var parameters = File.ReadLines(path)
|
|
||||||
.Take(6)
|
|
||||||
.Select((line, i) =>
|
|
||||||
{
|
|
||||||
if (!double.TryParse(line, NumberStyles.Float, CultureInfo.InvariantCulture, out double parameter))
|
|
||||||
{
|
|
||||||
throw new ArgumentException("Failed parsing line " + (i + 1) + " in world file \"" + path + "\".");
|
|
||||||
}
|
|
||||||
return parameter;
|
|
||||||
})
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
if (parameters.Count != 6)
|
|
||||||
{
|
|
||||||
throw new ArgumentException("Insufficient number of parameters in world file \"" + path + "\".");
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Matrix(
|
|
||||||
parameters[0], // line 1: A or M11
|
|
||||||
parameters[1], // line 2: D or M12
|
|
||||||
parameters[2], // line 3: B or M21
|
|
||||||
parameters[3], // line 4: E or M22
|
|
||||||
parameters[4], // line 5: C or OffsetX
|
|
||||||
parameters[5]); // line 6: F or OffsetY
|
|
||||||
}
|
|
||||||
|
|
||||||
public static MapProjection ReadProjectionFile(string path)
|
|
||||||
{
|
|
||||||
return new GeoApiProjection { WKT = File.ReadAllText(path) };
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ApplyToImage(Image image)
|
|
||||||
{
|
|
||||||
if (Rotation != 0d)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("Rotation must be zero.");
|
|
||||||
}
|
|
||||||
|
|
||||||
image.Source = Bitmap;
|
|
||||||
image.Stretch = Stretch.Fill;
|
|
||||||
|
|
||||||
MapPanel.SetBoundingBox(image, BoundingBox);
|
|
||||||
}
|
|
||||||
|
|
||||||
public FrameworkElement CreateImage()
|
|
||||||
{
|
|
||||||
FrameworkElement image = new Image
|
|
||||||
{
|
|
||||||
Source = Bitmap,
|
|
||||||
Stretch = Stretch.Fill
|
|
||||||
};
|
|
||||||
|
|
||||||
if (Rotation != 0d)
|
|
||||||
{
|
|
||||||
image.RenderTransform = new RotateTransform { Angle = Rotation };
|
|
||||||
var panel = new Grid();
|
|
||||||
panel.Children.Add(image);
|
|
||||||
image = panel;
|
|
||||||
}
|
|
||||||
|
|
||||||
MapPanel.SetBoundingBox(image, BoundingBox);
|
|
||||||
|
|
||||||
return image;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task<FrameworkElement> CreateImage(string imageFilePath)
|
|
||||||
{
|
|
||||||
return (await ReadImage(imageFilePath)).CreateImage();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static async void PathPropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
|
|
||||||
{
|
|
||||||
if (o is Image image && e.NewValue is string imageFilePath)
|
|
||||||
{
|
|
||||||
(await ReadImage(imageFilePath)).ApplyToImage(image);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,276 +0,0 @@
|
||||||
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
|
||||||
// © 2022 Clemens Fischer
|
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Globalization;
|
|
||||||
using System.IO;
|
|
||||||
using System.IO.Compression;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Xml;
|
|
||||||
#if WINUI
|
|
||||||
using Microsoft.UI.Xaml;
|
|
||||||
using Microsoft.UI.Xaml.Controls;
|
|
||||||
using Microsoft.UI.Xaml.Media;
|
|
||||||
#elif UWP
|
|
||||||
using Windows.UI.Xaml;
|
|
||||||
using Windows.UI.Xaml.Controls;
|
|
||||||
using Windows.UI.Xaml.Media;
|
|
||||||
#else
|
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Controls;
|
|
||||||
using System.Windows.Media;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace MapControl.Images
|
|
||||||
{
|
|
||||||
public class GroundOverlayPanel : MapPanel
|
|
||||||
{
|
|
||||||
class LatLonBox : BoundingBox
|
|
||||||
{
|
|
||||||
public LatLonBox(double south, double west, double north, double east, double rotation)
|
|
||||||
: base(south, west, north, east)
|
|
||||||
{
|
|
||||||
Rotation = rotation;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double Rotation { get; }
|
|
||||||
}
|
|
||||||
|
|
||||||
class ImageOverlay
|
|
||||||
{
|
|
||||||
public ImageOverlay(LatLonBox latLonBox, string imagePath, int zIndex)
|
|
||||||
{
|
|
||||||
LatLonBox = latLonBox;
|
|
||||||
ImagePath = imagePath;
|
|
||||||
ZIndex = zIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LatLonBox LatLonBox { get; }
|
|
||||||
public string ImagePath { get; }
|
|
||||||
public int ZIndex { get; }
|
|
||||||
public ImageSource ImageSource { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public static readonly DependencyProperty KmlFileProperty = DependencyProperty.Register(
|
|
||||||
nameof(KmlFile), typeof(string), typeof(GroundOverlayPanel),
|
|
||||||
new PropertyMetadata(null, async (o, e) => await ((GroundOverlayPanel)o).KmlFilePropertyChanged((string)e.NewValue)));
|
|
||||||
|
|
||||||
public string KmlFile
|
|
||||||
{
|
|
||||||
get { return (string)GetValue(KmlFileProperty); }
|
|
||||||
set { SetValue(KmlFileProperty, value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task KmlFilePropertyChanged(string path)
|
|
||||||
{
|
|
||||||
IEnumerable<ImageOverlay> imageOverlays = null;
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(path))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var ext = Path.GetExtension(path).ToLower();
|
|
||||||
if (ext == ".kmz")
|
|
||||||
{
|
|
||||||
imageOverlays = await ReadGroundOverlaysFromArchiveAsync(path);
|
|
||||||
}
|
|
||||||
else if (ext == ".kml")
|
|
||||||
{
|
|
||||||
imageOverlays = await ReadGroundOverlaysFromFileAsync(path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Debug.WriteLine($"GroundOverlayPanel: {path}: {ex.Message}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Children.Clear();
|
|
||||||
|
|
||||||
if (imageOverlays != null)
|
|
||||||
{
|
|
||||||
AddImageOverlays(imageOverlays);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AddImageOverlays(IEnumerable<ImageOverlay> imageOverlays)
|
|
||||||
{
|
|
||||||
foreach (var imageOverlay in imageOverlays.Where(i => i.ImageSource != null))
|
|
||||||
{
|
|
||||||
FrameworkElement overlay = new Image
|
|
||||||
{
|
|
||||||
Source = imageOverlay.ImageSource,
|
|
||||||
Stretch = Stretch.Fill,
|
|
||||||
UseLayoutRounding = false
|
|
||||||
};
|
|
||||||
|
|
||||||
if (imageOverlay.LatLonBox.Rotation != 0d)
|
|
||||||
{
|
|
||||||
overlay.RenderTransform = new RotateTransform { Angle = -imageOverlay.LatLonBox.Rotation };
|
|
||||||
overlay.RenderTransformOrigin = new Point(0.5, 0.5);
|
|
||||||
|
|
||||||
// additional Panel for map rotation, see MapPanel.ArrangeElementWithBoundingBox
|
|
||||||
var panel = new Grid { UseLayoutRounding = false };
|
|
||||||
panel.Children.Add(overlay);
|
|
||||||
overlay = panel;
|
|
||||||
}
|
|
||||||
|
|
||||||
SetBoundingBox(overlay, imageOverlay.LatLonBox);
|
|
||||||
Canvas.SetZIndex(overlay, imageOverlay.ZIndex);
|
|
||||||
Children.Add(overlay);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static async Task<IEnumerable<ImageOverlay>> ReadGroundOverlaysFromArchiveAsync(string archiveFile)
|
|
||||||
{
|
|
||||||
using (var archive = await Task.Run(() => ZipFile.OpenRead(archiveFile)))
|
|
||||||
{
|
|
||||||
var docEntry = await Task.Run(() => archive.GetEntry("doc.kml") ?? archive.Entries.FirstOrDefault(e => e.Name.EndsWith(".kml")));
|
|
||||||
|
|
||||||
if (docEntry == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentException("No KML entry found in " + archiveFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
var imageOverlays = await Task.Run(() =>
|
|
||||||
{
|
|
||||||
var kmlDocument = new XmlDocument();
|
|
||||||
|
|
||||||
using (var docStream = docEntry.Open())
|
|
||||||
{
|
|
||||||
kmlDocument.Load(docStream);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ReadGroundOverlays(kmlDocument).ToList();
|
|
||||||
});
|
|
||||||
|
|
||||||
foreach (var imageOverlay in imageOverlays)
|
|
||||||
{
|
|
||||||
var imageEntry = await Task.Run(() => archive.GetEntry(imageOverlay.ImagePath));
|
|
||||||
|
|
||||||
if (imageEntry != null)
|
|
||||||
{
|
|
||||||
using (var zipStream = imageEntry.Open())
|
|
||||||
using (var memoryStream = new MemoryStream())
|
|
||||||
{
|
|
||||||
await zipStream.CopyToAsync(memoryStream);
|
|
||||||
memoryStream.Seek(0, SeekOrigin.Begin);
|
|
||||||
|
|
||||||
imageOverlay.ImageSource = await ImageLoader.LoadImageAsync(memoryStream);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return imageOverlays;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static async Task<IEnumerable<ImageOverlay>> ReadGroundOverlaysFromFileAsync(string docFile)
|
|
||||||
{
|
|
||||||
docFile = Path.GetFullPath(docFile);
|
|
||||||
var docUri = new Uri(docFile);
|
|
||||||
|
|
||||||
var imageOverlays = await Task.Run(() =>
|
|
||||||
{
|
|
||||||
var kmlDocument = new XmlDocument();
|
|
||||||
kmlDocument.Load(docFile);
|
|
||||||
|
|
||||||
return ReadGroundOverlays(kmlDocument).ToList();
|
|
||||||
});
|
|
||||||
|
|
||||||
foreach (var imageOverlay in imageOverlays)
|
|
||||||
{
|
|
||||||
imageOverlay.ImageSource = await ImageLoader.LoadImageAsync(new Uri(docUri, imageOverlay.ImagePath));
|
|
||||||
}
|
|
||||||
|
|
||||||
return imageOverlays;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IEnumerable<ImageOverlay> ReadGroundOverlays(XmlDocument kmlDocument)
|
|
||||||
{
|
|
||||||
foreach (XmlElement groundOverlayElement in kmlDocument.GetElementsByTagName("GroundOverlay"))
|
|
||||||
{
|
|
||||||
LatLonBox latLonBox = null;
|
|
||||||
string imagePath = null;
|
|
||||||
int zIndex = 0;
|
|
||||||
|
|
||||||
foreach (var childElement in groundOverlayElement.ChildNodes.OfType<XmlElement>())
|
|
||||||
{
|
|
||||||
switch (childElement.LocalName)
|
|
||||||
{
|
|
||||||
case "LatLonBox":
|
|
||||||
latLonBox = ReadLatLonBox(childElement);
|
|
||||||
break;
|
|
||||||
case "Icon":
|
|
||||||
imagePath = ReadImagePath(childElement);
|
|
||||||
break;
|
|
||||||
case "drawOrder":
|
|
||||||
int.TryParse(childElement.InnerText.Trim(), out zIndex);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (latLonBox != null && imagePath != null)
|
|
||||||
{
|
|
||||||
yield return new ImageOverlay(latLonBox, imagePath, zIndex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string ReadImagePath(XmlElement element)
|
|
||||||
{
|
|
||||||
string href = null;
|
|
||||||
|
|
||||||
foreach (var childElement in element.ChildNodes.OfType<XmlElement>())
|
|
||||||
{
|
|
||||||
switch (childElement.LocalName)
|
|
||||||
{
|
|
||||||
case "href":
|
|
||||||
href = childElement.InnerText.Trim();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return href;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static LatLonBox ReadLatLonBox(XmlElement element)
|
|
||||||
{
|
|
||||||
double north = double.NaN;
|
|
||||||
double south = double.NaN;
|
|
||||||
double east = double.NaN;
|
|
||||||
double west = double.NaN;
|
|
||||||
double rotation = 0d;
|
|
||||||
|
|
||||||
foreach (var childElement in element.ChildNodes.OfType<XmlElement>())
|
|
||||||
{
|
|
||||||
switch (childElement.LocalName)
|
|
||||||
{
|
|
||||||
case "north":
|
|
||||||
double.TryParse(childElement.InnerText.Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out north);
|
|
||||||
break;
|
|
||||||
case "south":
|
|
||||||
double.TryParse(childElement.InnerText.Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out south);
|
|
||||||
break;
|
|
||||||
case "east":
|
|
||||||
double.TryParse(childElement.InnerText.Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out east);
|
|
||||||
break;
|
|
||||||
case "west":
|
|
||||||
double.TryParse(childElement.InnerText.Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out west);
|
|
||||||
break;
|
|
||||||
case "rotation":
|
|
||||||
double.TryParse(childElement.InnerText.Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out rotation);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return !double.IsNaN(north) && !double.IsNaN(south) && !double.IsNaN(east) && !double.IsNaN(west)
|
|
||||||
? new LatLonBox(south, west, north, east, rotation)
|
|
||||||
: null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,85 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
|
||||||
<PropertyGroup>
|
|
||||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
|
||||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
|
||||||
<ProjectGuid>{BE08B7BC-8C89-4837-BCE7-EDDDABEAB372}</ProjectGuid>
|
|
||||||
<OutputType>Library</OutputType>
|
|
||||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
|
||||||
<RootNamespace>MapControl.Images</RootNamespace>
|
|
||||||
<AssemblyName>MapImages.UWP</AssemblyName>
|
|
||||||
<DefaultLanguage>en-US</DefaultLanguage>
|
|
||||||
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
|
|
||||||
<TargetPlatformVersion Condition=" '$(TargetPlatformVersion)' == '' ">10.0.19041.0</TargetPlatformVersion>
|
|
||||||
<TargetPlatformMinVersion>10.0.17134.0</TargetPlatformMinVersion>
|
|
||||||
<MinimumVisualStudioVersion>14</MinimumVisualStudioVersion>
|
|
||||||
<FileAlignment>512</FileAlignment>
|
|
||||||
<ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
|
||||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
|
||||||
<DebugSymbols>true</DebugSymbols>
|
|
||||||
<DebugType>full</DebugType>
|
|
||||||
<Optimize>false</Optimize>
|
|
||||||
<OutputPath>bin\Debug\</OutputPath>
|
|
||||||
<DefineConstants>DEBUG;UWP</DefineConstants>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<WarningLevel>4</WarningLevel>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
|
||||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
|
||||||
<DebugType>pdbonly</DebugType>
|
|
||||||
<Optimize>true</Optimize>
|
|
||||||
<OutputPath>bin\Release\</OutputPath>
|
|
||||||
<DefineConstants>UWP</DefineConstants>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<WarningLevel>4</WarningLevel>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup>
|
|
||||||
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
|
|
||||||
</PropertyGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<Compile Include="..\Shared\GeoImage.cs">
|
|
||||||
<Link>GeoImage.cs</Link>
|
|
||||||
</Compile>
|
|
||||||
<Compile Include="..\Shared\GroundOverlayPanel.cs">
|
|
||||||
<Link>GroundOverlayPanel.cs</Link>
|
|
||||||
</Compile>
|
|
||||||
<Compile Include="..\WinUI\GeoImage.WinUI.cs">
|
|
||||||
<Link>GeoImage.WinUI.cs</Link>
|
|
||||||
</Compile>
|
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
|
||||||
<EmbeddedResource Include="Properties\MapImages.UWP.rd.xml" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform">
|
|
||||||
<Version>6.2.13</Version>
|
|
||||||
</PackageReference>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\..\MapControl\UWP\MapControl.UWP.csproj">
|
|
||||||
<Project>{9545f73c-9c35-4cf6-baae-19a0baebd344}</Project>
|
|
||||||
<Name>MapControl.UWP</Name>
|
|
||||||
</ProjectReference>
|
|
||||||
<ProjectReference Include="..\..\MapProjections\UWP\MapProjections.UWP.csproj">
|
|
||||||
<Project>{9ee69591-5edc-45e3-893e-2f9a4b82d538}</Project>
|
|
||||||
<Name>MapProjections.UWP</Name>
|
|
||||||
</ProjectReference>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<None Include="..\..\MapControl.snk">
|
|
||||||
<Link>MapControl.snk</Link>
|
|
||||||
</None>
|
|
||||||
</ItemGroup>
|
|
||||||
<PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' < '14.0' ">
|
|
||||||
<VisualStudioVersion>14.0</VisualStudioVersion>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup>
|
|
||||||
<SignAssembly>true</SignAssembly>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup>
|
|
||||||
<AssemblyOriginatorKeyFile>..\..\MapControl.snk</AssemblyOriginatorKeyFile>
|
|
||||||
</PropertyGroup>
|
|
||||||
<Import Project="$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets" />
|
|
||||||
</Project>
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
using System.Reflection;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
[assembly: AssemblyTitle("XAML Map Control Image Support Library for UWP")]
|
|
||||||
[assembly: AssemblyProduct("XAML Map Control")]
|
|
||||||
[assembly: AssemblyCompany("Clemens Fischer")]
|
|
||||||
[assembly: AssemblyCopyright("Copyright © 2022 Clemens Fischer")]
|
|
||||||
[assembly: AssemblyTrademark("")]
|
|
||||||
[assembly: AssemblyVersion("7.1.0")]
|
|
||||||
[assembly: AssemblyFileVersion("7.1.0")]
|
|
||||||
[assembly: AssemblyConfiguration("")]
|
|
||||||
[assembly: AssemblyCulture("")]
|
|
||||||
[assembly: ComVisible(false)]
|
|
||||||
|
|
@ -1,33 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!--
|
|
||||||
This file contains Runtime Directives, specifications about types your application accesses
|
|
||||||
through reflection and other dynamic code patterns. Runtime Directives are used to control the
|
|
||||||
.NET Native optimizer and ensure that it does not remove code accessed by your library. If your
|
|
||||||
library does not do any reflection, then you generally do not need to edit this file. However,
|
|
||||||
if your library reflects over types, especially types passed to it or derived from its types,
|
|
||||||
then you should write Runtime Directives.
|
|
||||||
|
|
||||||
The most common use of reflection in libraries is to discover information about types passed
|
|
||||||
to the library. Runtime Directives have three ways to express requirements on types passed to
|
|
||||||
your library.
|
|
||||||
|
|
||||||
1. Parameter, GenericParameter, TypeParameter, TypeEnumerableParameter
|
|
||||||
Use these directives to reflect over types passed as a parameter.
|
|
||||||
|
|
||||||
2. SubTypes
|
|
||||||
Use a SubTypes directive to reflect over types derived from another type.
|
|
||||||
|
|
||||||
3. AttributeImplies
|
|
||||||
Use an AttributeImplies directive to indicate that your library needs to reflect over
|
|
||||||
types or methods decorated with an attribute.
|
|
||||||
|
|
||||||
For more information on writing Runtime Directives for libraries, please visit
|
|
||||||
https://go.microsoft.com/fwlink/?LinkID=391919
|
|
||||||
-->
|
|
||||||
<Directives xmlns="http://schemas.microsoft.com/netfx/2013/01/metadata">
|
|
||||||
<Library Name="MapImages.UWP">
|
|
||||||
|
|
||||||
<!-- add directives for your library here -->
|
|
||||||
|
|
||||||
</Library>
|
|
||||||
</Directives>
|
|
||||||
|
|
@ -1,109 +0,0 @@
|
||||||
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
|
||||||
// © 2022 Clemens Fischer
|
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows.Media;
|
|
||||||
using System.Windows.Media.Imaging;
|
|
||||||
|
|
||||||
namespace MapControl.Images
|
|
||||||
{
|
|
||||||
public partial class GeoImage
|
|
||||||
{
|
|
||||||
public static Task<GeoImage> ReadGeoTiff(string imageFilePath)
|
|
||||||
{
|
|
||||||
return Task.Run(() =>
|
|
||||||
{
|
|
||||||
BitmapSource bitmap;
|
|
||||||
Matrix transform;
|
|
||||||
|
|
||||||
using (var stream = File.OpenRead(imageFilePath))
|
|
||||||
{
|
|
||||||
bitmap = BitmapFrame.Create(stream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
|
|
||||||
}
|
|
||||||
|
|
||||||
var metadata = bitmap.Metadata as BitmapMetadata;
|
|
||||||
|
|
||||||
if (metadata.GetQuery((string)PixelScaleQuery) is double[] pixelScale && pixelScale.Length == 3 &&
|
|
||||||
metadata.GetQuery((string)TiePointQuery) is double[] tiePoint && tiePoint.Length >= 6)
|
|
||||||
{
|
|
||||||
transform = new Matrix(pixelScale[0], 0d, 0d, -pixelScale[1], tiePoint[3], tiePoint[4]);
|
|
||||||
}
|
|
||||||
else if (metadata.GetQuery((string)TransformQuery) is double[] tform && tform.Length == 16)
|
|
||||||
{
|
|
||||||
transform = new Matrix(tform[0], tform[1], tform[4], tform[5], tform[3], tform[7]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new ArgumentException("No coordinate transformation found in \"" + imageFilePath + "\".");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (metadata.GetQuery((string)NoDataQuery) is string noData && int.TryParse(noData, out int noDataValue))
|
|
||||||
{
|
|
||||||
bitmap = ConvertTransparentPixel(bitmap, noDataValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new GeoImage(bitmap, transform, (MapProjection)null);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public static BitmapSource ConvertTransparentPixel(BitmapSource source, int transparentPixel)
|
|
||||||
{
|
|
||||||
BitmapPalette sourcePalette = null;
|
|
||||||
var targetFormat = source.Format;
|
|
||||||
|
|
||||||
if (source.Format == PixelFormats.Indexed8 ||
|
|
||||||
source.Format == PixelFormats.Indexed4 ||
|
|
||||||
source.Format == PixelFormats.Indexed2 ||
|
|
||||||
source.Format == PixelFormats.Indexed1)
|
|
||||||
{
|
|
||||||
sourcePalette = source.Palette;
|
|
||||||
}
|
|
||||||
else if (source.Format == PixelFormats.Gray8)
|
|
||||||
{
|
|
||||||
sourcePalette = BitmapPalettes.Gray256;
|
|
||||||
targetFormat = PixelFormats.Indexed8;
|
|
||||||
}
|
|
||||||
else if (source.Format == PixelFormats.Gray4)
|
|
||||||
{
|
|
||||||
sourcePalette = BitmapPalettes.Gray16;
|
|
||||||
targetFormat = PixelFormats.Indexed4;
|
|
||||||
}
|
|
||||||
else if (source.Format == PixelFormats.Gray2)
|
|
||||||
{
|
|
||||||
sourcePalette = BitmapPalettes.Gray4;
|
|
||||||
targetFormat = PixelFormats.Indexed2;
|
|
||||||
}
|
|
||||||
else if (source.Format == PixelFormats.BlackWhite)
|
|
||||||
{
|
|
||||||
sourcePalette = BitmapPalettes.BlackAndWhite;
|
|
||||||
targetFormat = PixelFormats.Indexed1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sourcePalette == null || transparentPixel >= sourcePalette.Colors.Count)
|
|
||||||
{
|
|
||||||
return source;
|
|
||||||
}
|
|
||||||
|
|
||||||
var colors = sourcePalette.Colors.ToList();
|
|
||||||
|
|
||||||
colors[transparentPixel] = Colors.Transparent;
|
|
||||||
|
|
||||||
var stride = (source.PixelWidth * source.Format.BitsPerPixel + 7) / 8;
|
|
||||||
var buffer = new byte[stride * source.PixelHeight];
|
|
||||||
|
|
||||||
source.CopyPixels(buffer, stride, 0);
|
|
||||||
|
|
||||||
var target = BitmapSource.Create(
|
|
||||||
source.PixelWidth, source.PixelHeight, source.DpiX, source.DpiY,
|
|
||||||
targetFormat, new BitmapPalette(colors), buffer, stride);
|
|
||||||
|
|
||||||
target.Freeze();
|
|
||||||
|
|
||||||
return target;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFrameworks>net6.0-windows;net5.0-windows;netcoreapp3.1;net48;net462</TargetFrameworks>
|
|
||||||
<UseWPF>true</UseWPF>
|
|
||||||
<RootNamespace>MapControl.Images</RootNamespace>
|
|
||||||
<AssemblyTitle>XAML Map Control Image Support Library for WPF</AssemblyTitle>
|
|
||||||
<Product>XAML Map Control</Product>
|
|
||||||
<Version>7.1.0</Version>
|
|
||||||
<Authors>Clemens Fischer</Authors>
|
|
||||||
<Copyright>Copyright © 2022 Clemens Fischer</Copyright>
|
|
||||||
<SignAssembly>true</SignAssembly>
|
|
||||||
<AssemblyOriginatorKeyFile>..\..\MapControl.snk</AssemblyOriginatorKeyFile>
|
|
||||||
<DelaySign>false</DelaySign>
|
|
||||||
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
|
|
||||||
<PackageId>XAML.MapControl.MapImages</PackageId>
|
|
||||||
<DefineConstants></DefineConstants>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<None Include="..\..\MapControl.snk" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Compile Include="..\Shared\*.cs" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup Condition="'$(TargetFramework)'=='net48' or '$(TargetFramework)'=='net462'">
|
|
||||||
<Reference Include="System.IO.Compression" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\..\MapControl\WPF\MapControl.WPF.csproj" />
|
|
||||||
<ProjectReference Include="..\..\MapProjections\WPF\MapProjections.WPF.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
</Project>
|
|
||||||
|
|
@ -1,66 +0,0 @@
|
||||||
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
|
||||||
// © 2022 Clemens Fischer
|
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using Windows.Graphics.Imaging;
|
|
||||||
using Windows.Storage;
|
|
||||||
#if WINUI
|
|
||||||
using Microsoft.UI.Xaml.Media.Imaging;
|
|
||||||
#else
|
|
||||||
using Windows.UI.Xaml.Media.Imaging;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace MapControl.Images
|
|
||||||
{
|
|
||||||
public partial class GeoImage
|
|
||||||
{
|
|
||||||
public static async Task<GeoImage> ReadGeoTiff(string imageFilePath)
|
|
||||||
{
|
|
||||||
var file = await StorageFile.GetFileFromPathAsync(Path.GetFullPath(imageFilePath));
|
|
||||||
|
|
||||||
using (var stream = await file.OpenReadAsync())
|
|
||||||
{
|
|
||||||
WriteableBitmap bitmap;
|
|
||||||
Matrix transform;
|
|
||||||
|
|
||||||
var decoder = await BitmapDecoder.CreateAsync(stream);
|
|
||||||
|
|
||||||
using (var swbmp = await decoder.GetSoftwareBitmapAsync())
|
|
||||||
{
|
|
||||||
bitmap = new WriteableBitmap(swbmp.PixelWidth, swbmp.PixelHeight);
|
|
||||||
swbmp.CopyToBuffer(bitmap.PixelBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
var query = new List<string>
|
|
||||||
{
|
|
||||||
PixelScaleQuery, TiePointQuery, TransformQuery //, NoDataQuery
|
|
||||||
};
|
|
||||||
|
|
||||||
var metadata = await decoder.BitmapProperties.GetPropertiesAsync(query);
|
|
||||||
|
|
||||||
if (metadata.TryGetValue(PixelScaleQuery, out BitmapTypedValue pixelScaleValue) &&
|
|
||||||
pixelScaleValue.Value is double[] pixelScale && pixelScale.Length == 3 &&
|
|
||||||
metadata.TryGetValue(TiePointQuery, out BitmapTypedValue tiePointValue) &&
|
|
||||||
tiePointValue.Value is double[] tiePoint && tiePoint.Length >= 6)
|
|
||||||
{
|
|
||||||
transform = new Matrix(pixelScale[0], 0d, 0d, -pixelScale[1], tiePoint[3], tiePoint[4]);
|
|
||||||
}
|
|
||||||
else if (metadata.TryGetValue(TransformQuery, out BitmapTypedValue tformValue) &&
|
|
||||||
tformValue.Value is double[] tform && tform.Length == 16)
|
|
||||||
{
|
|
||||||
transform = new Matrix(tform[0], tform[1], tform[4], tform[5], tform[3], tform[7]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new ArgumentException("No coordinate transformation found in \"" + imageFilePath + "\".");
|
|
||||||
}
|
|
||||||
|
|
||||||
return new GeoImage(bitmap, transform, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,38 +0,0 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>net6.0-windows10.0.19041.0</TargetFramework>
|
|
||||||
<TargetPlatformMinVersion>10.0.17763.0</TargetPlatformMinVersion>
|
|
||||||
<RuntimeIdentifiers>win10-x86;win10-x64;win10-arm64</RuntimeIdentifiers>
|
|
||||||
<UseWinUI>true</UseWinUI>
|
|
||||||
<RootNamespace>MapControl.Images</RootNamespace>
|
|
||||||
<AssemblyTitle>XAML Map Control Image Support Library for WinUI</AssemblyTitle>
|
|
||||||
<Product>XAML Map Control</Product>
|
|
||||||
<Version>7.1.0</Version>
|
|
||||||
<Authors>Clemens Fischer</Authors>
|
|
||||||
<Copyright>Copyright © 2022 Clemens Fischer</Copyright>
|
|
||||||
<SignAssembly>true</SignAssembly>
|
|
||||||
<AssemblyOriginatorKeyFile>..\..\MapControl.snk</AssemblyOriginatorKeyFile>
|
|
||||||
<DelaySign>false</DelaySign>
|
|
||||||
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
|
|
||||||
<PackageId>XAML.MapControl.MapImages</PackageId>
|
|
||||||
<DefineConstants>WINUI</DefineConstants>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<None Include="..\..\MapControl.snk" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Compile Include="..\Shared\*.cs" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.0.0" />
|
|
||||||
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22000.196" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\..\MapControl\WinUI\MapControl.WinUI.csproj" />
|
|
||||||
<ProjectReference Include="..\..\MapProjections\WinUI\MapProjections.WinUI.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
</Project>
|
|
||||||
Loading…
Reference in a new issue