초기 커밋: SheetMe 서식생성기 (P0~P5 완료 상태)
레거시 서식생성기(VB.NET WinForms) 대체용 C#/.NET 10 WPF 디자이너. 기준선: 실DB 활성 디자인 1,271건 왕복 의미론 diff 0 / 예외 0, 단위 테스트 49/49. 이 커밋에 함께 포함된 자격증명 분리: - appsettings.json 을 __HOST__/__PASSWORD__ 플레이스홀더로 전환 - 실접속 정보는 appsettings.Development.json 으로 분리(.gitignore 제외, csproj Debug 조건부 복사라 Release 산출물에 실리지 않음) - ConfigLoader 를 환경변수 > Development > appsettings 순 레이어링으로 변경, 미치환 플레이스홀더는 '미설정'으로 간주 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,172 @@
|
||||
using System.IO;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using SheetMe.Designer.Services;
|
||||
using SheetMe.Designer.Views;
|
||||
|
||||
namespace SheetMe.Designer;
|
||||
|
||||
/// <summary>
|
||||
/// 서식생성기 애플리케이션 진입점.
|
||||
/// 명령행: --render-smoke <입력.xml> <출력.png> — 첫 페이지를 오프스크린 렌더해 PNG 저장(검증용) 후 종료.
|
||||
/// </summary>
|
||||
public partial class App : Application
|
||||
{
|
||||
/// <summary>기동 — 스모크 모드 분기 또는 메인 셸 표시</summary>
|
||||
protected override void OnStartup(StartupEventArgs e)
|
||||
{
|
||||
base.OnStartup(e);
|
||||
|
||||
if (e.Args.Length >= 3 && e.Args[0] == "--render-smoke")
|
||||
{
|
||||
var exitCode = RunRenderSmoke(e.Args[1], e.Args[2]);
|
||||
Shutdown(exitCode);
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.Args.Length >= 2 && e.Args[0] == "--edit-smoke")
|
||||
{
|
||||
Shutdown(Diagnostics.EditSmoke.Run(e.Args[1]));
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.Args.Length >= 2 && e.Args[0] == "--db-smoke")
|
||||
{
|
||||
var max = e.Args.Length >= 3 && int.TryParse(e.Args[2], out var n) ? n : 30;
|
||||
Shutdown(Diagnostics.DbSmoke.RunReadSmoke(e.Args[1], max));
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.Args.Length >= 3 && e.Args[0] == "--db-save-smoke")
|
||||
{
|
||||
Shutdown(Diagnostics.DbSmoke.RunSaveSmoke(e.Args[1], e.Args[2]));
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.Args.Length >= 3 && e.Args[0] == "--db-find")
|
||||
{
|
||||
Shutdown(Diagnostics.DbSmoke.RunFind(e.Args[1], e.Args[2]));
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.Args.Length >= 3 && e.Args[0] == "--db-columns")
|
||||
{
|
||||
Shutdown(Diagnostics.DbSmoke.RunColumns(e.Args[1], e.Args[2]));
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.Args.Length >= 3 && e.Args[0] == "--db-row")
|
||||
{
|
||||
Shutdown(Diagnostics.DbSmoke.RunRow(e.Args[1], e.Args[2]));
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.Args.Length >= 3 && e.Args[0] == "--db-sample")
|
||||
{
|
||||
Shutdown(Diagnostics.DbSmoke.RunSample(e.Args[1], e.Args[2]));
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.Args.Length >= 3 && e.Args[0] == "--db-word-smoke")
|
||||
{
|
||||
Shutdown(Diagnostics.DbSmoke.RunWordSmoke(e.Args[1], e.Args[2]));
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.Args.Length >= 3 && e.Args[0] == "--db-spd")
|
||||
{
|
||||
Shutdown(Diagnostics.DbSmoke.RunSpreadDump(e.Args[1], e.Args[2]));
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.Args.Length >= 3 && e.Args[0] == "--db-xml")
|
||||
{
|
||||
Shutdown(Diagnostics.DbSmoke.RunDesignXml(e.Args[1], e.Args[2]));
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.Args.Length >= 3 && e.Args[0] == "--db-render")
|
||||
{
|
||||
Shutdown(RunDbRenderSmoke(e.Args[1], e.Args[2]));
|
||||
return;
|
||||
}
|
||||
|
||||
Services.ThemeManager.LoadSaved();
|
||||
new MainView().Show();
|
||||
}
|
||||
|
||||
/// <summary>첫 페이지 오프스크린 렌더 → PNG (렌더 파이프라인 자동 검증)</summary>
|
||||
private static int RunRenderSmoke(string xmlPath, string pngPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
var store = new Data.Stores.XmlFileFormStore();
|
||||
var document = store.LoadFile(xmlPath);
|
||||
var page = DocumentMapper.CreatePage(document.Pages[0], 0);
|
||||
|
||||
var view = new PageView { DataContext = page };
|
||||
var size = new Size(page.WidthDip, page.HeightDip);
|
||||
view.Measure(size);
|
||||
view.Arrange(new Rect(size));
|
||||
view.UpdateLayout();
|
||||
|
||||
var bitmap = new RenderTargetBitmap(
|
||||
(int)Math.Ceiling(size.Width), (int)Math.Ceiling(size.Height), 96, 96, PixelFormats.Pbgra32);
|
||||
bitmap.Render(view);
|
||||
|
||||
var encoder = new PngBitmapEncoder();
|
||||
encoder.Frames.Add(BitmapFrame.Create(bitmap));
|
||||
using var stream = File.Create(pngPath);
|
||||
encoder.Save(stream);
|
||||
|
||||
Console.WriteLine($"렌더 스모크 완료: {pngPath} ({size.Width}x{size.Height}, " +
|
||||
$"페이지 {document.Pages.Count}, 경고 {document.Meta.ReadWarnings.Count})");
|
||||
return 0;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.Error.WriteLine($"렌더 스모크 실패: {ex}");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>DB 서식 첫 페이지 오프스크린 렌더 → PNG (Spread 격자 주입 경로 포함 검증)</summary>
|
||||
private static int RunDbRenderSmoke(string shtCod, string pngPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
var dataBusiness = new DataBusiness.FormDesignDataBusiness();
|
||||
var document = dataBusiness.OpenFromDb(shtCod);
|
||||
if (document is null)
|
||||
{
|
||||
File.WriteAllText(pngPath + ".err.txt", $"활성 디자인 없음: {shtCod}");
|
||||
return 1;
|
||||
}
|
||||
|
||||
var designer = new ViewModels.DesignerViewModel(document, dataBusiness.LoadSpreadGrids(shtCod));
|
||||
var page = designer.Pages[0];
|
||||
|
||||
var view = new PageView { DataContext = page };
|
||||
var size = new Size(page.WidthDip, page.HeightDip);
|
||||
view.Measure(size);
|
||||
view.Arrange(new Rect(size));
|
||||
view.UpdateLayout();
|
||||
|
||||
var bitmap = new RenderTargetBitmap(
|
||||
(int)Math.Ceiling(size.Width), (int)Math.Ceiling(size.Height), 96, 96, PixelFormats.Pbgra32);
|
||||
bitmap.Render(view);
|
||||
|
||||
var encoder = new PngBitmapEncoder();
|
||||
encoder.Frames.Add(BitmapFrame.Create(bitmap));
|
||||
using var stream = File.Create(pngPath);
|
||||
encoder.Save(stream);
|
||||
return 0;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
File.WriteAllText(pngPath + ".err.txt", ex.ToString());
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user