Example #1
0
        private string CreateTitle(OutputSizeInfo size)
        {
            if (size.Par.Num == size.Par.Den)
            {
                return(string.Format(PreviewRes.PreviewWindowTitleSimple, size.OutputWidth, size.OutputHeight));
            }
            else
            {
                int width     = size.OutputWidth;
                int height    = size.OutputHeight;
                int parWidth  = size.Par.Num;
                int parHeight = size.Par.Den;

                if (parWidth <= 0 || parHeight <= 0)
                {
                    StaticResolver.Resolve <IAppLogger>().LogError("HandBrake returned a negative pixel aspect ratio. Cannot show preview.");
                    return(PreviewRes.NoVideoSourceTitle);
                }

                return(string.Format(
                           PreviewRes.PreviewWindowTitleComplex,
                           Math.Round(width * ((double)parWidth / parHeight)),
                           height,
                           width,
                           height));
            }
        }
Example #2
0
 private void UpdateTitle(OutputSizeInfo size)
 {
     if (size.Par.Num == size.Par.Den)
     {
         this.Title = string.Format(PreviewRes.PreviewWindowTitleSimple, size.OutputWidth, size.OutputHeight);
     }
     else
     {
         this.Title = string.Format(
             PreviewRes.PreviewWindowTitleComplex,
             Math.Round(this.PreviewDisplayWidth),
             Math.Round(this.PreviewDisplayHeight),
             size.OutputWidth,
             size.OutputHeight);
     }
 }
Example #3
0
        public void Refresh()
        {
            if (this.mainViewModel.SelectedTitle != null)
            {
                var profile = this.presetsService.SelectedPreset.Preset.EncodingProfile;

                OutputSizeInfo outputSizeInfo = JsonEncodeFactory.GetOutputSize(profile, this.mainViewModel.SelectedTitle);

                if (this.Size == null || !outputSizeInfo.Equals(this.Size))
                {
                    this.Size = outputSizeInfo;
                }
            }
            else
            {
                this.Size = null;
            }
        }
Example #4
0
        public void RefreshImageSize()
        {
            var        previewVM = (PreviewWindowViewModel)this.DataContext;
            PreviewFit fitControl;

            OutputSizeInfo outputSize = previewVM.PreviewImageService.OutputSizeInfo;

            if (outputSize != null)
            {
                int displayHeight = outputSize.OutputHeight;
                int displayWidth  = outputSize.DisplayWidth;

                switch (previewVM.MainDisplay)
                {
                case PreviewMainDisplay.Default:
                    fitControl = this.MainContent as PreviewFit;
                    fitControl?.ResizeHolder(this.previewArea, displayWidth, displayHeight, showOneToOneWhenSmaller: true);

                    break;

                case PreviewMainDisplay.FitToWindow:
                    fitControl = this.MainContent as PreviewFit;
                    fitControl?.ResizeHolder(this.previewArea, displayWidth, displayHeight, showOneToOneWhenSmaller: false);

                    break;

                case PreviewMainDisplay.OneToOne:
                    var oneToOneControl = this.MainContent as PreviewOneToOne;
                    oneToOneControl?.ResizeHolder(displayWidth, displayHeight);

                    break;

                case PreviewMainDisplay.StillCorners:
                    var cornersControl = this.MainContent as PreviewCorners;
                    cornersControl?.UpdateCornerImages();

                    break;
                }
            }
        }
        public SizingPanelViewModel(EncodingWindowViewModel encodingWindowViewModel)
            : base(encodingWindowViewModel)
        {
            this.AutomaticChange = true;

            this.RotationChoices = new List <RotationViewModel>
            {
                new RotationViewModel {
                    Rotation = VCPictureRotation.None, Display = CommonRes.None, Image = "/Icons/Empty.png", ShowImage = false
                },
                new RotationViewModel {
                    Rotation = VCPictureRotation.Clockwise90, Display = EncodingRes.Rotation_Clockwise90, Image = "/Icons/rotate_90_cw.png"
                },
                new RotationViewModel {
                    Rotation = VCPictureRotation.Clockwise270, Display = EncodingRes.Rotation_Counterclockwise90, Image = "/Icons/rotate_90_ccw.png"
                },
                new RotationViewModel {
                    Rotation = VCPictureRotation.Clockwise180, Display = EncodingRes.Rotation_180, Image = "/Icons/rotate_180.png"
                }
            };

            this.SizingModeChoices = new List <ComboChoice <VCSizingMode> >
            {
                new ComboChoice <VCSizingMode>(VCSizingMode.Automatic, CommonRes.Automatic),
                new ComboChoice <VCSizingMode>(VCSizingMode.Manual, EncodingRes.SizingModeManual),
            };

            this.ScalingModeChoices = new List <ComboChoice <VCScalingMode> >
            {
                new ComboChoice <VCScalingMode>(VCScalingMode.DownscaleOnly, EncodingRes.ScalingMode_DownscaleOnly),
                new ComboChoice <VCScalingMode>(VCScalingMode.UpscaleFill, EncodingRes.ScalingMode_Fill),
                new ComboChoice <VCScalingMode>(VCScalingMode.Upscale2X, string.Format(EncodingRes.UpscaleMaxFormat, 2)),
                new ComboChoice <VCScalingMode>(VCScalingMode.Upscale3X, string.Format(EncodingRes.UpscaleMaxFormat, 3)),
                new ComboChoice <VCScalingMode>(VCScalingMode.Upscale4X, string.Format(EncodingRes.UpscaleMaxFormat, 4)),
            };

            this.PaddingModeChoices = new List <ComboChoice <VCPaddingMode> >
            {
                new ComboChoice <VCPaddingMode>(VCPaddingMode.None, CommonRes.None),
                new ComboChoice <VCPaddingMode>(VCPaddingMode.Fill, EncodingRes.PaddingMode_Fill),
                new ComboChoice <VCPaddingMode>(VCPaddingMode.Width, EncodingRes.PaddingMode_Width),
                new ComboChoice <VCPaddingMode>(VCPaddingMode.Height, EncodingRes.PaddingMode_Height),
                new ComboChoice <VCPaddingMode>(VCPaddingMode.Custom, CommonRes.Custom),
            };

            this.RegisterProfileProperties();

            // WidthLabel
            this.WhenAnyValue(x => x.SizingMode, x => x.PaddingMode, x => x.ScalingMode, (sizingMode, paddingMode, scalingMode) =>
            {
                if (sizingMode == VCSizingMode.Manual)
                {
                    return(EncodingRes.WidthLabel);
                }

                switch (paddingMode)
                {
                case VCPaddingMode.Fill:
                case VCPaddingMode.Width:
                    return(EncodingRes.WidthLabel);

                case VCPaddingMode.Height:
                    return(EncodingRes.MaxWidthLabel);

                case VCPaddingMode.None:
                case VCPaddingMode.Custom:
                    switch (scalingMode)
                    {
                    case VCScalingMode.UpscaleFill:
                        return(EncodingRes.TargetWidthLabel);

                    default:
                        return(EncodingRes.MaxWidthLabel);
                    }
                }

                return(string.Empty);
            }).ToProperty(this, x => x.WidthLabel, out this.widthLabel);

            // HeightLabel
            this.WhenAnyValue(x => x.SizingMode, x => x.PaddingMode, x => x.ScalingMode, (sizingMode, paddingMode, scalingMode) =>
            {
                if (sizingMode == VCSizingMode.Manual)
                {
                    return(EncodingRes.HeightLabel);
                }

                switch (paddingMode)
                {
                case VCPaddingMode.Fill:
                case VCPaddingMode.Height:
                    return(EncodingRes.HeightLabel);

                case VCPaddingMode.Width:
                    return(EncodingRes.MaxHeightLabel);

                case VCPaddingMode.None:
                case VCPaddingMode.Custom:
                    switch (scalingMode)
                    {
                    case VCScalingMode.UpscaleFill:
                        return(EncodingRes.TargetHeightLabel);

                    default:
                        return(EncodingRes.MaxHeightLabel);
                    }
                }

                return(string.Empty);
            }).ToProperty(this, x => x.HeightLabel, out this.heightLabel);

            // AllowEmptyResolution
            this.WhenAnyValue(x => x.SizingMode, x => x.PaddingMode, x => x.ScalingMode, (sizingMode, paddingMode, scalingMode) =>
            {
                if (sizingMode == VCSizingMode.Manual)
                {
                    return(false);
                }

                switch (paddingMode)
                {
                case VCPaddingMode.None:
                case VCPaddingMode.Custom:
                    return(scalingMode != VCScalingMode.UpscaleFill);;

                default:
                    return(false);
                }
            }).ToProperty(this, x => x.AllowEmptyResolution, out this.allowEmptyResolution);

            // InputPreview
            this.MainViewModel.WhenAnyValue(x => x.SelectedTitle).Select(selectedTitle =>
            {
                var previewLines = new List <SizingPreviewLineViewModel>();
                if (selectedTitle == null)
                {
                    return(previewLines);
                }

                string inputStorageResolutionString = selectedTitle.Geometry.Width + " x " + selectedTitle.Geometry.Height;
                if (selectedTitle.Geometry.PAR.Num == selectedTitle.Geometry.PAR.Den)
                {
                    previewLines.Add(new SizingPreviewLineViewModel(EncodingRes.ResolutionLabel, inputStorageResolutionString));
                }
                else
                {
                    previewLines.Add(new SizingPreviewLineViewModel(EncodingRes.StorageResolutionLabel, inputStorageResolutionString));
                    previewLines.Add(new SizingPreviewLineViewModel(EncodingRes.PixelAspectRatioLabel, CreateParDisplayString(selectedTitle.Geometry.PAR.Num, selectedTitle.Geometry.PAR.Den)));

                    double pixelAspectRatio = ((double)selectedTitle.Geometry.PAR.Num) / selectedTitle.Geometry.PAR.Den;
                    double displayWidth     = selectedTitle.Geometry.Width * pixelAspectRatio;
                    int displayWidthRounded = (int)Math.Round(displayWidth);

                    string displayResolutionString = displayWidthRounded + " x " + selectedTitle.Geometry.Height;

                    previewLines.Add(new SizingPreviewLineViewModel(EncodingRes.DisplayResolutionLabel, displayResolutionString));
                }

                return(previewLines);
            }).ToProperty(this, x => x.InputPreview, out this.inputPreview);

            // OutputPreview
            this.outputSizeService.WhenAnyValue(x => x.Size).Select(size =>
            {
                var previewLines = new List <SizingPreviewLineViewModel>();
                if (size == null)
                {
                    return(previewLines);
                }

                string outputStorageResolutionString = size.OutputWidth + " x " + size.OutputHeight;
                if (size.Par.Num == size.Par.Den)
                {
                    previewLines.Add(new SizingPreviewLineViewModel(EncodingRes.ResolutionLabel, outputStorageResolutionString));
                }
                else
                {
                    previewLines.Add(new SizingPreviewLineViewModel(EncodingRes.StorageResolutionLabel, outputStorageResolutionString));
                    previewLines.Add(new SizingPreviewLineViewModel(EncodingRes.PixelAspectRatioLabel, CreateParDisplayString(size.Par.Num, size.Par.Den)));

                    string displayResolutionString = Math.Round(size.OutputWidth * (((double)size.Par.Num) / size.Par.Den)) + " x " + size.OutputHeight;
                    previewLines.Add(new SizingPreviewLineViewModel(EncodingRes.DisplayResolutionLabel, displayResolutionString));
                }

                return(previewLines);
            }).ToProperty(this, x => x.OutputPreview, out this.outputPreview);

            // PadColorEnabled
            this.WhenAnyValue(x => x.PaddingMode, paddingMode =>
            {
                return(paddingMode != VCPaddingMode.None);
            }).ToProperty(this, x => x.PadColorEnabled, out this.padColorEnabled);

            // CroppingUIEnabled
            this.WhenAnyValue(x => x.CroppingType, croppingType =>
            {
                return(croppingType == VCCroppingType.Custom);
            }).ToProperty(this, x => x.CroppingUIEnabled, out this.croppingUIEnabled);

            // Update the underlying profile when our local Crop properties change. This only applies for
            // CroppingType.Custom
            this.WhenAnyValue(x => x.CropTop)
            .Skip(1)
            .Subscribe(cropTop =>
            {
                this.UpdateProfileProperty(
                    () => this.Profile.Cropping,
                    nameof(this.Profile.Cropping.Top),
                    nameof(this.CropTop),
                    cropTop,
                    raisePropertyChanged: false);
            });
            this.WhenAnyValue(x => x.CropBottom)
            .Skip(1)
            .Subscribe(cropBottom =>
            {
                this.UpdateProfileProperty(
                    () => this.Profile.Cropping,
                    nameof(this.Profile.Cropping.Bottom),
                    nameof(this.CropBottom),
                    cropBottom,
                    raisePropertyChanged: false);
            });
            this.WhenAnyValue(x => x.CropLeft)
            .Skip(1)
            .Subscribe(cropLeft =>
            {
                this.UpdateProfileProperty(
                    () => this.Profile.Cropping,
                    nameof(this.Profile.Cropping.Left),
                    nameof(this.CropLeft),
                    cropLeft,
                    raisePropertyChanged: false);
            });
            this.WhenAnyValue(x => x.CropRight)
            .Skip(1)
            .Subscribe(cropRight =>
            {
                this.UpdateProfileProperty(
                    () => this.Profile.Cropping,
                    nameof(this.Profile.Cropping.Right),
                    nameof(this.CropRight),
                    cropRight,
                    raisePropertyChanged: false);
            });

            // Auto-fill the cropping properties when type is Auto or None
            this.WhenAnyValue(
                x => x.CroppingType,
                x => x.MainViewModel.SelectedTitle,
                (croppingType, selectedTitle) =>
            {
                return(new { croppingType, selectedTitle });
            })
            .Subscribe(x =>
            {
                bool oldAutoValue = this.AutomaticChange;

                if (x.croppingType == VCCroppingType.None)
                {
                    this.AutomaticChange = true;
                    this.CropTop         = 0;
                    this.CropBottom      = 0;
                    this.CropLeft        = 0;
                    this.CropRight       = 0;
                }
                else if (x.croppingType == VCCroppingType.Automatic)
                {
                    this.AutomaticChange = true;

                    if (x.selectedTitle == null)
                    {
                        this.CropTop    = 0;
                        this.CropBottom = 0;
                        this.CropLeft   = 0;
                        this.CropRight  = 0;
                    }
                    else
                    {
                        this.CropTop    = x.selectedTitle.Crop[0];
                        this.CropBottom = x.selectedTitle.Crop[1];
                        this.CropLeft   = x.selectedTitle.Crop[2];
                        this.CropRight  = x.selectedTitle.Crop[3];
                    }
                }

                this.AutomaticChange = oldAutoValue;
            });

            // When the preset changes, update the local crop values for Custom.
            this.PresetsService.WhenAnyValue(x => x.SelectedPreset.Preset.EncodingProfile)
            .Subscribe(_ =>
            {
                if (this.PresetsService.SelectedPreset.Preset.EncodingProfile.CroppingType == VCCroppingType.Custom)
                {
                    bool oldAutoValue    = this.AutomaticChange;
                    this.AutomaticChange = true;
                    var cropping         = this.PresetsService.SelectedPreset.Preset.EncodingProfile.Cropping;
                    this.CropLeft        = cropping.Left;
                    this.CropTop         = cropping.Top;
                    this.CropRight       = cropping.Right;
                    this.CropBottom      = cropping.Bottom;
                    this.AutomaticChange = oldAutoValue;
                }
            });

            // PaddingUIEnabled
            this.WhenAnyValue(x => x.SizingMode, x => x.PaddingMode, (sizingMode, paddingMode) =>
            {
                if (sizingMode == VCSizingMode.Manual)
                {
                    return(true);
                }

                return(paddingMode == VCPaddingMode.Custom);
            }).ToProperty(this, x => x.PaddingUIEnabled, out this.paddingUIEnabled);

            // Update the underlying profile when our local Pad properties change.
            this.WhenAnyValue(x => x.PadTop)
            .Skip(1)
            .Subscribe(padTop =>
            {
                this.UpdateProfileProperty(
                    () => this.Profile.Padding,
                    nameof(this.Profile.Padding.Top),
                    nameof(this.PadTop),
                    padTop,
                    raisePropertyChanged: false);
            });
            this.WhenAnyValue(x => x.PadBottom)
            .Skip(1)
            .Subscribe(padBottom =>
            {
                this.UpdateProfileProperty(
                    () => this.Profile.Padding,
                    nameof(this.Profile.Padding.Bottom),
                    nameof(this.PadBottom),
                    padBottom,
                    raisePropertyChanged: false);
            });
            this.WhenAnyValue(x => x.PadLeft)
            .Skip(1)
            .Subscribe(padLeft =>
            {
                this.UpdateProfileProperty(
                    () => this.Profile.Padding,
                    nameof(this.Profile.Padding.Left),
                    nameof(this.PadLeft),
                    padLeft,
                    raisePropertyChanged: false);
            });
            this.WhenAnyValue(x => x.PadRight)
            .Skip(1)
            .Subscribe(padRight =>
            {
                this.UpdateProfileProperty(
                    () => this.Profile.Padding,
                    nameof(this.Profile.Padding.Right),
                    nameof(this.PadRight),
                    padRight,
                    raisePropertyChanged: false);
            });

            // Auto-fill the padding properties when UI is disabled
            this.WhenAnyValue(
                x => x.SizingMode,
                x => x.ScalingMode,
                x => x.PaddingMode,
                x => x.Width,
                x => x.Height,
                x => x.MainViewModel.SelectedTitle,
                (sizingMode, scalingMode, paddingMode, width, height, selectedTitle) =>
            {
                return(new { sizingMode, scalingMode, paddingMode, width, height, selectedTitle });
            })
            .Subscribe(x =>
            {
                bool oldAutoValue = this.AutomaticChange;

                if (x.sizingMode == VCSizingMode.Automatic && x.paddingMode == VCPaddingMode.None)
                {
                    this.AutomaticChange = true;
                    this.PadTop          = 0;
                    this.PadBottom       = 0;
                    this.PadLeft         = 0;
                    this.PadRight        = 0;
                }
                else if (x.sizingMode == VCSizingMode.Automatic && x.paddingMode != VCPaddingMode.Custom)
                {
                    if (x.selectedTitle == null)
                    {
                        this.PadTop    = 0;
                        this.PadBottom = 0;
                        this.PadLeft   = 0;
                        this.PadRight  = 0;
                    }
                    else
                    {
                        // Calculate the correct padding from input variables
                        OutputSizeInfo outputSize = JsonEncodeFactory.GetOutputSize(this.Profile, x.selectedTitle);
                        this.PadTop    = outputSize.Padding.Top;
                        this.PadBottom = outputSize.Padding.Bottom;
                        this.PadLeft   = outputSize.Padding.Left;
                        this.PadRight  = outputSize.Padding.Right;
                    }
                }

                this.AutomaticChange = oldAutoValue;
            });

            // When the preset changes, update the local pad values.
            this.PresetsService.WhenAnyValue(x => x.SelectedPreset.Preset.EncodingProfile)
            .Subscribe(_ =>
            {
                VCProfile profile = this.PresetsService.SelectedPreset.Preset.EncodingProfile;

                if (profile.SizingMode == VCSizingMode.Manual || profile.PaddingMode == VCPaddingMode.Custom)
                {
                    bool oldAutoValue    = this.AutomaticChange;
                    this.AutomaticChange = true;
                    var padding          = profile.Padding;
                    this.PadLeft         = padding.Left;
                    this.PadTop          = padding.Top;
                    this.PadRight        = padding.Right;
                    this.PadBottom       = padding.Bottom;
                    this.AutomaticChange = oldAutoValue;
                }
            });


            this.AutomaticChange = false;
        }
Example #6
0
        private void RefreshPreviews()
        {
            this.job = this.mainViewModel.EncodeJob;

            OutputSizeInfo newOutputSizeInfo = this.outputSizeService.Size;

            int width     = newOutputSizeInfo.OutputWidth;
            int height    = newOutputSizeInfo.OutputHeight;
            int parWidth  = newOutputSizeInfo.Par.Num;
            int parHeight = newOutputSizeInfo.Par.Den;

            if (parWidth <= 0 || parHeight <= 0)
            {
                this.HasPreview = false;

                StaticResolver.Resolve <IAppLogger>().LogError("HandBrake returned a negative pixel aspect ratio. Cannot show preview.");
                return;
            }

            if (width < 100 || height < 100)
            {
                this.HasPreview = false;

                return;
            }

            this.OutputSizeInfo = newOutputSizeInfo;

            var profile = this.PresetsService.SelectedPreset.Preset.EncodingProfile;

            this.PadColor = ColorUtilities.ToWindowsColor(profile.PadColor);

            // Update the number of previews.
            this.previewCount = this.ScanInstance.PreviewCount;
            foreach (PreviewImageServiceClient client in this.clients.Items)
            {
                if (client.PreviewIndex >= this.previewCount)
                {
                    client.PreviewIndex = this.previewCount - 1;
                }
            }

            this.RaisePropertyChanged(nameof(this.PreviewCount));

            this.HasPreview = true;

            lock (this.imageSync)
            {
                this.previewImageCache = new BitmapSource[this.previewCount];
                updateVersion++;

                // Clear main work queue.
                this.previewImageWorkQueue.Clear();

                // Clear old images out of the file cache.
                this.ClearImageFileCache();

                this.imageFileSync = new List <object>(this.previewCount);
                for (int i = 0; i < this.previewCount; i++)
                {
                    this.imageFileSync.Add(new object());
                }

                this.BeginBackgroundImageLoad();
            }
        }
Example #7
0
        private void RefreshPreviews()
        {
            this.originalScanInstance = this.ScanInstance;
            this.job = this.mainViewModel.EncodeJob;

            OutputSizeInfo newOutputSizeInfo = this.outputSizeService.Size;

            int width     = newOutputSizeInfo.OutputWidth;
            int height    = newOutputSizeInfo.OutputHeight;
            int parWidth  = newOutputSizeInfo.Par.Num;
            int parHeight = newOutputSizeInfo.Par.Den;

            if (parWidth <= 0 || parHeight <= 0)
            {
                this.HasPreview = false;
                this.Title      = PreviewRes.NoVideoSourceTitle;

                Ioc.Get <IAppLogger>().LogError("HandBrake returned a negative pixel aspect ratio. Cannot show preview.");
                return;
            }

            if (width < 100 || height < 100)
            {
                this.HasPreview = false;
                this.UpdateTitle(newOutputSizeInfo);

                return;
            }

            this.PreviewDisplayHeight = height;
            this.PreviewDisplayWidth  = width * ((double)parWidth / parHeight);

            this.OutputSizeInfo = newOutputSizeInfo;

            var profile = this.PresetsService.SelectedPreset.Preset.EncodingProfile;

            this.PadColor = ColorUtilities.ToWindowsColor(profile.PadColor);

            // Update the number of previews.
            this.previewCount = this.ScanInstance.PreviewCount;
            if (this.selectedPreview >= this.previewCount)
            {
                this.selectedPreview = this.previewCount - 1;
                this.RaisePropertyChanged(nameof(this.SelectedPreview));
            }

            this.RaisePropertyChanged(nameof(this.PreviewCount));

            this.HasPreview = true;

            lock (this.imageSync)
            {
                this.previewImageCache = new BitmapSource[this.previewCount];
                updateVersion++;

                // Clear main work queue.
                this.previewImageWorkQueue.Clear();

                this.imageFileCacheFolder = Path.Combine(
                    Utilities.ImageCacheFolder,
                    Process.GetCurrentProcess().Id.ToString(CultureInfo.InvariantCulture),
                    updateVersion.ToString(CultureInfo.InvariantCulture));
                if (!Directory.Exists(this.imageFileCacheFolder))
                {
                    Directory.CreateDirectory(this.imageFileCacheFolder);
                }

                // Clear old images out of the file cache.
                this.ClearImageFileCache();

                this.imageFileSync = new List <object>(this.previewCount);
                for (int i = 0; i < this.previewCount; i++)
                {
                    this.imageFileSync.Add(new object());
                }

                this.BeginBackgroundImageLoad();

                this.View?.RefreshImageSize();
            }

            this.UpdateTitle(newOutputSizeInfo);
        }