Skip to content

Commit bd2cc54

Browse files
Add display aspect ratio correction for anamorphic DVD previews
Compute DAR from SAR metadata (e.g. 32:27 for anamorphic DVDs) and pass it to the before/after comparison widget, which uses FittedBox to stretch the preview to the correct display aspect ratio. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 8606bbc commit bd2cc54

2 files changed

Lines changed: 45 additions & 0 deletions

File tree

app/lib/views/preview_panel.dart

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,31 @@ class _PreviewPanelState extends State<PreviewPanel> {
4242
}
4343

4444
Widget _buildPreviewComparison(BuildContext context, MainViewModel viewModel) {
45+
// Compute display aspect ratio for SAR correction.
46+
// DAR = (width / height) * (sarNum / sarDen)
47+
// Only needed when SAR is non-square (e.g. anamorphic DVD 32:27).
48+
double? displayAspectRatio;
49+
final videoInfo = viewModel.videoInfo;
50+
if (videoInfo != null && videoInfo.sar != null) {
51+
final parts = videoInfo.sar!.split(':');
52+
if (parts.length == 2) {
53+
final sarNum = double.tryParse(parts[0]);
54+
final sarDen = double.tryParse(parts[1]);
55+
if (sarNum != null && sarDen != null && sarDen > 0) {
56+
displayAspectRatio =
57+
(videoInfo.width / videoInfo.height) * (sarNum / sarDen);
58+
}
59+
}
60+
}
61+
4562
return Padding(
4663
padding: const EdgeInsets.all(16),
4764
child: BeforeAfterComparisonWidget(
4865
beforeImage: viewModel.currentFrame,
4966
afterImage: viewModel.processedPreview ?? viewModel.currentFrame,
5067
isBeforeLoading: viewModel.isAnalyzing,
5168
isAfterLoading: viewModel.isGeneratingPreview,
69+
displayAspectRatio: displayAspectRatio,
5270
),
5371
);
5472
}

app/lib/widgets/before_after_comparison.dart

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,18 @@ class BeforeAfterComparisonWidget extends StatefulWidget {
2828
/// Whether the after image is loading.
2929
final bool isAfterLoading;
3030

31+
/// Display aspect ratio for SAR correction (e.g. 16/9 for anamorphic DVD).
32+
/// When null, the image's native pixel aspect ratio is used (square pixels).
33+
final double? displayAspectRatio;
34+
3135
const BeforeAfterComparisonWidget({
3236
super.key,
3337
this.beforeImage,
3438
this.afterImage,
3539
this.initialDividerPosition = 0.5,
3640
this.isBeforeLoading = false,
3741
this.isAfterLoading = false,
42+
this.displayAspectRatio,
3843
});
3944

4045
@override
@@ -412,6 +417,28 @@ class _BeforeAfterComparisonWidgetState
412417
required String label,
413418
}) {
414419
if (imageData != null) {
420+
// For non-square pixels (anamorphic DVD etc.), the image's pixel
421+
// dimensions don't match the intended display aspect ratio.
422+
// FittedBox scales its child uniformly to fit the parent while
423+
// preserving the SizedBox's aspect ratio — works even under the
424+
// tight constraints from StackFit.expand.
425+
if (widget.displayAspectRatio != null) {
426+
return FittedBox(
427+
fit: BoxFit.contain,
428+
child: SizedBox(
429+
width: widget.displayAspectRatio! * 1000,
430+
height: 1000,
431+
child: Image.memory(
432+
imageData,
433+
fit: BoxFit.fill,
434+
gaplessPlayback: true,
435+
filterQuality: FilterQuality.none,
436+
),
437+
),
438+
);
439+
}
440+
441+
// Square pixels: contain maintains the image's native aspect ratio.
415442
return Image.memory(
416443
imageData,
417444
fit: BoxFit.contain,

0 commit comments

Comments
 (0)