Orientamento regolabile, profilo di qualita' e icona dell'applicazione

ORIENTAMENTO
Il tag Exif dice come raddrizzare l'immagine, ma non basta leggerlo: alcuni
decodificatori di sistema lo applicano gia' per conto proprio e altri no, e la
stessa installazione di Windows si comporta diversamente a seconda del formato.
Applicare la trasformazione due volte ribalta il fotogramma, non applicarla mai
lo lascia coricato.

In modalita' automatica Titano confronta ora le dimensioni che il decodificatore
restituisce con quelle che il file dichiara di contenere: se la trasformazione
scambia gli assi ed e' gia' stata applicata, non la riapplica. La sezione
Generale mostra cosa ha dedotto e con quale motivo, e permette di imporre una
delle sei trasformazioni Exif quando i metadati sono sbagliati. L'anteprima
mostra subito l'effetto della scelta.

Sui DNG GoPro il rilevamento riporta "specchiata orizzontalmente (dal tag Exif
del file)": e' quanto dichiara il file e quanto applicano i lettori conformi
alla specifica DNG. Se all'occhio risulta sbagliato, ora si cambia dal menu.

QUALITA' PRIMA DELLA VELOCITA'
Nuovo profilo di elaborazione con tre livelli, predefinito su Massima. Governa
la finezza della griglia del campo vettoriale, i livelli della piramide, le
iterazioni per livello, i campioni per pixel della scia e la risoluzione della
passata fotometrica. Costa circa tre volte il tempo del profilo Standard e si
vede nei bordi dei soggetti in movimento.

Non e' stato introdotto alcun uso del disco come memoria d'appoggio: nessuna
fase della pipeline supera cio' che la RAM regge, e i file temporanei sono
esclusi per scelta architetturale. Se in futuro servira' tenere in vita molti
fotogrammi a piena risoluzione, quella e' la porta da cui entrare.

ICONA
Scie stellari attorno al polo celeste: l'immagine in cui il tempo diventa
visibile, e che dice insieme time-lapse e cielo notturno senza ricorrere a
orologi o otturatori. Disegnata in-house con GDI+, contenitore ICO scritto a
mano con sette livelli. Sotto i venti pixel il disegno si semplifica a due archi
piu' spessi: alla dimensione della barra delle applicazioni sette scie sottili
diventerebbero una macchia.

La verifica del motore sale a 25 controlli: si aggiunge che lo specchiamento
richiesto sposti davvero i pixel.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-14 15:53:10 +02:00
co-authored by Claude Opus 5
parent e476ebb648
commit 332f02d17d
14 changed files with 588 additions and 15 deletions
+57
View File
@@ -11,9 +11,13 @@ namespace Titano.UI;
/// </summary>
internal sealed class SettingsPanel : Panel
{
/// <summary>Valori Exif corrispondenti alle voci del menu dell'orientamento; null = automatico.</summary>
private static readonly int?[] OrientationValues = [null, 1, 2, 4, 6, 3, 8];
private readonly TitanoProject _project;
private readonly TabStrip _tabs;
private readonly Panel[] _pages;
private LabeledCombo? _orientationCombo;
/// <summary>Un parametro del deflicker è cambiato: basta ricalcolare la curva.</summary>
public event EventHandler? DeflickerChanged;
@@ -66,6 +70,18 @@ internal sealed class SettingsPanel : Panel
ShowPage(0);
}
/// <summary>
/// Riporta nel menu l'esito del rilevamento, così la voce "Automatico" dice cosa ha deciso.
/// </summary>
public void ShowDetectedOrientation(Imaging.OrientationDetection detection)
{
if (_orientationCombo is null || _orientationCombo.Combo.Items.Count == 0) return;
int selected = _orientationCombo.Combo.SelectedIndex;
_orientationCombo.Combo.Items[0] = $"Automatico — {detection.Description}";
_orientationCombo.Combo.SelectedIndex = selected;
}
/// <summary>Seleziona una delle tre sezioni; usata anche dalla modalità di cattura.</summary>
internal void SelectPage(int index) => _tabs.SelectedIndex = index;
@@ -97,6 +113,37 @@ internal sealed class SettingsPanel : Panel
AnalysisInvalidated?.Invoke(this, EventArgs.Empty);
}));
_orientationCombo = Combo("Orientamento dei fotogrammi",
["Automatico", "Nessuna rotazione", "Specchia orizzontalmente", "Specchia verticalmente",
"Ruota 90° in senso orario", "Ruota 180°", "Ruota 90° in senso antiorario"],
Array.IndexOf(OrientationValues, _project.General.OrientationOverride),
index =>
{
_project.General.OrientationOverride = OrientationValues[Math.Clamp(index, 0, OrientationValues.Length - 1)];
AnalysisInvalidated?.Invoke(this, EventArgs.Empty);
});
stack.Add(_orientationCombo);
stack.Add(Note("In automatico l'orientamento viene dedotto dai metadati del primo scatto e " +
"confrontato con ciò che il decodificatore di sistema restituisce, così la " +
"trasformazione non viene applicata due volte. Se il risultato non convince, " +
"l'anteprima mostra subito l'effetto di una scelta manuale."));
stack.Add(new SectionHeader("Qualità di elaborazione"));
stack.Add(Combo("Profilo",
["Bozza — veloce", "Standard — equilibrio", "Massima — resa migliore"],
(int)_project.General.Quality,
index =>
{
_project.ApplyQualityProfile((QualityProfile)Math.Clamp(index, 0, 2));
AnalysisInvalidated?.Invoke(this, EventArgs.Empty);
}));
stack.Add(Note("Il profilo governa finezza del campo vettoriale, campioni della sfocatura e " +
"risoluzione della passata fotometrica, e sovrascrive i cursori delle sezioni " +
"avanzate. Più qualità significa più tempo, non un file più grande."));
stack.Add(new SectionHeader("Prestazioni"));
stack.Add(Slider("Larghezza della passata di analisi", 256, 2048, _project.General.AnalysisWidth, 64, "0", "px",
value =>
@@ -282,6 +329,16 @@ internal sealed class SettingsPanel : Panel
control.Top = _y;
control.Width = Panel.ClientSize.Width - 34;
control.Anchor = AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Right;
// Le note esplicative variano in lunghezza: si misurano sulla larghezza reale
// della colonna, altrimenti le più lunghe finirebbero tagliate a metà frase.
if (control is Label note && !note.AutoSize)
{
var measured = TextRenderer.MeasureText(note.Text, note.Font,
new Size(control.Width, 0), TextFormatFlags.WordBreak);
control.Height = measured.Height + 8;
}
Panel.Controls.Add(control);
_y += control.Height + 6;
}