From 5d8798f1f7ea63f226c15d359a5ef98370b466fe Mon Sep 17 00:00:00 2001 From: Alberto Balbo Date: Thu, 13 Aug 2026 21:51:39 +0200 Subject: [PATCH] Avvio in debug da VS Code e correzione dell'output a riga di comando MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Aggiunta la configurazione .vscode allineata a quella di Mimante ed Encelado: F5 apre la finestra di Titano, una seconda configurazione entra con i breakpoint nella verifica del motore (--selftest), che è un punto d'ingresso separato e non raggiungibile dall'interfaccia. Nei task: build, verifica, cattura interfaccia e pulisci. La verifica usciva con codice 0 ma senza stampare nulla quando lanciata con "dotnet run" o con l'output su file. La causa è AttachConsole: l'eseguibile è un'applicazione a finestre e senza aggancio non si farebbe leggere da un terminale, ma se lo standard output è già dirottato l'aggancio lo sostituisce e i messaggi finiscono nella console invece che nella pipe. Ora l'aggancio avviene solo quando l'output non è già dirottato. Verificato nei tre casi: eseguibile diretto, dotnet run e redirezione su file, 55 righe in tutti e tre. Svuotato Modifiche.txt: il file è dell'utente. Co-Authored-By: Claude Opus 5 --- Titano/.vscode/extensions.json | 7 +++ Titano/.vscode/launch.json | 43 +++++++++++++++ Titano/.vscode/tasks.json | 95 ++++++++++++++++++++++++++++++++++ Titano/Modifiche.txt | 72 -------------------------- Titano/Program.cs | 20 ++++++- 5 files changed, 163 insertions(+), 74 deletions(-) create mode 100644 Titano/.vscode/extensions.json create mode 100644 Titano/.vscode/launch.json create mode 100644 Titano/.vscode/tasks.json diff --git a/Titano/.vscode/extensions.json b/Titano/.vscode/extensions.json new file mode 100644 index 0000000..754703a --- /dev/null +++ b/Titano/.vscode/extensions.json @@ -0,0 +1,7 @@ +{ + "recommendations": [ + // Fornisce il debugger "coreclr" richiesto da launch.json. + "ms-dotnettools.csharp", + "ms-dotnettools.csdevkit" + ] +} diff --git a/Titano/.vscode/launch.json b/Titano/.vscode/launch.json new file mode 100644 index 0000000..dd634c1 --- /dev/null +++ b/Titano/.vscode/launch.json @@ -0,0 +1,43 @@ +{ + // Titano è un'applicazione desktop: F5 apre la stessa finestra che si ottiene + // facendo doppio clic su Titano.exe. La seconda configurazione esiste perché la + // verifica del motore NON è raggiungibile da quella finestra — è un punto + // d'ingresso a sé (--selftest), e volerci mettere un breakpoint dentro è la + // ragione più frequente per aprire il debugger su questo progetto. + "version": "0.2.0", + "configurations": [ + { + "name": "Titano", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "build", + "program": "${workspaceFolder}/bin/Debug/net10.0-windows/Titano.exe", + "args": [], + "cwd": "${workspaceFolder}/bin/Debug/net10.0-windows", + "console": "internalConsole", + "stopAtEntry": false, + "enableStepFiltering": true + }, + { + // Terminale integrato e non console interna: --selftest scrive con + // AttachConsole sulla console del processo padre, che nella console interna + // non esiste. Nel terminale l'esito delle 23 verifiche si legge davvero. + "name": "Titano — verifica del motore", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "build", + "program": "${workspaceFolder}/bin/Debug/net10.0-windows/Titano.exe", + "args": ["--selftest"], + "cwd": "${workspaceFolder}/bin/Debug/net10.0-windows", + "console": "integratedTerminal", + "stopAtEntry": false, + "enableStepFiltering": true + }, + { + "name": "Attach a Titano (processo già avviato)", + "type": "coreclr", + "request": "attach", + "processName": "Titano.exe" + } + ] +} diff --git a/Titano/.vscode/tasks.json b/Titano/.vscode/tasks.json new file mode 100644 index 0000000..00730fe --- /dev/null +++ b/Titano/.vscode/tasks.json @@ -0,0 +1,95 @@ +{ + // Stessa impostazione di Mimante ed Encelado: attività "process" che chiamano + // dotnet, nomi in italiano, $msCompile per portare gli errori nel pannello + // Problemi. Titano non ha una catena MSBuild dedicata perché non ne ha bisogno: + // è un solo progetto, senza pacchetti da ripristinare e senza installatore. + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "detail": "Compilazione di debug, per F5 e per il controllo rapido degli errori.", + "type": "process", + "command": "dotnet", + "args": [ + "build", + "${workspaceFolder}/Titano.slnx", + "-c", + "Debug", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "group": { "kind": "build", "isDefault": true }, + "problemMatcher": "$msCompile" + }, + { + "label": "verifica", + "detail": "Genera una sequenza sintetica e la fa attraversare tutta la pipeline: 23 controlli, encoder e contenitore compresi. Da eseguire dopo ogni modifica.", + // In Release e non in Debug: le stesse verifiche passano da ~47 s a ~6 s, + // perché i cicli in virgola mobile di flow e blur non sono ottimizzati in Debug. + "type": "process", + "command": "dotnet", + "args": [ + "run", + "--project", + "${workspaceFolder}/Titano.csproj", + "-c", + "Release", + "--", + "--selftest" + ], + "group": { "kind": "test", "isDefault": true }, + "presentation": { "reveal": "always", "panel": "dedicated" }, + "problemMatcher": "$msCompile" + }, + { + "label": "cattura interfaccia", + "detail": "Salva un'immagine della finestra in bin/interfaccia.png. Serve a controllare la resa dei controlli disegnati a mano senza doverli guardare a occhio.", + "type": "process", + "command": "dotnet", + "args": [ + "run", + "--project", + "${workspaceFolder}/Titano.csproj", + "-c", + "Release", + "--", + "--capture", + "${workspaceFolder}/bin/interfaccia.png", + "${input:sequenza}", + "${input:scheda}" + ], + "presentation": { "reveal": "always", "panel": "dedicated" }, + "problemMatcher": [] + }, + { + "label": "pulisci", + "detail": "Rimuove bin e obj di entrambe le configurazioni.", + "type": "process", + "command": "dotnet", + "args": ["clean", "${workspaceFolder}/Titano.slnx", "-v", "m"], + "problemMatcher": [] + } + ], + "inputs": [ + { + "id": "sequenza", + "type": "promptString", + // Il valore predefinito è la sequenza lasciata sul disco dal task "verifica": + // eseguito quello, la cattura ha già qualcosa di sensato da mostrare. + // Lasciando il campo vuoto si cattura la finestra senza sequenza caricata. + "description": "Cartella della sequenza da caricare (vuoto = finestra vuota)", + "default": "${env:TEMP}\\Titano.SelfTest\\sequenza" + }, + { + "id": "scheda", + "type": "pickString", + "description": "Quale sezione del pannello di configurazione mostrare", + "options": [ + { "label": "Generale", "value": "0" }, + { "label": "Elaborazione immagini", "value": "1" }, + { "label": "Esportazione", "value": "2" } + ], + "default": "0" + } + ] +} diff --git a/Titano/Modifiche.txt b/Titano/Modifiche.txt index 1c506eb..e69de29 100644 --- a/Titano/Modifiche.txt +++ b/Titano/Modifiche.txt @@ -1,72 +0,0 @@ -TITANO - registro delle modifiche -================================= - -2026-08-13 Prima versione completa dell'applicazione. - - Sviluppo da zero di Titano, applicazione desktop per time-lapse professionali, - con il vincolo di non usare alcuna libreria o strumento di terze parti. - Il progetto non contiene nessun PackageReference: oltre alla libreria standard - di .NET si usano solo API native di Windows richiamate via P/Invoke scritto a mano. - - MODULI REALIZZATI - - 1. Ingestion e parsing metadati (Metadata/) - - Parser binario TIFF/Exif proprietario: header, catena di IFD, tutti i tipi - di dato della specifica, sotto-directory Exif e GPS. - - Riconoscimento dei contenitori: JPEG (percorso dei marker senza decodifica), - TIFF e RAW derivati, PNG (percorso dei chunk), HEIF/AVIF/WebP per scansione. - - Scanner XMP proprietario come sorgente complementare. - - Timestamp con frazione di secondo (SubSecTimeOriginal) e fuso orario; - tempo di posa, apertura e ISO anche nelle varianti APEX. - - Calcolo degli intervalli reali, cadenza nominale mediana e segnalazione - delle pause dell'intervallometro. - - 2. Deflicker e smoothing dell'esposizione (Analysis/) - - Misura della luminanza come media logaritmica troncata su istogramma, - calcolata in luce lineare su campionamento a griglia fissa. - - Curva target da regressione lineare locale pesata su finestra mobile, con - seconda passata robusta (peso di Tukey) che scarta i fotogrammi anomali. - Le rampe reali di luce restano intatte, lo sfarfallio viene rimosso. - - Applicazione dei guadagni con compressione dolce delle alte luci e - stabilizzazione opzionale del bilanciamento colore. - - 3. Motion blur sintetico e interpolazione (Motion/) - - Optical flow proprietario: piramide gaussiana e schema differenziale - iterativo su griglia rada, con filtro mediano fra i livelli. - - Shutter angle reale per fotogramma; sfocatura mancante composta in - quadratura e resa con filtro di ricostruzione direzionale. - - Interpolazione temporale con warping bidirezionale per uniformare la - cadenza e gestire in modo adattivo la durata dei fotogrammi. - - 4. Streaming ed encoding video (Video/) - - Multiplexer MP4 (ISO-BMFF) scritto da zero: ftyp, mdat in streaming con - dimensione a 64 bit, moov completo con stts a durate variabili, stss, - stsz, co64, avcC/hvcC costruiti dai parameter set del bitstream. - - Encoder pilotato direttamente come Media Foundation Transform, con - percorso asincrono per le trasformazioni hardware (Intel/AMD/NVIDIA) - e ripiego automatico su quelle software. - - Conversione RGB lineare a NV12 BT.709 scritta in-house. - - 5. Interfaccia (UI/) - - Tema scuro con ogni controllo disegnato a mano in GDI+: pulsanti, - interruttori, cursori, schede, barra di avanzamento. - - Grafico vettoriale della curva di esposizione: luminanza misurata - sovrapposta alla curva target, area di correzione, corsia dei guadagni, - fasce delle anomalie di cadenza, zoom, spostamento e tooltip. - - Tabella dei fotogrammi a rendering virtuale. - - Pannello di configurazione in tre sezioni: Generale, Elaborazione - immagini, Esportazione video. - - Anteprima elaborata dallo stesso motore usato in esportazione. - - ARCHITETTURA - - Nessun file temporaneo: i dati passano fra le fasi solo in memoria, l'unica - scrittura su disco è il flusso compresso finale. - - Impronta di memoria costante: buffer poolati e canale a capacità limitata, - l'occupazione non dipende dal numero di fotogrammi della sequenza. - - Thread di calcolo separati dal thread dell'interfaccia. - - VERIFICA - Comando "Titano.exe --selftest": genera una sequenza sintetica dalle - proprietà note e la fa attraversare l'intera pipeline confrontando 23 - grandezze con i valori attesi. Tutte superate, compresa la ri-decodifica - del file prodotto con il lettore di sistema. diff --git a/Titano/Program.cs b/Titano/Program.cs index 3bfeb26..128d88e 100644 --- a/Titano/Program.cs +++ b/Titano/Program.cs @@ -15,7 +15,7 @@ internal static class Program { if (args.Length > 0 && args[0] is "--selftest" or "-t") { - AttachConsole(AttachParentProcess); + EnsureConsole(); string directory = args.Length > 1 ? args[1] : Path.Combine(Path.GetTempPath(), "Titano.SelfTest"); @@ -28,7 +28,7 @@ internal static class Program if (args.Length > 1 && args[0] == "--capture") { - AttachConsole(AttachParentProcess); + EnsureConsole(); ApplicationConfiguration.Initialize(); return Capture(args[1], args.Length > 2 ? args[2] : null, args.Length > 3 && int.TryParse(args[3], out int tab) ? tab : 0); @@ -39,6 +39,22 @@ internal static class Program return 0; } + /// + /// Rende visibili i messaggi delle modalità a riga di comando. + /// + /// L'eseguibile è compilato come applicazione a finestre e quindi nasce senza console: + /// agganciare quella del processo padre è l'unico modo di farsi leggere da un terminale. + /// Ma se lo standard output è già dirottato — una pipe, un file di registro, il task di + /// un editor — l'aggancio sostituirebbe quel dirottamento e i messaggi finirebbero nella + /// console invece che dove sono attesi. In quel caso non si aggancia niente: i gestori + /// ereditati vanno già bene. + /// + private static void EnsureConsole() + { + if (Console.IsOutputRedirected) return; + AttachConsole(AttachParentProcess); + } + /// /// Apre l'interfaccia, opzionalmente vi carica una sequenza, e ne salva un'immagine. /// Serve a verificare la resa dei controlli disegnati a mano senza intervento manuale.