mirror of https://github.com/icsharpcode/ILSpy.git
Browse Source
Single .NET classlib that embeds one resource of every type the Avalonia port recognises — .xml / .xsd / .xslt / .xaml / .png / .bmp / .jpg / .gif / .ico / .cur / .resources / .bin (unknown-extension fall-through). The image fixtures render a 64×64 cream square with a blue circle and red diagonal stripe so the inline preview is obviously decoded rather than blank; the .ico is multi-frame (16/32/48) so future per-frame work has something to chew on. Assisted-by: Claude:claude-opus-4-7:Claude Codepull/3755/head
15 changed files with 269 additions and 0 deletions
@ -0,0 +1,130 @@ |
|||||||
|
// Tiny helper that produces all the binary fixture files (PNG / BMP / JPG / GIF / ICO / CUR /
|
||||||
|
// .resources / .bin) into the fixtures/ directory. Text fixtures (XML / XSD / XSLT / XAML) are
|
||||||
|
// checked in as-is. Run with `dotnet run --project Generate.csproj` from this directory.
|
||||||
|
//
|
||||||
|
// Each image format renders an obvious recognizable shape (coloured square with a circle and a
|
||||||
|
// diagonal stripe) at 64×64 so manual ILSpy testing can eyeball that the rendering pipeline
|
||||||
|
// is decoding the bytes — not just rendering a blank tile.
|
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.IO; |
||||||
|
using System.Resources; |
||||||
|
|
||||||
|
using SixLabors.ImageSharp; |
||||||
|
using SixLabors.ImageSharp.Drawing.Processing; |
||||||
|
using SixLabors.ImageSharp.Formats; |
||||||
|
using SixLabors.ImageSharp.Formats.Bmp; |
||||||
|
using SixLabors.ImageSharp.Formats.Gif; |
||||||
|
using SixLabors.ImageSharp.Formats.Jpeg; |
||||||
|
using SixLabors.ImageSharp.Formats.Png; |
||||||
|
using SixLabors.ImageSharp.PixelFormats; |
||||||
|
using SixLabors.ImageSharp.Processing; |
||||||
|
|
||||||
|
var dir = Path.Combine(AppContext.BaseDirectory, "..", "..", "..", "fixtures"); |
||||||
|
dir = Path.GetFullPath(dir); |
||||||
|
Directory.CreateDirectory(dir); |
||||||
|
|
||||||
|
WriteImage(Path.Combine(dir, "logo.png"), new PngEncoder()); |
||||||
|
WriteImage(Path.Combine(dir, "logo.bmp"), new BmpEncoder()); |
||||||
|
WriteImage(Path.Combine(dir, "logo.jpg"), new JpegEncoder { Quality = 92 }); |
||||||
|
WriteImage(Path.Combine(dir, "logo.gif"), new GifEncoder()); |
||||||
|
|
||||||
|
// Multi-frame .ico: 16x16, 32x32, 48x48, each PNG-encoded inside the ICO container so Avalonia
|
||||||
|
// can decode the largest frame for preview while a savvy viewer can pick any.
|
||||||
|
File.WriteAllBytes(Path.Combine(dir, "favicon.ico"), BuildIcoOrCur(isCursor: false, sizes: new[] { 16, 32, 48 })); |
||||||
|
File.WriteAllBytes(Path.Combine(dir, "pointer.cur"), BuildIcoOrCur(isCursor: true, sizes: new[] { 32 })); |
||||||
|
|
||||||
|
// .resources file with a mix of strings and other-typed entries — the .resources DataGrid view
|
||||||
|
// splits these into two tables.
|
||||||
|
var ms = new MemoryStream(); |
||||||
|
using (var rw = new ResourceWriter(ms)) |
||||||
|
{ |
||||||
|
rw.AddResource("greeting", "Hello, world"); |
||||||
|
rw.AddResource("city", "Linz"); |
||||||
|
rw.AddResource("year", 2026); |
||||||
|
rw.AddResource("ratio", 1.61803); |
||||||
|
rw.AddResource("flag", true); |
||||||
|
} |
||||||
|
File.WriteAllBytes(Path.Combine(dir, "Strings.resources"), ms.ToArray()); |
||||||
|
|
||||||
|
// Unknown extension — should fall through to the generic ResourceTreeNode.
|
||||||
|
File.WriteAllBytes(Path.Combine(dir, "blob.bin"), new byte[] { 0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE, 0xBA, 0xBE }); |
||||||
|
|
||||||
|
Console.WriteLine($"Wrote fixtures into {dir}"); |
||||||
|
|
||||||
|
// --- helpers ---
|
||||||
|
|
||||||
|
static void WriteImage(string path, IImageEncoder encoder, int size = 64) |
||||||
|
{ |
||||||
|
using var img = RenderShape(size); |
||||||
|
using var fs = File.Create(path); |
||||||
|
img.Save(fs, encoder); |
||||||
|
} |
||||||
|
|
||||||
|
static Image<Rgba32> RenderShape(int size) |
||||||
|
{ |
||||||
|
var img = new Image<Rgba32>(size, size, new Rgba32(0xFF, 0xF6, 0xE5)); |
||||||
|
img.Mutate(ctx => { |
||||||
|
// Filled blue circle in the centre.
|
||||||
|
ctx.Fill(new Rgba32(0x33, 0x99, 0xCC), |
||||||
|
new SixLabors.ImageSharp.Drawing.EllipsePolygon(size / 2f, size / 2f, size * 0.35f)); |
||||||
|
// Red diagonal stripe.
|
||||||
|
ctx.DrawLine(new Rgba32(0xCC, 0x33, 0x33), |
||||||
|
Math.Max(2, size / 16f), |
||||||
|
new PointF(0, size), |
||||||
|
new PointF(size, 0)); |
||||||
|
// 1px dark border so the bounds are obvious against any background.
|
||||||
|
ctx.Draw(new Rgba32(0x33, 0x33, 0x33), 1, |
||||||
|
new RectangleF(0, 0, size - 1, size - 1)); |
||||||
|
}); |
||||||
|
return img; |
||||||
|
} |
||||||
|
|
||||||
|
// Builds an ICO/CUR file containing one PNG-encoded entry per requested size. The on-disk
|
||||||
|
// layout: ICONDIR + ICONDIRENTRY[*] + concatenated frame bytes; only byte 2 (image type)
|
||||||
|
// distinguishes ICO (1) from CUR (2). Hotspot for cursors is centred at (size/2, size/2).
|
||||||
|
static byte[] BuildIcoOrCur(bool isCursor, int[] sizes) |
||||||
|
{ |
||||||
|
var frames = new List<byte[]>(sizes.Length); |
||||||
|
var pngEncoder = new PngEncoder(); |
||||||
|
foreach (var sz in sizes) |
||||||
|
{ |
||||||
|
using var img = RenderShape(sz); |
||||||
|
using var ms = new MemoryStream(); |
||||||
|
img.Save(ms, pngEncoder); |
||||||
|
frames.Add(ms.ToArray()); |
||||||
|
} |
||||||
|
var fileMs = new MemoryStream(); |
||||||
|
var w = new BinaryWriter(fileMs); |
||||||
|
w.Write((ushort)0); // reserved
|
||||||
|
w.Write((ushort)(isCursor ? 2 : 1)); // type: 1=ICO, 2=CUR
|
||||||
|
w.Write((ushort)sizes.Length); // image count
|
||||||
|
int dirSize = 6 + 16 * sizes.Length; |
||||||
|
int offset = dirSize; |
||||||
|
for (int i = 0; i < sizes.Length; i++) |
||||||
|
{ |
||||||
|
var sz = sizes[i]; |
||||||
|
var dim = (byte)(sz >= 256 ? 0 : sz); |
||||||
|
w.Write(dim); // width
|
||||||
|
w.Write(dim); // height
|
||||||
|
w.Write((byte)0); // palette count
|
||||||
|
w.Write((byte)0); // reserved
|
||||||
|
if (isCursor) |
||||||
|
{ |
||||||
|
w.Write((ushort)(sz / 2)); // hotspot X
|
||||||
|
w.Write((ushort)(sz / 2)); // hotspot Y
|
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
w.Write((ushort)1); // colour planes
|
||||||
|
w.Write((ushort)32); // bits per pixel
|
||||||
|
} |
||||||
|
w.Write((uint)frames[i].Length); // bytes in frame
|
||||||
|
w.Write((uint)offset); // offset to frame
|
||||||
|
offset += frames[i].Length; |
||||||
|
} |
||||||
|
foreach (var frame in frames) |
||||||
|
w.Write(frame); |
||||||
|
return fileMs.ToArray(); |
||||||
|
} |
||||||
@ -0,0 +1,18 @@ |
|||||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||||
|
<PropertyGroup> |
||||||
|
<OutputType>Exe</OutputType> |
||||||
|
<TargetFramework>net10.0</TargetFramework> |
||||||
|
<RootNamespace>TestFixtures.Generate</RootNamespace> |
||||||
|
<Nullable>enable</Nullable> |
||||||
|
<!-- This generator runs once to (re)build the binary fixtures and isn't part of the |
||||||
|
solution's CPM scope; pin SkiaSharp inline so the parent Directory.Packages.props |
||||||
|
doesn't need to learn about a one-shot tool. --> |
||||||
|
<ManagePackageVersionsCentrally>false</ManagePackageVersionsCentrally> |
||||||
|
</PropertyGroup> |
||||||
|
<ItemGroup> |
||||||
|
<!-- ImageSharp covers every encoder we need (PNG/JPG/BMP/GIF) cross-platform; SkiaSharp's |
||||||
|
encoder list doesn't include BMP/GIF. --> |
||||||
|
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.11" /> |
||||||
|
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="2.1.4" /> |
||||||
|
</ItemGroup> |
||||||
|
</Project> |
||||||
@ -0,0 +1,34 @@ |
|||||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||||
|
<PropertyGroup> |
||||||
|
<TargetFramework>net10.0</TargetFramework> |
||||||
|
<AssemblyName>TestFixtures.Resources</AssemblyName> |
||||||
|
<RootNamespace>TestFixtures.Resources</RootNamespace> |
||||||
|
<Nullable>enable</Nullable> |
||||||
|
<!-- Standalone fixture for manual ILSpy testing — keep build artifacts entirely |
||||||
|
under this directory so the parent solution doesn't try to compile it. --> |
||||||
|
<BaseOutputPath>$(MSBuildThisFileDirectory)bin\</BaseOutputPath> |
||||||
|
</PropertyGroup> |
||||||
|
|
||||||
|
<ItemGroup> |
||||||
|
<!-- Each resource keeps its file name as the manifest name so it ends up routed to the |
||||||
|
right specialised resource node by extension. --> |
||||||
|
<EmbeddedResource Include="fixtures\sample.xml" LogicalName="sample.xml" /> |
||||||
|
<EmbeddedResource Include="fixtures\schema.xsd" LogicalName="schema.xsd" /> |
||||||
|
<EmbeddedResource Include="fixtures\transform.xslt" LogicalName="transform.xslt" /> |
||||||
|
<EmbeddedResource Include="fixtures\Window.xaml" LogicalName="Window.xaml" /> |
||||||
|
<EmbeddedResource Include="fixtures\logo.png" LogicalName="logo.png" /> |
||||||
|
<EmbeddedResource Include="fixtures\logo.bmp" LogicalName="logo.bmp" /> |
||||||
|
<EmbeddedResource Include="fixtures\logo.jpg" LogicalName="logo.jpg" /> |
||||||
|
<EmbeddedResource Include="fixtures\logo.gif" LogicalName="logo.gif" /> |
||||||
|
<EmbeddedResource Include="fixtures\favicon.ico" LogicalName="favicon.ico" /> |
||||||
|
<EmbeddedResource Include="fixtures\pointer.cur" LogicalName="pointer.cur" /> |
||||||
|
<EmbeddedResource Include="fixtures\Strings.resources" LogicalName="Strings.resources" /> |
||||||
|
<EmbeddedResource Include="fixtures\blob.bin" LogicalName="blob.bin" /> |
||||||
|
</ItemGroup> |
||||||
|
|
||||||
|
<!-- Generate.cs is for the Generate.csproj only; exclude from compilation here. --> |
||||||
|
<ItemGroup> |
||||||
|
<Compile Remove="Generate.cs" /> |
||||||
|
<None Remove="Generate.cs" /> |
||||||
|
</ItemGroup> |
||||||
|
</Project> |
||||||
Binary file not shown.
@ -0,0 +1,20 @@ |
|||||||
|
<Window xmlns="https://github.com/avaloniaui" |
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||||
|
Title="Demo Window" |
||||||
|
Width="640" |
||||||
|
Height="480"> |
||||||
|
<DockPanel> |
||||||
|
<TextBlock DockPanel.Dock="Top" |
||||||
|
Text="Hello, world" |
||||||
|
FontSize="20" |
||||||
|
Margin="12" /> |
||||||
|
<Border BorderBrush="Gray" |
||||||
|
BorderThickness="1" |
||||||
|
Margin="12"> |
||||||
|
<StackPanel> |
||||||
|
<Button Content="Click me" /> |
||||||
|
<TextBox Text="Some text" /> |
||||||
|
</StackPanel> |
||||||
|
</Border> |
||||||
|
</DockPanel> |
||||||
|
</Window> |
||||||
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 796 B |
@ -0,0 +1,15 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<configuration> |
||||||
|
<appSettings> |
||||||
|
<add key="environment" value="staging" /> |
||||||
|
<add key="timeoutSeconds" value="30" /> |
||||||
|
</appSettings> |
||||||
|
<connectionStrings> |
||||||
|
<add name="default" |
||||||
|
connectionString="Data Source=.;Initial Catalog=Demo;Integrated Security=True" |
||||||
|
providerName="System.Data.SqlClient" /> |
||||||
|
</connectionStrings> |
||||||
|
<runtime> |
||||||
|
<gcServer enabled="true" /> |
||||||
|
</runtime> |
||||||
|
</configuration> |
||||||
@ -0,0 +1,26 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" |
||||||
|
targetNamespace="http://example.com/order" |
||||||
|
xmlns="http://example.com/order" |
||||||
|
elementFormDefault="qualified"> |
||||||
|
<xs:element name="order"> |
||||||
|
<xs:complexType> |
||||||
|
<xs:sequence> |
||||||
|
<xs:element name="customer" type="xs:string" /> |
||||||
|
<xs:element name="items"> |
||||||
|
<xs:complexType> |
||||||
|
<xs:sequence> |
||||||
|
<xs:element name="item" maxOccurs="unbounded"> |
||||||
|
<xs:complexType> |
||||||
|
<xs:attribute name="sku" type="xs:string" use="required" /> |
||||||
|
<xs:attribute name="qty" type="xs:positiveInteger" use="required" /> |
||||||
|
</xs:complexType> |
||||||
|
</xs:element> |
||||||
|
</xs:sequence> |
||||||
|
</xs:complexType> |
||||||
|
</xs:element> |
||||||
|
</xs:sequence> |
||||||
|
<xs:attribute name="id" type="xs:string" use="required" /> |
||||||
|
</xs:complexType> |
||||||
|
</xs:element> |
||||||
|
</xs:schema> |
||||||
@ -0,0 +1,25 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<xsl:stylesheet version="1.0" |
||||||
|
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> |
||||||
|
<xsl:output method="html" indent="yes" /> |
||||||
|
|
||||||
|
<xsl:template match="/orders"> |
||||||
|
<html> |
||||||
|
<body> |
||||||
|
<h1>Orders</h1> |
||||||
|
<table border="1"> |
||||||
|
<tr> |
||||||
|
<th>ID</th> |
||||||
|
<th>Customer</th> |
||||||
|
</tr> |
||||||
|
<xsl:for-each select="order"> |
||||||
|
<tr> |
||||||
|
<td><xsl:value-of select="@id" /></td> |
||||||
|
<td><xsl:value-of select="customer" /></td> |
||||||
|
</tr> |
||||||
|
</xsl:for-each> |
||||||
|
</table> |
||||||
|
</body> |
||||||
|
</html> |
||||||
|
</xsl:template> |
||||||
|
</xsl:stylesheet> |
||||||
Loading…
Reference in new issue