feat(core): SnapshotService — рендер 3D-модели в PNG (S4, "зрение агента")

- RasterImageFormat (PNG/JPG/BMP/...) + MIME-типы + парсинг
- SnapshotService: ksDocument3D.SaveAsToRasterFormat -> временный файл -> байты
  (resultArrayBytes при заданном имени файла не заполняется; рендер в файл надёжен)
- tests: снимок активной детали возвращает валидный PNG (визуально проверено)
- docs/OPEN_QUESTIONS.md: зафиксирован нюанс resultArrayBytes

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-25 23:48:35 +03:00
parent f0995a67e6
commit d4502409de
4 changed files with 181 additions and 0 deletions
@@ -0,0 +1,45 @@
using Kompas.Mcp.Core.Documents;
using Kompas.Mcp.Core.Vision;
namespace Kompas.Mcp.Tests.Integration;
/// <summary>Интеграция: снимок модели в растр («зрение агента»).</summary>
[Trait("Category", "Integration")]
[Collection(KompasCollection.Name)]
public sealed class SnapshotTests
{
private readonly DocumentService _docs;
private readonly SnapshotService _snap;
public SnapshotTests(KompasFixture fx)
{
_docs = new DocumentService(fx.Session, fx.Dispatcher);
_snap = new SnapshotService(fx.Session, fx.Dispatcher);
}
[Fact]
public async Task Snapshot_active_part_returns_valid_png()
{
await _docs.CreateAsync(KompasDocumentType.Part);
try
{
var path = TestPaths.NewFile(".png");
var snap = await _snap.CaptureActiveModelAsync(RasterImageFormat.Png, saveToFile: path);
Assert.Equal(RasterImageFormat.Png, snap.Format);
Assert.True(snap.Bytes.Length > 100, "Снимок подозрительно мал.");
// Сигнатура PNG: 89 50 4E 47 0D 0A 1A 0A
Assert.Equal(0x89, snap.Bytes[0]);
Assert.Equal((byte)'P', snap.Bytes[1]);
Assert.Equal((byte)'N', snap.Bytes[2]);
Assert.Equal((byte)'G', snap.Bytes[3]);
Assert.True(File.Exists(path));
}
finally
{
await _docs.CloseAsync(save: false);
}
}
}