Ejemplo n.º 1
0
        public void Fill(BlockCoordinates[] selected)
        {
            _buffer = new List <Block>();

            foreach (BlockCoordinates coordinate in selected)
            {
                if (SourceMask != null)
                {
                    if (!SourceMask.Test(coordinate))
                    {
                        continue;
                    }
                }

                _buffer.Add(_level.GetBlock(coordinate));
                SourceFuncion?.Invoke(coordinate);
            }
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Метод запускает задание сопоставления имен файлов по ключам во входящей папке по заданным правилам
        /// </summary>
        public void Execute()
        {
            _log.Info(string.Format("Запуск задания... Key:  {0}, Source: '{1}', SourceMask: '{2}', Destination: '{3}', CompareMask: {4}', Archive: {5}', DataBinding: '{6}', Overwrite: {7}", Key, Source, SourceMask, Destination, CompareMask, ArchivePath, DataBinding, Overwrite));

            // Проверка на доступность объекта
            if (Enabled)
            {
                #region Инициализация счетчиков

                int _processed = 0;
                int _success   = 0;
                int _errors    = 0;
                int _warnings  = 0;

                #endregion

                // Создание объекта для получения данных из каталога ресурсов
                Debug("Конфигурирование объекта SourceCatalogEntityChecker...");
                var _checker = new SourceCatalogEntityChecker(ConfigurationManager.AppSettings.Get("ECR_Config.Database.Connection.ConnectionString"), DataBinding);

                #region Формирование маски для выборки файлов из папки

                Debug("Определение маски для выборки...");

                var _mask = _sourceMask.Replace("[ext]", "*");
                for (var i = 0; i < __key_tokens.Length; i++)
                {
                    _mask = _mask.Replace(__key_tokens[i], "*");
                }
                _mask = _mask.Replace(__number_token, "*");

                #endregion

                // input

                #region Формирование токена для поиска позиции по ключу

                Debug("Формирование токена для поиска позиции...");

                var _input_key_token = string.Empty;
                for (var i = 0; i < __key_tokens.Length; i++)
                {
                    if (SourceMask.IndexOf(__key_tokens[i]) <= -1)
                    {
                        continue;
                    }
                    _input_key_token = __key_tokens[i];
                    break;
                }

                // Идентифицирующий позицию ключ всегда один, если по факту это не так - генерируем исключение
                if (_input_key_token.Length == 0)
                {
                    throw new Exception("Входящий токен не определен или определен некорректно");
                }

                // number

                // Идентифицирующий номер всегда один, определяем из маски исходного файла
                var _number_token = string.Empty;
                if (SourceMask.IndexOf(__number_token) > -1)
                {
                    _number_token = __number_token;
                }

                #endregion

                // output

                #region Формирование токена ключа для подстановки в output

                Debug("Формирование токена ключа для подстановки в output...");

                var _output_key_token = string.Empty;
                for (var i = 0; i < __key_tokens.Length; i++)
                {
                    if (CompareMask.IndexOf(__key_tokens[i]) > -1)
                    {
                        _output_key_token = __key_tokens[i];
                        break;
                    }
                }
                if (_output_key_token.Length == 0)
                {
                    throw new Exception("Исходящий токен не определен или определен некорректно");
                }

                #endregion

                // Получение списка файлов, находящихся в исходной папке
                Debug("Получение списка исходных файлов...");
                var _files = Directory.GetFiles(Source, _mask);

                if (_files.Length > 0)
                {
                    Debug("Проверка имен файлов...");
                    for (var i = 0; i < _files.Length; i++)
                    {
                        try
                        {
                            Debug(string.Format("Обрабатывается файл: '{0}'...", _files[i]));
                            _processed++;

                            // Замена [ext] и расширения файла в шаблоне названия исходного файла
                            var _pattern = SourceMask.Replace("[ext]", Path.GetExtension(_files[i]).Replace(".", ""));
                            _pattern = _pattern.Replace(Path.GetExtension(_files[i]), "");

                            Debug(string.Format("'{0}': входящий шаблон сконфигурирован", _files[i]));

                            // Получение значений входящих токенов для key и number

                            var _number = string.Empty;
                            if (_number_token.Length > 0)
                            {
                                _number = GetKeyTokenValue(Path.GetFileName(_files[i]), _pattern, _number_token, _input_key_token);
                            }

                            var _input_key = GetKeyTokenValue(Path.GetFileName(_files[i]).Replace("_" + _number, string.Empty).Replace("__", "_"), _pattern, _input_key_token, "_" + _number_token);
                            Debug(string.Format("'{0}': входящий ключ сконфигурирован", _files[i]));

                            if (_number.Length > 0)
                            {
                                while (_number.Substring(0, 1) == "0")
                                {
                                    _number = _number.Substring(1, _number.Length - 1);
                                }
                            }
                            Debug(string.Format("'{0}': input number configured", _files[i]));


                            // Проверяем существование товарной позиции в каталоге
                            Debug(string.Format("Проверка существования элемента... Key type: '{0}', key value: '{1}'", _input_key_token, _input_key));
                            if (!_checker.CheckItemExists(_input_key_token.Replace("[", "").Replace("]", ""), _input_key))
                            {
                                _log.Warn(string.Format("Элемент не задан в исходном каталоге. Key type: '{0}', key value: '{1}', source file: '{2}'", _input_key_token, _input_key, _files[i]));
                                _warnings++;

                                // Если задан путь для разрешения конфликтов - перемещаем файл по заданному пути (overwrite = true)
                                if (ConflictsPath.Length > 0)
                                {
                                    Debug(string.Format("Копирование файла в папку конфликтов: '{0}'", _files[i]));
                                    File.Copy(_files[i], ConflictsPath + Path.GetFileName(_files[i]), true);
                                    Debug(string.Format("'{0}': файл скопирован в папку конфликтов", _files[i]));
                                    Debug(string.Format("Удаление файла: '{0}'", _files[i]));
                                    File.Delete(_files[i]);
                                    Debug(string.Format("'{0}': файл успешно удален", _files[i]));
                                }
                            }
                            else
                            {
                                // Получаем значение ключа по исходному;
                                var _output_key = _checker.CompareKeys(_input_key_token.Replace("[", "").Replace("]", ""),
                                                                       _input_key,
                                                                       _output_key_token.Replace("[", "").Replace("]", ""));

                                Debug(string.Format("'{0}': исходящий ключ сконфигурирован", _files[i]));

                                // Определяем новое имя файла в соответствии с заданной маской
                                var _output_file_name = CompareMask.Replace("[ext]", Path.GetExtension(_files[i]).Replace(".", ""));
                                _output_file_name = _output_file_name.Replace(_output_key_token, _output_key);

                                if ((_number_token.Length > 0) & (CompareMask.IndexOf(_number_token) > -1))
                                {
                                    _output_file_name = _output_file_name.Replace(_number_token, _number);
                                }

                                Debug(string.Format("'{0}': исходящее имя файла определено", _files[i]));

                                // Если параметр Archive задан, то копируем файл в архив;
                                // Параметр OverwriteFiles определяет, нужно ли заменять файл, если он уже существует;
                                // В случае, если файл по каким-либо причинам не скопировался, генерируется наследуемый Exception;
                                // В случае, если файл существует и Overwrite = false генерируется наследуемый Exception;
                                if (ArchivePath.Length > 0)
                                {
                                    Debug(string.Format("КОпирование файла в папку архива: '{0}'", _files[i]));
                                    var _path_archive = ArchivePath + _output_file_name;
                                    File.Copy(_files[i], @_path_archive, Overwrite);
                                    Debug(string.Format("'{0}': файл скопирован в папку архива", _files[i]));
                                }

                                // Копируем файл с новым именем в целевую папку;
                                Debug(string.Format("Копирование файла в исходящую папку: '{0}'", _files[i]));
                                var _path_dest = Destination + _output_file_name;
                                File.Copy(_files[i], @_path_dest, Overwrite);
                                Debug(string.Format("'{0}': файл скопирован в исходящую папку", _files[i]));

                                // Удаляем файл из исходной папки
                                Debug(string.Format("Удаление файла: '{0}'", _files[i]));
                                File.Delete(_files[i]);
                                Debug(string.Format("'{0}': файл удален", _files[i]));

                                _log.Info(string.Format("Файл успешно переименован: '{0}', исходящее имя файла: '{1}'", _files[i], _path_dest));
                                _success++;
                            }
                        }
                        catch (Exception e)
                        {
                            _log.Error(string.Format("Ошибка переименования файла. Файл: '{0}'", _files[i]), e);
                            _errors++;
                        }
                    }
                }

                _log.Info(string.Format("Задание выполнено успешно: {0}. Обработано: {1}, успешно: {2}, с ошибками: {3}, предупреждений: {4}.", Key, _processed, _success, _errors, _warnings));
            }
            else
            {
                // Если объект недоступен, то пишем в лог и выходим
                _log.Warn(string.Format("Задание: {0} заблокировано. Задание неактивно либо доступ запрещен", Key));
            }
        }
Ejemplo n.º 3
0
        protected dynamic RenderFrame(OverlayInfo info)
        {
            var src  = Source.Dynamic();
            var crop = info.GetCrop();
            var over = Overlay.Dynamic();

            if (info.GetCrop() != RectangleF.Empty || info.Width != overSize.Width || info.Height != overSize.Height)
            {
                over = over.Invoke(
                    info.Width > Overlay.GetVideoInfo().width ? Upsize : Downsize,
                    info.Width, info.Height, crop.Left, crop.Top, -crop.Right, -crop.Bottom);
            }
            var overMask = OverlayMask?.Dynamic().BicubicResize(info.Width, info.Height);

            var mergedWidth  = srcSize.Width + Math.Max(-info.X, 0) + Math.Max(info.Width + info.X - srcSize.Width, 0);
            var mergedHeight = srcSize.Height + Math.Max(-info.Y, 0) + Math.Max(info.Height + info.Y - srcSize.Height, 0);
            var mergedAr     = mergedWidth / (double)mergedHeight;
            var outAr        = GetVideoInfo().width / (double)GetVideoInfo().height;
            var wider        = mergedAr > outAr;

            if (Mode == OverlayMode.FitBorders)
            {
                wider = !wider;
            }
            var finalWidth  = wider ? GetVideoInfo().width : (int)Math.Round(GetVideoInfo().width *(mergedAr / outAr));
            var finalHeight = wider ? (int)Math.Round(GetVideoInfo().height *(outAr / mergedAr)) : GetVideoInfo().height;
            var finalX      = wider ? 0 : (GetVideoInfo().width - finalWidth) / 2;
            var finalY      = wider ? (GetVideoInfo().height - finalHeight) / 2 : 0;

            if (ColorAdjust != ColorAdjustMode.None && ColorAdjust != ColorAdjustMode.Average)
            {
                var clip2Adjust = ColorAdjust == ColorAdjustMode.AsOverlay ? src : over;
                var srcTest     = src.Crop(Math.Max(0, info.X), Math.Max(0, info.Y),
                                           -Math.Max(0, srcSize.Width - info.X - info.Width),
                                           -Math.Max(0, srcSize.Height - info.Y - info.Height));
                var overTest = over.Crop(Math.Max(0, -info.X), Math.Max(0, -info.Y),
                                         -Math.Max(0, -(srcSize.Width - info.X - info.Width)),
                                         -Math.Max(0, -(srcSize.Height - info.Y - info.Height)));
                var maskTest = SourceMask?.Dynamic().Crop(Math.Max(0, info.X), Math.Max(0, info.Y),
                                                          -Math.Max(0, srcSize.Width - info.X - info.Width),
                                                          -Math.Max(0, srcSize.Height - info.Y - info.Height));;
                if (overMask != null)
                {
                    maskTest = (maskTest ?? GetBlankClip(Source, true).Dynamic())
                               .Overlay(overMask, info.X, info.Y, mode: "darken")
                               .Crop(Math.Max(0, -info.X), Math.Max(0, -info.Y),
                                     -Math.Max(0, -(srcSize.Width - info.X - info.Width)),
                                     -Math.Max(0, -(srcSize.Height - info.Y - info.Height)));
                }
                if (!GetVideoInfo().IsRGB() && !string.IsNullOrEmpty(Matrix))
                {
                    srcTest     = srcTest.ConvertToRgb24(matrix: Matrix);
                    overTest    = overTest.ConvertToRgb24(matrix: Matrix);
                    maskTest    = maskTest?.ConvertToRgb24(matrix: Matrix);
                    clip2Adjust = clip2Adjust.ConvertToRgb24(matrix: Matrix);
                }
                var sample    = ColorAdjust == ColorAdjustMode.AsOverlay ? srcTest : overTest;
                var reference = ColorAdjust == ColorAdjustMode.AsOverlay ? overTest : srcTest;
                var adjusted  = clip2Adjust.ColorAdjust(sample, reference, maskTest, maskTest, channels: LumaOnly ? "y" : "yuv");
                if (!GetVideoInfo().IsRGB() && !string.IsNullOrEmpty(Matrix))
                {
                    adjusted = adjusted.ConvertToYV24(matrix: Matrix);
                }
                if (ColorAdjust == ColorAdjustMode.AsOverlay)
                {
                    src = adjusted;
                }
                else
                {
                    over = adjusted;
                }
            }

            if (ColorAdjust == ColorAdjustMode.Average)
            {
                var srcTest = src.Crop(Math.Max(0, info.X), Math.Max(0, info.Y),
                                       -Math.Max(0, srcSize.Width - info.X - info.Width),
                                       -Math.Max(0, srcSize.Height - info.Y - info.Height));
                var overTest = over.Crop(Math.Max(0, -info.X), Math.Max(0, -info.Y),
                                         -Math.Max(0, -(srcSize.Width - info.X - info.Width)),
                                         -Math.Max(0, -(srcSize.Height - info.Y - info.Height)));
                src  = src.ColorAdjust(srcTest, overTest).Merge(src, weight: 0.5);
                over = over.Merge(over.ColorAdjust(overTest, srcTest), weight: 0.501);
            }

            dynamic GetOverMask(int length, bool gradientMask, bool noiseMask)
            {
                return(over.OverlayMask(
                           left: info.X > 0 ? length : 0,
                           top: info.Y > 0 ? length : 0,
                           right: srcSize.Width - info.X - info.Width > 0 ? length : 0,
                           bottom: srcSize.Height - info.Y - info.Height > 0 ? length : 0,
                           gradient: gradientMask, noise: noiseMask, seed: DynamicNoise ? info.FrameNumber : 0));
            }

            dynamic GetSourceMask(int length, bool gradientMask, bool noiseMask)
            {
                return(src.OverlayMask(
                           left: info.X < 0 ? length : 0,
                           top: info.Y < 0 ? length : 0,
                           right: srcSize.Width - info.X - info.Width < 0 ? length : 0,
                           bottom: srcSize.Height - info.Y - info.Height < 0 ? length : 0,
                           gradient: gradientMask, noise: noiseMask, seed: DynamicNoise ? info.FrameNumber : 0));
            }

            dynamic GetMask(Func <int, bool, bool, dynamic> func)
            {
                if (Gradient > 0 && Gradient == Noise)
                {
                    return(func(Gradient, true, true));
                }
                dynamic mask = null;

                if (Gradient > 0)
                {
                    mask = func(Gradient, true, false);
                }
                if (Noise > 0)
                {
                    var noiseMask = func(Noise, false, true);
                    mask = mask == null ? noiseMask : mask.Overlay(noiseMask, mode: "darken");
                }
                return(mask);
            }

            dynamic Rotate(dynamic clip, bool invert) => clip == null
                ? null
                : (info.Angle == 0 ? clip : clip.Invoke(this.Rotate, (invert ? -info.Angle : info.Angle) / 100.0));

            switch (Mode)
            {
            case OverlayMode.Fit:
            case OverlayMode.Difference:
            {
                var mode = LumaOnly ? "luma" : "blend";
                if (Mode == OverlayMode.Difference)
                {
                    mode = "difference";
                }
                var mask = GetMask(GetOverMask);
                if (overMask != null && mask != null)
                {
                    mask = mask.Overlay(overMask, mode: "darken");
                }
                if (SourceMask != null && mask != null)
                {
                    mask = mask.Overlay(Rotate(SourceMask.Dynamic().Invert(), true), -info.X, -info.Y, mode: "lighten");
                }
                if (mask == null && info.Angle != 0)
                {
                    mask = ((Clip)GetBlankClip(over, true)).Dynamic();
                }
                var hybrid = Opacity < double.Epsilon ? src : src.Overlay(Rotate(over, false), info.X, info.Y, mask: Rotate(mask, false), opacity: Opacity, mode: mode);
                if (GetVideoInfo().width == srcSize.Width && GetVideoInfo().height == srcSize.Height)
                {
                    return(hybrid);
                }
                return(hybrid.Invoke(Downsize, GetVideoInfo().width, GetVideoInfo().height));
            }

            case OverlayMode.Fill:
            {
                var maskOver = GetMask(GetOverMask);
                var maskSrc  = GetMask(GetSourceMask);
                if (overMask != null && maskOver != null)
                {
                    maskOver = maskOver.Overlay(overMask, mode: "darken");
                }
                if (SourceMask != null && maskOver != null)
                {
                    maskOver = maskOver.Overlay(SourceMask.Dynamic().Invert().Invoke(this.Rotate, -info.Angle / 100.0), -info.X, -info.Y, mode: "lighten");
                }
                dynamic hybrid = src.BlankClip(width: mergedWidth, height: mergedHeight);
                if (Opacity - 1 <= -double.Epsilon)
                {
                    hybrid = hybrid.Overlay(src, Math.Max(0, -info.X), Math.Max(0, -info.Y));
                }
                else
                {
                    maskSrc = null;
                }
                if (maskOver != null || Opacity - 1 < double.Epsilon)
                {
                    hybrid = hybrid.Overlay(over.Invoke(this.Rotate, info.Angle / 100.0), Math.Max(0, info.X), Math.Max(0, info.Y));
                }
                if (maskOver == null && info.Angle != 0)
                {
                    maskOver = GetBlankClip(over, true).Dynamic();
                }
                return(hybrid.Overlay(src, Math.Max(0, -info.X), Math.Max(0, -info.Y), mask: maskSrc)
                       .Overlay(over.Invoke(this.Rotate, info.Angle / 100.0), Math.Max(0, info.X), Math.Max(0, info.Y),
                                opacity: Opacity, mask: maskOver?.Invoke(this.Rotate, info.Angle / 100.0))
                       .Invoke(Downsize, finalWidth, finalHeight)
                       .AddBorders(finalX, finalY, GetVideoInfo().width - finalX - finalWidth, GetVideoInfo().height - finalY - finalHeight));
            }

            case OverlayMode.FillRectangle:
            case OverlayMode.FitBorders:
            {
                var maskOver = GetMask(GetOverMask);
                var maskSrc  = GetMask(GetSourceMask);
                if (overMask != null && maskOver != null)
                {
                    maskOver = maskOver.Overlay(overMask, mode: "darken");
                }
                if (SourceMask != null && maskOver != null)
                {
                    maskOver = maskOver.Overlay(SourceMask.Dynamic().Invert().Invoke(this.Rotate, -info.Angle / 100.0), -info.X, -info.Y, mode: "lighten");
                }
                var background = src.BilinearResize(mergedWidth / 3, mergedHeight / 3).Overlay(over.BilinearResize(mergedWidth / 3, mergedHeight / 3),
                                                                                               opacity: 0.5, mask: overMask?.BilinearResize(mergedWidth / 3, mergedHeight / 3)); //TODO !!!!!!!!!!
                for (var i = 0; i < 15; i++)
                {
                    background = background.Blur(1.5);
                }
                background = background.GaussResize(mergedWidth, mergedHeight, p: 3);
                //var background = src.BlankClip(width: mergedWidth, height: mergedHeight)
                //        .Overlay(src, Math.Max(0, -info.X), Math.Max(0, -info.Y))
                //        .Overlay(over.Invoke(rotateFunc, info.Angle / 100.0), Math.Max(0, info.X), Math.Max(0, info.Y));
                if (Opacity - 1 <= -double.Epsilon)
                {
                    background = background.Overlay(over.Invoke(this.Rotate, info.Angle / 100.0), Math.Max(0, info.X), Math.Max(0, info.Y), mask: maskOver?.Invoke(this.Rotate, info.Angle / 100.0));
                }
                var hybrid = background.Overlay(src, Math.Max(0, -info.X), Math.Max(0, -info.Y), mask: maskSrc)
                             .Overlay(over.Invoke(this.Rotate, info.Angle / 100.0), Math.Max(0, info.X), Math.Max(0, info.Y), mask: maskOver?.Invoke(this.Rotate, info.Angle / 100.0), opacity: Opacity)
                             .Invoke(Downsize, finalWidth, finalHeight);
                if (Mode == OverlayMode.FillRectangle)
                {
                    return(hybrid.AddBorders(finalX, finalY, GetVideoInfo().width - finalX - finalWidth, GetVideoInfo().height - finalY - finalHeight));
                }
                var srcRect        = new Rectangle(0, 0, srcSize.Width, srcSize.Height);
                var overRect       = new Rectangle(info.X, info.Y, info.Width, info.Height);
                var union          = Rectangle.Union(srcRect, overRect);
                var intersect      = Rectangle.Intersect(srcRect, overRect);
                var cropLeft       = intersect.Left - union.Left;
                var cropTop        = intersect.Top - union.Top;
                var cropRight      = union.Right - intersect.Right;
                var cropBottom     = union.Bottom - intersect.Bottom;
                var cropWidthCoef  = cropRight == 0 ? 1 : ((double)cropLeft / cropRight) / ((double)cropLeft / cropRight + 1);
                var cropHeightCoef = cropBottom == 0 ? 1 : ((double)cropTop / cropBottom) / ((double)cropTop / cropBottom + 1);
                cropLeft   = (int)((finalWidth - GetVideoInfo().width) * cropWidthCoef);
                cropTop    = (int)((finalHeight - GetVideoInfo().height) * cropHeightCoef);
                cropRight  = finalWidth - GetVideoInfo().width - cropLeft;
                cropBottom = finalHeight - GetVideoInfo().height - cropTop;
                return(hybrid.Crop(cropLeft, cropTop, -cropRight, -cropBottom));
            }

            case OverlayMode.FillFull:
            {
                finalWidth  = wider ? mergedWidth : (int)Math.Round(mergedHeight * outAr);
                finalHeight = wider ? (int)Math.Round(mergedWidth / outAr) : mergedHeight;
                finalX      = (finalWidth - mergedWidth) / 2;
                finalY      = (finalHeight - mergedHeight) / 2;
                var maskOver = GetMask(GetOverMask);
                var maskSrc  = GetMask(GetSourceMask);
                if (maskSrc != null && maskOver != null)
                {
                    maskOver = maskOver.Overlay(maskSrc.Invert().Invoke(this.Rotate, -info.Angle / 100.0), -info.X, -info.Y, mode: "lighten");
                }
                if (overMask != null && maskOver != null)
                {
                    maskOver = maskOver.Overlay(overMask, mode: "darken");
                }
                if (SourceMask != null && maskOver != null)
                {
                    maskOver = maskOver.Overlay(SourceMask.Dynamic().Invert().Invoke(this.Rotate, -info.Angle / 100.0), -info.X, -info.Y, mode: "lighten");
                }
                var background = over.BilinearResize(finalWidth / 4, finalHeight / 4);
                for (var i = 0; i < 10; i++)
                {
                    background = background.Blur(1.5);
                }
                var hybrid = background.GaussResize(finalWidth, finalHeight, p: 3);
                if (maskOver != null)
                {
                    hybrid = hybrid.Overlay(over.Invoke(this.Rotate, info.Angle / 100.0), finalX + Math.Max(0, info.X), finalY + Math.Max(0, info.Y));
                }
                if (maskOver == null && info.Angle != 0)
                {
                    maskOver = GetBlankClip(over, true).Dynamic();
                }
                return(hybrid.Overlay(src, finalX + Math.Max(0, -info.X), finalY + Math.Max(0, -info.Y))
                       .Overlay(over.Invoke(this.Rotate, info.Angle / 100.0), finalX + Math.Max(0, info.X), finalY + Math.Max(0, info.Y), mask: maskOver?.Invoke(this.Rotate, info.Angle / 100.0))
                       .Invoke(Downsize, GetVideoInfo().width, GetVideoInfo().height));
            }

            case OverlayMode.Mask:
            {
                src = GetBlankClip((Clip)src, true).Dynamic();
                if (SourceMask != null)
                {
                    src = src.Overlay(SourceMask, mode: "darken");
                }
                over = GetBlankClip((Clip)over, true).Dynamic();
                return(src.BlankClip(width: mergedWidth, height: mergedHeight)
                       .Overlay(src, Math.Max(0, -info.X), Math.Max(0, -info.Y))
                       .Overlay(over.Invoke(this.Rotate, info.Angle / 100.0), Math.Max(0, info.X), Math.Max(0, info.Y))
                       .Invoke(Downsize, finalWidth, finalHeight)
                       .AddBorders(finalX, finalY, GetVideoInfo().width - finalX - finalWidth, GetVideoInfo().height - finalY - finalHeight));
            }

            default:
                throw new AvisynthException();
            }
        }