internal AnchorActualInfo GetAnchorActualInfo(int anchorId)
        {
            Template.Anchor a = pageCollection.ActiveTemplate.Anchors.Find(x => x.Id == anchorId);
            if (a == null)
            {
                throw new Exception("Anchor[id=" + anchorId + "] does not exist.");
            }
            if (!a.IsSet())
            {
                throw new Exception("Anchor[id=" + anchorId + "] is not set.");
            }

            StringBuilder sb = new StringBuilder(Serialization.Json.Serialize(a, false));

            for (int?id = a.ParentAnchorId; id != null;)
            {
                Template.Anchor pa = pageCollection.ActiveTemplate.Anchors.Find(x => x.Id == id);
                sb.Append(Serialization.Json.Serialize(pa, false));
                id = pa.ParentAnchorId;
            }
            string sa = sb.ToString();

            if (!anchorHashes2anchorActualInfo.TryGetValue(sa, out AnchorActualInfo anchorActualInfo))
            {
                anchorActualInfo = new AnchorActualInfo(a, this);
                anchorHashes2anchorActualInfo[sa] = anchorActualInfo;
            }
            return(anchorActualInfo);
        }
Exemple #2
0
        void _setAnchorStatus(int anchorId)
        {
            Template.Anchor a = getAnchor(anchorId, out DataGridViewRow row);
            if (a == null || row == null)
            {
                return;
            }

            if (pages == null)
            {
                return;
            }

            pages.ActiveTemplate = getTemplateFromUI(false);
            a = pages.ActiveTemplate.Anchors.FirstOrDefault(x => x.Id == anchorId);
            if (a == null)
            {
                throw new Exception("Anchor[Id=" + a.Id + "] does not exist.");
            }

            bool set = true;

            for (Template.Anchor a_ = a; a_ != null; a_ = pages.ActiveTemplate.Anchors.FirstOrDefault(x => x.Id == a_.ParentAnchorId))
            {
                if (!a_.IsSet())
                {
                    set = false;
                    getAnchor(a_.Id, out DataGridViewRow r_);
                    setRowStatus(statuses.WARNING, r_, "Not set");
                }
            }
            if (!set)
            {
                return;
            }
            Page.AnchorActualInfo aai = pages[currentPageI].GetAnchorActualInfo(a.Id);
            getAnchor(a.Id, out DataGridViewRow r);
            if (!aai.Found)
            {
                setRowStatus(statuses.ERROR, r, "Not found");
            }
            else
            {
                setRowStatus(statuses.SUCCESS, r, "Found");
            }
        }
Exemple #3
0
        //internal AnchorActualInfo GetAnchorActualInfo(int anchorId)
        //{
        //    Template.Anchor a = PageCollection.ActiveTemplate.Anchors.Find(x => x.Id == anchorId);
        //    if (a == null)
        //        throw new Exception("Anchor[id=" + anchorId + "] does not exist.");
        //    if (!a.IsSet())
        //        throw new Exception("Anchor[id=" + anchorId + "] is not set.");

        //    StringBuilder sb = new StringBuilder(Serialization.Json.Serialize(a, false));
        //    for (int? id = a.ParentAnchorId; id != null;)
        //    {
        //        Template.Anchor pa = PageCollection.ActiveTemplate.Anchors.Find(x => x.Id == id);
        //        sb.Append(Serialization.Json.Serialize(pa, false));
        //        id = pa.ParentAnchorId;
        //    }
        //    string sa = sb.ToString();
        //    if (!anchorHashes2anchorActualInfo.TryGetValue(sa, out AnchorActualInfo anchorActualInfo))
        //    {
        //        anchorActualInfo = new AnchorActualInfo(a, this);
        //        anchorHashes2anchorActualInfo[sa] = anchorActualInfo;
        //    }
        //    return anchorActualInfo;
        //}
        //Dictionary<string, AnchorActualInfo> anchorHashes2anchorActualInfo = new Dictionary<string, AnchorActualInfo>();

        internal AnchorActualInfo GetAnchorActualInfo(int anchorId)
        {
            Template.Anchor a = PageCollection.ActiveTemplate.Anchors.Find(x => x.Id == anchorId);
            if (a == null)
            {
                throw new Exception("Anchor[id=" + anchorId + "] does not exist.");
            }
            if (!a.IsSet())
            {
                throw new Exception("Anchor[id=" + anchorId + "] is not set.");
            }

            if (!anchorIds2anchorActualInfo.TryGetValue(a.Id, out AnchorActualInfo anchorActualInfo))
            {
                anchorActualInfo = new AnchorActualInfo(a, this);
                anchorIds2anchorActualInfo[a.Id] = anchorActualInfo;
            }
            return(anchorActualInfo);
        }
        internal Template GetTemplateFromUI(bool saving)
        {
            Template t = new Template();

            if (saving && string.IsNullOrWhiteSpace(name.Text))
            {
                throw new Exception("Name is empty!");
            }

            t.Name = name.Text.Trim();

            t.TextAutoInsertSpace = new TextAutoInsertSpace
            {
                Threshold      = (float)textAutoInsertSpaceThreshold.Value,
                Representative = Regex.Unescape(textAutoInsertSpaceRepresentative.Text),
            };

            t.CvImageScalePyramidStep = (int)CvImageScalePyramidStep.Value;
            t.TesseractPageSegMode    = (Tesseract.PageSegMode)TesseractPageSegMode.SelectedItem;

            if (SingleFieldFromFieldImage.Checked)
            {
                t.FieldOcrMode |= Template.FieldOcrModes.SingleFieldFromFieldImage;
            }
            else
            {
                t.FieldOcrMode &= ~Template.FieldOcrModes.SingleFieldFromFieldImage;
            }
            if (ColumnFieldFromFieldImage.Checked)
            {
                t.FieldOcrMode |= Template.FieldOcrModes.ColumnFieldFromFieldImage;
            }
            else
            {
                t.FieldOcrMode &= ~Template.FieldOcrModes.ColumnFieldFromFieldImage;
            }

            bitmapPreparationForm.SetTemplate(t);

            bool?      removeNotLinkedAnchors = null;
            List <int> conditionAnchorIds     = null;

            if (saving)
            {
                conditionAnchorIds = new List <int>();
                foreach (DataGridViewRow r in conditions.Rows)
                {
                    Template.Condition c = (Template.Condition)r.Tag;
                    if (c != null && c.IsSet())
                    {
                        conditionAnchorIds.AddRange(BooleanEngine.GetAnchorIds(c.Value));
                    }
                }
                conditionAnchorIds = conditionAnchorIds.Distinct().ToList();
            }
            t.Anchors = new List <Template.Anchor>();
            foreach (DataGridViewRow r in anchors.Rows)
            {
                Template.Anchor a = (Template.Anchor)r.Tag;
                if (a == null)
                {
                    continue;
                }

                if (saving)
                {
                    if (!a.IsSet())
                    {
                        throw new Exception("Anchor[Id=" + a.Id + "] is not set!");
                    }

                    if (!conditionAnchorIds.Contains(a.Id))
                    {
                        bool engaged = false;
                        foreach (DataGridViewRow rr in anchors.Rows)
                        {
                            Template.Anchor a_ = (Template.Anchor)rr.Tag;
                            if (a_ == null)
                            {
                                continue;
                            }
                            if (a_.ParentAnchorId == a.Id)
                            {
                                engaged = true;
                                break;
                            }
                        }
                        if (!engaged)
                        {
                            foreach (DataGridViewRow rr in fields.Rows)
                            {
                                Template.Field m = (Template.Field)rr.Tag;
                                if (m != null && (m.LeftAnchor?.Id == a.Id || m.TopAnchor?.Id == a.Id || m.RightAnchor?.Id == a.Id || m.BottomAnchor?.Id == a.Id))
                                {
                                    engaged = true;
                                    break;
                                }
                            }
                            if (!engaged)
                            {
                                if (a.Id != t.ScalingAnchorId)
                                {
                                    if (removeNotLinkedAnchors == null)
                                    {
                                        removeNotLinkedAnchors = Message.YesNo("The template contains not linked anchor[s]. Remove them?");
                                    }
                                    if (removeNotLinkedAnchors == true)
                                    {
                                        continue;
                                    }
                                }
                            }
                        }
                    }
                }
                t.Anchors.Add((Template.Anchor)Serialization.Json.Clone2(a));
            }
            t.Anchors = t.Anchors.OrderBy(a => a.Id).ToList();

            if (saving)
            {
                t.GetScalingAnchor();//check is it is correct;
            }
            t.Conditions = new List <Template.Condition>();
            foreach (DataGridViewRow r in conditions.Rows)
            {
                Template.Condition c = (Template.Condition)r.Tag;
                if (c == null)
                {
                    continue;
                }
                if (saving)
                {
                    if (!c.IsSet())
                    {
                        throw new Exception("Condition[name=" + c.Name + "] is not set!");
                    }
                    BooleanEngine.Check(c.Value, t.Anchors.Select(x => x.Id));
                }
                t.Conditions.Add(Serialization.Json.Clone(c));
            }
            if (saving)
            {
                var dcs = t.Conditions.GroupBy(x => x.Name).Where(x => x.Count() > 1).FirstOrDefault();
                if (dcs != null)
                {
                    throw new Exception("Condition '" + dcs.First().Name + "' is duplicated!");
                }
            }

            t.Fields = new List <Template.Field>();
            foreach (DataGridViewRow r in fields.Rows)
            {
                Template.Field f = (Template.Field)r.Tag;
                if (f == null)
                {
                    continue;
                }
                if (saving && !f.IsSet())
                {
                    throw new Exception("Field[" + r.Index + "] is not set!");
                }
                if (saving)
                {
                    foreach (int?ai in new List <int?> {
                        f.LeftAnchor?.Id, f.TopAnchor?.Id, f.RightAnchor?.Id, f.BottomAnchor?.Id
                    })
                    {
                        if (ai != null && t.Anchors.FirstOrDefault(x => x.Id == ai) == null)
                        {
                            throw new Exception("Anchor[Id=" + ai + " does not exist.");
                        }
                    }
                }
                t.Fields.Add(Serialization.Json.Clone(f));
            }
            if (saving)
            {
                if (t.Fields.Count < 1)
                {
                    throw new Exception("Fields is empty!");
                }
                //var dfs = t.Fields.GroupBy(x => x.Name).Where(x => x.Count() > 1).FirstOrDefault();
                //if (dfs != null)
                //    throw new Exception("Field '" + dfs.First().Name + "' is duplicated!");

                //foreach (string columnOfTable in t.Fields.Where(x => x is Template.Field.PdfText).Select(x => (Template.Field.PdfText)x).Where(x => x.ColumnOfTable != null).Select(x => x.ColumnOfTable))
                //{
                //    Dictionary<string, List<Template.Field>> fieldName2orderedFields = new Dictionary<string, List<Template.Field>>();
                //    foreach (Template.Field.PdfText pt in t.Fields.Where(x => x is Template.Field.PdfText).Select(x => (Template.Field.PdfText)x).Where(x => x.ColumnOfTable == columnOfTable))
                //    {
                //        List<Template.Field> fs;
                //        if (!fieldName2orderedFields.TryGetValue(pt.Name, out fs))
                //        {
                //            fs = new List<Template.Field>();
                //            fieldName2orderedFields[pt.Name] = fs;
                //        }
                //        fs.Add(pt);
                //    }
                //    int definitionCount = fieldName2orderedFields.Max(x => x.Value.Count());
                //    foreach (string fn in fieldName2orderedFields.Keys)
                //        if (definitionCount > fieldName2orderedFields[fn].Count)
                //            throw new Exception("Field '" + fn + "' is column of table " + columnOfTable + " and so it must have the same number of definitions as the rest column fields!");
                //}

                //foreach (Template.Field f0 in t.Fields)
                //{
                //    int tableDefinitionsCount = t.Fields.Where(x => x.Name == f0.Name).Count();
                //    string fn = t.Fields.Where(x => x.ColumnOfTable == f0.Name).GroupBy(x => x.Name).Where(x => x.Count() > tableDefinitionsCount).FirstOrDefault()?.First().Name;
                //    if (fn != null)
                //        throw new Exception("Field '" + fn + "' is a column of table field " + f0.Name + " so " + f0.Name + " must have number of definitions not less then that of " + fn + ".");
                //}

                //it is done only to avoid unneeded OCR
                //string fn = t.Fields.Where(x => x.ColumnOfTable != null && (x.DefaultValueType != Template.Field.ValueTypes.PdfText && x.DefaultValueType != Template.Field.ValueTypes.PdfTextLines)).FirstOrDefault()?.Name;
                //if (fn != null)
                //    throw new Exception("Field '" + fn + "' is a column of a table field. Its default value type can be either " + Template.Field.ValueTypes.PdfText + " or " + Template.Field.ValueTypes.PdfTextLines);
            }

            if (saving)
            {
                t.Editor = new Template.EditorSettings
                {
                    TestFile         = testFile.Text,
                    TestPictureScale = pictureScale.Value,
                    ExtractFieldsAutomaticallyWhenPageChanged = ExtractFieldsAutomaticallyWhenPageChanged.Checked,
                    ShowFieldTextLineSeparators = ShowFieldTextLineSeparators.Checked,
                    CheckConditionsAutomaticallyWhenPageChanged = CheckConditionsAutomaticallyWhenPageChanged.Checked,
                };
            }

            return(t);
        }
Exemple #5
0
        bool findAndDrawAnchor(int anchorId)
        {
            if (pages == null)
            {
                return(false);
            }

            pages.ActiveTemplate = getTemplateFromUI(false);
            Template.Anchor a = pages.ActiveTemplate.Anchors.FirstOrDefault(x => x.Id == anchorId);
            if (a == null)
            {
                throw new Exception("Anchor[Id=" + a.Id + "] does not exist.");
            }

            bool set = true;

            for (Template.Anchor a_ = a; a_ != null; a_ = pages.ActiveTemplate.Anchors.FirstOrDefault(x => x.Id == a_.ParentAnchorId))
            {
                if (a != a_)
                {
                    showAnchorRowAs(a_.Id, rowStates.Parent, false);
                }
                if (!a_.IsSet())
                {
                    set = false;
                    getAnchor(a_.Id, out DataGridViewRow r_);
                    setRowStatus(statuses.WARNING, r_, "Not set");
                }
            }
            if (!set)
            {
                return(false);
            }
            getAnchor(a.Id, out DataGridViewRow r);
            if (!pages[currentPageI].GetAnchorActualInfo(a.Id).Found)
            {
                setRowStatus(statuses.ERROR, r, "Not found");
                return(false);
            }
            setRowStatus(statuses.SUCCESS, r, "Found");

            for (Template.Anchor a_ = a; a_ != null; a_ = pages.ActiveTemplate.Anchors.FirstOrDefault(x => x.Id == a_.ParentAnchorId))
            {
                SizeF      shift = pages[currentPageI].GetAnchorActualInfo(a_.Id).Shift;
                RectangleF r_    = a_.Rectangle();
                r_.X += shift.Width;
                r_.Y += shift.Height;
                if (a_ == a)
                {
                    if (currentAnchorControl != null)
                    {
                        drawBoxes(Settings.Appearance.SelectionBoxColor, Settings.Appearance.SelectionBoxBorderWidth, new List <RectangleF> {
                            r_
                        });
                        owners2resizebleBox[a_] = new ResizebleBox(a_, r_, Settings.Appearance.SelectionBoxBorderWidth);
                    }
                    else
                    {
                        drawBoxes(Settings.Appearance.AnchorBoxColor, Settings.Appearance.AnchorBoxBorderWidth, new List <RectangleF> {
                            r_
                        });
                    }
                }
                else
                {
                    drawBoxes(Settings.Appearance.AscendantAnchorBoxColor, Settings.Appearance.AscendantAnchorBoxBorderWidth, new List <RectangleF> {
                        r_
                    });
                }

                List <RectangleF> bs = null;
                switch (a_.Type)
                {
                case Template.Anchor.Types.PdfText:
                {
                    var pt = (Template.Anchor.PdfText)a_;
                    bs = pt.CharBoxs.Select(x => new RectangleF(x.Rectangle.X + shift.Width, x.Rectangle.Y + shift.Height, x.Rectangle.Width, x.Rectangle.Height)).ToList();
                }
                break;

                case Template.Anchor.Types.OcrText:
                {
                    var ot = (Template.Anchor.OcrText)a_;
                    bs = ot.CharBoxs.Select(x => new RectangleF(x.Rectangle.X + shift.Width, x.Rectangle.Y + shift.Height, x.Rectangle.Width, x.Rectangle.Height)).ToList();
                }
                break;

                case Template.Anchor.Types.ImageData:
                    //bs = new List<System.Drawing.RectangleF> { rs[0] };
                    break;

                case Template.Anchor.Types.CvImage:
                    //bs = new List<System.Drawing.RectangleF> { rs[0] };
                    break;

                default:
                    throw new Exception("Unknown option: " + a_.Type);
                }
                if (bs != null)
                {
                    if (a_ == a)
                    {
                        drawBoxes(Settings.Appearance.AnchorBoxColor, Settings.Appearance.AnchorBoxBorderWidth, bs);
                    }
                    else
                    {
                        drawBoxes(Settings.Appearance.AscendantAnchorBoxColor, Settings.Appearance.AscendantAnchorBoxBorderWidth, bs);
                    }
                }
            }
            return(true);
        }
        bool _findAnchor(Template.Anchor a, PointF parentAnchorPoint0, Func <PointF, bool> proceedOnFound)
        {
            if (!a.IsSet())
            {
                return(false);
            }
            RectangleF rectangle = a.Rectangle();
            RectangleF searchRectangle;

            {
                if (a.ParentAnchorId != null)
                {
                    RectangleF pameir = pageCollection.ActiveTemplate.Anchors.Find(x => x.Id == a.ParentAnchorId).Rectangle();
                    rectangle.X += parentAnchorPoint0.X - pameir.X;
                    rectangle.Y += parentAnchorPoint0.Y - pameir.Y;
                }
                if (a.SearchRectangleMargin >= 0)
                {
                    searchRectangle = getSearchRectangle(rectangle, a.SearchRectangleMargin);
                }
                else
                {
                    searchRectangle = new RectangleF();//not used, just stub to compile
                }
            }

            switch (a.Type)
            {
            case Template.Anchor.Types.PdfText:
            {
                Template.Anchor.PdfText pt = (Template.Anchor.PdfText)a;
                List <Template.Anchor.PdfText.CharBox> cbs = pt.CharBoxs;
                if (pt.IgnoreInvisibleChars)
                {
                    cbs = cbs.Where(x => !Pdf.InvisibleCharacters.Contains(x.Char)).ToList();
                }
                if (cbs.Count < 1)
                {
                    int w = (int)(Bitmap.Width * Settings.Constants.Image2PdfResolutionRatio - rectangle.Width);
                    int h = (int)(Bitmap.Height * Settings.Constants.Image2PdfResolutionRatio - rectangle.Height);
                    for (int i = 0; i < w; i++)
                    {
                        for (int j = 0; j < h; j++)
                        {
                            RectangleF actualR = new RectangleF(i, j, rectangle.Width, rectangle.Height);
                            if (PdfCharBoxs.FirstOrDefault(x => actualR.Contains(x.R) && (!pt.IgnoreInvisibleChars || !Pdf.InvisibleCharacters.Contains(x.Char))) == null &&
                                !proceedOnFound(actualR.Location)
                                )
                            {
                                return(true);
                            }
                        }
                    }
                    return(false);
                }
                IEnumerable <Pdf.CharBox> tcb0s;
                if (pt.SearchRectangleMargin < 0)
                {
                    tcb0s = PdfCharBoxs.Where(x => x.Char == cbs[0].Char);
                }
                else
                {
                    tcb0s = PdfCharBoxs.Where(x => x.Char == cbs[0].Char && searchRectangle.Contains(x.R));
                }
                List <Pdf.CharBox> tcbs = new List <Pdf.CharBox>();
                foreach (Pdf.CharBox tcb0 in tcb0s)
                {
                    tcbs.Clear();
                    tcbs.Add(tcb0);
                    for (int i = 1; i < cbs.Count; i++)
                    {
                        PointF p;
                        if (pt.PositionDeviationIsAbsolute)
                        {
                            p = new PointF(tcb0.R.X + cbs[i].Rectangle.X - cbs[0].Rectangle.X, tcb0.R.Y + cbs[i].Rectangle.Y - cbs[0].Rectangle.Y);
                        }
                        else
                        {
                            p = new PointF(tcbs[i - 1].R.X + cbs[i].Rectangle.X - cbs[i - 1].Rectangle.X, tcbs[i - 1].R.Y + cbs[i].Rectangle.Y - cbs[i - 1].Rectangle.Y);
                        }
                        foreach (Pdf.CharBox bt in PdfCharBoxs.Where(x => x.Char == cbs[i].Char))
                        {
                            if (Math.Abs(bt.R.X - p.X) <= pt.PositionDeviation && Math.Abs(bt.R.Y - p.Y) <= pt.PositionDeviation)
                            {
                                tcbs.Add(bt);
                                break;
                            }
                        }
                        if (tcbs.Count - 1 < i)
                        {
                            break;
                        }
                    }
                    if (tcbs.Count == cbs.Count)
                    {
                        SizeF      shift   = new SizeF(tcbs[0].R.X - cbs[0].Rectangle.X, tcbs[0].R.Y - cbs[0].Rectangle.Y);
                        RectangleF actualR = new RectangleF(rectangle.X + shift.Width, rectangle.Y + shift.Height, rectangle.Width, rectangle.Height);
                        if (PdfCharBoxs.FirstOrDefault(x => actualR.Contains(x.R) && !tcbs.Contains(x) && (!pt.IgnoreInvisibleChars || !Pdf.InvisibleCharacters.Contains(x.Char))) == null &&
                            !proceedOnFound(actualR.Location)
                            )
                        {
                            return(true);
                        }
                    }
                }
            }
                return(false);

            case Template.Anchor.Types.OcrText:
            {
                Template.Anchor.OcrText ot = (Template.Anchor.OcrText)a;
                List <Template.Anchor.OcrText.CharBox> cbs = ot.CharBoxs;
                if (cbs.Count < 1)
                {
                    int w = (int)(ActiveTemplateBitmap.Width * Settings.Constants.Image2PdfResolutionRatio - rectangle.Width);
                    int h = (int)(ActiveTemplateBitmap.Height * Settings.Constants.Image2PdfResolutionRatio - rectangle.Height);
                    for (int i = 0; i < w; i++)
                    {
                        for (int j = 0; j < h; j++)
                        {
                            RectangleF actualR = new RectangleF(i, j, rectangle.Width, rectangle.Height);
                            if (ActiveTemplateOcrCharBoxs.FirstOrDefault(x => actualR.Contains(x.R)) == null &&
                                !proceedOnFound(actualR.Location)
                                )
                            {
                                return(true);
                            }
                        }
                    }
                    return(false);
                }
                List <Ocr.CharBox>        contaningOcrCharBoxs;
                PointF                    searchRectanglePosition = new PointF(0, 0);
                IEnumerable <Ocr.CharBox> tcb0s;
                if (ot.OcrEntirePage)
                {
                    contaningOcrCharBoxs = ActiveTemplateOcrCharBoxs;
                    if (ot.SearchRectangleMargin < 0)
                    {
                        tcb0s = contaningOcrCharBoxs.Where(x => x.Char == cbs[0].Char);
                    }
                    else
                    {
                        tcb0s = contaningOcrCharBoxs.Where(x => x.Char == cbs[0].Char && searchRectangle.Contains(x.R));
                    }
                }
                else if (ot.SearchRectangleMargin < 0)
                {
                    contaningOcrCharBoxs = ActiveTemplateOcrCharBoxs;
                    tcb0s = contaningOcrCharBoxs.Where(x => x.Char == cbs[0].Char);
                }
                else
                {
                    RectangleF contaningRectangle = searchRectangle;
                    for (int i = 1; i < ot.CharBoxs.Count; i++)
                    {
                        contaningRectangle = RectangleF.Union(contaningRectangle, getSearchRectangle(ot.CharBoxs[i].Rectangle.GetSystemRectangleF(), a.SearchRectangleMargin));
                    }
                    contaningOcrCharBoxs    = Ocr.This.GetCharBoxs(GetRectangleFromActiveTemplateBitmap(contaningRectangle.X / Settings.Constants.Image2PdfResolutionRatio, contaningRectangle.Y / Settings.Constants.Image2PdfResolutionRatio, contaningRectangle.Width / Settings.Constants.Image2PdfResolutionRatio, contaningRectangle.Height / Settings.Constants.Image2PdfResolutionRatio));
                    searchRectanglePosition = new PointF(contaningRectangle.X < 0 ? 0 : contaningRectangle.X, contaningRectangle.Y < 0 ? 0 : contaningRectangle.Y);
                    RectangleF unshiftedMainElementSearchRectangle = new RectangleF(searchRectangle.X - searchRectanglePosition.X, searchRectangle.Y - searchRectanglePosition.Y, searchRectangle.Width, searchRectangle.Height);
                    tcb0s = contaningOcrCharBoxs.Where(x => x.Char == cbs[0].Char && unshiftedMainElementSearchRectangle.Contains(x.R));
                }
                List <Ocr.CharBox> tcbs = new List <Ocr.CharBox>();
                foreach (Ocr.CharBox tcb0 in tcb0s)
                {
                    tcbs.Clear();
                    tcbs.Add(tcb0);
                    for (int i = 1; i < cbs.Count; i++)
                    {
                        PointF p;
                        if (ot.PositionDeviationIsAbsolute)
                        {
                            p = new PointF(tcb0.R.X + cbs[i].Rectangle.X - cbs[0].Rectangle.X, tcb0.R.Y + cbs[i].Rectangle.Y - cbs[0].Rectangle.Y);
                        }
                        else
                        {
                            p = new PointF(tcbs[i - 1].R.X + cbs[i].Rectangle.X - cbs[i - 1].Rectangle.X, tcbs[i - 1].R.Y + cbs[i].Rectangle.Y - cbs[i - 1].Rectangle.Y);
                        }
                        foreach (Ocr.CharBox bt in contaningOcrCharBoxs.Where(x => x.Char == cbs[i].Char))
                        {
                            if (Math.Abs(bt.R.X - p.X) <= ot.PositionDeviation && Math.Abs(bt.R.Y - p.Y) <= ot.PositionDeviation)
                            {
                                tcbs.Add(bt);
                                break;
                            }
                        }
                        if (tcbs.Count - 1 < i)
                        {
                            break;
                        }
                    }
                    if (tcbs.Count == cbs.Count)
                    {
                        SizeF      shift   = new SizeF(tcbs[0].R.X - cbs[0].Rectangle.X, tcbs[0].R.Y - cbs[0].Rectangle.Y);
                        RectangleF actualR = new RectangleF(rectangle.X + shift.Width, rectangle.Y + shift.Height, rectangle.Width, rectangle.Height);
                        if (contaningOcrCharBoxs.FirstOrDefault(x => actualR.Contains(x.R) && !tcbs.Contains(x)) == null &&
                            !proceedOnFound(actualR.Location)
                            )
                        {
                            return(true);
                        }
                    }
                }
            }
                return(false);

            case Template.Anchor.Types.ImageData:
            {
                Template.Anchor.ImageData idv = (Template.Anchor.ImageData)a;
                Point     searchRectanglePosition;
                ImageData id0;
                if (idv.SearchRectangleMargin < 0)
                {
                    id0 = ActiveTemplateImageData;
                    searchRectanglePosition = new Point(0, 0);
                }
                else
                {
                    searchRectanglePosition = new Point(searchRectangle.X < 0 ? 0 : (int)searchRectangle.X, searchRectangle.Y < 0 ? 0 : (int)searchRectangle.Y);
                    id0 = new ImageData(GetRectangleFromActiveTemplateBitmap(searchRectangle.X / Settings.Constants.Image2PdfResolutionRatio, searchRectangle.Y / Settings.Constants.Image2PdfResolutionRatio, searchRectangle.Width / Settings.Constants.Image2PdfResolutionRatio, searchRectangle.Height / Settings.Constants.Image2PdfResolutionRatio));
                }
                Point?p_ = idv.Image.FindWithinImage(id0, idv.BrightnessTolerance, idv.DifferentPixelNumberTolerance, idv.FindBestImageMatch);
                if (p_ == null)
                {
                    return(false);
                }
                Point p = (Point)p_;
                return(!proceedOnFound(new PointF(searchRectanglePosition.X + p.X, searchRectanglePosition.Y + p.Y)));
            }

            default:
                throw new Exception("Unknown option: " + a.Type);
            }
        }
        internal Template GetTemplateFromUI(bool saving)
        {
            Template t = new Template();

            if (saving && string.IsNullOrWhiteSpace(name.Text))
            {
                throw new Exception("Name is empty!");
            }

            t.Name = name.Text.Trim();

            t.TextAutoInsertSpace = new TextAutoInsertSpace
            {
                Threshold          = (float)textAutoInsertSpace_Threshold.Value,
                IgnoreSourceSpaces = textAutoInsertSpace_IgnoreSourceSpaces.Checked,
                //Representative//default
            };

            t.TesseractPageSegMode      = (Tesseract.PageSegMode)TesseractPageSegMode.SelectedItem;
            t.AdjustLineBorders         = AdjustLineBorders.Checked;
            t.SingleFieldFromFieldImage = SingleFieldFromFieldImage.Checked;
            t.ColumnCellFromCellImage   = ColumnCellFromCellImage.Checked;
            if (CharSizeFilterMinWidth.Value > 0 || CharSizeFilterMaxWidth.Value > 0 || CharSizeFilterMinHeight.Value > 0 || CharSizeFilterMaxHeight.Value > 0)
            {
                t.CharFilter = new CharFilter {
                    MinWidth = (float)CharSizeFilterMinWidth.Value, MaxWidth = (float)CharSizeFilterMaxWidth.Value, MinHeight = (float)CharSizeFilterMinHeight.Value, MaxHeight = (float)CharSizeFilterMaxHeight.Value
                }
            }
            ;
            if (LinePaddingY.Value > 0)
            {
                t.LinePaddingY = (int)LinePaddingY.Value;
            }

            bitmapPreparationForm.SetTemplate(t);

            bool?      removeNotLinkedAnchors = null;
            List <int> conditionAnchorIds     = null;

            if (saving)
            {
                conditionAnchorIds = new List <int>();
                foreach (DataGridViewRow r in conditions.Rows)
                {
                    Template.Condition c = (Template.Condition)r.Tag;
                    if (c != null && c.IsSet())
                    {
                        conditionAnchorIds.AddRange(BooleanEngine.GetAnchorIds(c.Value));
                    }
                }
                conditionAnchorIds = conditionAnchorIds.Distinct().ToList();
            }
            t.Anchors = new List <Template.Anchor>();
            foreach (DataGridViewRow r in anchors.Rows)
            {
                Template.Anchor a = (Template.Anchor)r.Tag;
                if (a == null)
                {
                    continue;
                }

                if (saving)
                {
                    if (!a.IsSet())
                    {
                        throw new Exception("Anchor[Id=" + a.Id + "] is not set!");
                    }

                    if (!conditionAnchorIds.Contains(a.Id))
                    {
                        bool engaged = false;
                        foreach (DataGridViewRow rr in anchors.Rows)
                        {
                            Template.Anchor a_ = (Template.Anchor)rr.Tag;
                            if (a_ == null)
                            {
                                continue;
                            }
                            if (a_.ParentAnchorId == a.Id)
                            {
                                engaged = true;
                                break;
                            }
                        }
                        if (!engaged)
                        {
                            foreach (DataGridViewRow rr in fields.Rows)
                            {
                                Template.Field m = (Template.Field)rr.Tag;
                                if (m != null && (m.LeftAnchor?.Id == a.Id || m.TopAnchor?.Id == a.Id || m.RightAnchor?.Id == a.Id || m.BottomAnchor?.Id == a.Id))
                                {
                                    engaged = true;
                                    break;
                                }
                            }
                            if (!engaged)
                            {
                                if (a.Id != t.ScalingAnchorId)
                                {
                                    if (removeNotLinkedAnchors == null)
                                    {
                                        removeNotLinkedAnchors = Message.YesNo("The template contains not linked anchor[s]. Remove them?", this);
                                    }
                                    if (removeNotLinkedAnchors == true)
                                    {
                                        continue;
                                    }
                                }
                            }
                        }
                    }
                }
                t.Anchors.Add((Template.Anchor)Serialization.Json.Clone2(a));
            }
            t.Anchors = t.Anchors.OrderBy(a => a.Id).ToList();

            if (saving)
            {
                t.GetScalingAnchor();//check is it is correct;
            }
            t.Conditions = new List <Template.Condition>();
            foreach (DataGridViewRow r in conditions.Rows)
            {
                Template.Condition c = (Template.Condition)r.Tag;
                if (c == null)
                {
                    continue;
                }
                if (saving)
                {
                    if (!c.IsSet())
                    {
                        throw new Exception("Condition[name=" + c.Name + "] is not set!");
                    }
                    BooleanEngine.Check(c.Value, t.Anchors.Select(x => x.Id));
                }
                t.Conditions.Add((Template.Condition)Serialization.Json.Clone2(c));
            }
            if (saving)
            {
                var dcs = t.Conditions.GroupBy(x => x.Name).Where(x => x.Count() > 1).FirstOrDefault();
                if (dcs != null)
                {
                    throw new Exception("Condition '" + dcs.First().Name + "' is duplicated!");
                }
            }

            t.Fields = new List <Template.Field>();
            foreach (DataGridViewRow r in fields.Rows)
            {
                Template.Field f = (Template.Field)r.Tag;
                if (f == null)
                {
                    continue;
                }
                if (saving && !f.IsSet())
                {
                    throw new Exception("Field[" + r.Index + "] is not set!");
                }
                if (saving)
                {
                    foreach (int?ai in new List <int?> {
                        f.LeftAnchor?.Id, f.TopAnchor?.Id, f.RightAnchor?.Id, f.BottomAnchor?.Id
                    })
                    {
                        if (ai != null && t.Anchors.FirstOrDefault(x => x.Id == ai) == null)
                        {
                            throw new Exception("Anchor[Id=" + ai + " does not exist.");
                        }
                    }
                }
                t.Fields.Add((Template.Field)Serialization.Json.Clone2(f));
            }
            if (saving)
            {
                if (t.Fields.Count < 1)
                {
                    throw new Exception("Fields is empty!");
                }

                var fs = t.Fields.GroupBy(x => x.Name).Where(x => x.GroupBy(a => a.GetType()).Count() > 1).FirstOrDefault();
                if (fs != null)
                {
                    throw new Exception("Definitions of the field '" + fs.First().Name + "' are not of the same type!");
                }
            }

            if (saving)
            {
                t.Editor = new Template.EditorSettings
                {
                    //TestFile = testFile.Text,
                    TestPictureScale = pictureScale.Value,
                    ExtractFieldsAutomaticallyWhenPageChanged = ExtractFieldsAutomaticallyWhenPageChanged.Checked,
                    ShowFieldTextLineSeparators = ShowFieldTextLineSeparators.Checked,
                    CheckConditionsAutomaticallyWhenPageChanged = CheckConditionsAutomaticallyWhenPageChanged.Checked,
                };
            }

            return(t);
        }
    }
        Template getTemplateFromUI(bool saving)
        {
            Template t = new Template();

            if (saving && string.IsNullOrWhiteSpace(name.Text))
            {
                throw new Exception("Name is empty!");
            }

            t.Name = name.Text.Trim();

            t.TextAutoInsertSpace = new TextAutoInsertSpace
            {
                Threshold      = (float)textAutoInsertSpaceThreshold.Value,
                Representative = textAutoInsertSpaceRepresentative.Text,
            };

            t.PageRotation        = (Template.PageRotations)pageRotation.SelectedIndex;
            t.AutoDeskew          = autoDeskew.Checked;
            t.AutoDeskewThreshold = (int)autoDeskewThreshold.Value;

            bool?removeNotLinkedAnchors = null;

            t.Anchors = new List <Template.Anchor>();
            List <int> conditionAnchorIds = null;

            if (saving)
            {
                conditionAnchorIds = new List <int>();
                foreach (DataGridViewRow r in conditions.Rows)
                {
                    Template.Condition c = (Template.Condition)r.Tag;
                    if (c != null && c.IsSet())
                    {
                        conditionAnchorIds.AddRange(BooleanEngine.GetAnchorIds(c.Value));
                    }
                }
                conditionAnchorIds = conditionAnchorIds.Distinct().ToList();
            }
            foreach (DataGridViewRow r in anchors.Rows)
            {
                Template.Anchor a = (Template.Anchor)r.Tag;
                if (a == null)
                {
                    continue;
                }

                if (saving)
                {
                    if (!a.IsSet())
                    {
                        throw new Exception("Anchor[Id=" + a.Id + "] is not set!");
                    }

                    bool engaged = false;
                    if (conditionAnchorIds.Contains(a.Id))
                    {
                        engaged = true;
                    }
                    if (!engaged)
                    {
                        foreach (DataGridViewRow rr in anchors.Rows)
                        {
                            Template.Anchor a_ = (Template.Anchor)rr.Tag;
                            if (a_ == null)
                            {
                                continue;
                            }
                            if (a_.ParentAnchorId == a.Id)
                            {
                                engaged = true;
                                break;
                            }
                        }
                    }
                    if (!engaged)
                    {
                        foreach (DataGridViewRow rr in fields.Rows)
                        {
                            Template.Field m = (Template.Field)rr.Tag;
                            if (m != null && (m.LeftAnchor?.Id == a.Id || m.TopAnchor?.Id == a.Id || m.RightAnchor?.Id == a.Id || m.BottomAnchor?.Id == a.Id))
                            {
                                engaged = true;
                                break;
                            }
                        }
                    }
                    if (!engaged)
                    {
                        if (removeNotLinkedAnchors == null)
                        {
                            removeNotLinkedAnchors = Message.YesNo("The template contains not linked anchor[s]. Should they be removed?");
                        }
                        if (removeNotLinkedAnchors == true)
                        {
                            continue;
                        }
                    }
                }

                t.Anchors.Add(a);
            }
            t.Anchors = t.Anchors.OrderBy(a => a.Id).ToList();

            t.Conditions = new List <Template.Condition>();
            foreach (DataGridViewRow r in conditions.Rows)
            {
                Template.Condition c = (Template.Condition)r.Tag;
                if (c == null)
                {
                    continue;
                }
                if (saving)
                {
                    if (!c.IsSet())
                    {
                        throw new Exception("Condition[name=" + c.Name + "] is not set!");
                    }
                    BooleanEngine.Check(c.Value, t.Anchors.Select(x => x.Id));
                }
                t.Conditions.Add(c);
            }
            if (saving)
            {
                var dcs = t.Conditions.GroupBy(x => x.Name).Where(x => x.Count() > 1).FirstOrDefault();
                if (dcs != null)
                {
                    throw new Exception("Condition '" + dcs.First().Name + "' is duplicated!");
                }
            }

            t.Fields = new List <Template.Field>();
            foreach (DataGridViewRow r in fields.Rows)
            {
                Template.Field f = (Template.Field)r.Tag;
                if (f == null)
                {
                    continue;
                }
                if (saving && !f.IsSet())
                {
                    throw new Exception("Field[" + r.Index + "] is not set!");
                }
                if (saving)
                {
                    foreach (int?ai in new List <int?> {
                        f.LeftAnchor?.Id, f.TopAnchor?.Id, f.RightAnchor?.Id, f.BottomAnchor?.Id
                    })
                    {
                        if (ai != null && t.Anchors.FirstOrDefault(x => x.Id == ai) == null)
                        {
                            throw new Exception("Anchor[Id=" + ai + " does not exist.");
                        }
                    }
                }
                t.Fields.Add(f);
            }
            if (saving)
            {
                if (t.Fields.Count < 1)
                {
                    throw new Exception("Fields is empty!");
                }
                //var dfs = t.Fields.GroupBy(x => x.Name).Where(x => x.Count() > 1).FirstOrDefault();
                //if (dfs != null)
                //    throw new Exception("Field '" + dfs.First().Name + "' is duplicated!");

                //foreach (string columnOfTable in t.Fields.Where(x => x is Template.Field.PdfText).Select(x => (Template.Field.PdfText)x).Where(x => x.ColumnOfTable != null).Select(x => x.ColumnOfTable))
                //{
                //    Dictionary<string, List<Template.Field>> fieldName2orderedFields = new Dictionary<string, List<Template.Field>>();
                //    foreach (Template.Field.PdfText pt in t.Fields.Where(x => x is Template.Field.PdfText).Select(x => (Template.Field.PdfText)x).Where(x => x.ColumnOfTable == columnOfTable))
                //    {
                //        List<Template.Field> fs;
                //        if (!fieldName2orderedFields.TryGetValue(pt.Name, out fs))
                //        {
                //            fs = new List<Template.Field>();
                //            fieldName2orderedFields[pt.Name] = fs;
                //        }
                //        fs.Add(pt);
                //    }
                //    int definitionCount = fieldName2orderedFields.Max(x => x.Value.Count());
                //    foreach (string fn in fieldName2orderedFields.Keys)
                //        if (definitionCount > fieldName2orderedFields[fn].Count)
                //            throw new Exception("Field '" + fn + "' is column of table " + columnOfTable + " and so it must have the same number of definitions as the rest column fields!");
                //}
                foreach (Template.Field f0 in t.Fields)
                {
                    int    tableDefinitionsCount = t.Fields.Where(x => x.Name == f0.Name).Count();
                    string fn = t.Fields.Where(x => x.ColumnOfTable == f0.Name).GroupBy(x => x.Name).Where(x => x.Count() > tableDefinitionsCount).FirstOrDefault()?.First().Name;
                    if (fn != null)
                    {
                        throw new Exception("Field '" + fn + "' is a column of table field " + f0.Name + " so " + f0.Name + " must have number of definitions not less then that of " + fn + ".");
                    }
                }
            }

            if (saving)
            {
                t.Editor = new Template.EditorSettings
                {
                    TestFile         = testFile.Text,
                    TestPictureScale = pictureScale.Value,
                    ExtractFieldsAutomaticallyWhenPageChanged   = ExtractFieldsAutomaticallyWhenPageChanged.Checked,
                    CheckConditionsAutomaticallyWhenPageChanged = CheckConditionsAutomaticallyWhenPageChanged.Checked,
                };
            }

            return(t);
        }
        bool findAnchor(Template.Anchor a, PointF parentAnchorPoint0, Func <PointF, bool> findNext)
        {
            if (!a.IsSet())
            {
                return(false);
            }
            RectangleF rectangle = a.Rectangle();
            RectangleF searchRectangle;

            {
                if (a.ParentAnchorId != null)
                {
                    RectangleF pameir = PageCollection.ActiveTemplate.Anchors.Find(x => x.Id == a.ParentAnchorId).Rectangle();
                    rectangle.X += parentAnchorPoint0.X - pameir.X;
                    rectangle.Y += parentAnchorPoint0.Y - pameir.Y;
                }
                if (a.SearchRectangleMargin >= 0)
                {
                    searchRectangle = getSearchRectangle(rectangle, a.SearchRectangleMargin);
                }
                else
                {
                    searchRectangle = new RectangleF();//not used, just stub to compile
                }
            }

            switch (a.Type)
            {
            case Template.Anchor.Types.PdfText:
            {
                Template.Anchor.PdfText pt = (Template.Anchor.PdfText)a;
                List <Template.Anchor.PdfText.CharBox> cbs = pt.CharBoxs;
                if (pt.IgnoreInvisibleChars)
                {
                    cbs = cbs.Where(x => !Pdf.InvisibleCharacters.Contains(x.Char)).ToList();
                }
                if (cbs.Count < 1)
                {
                    int w = Size.Width;
                    int h = Size.Height;
                    for (int i = 0; i < w; i++)
                    {
                        for (int j = 0; j < h; j++)
                        {
                            RectangleF actualR = new RectangleF(i, j, rectangle.Width, rectangle.Height);
                            if (        //check that the rectangle contains nothing
                                PdfCharBoxs.FirstOrDefault(x => actualR.Contains(x.R) && (!pt.IgnoreInvisibleChars || !Pdf.InvisibleCharacters.Contains(x.Char))) == null &&
                                !findNext(actualR.Location)
                                )
                            {
                                return(true);
                            }
                        }
                    }
                    return(false);
                }
                IEnumerable <Pdf.CharBox> tcb0s;
                if (pt.SearchRectangleMargin < 0)
                {
                    tcb0s = PdfCharBoxs.Where(x => x.Char == cbs[0].Char);
                }
                else
                {
                    tcb0s = PdfCharBoxs.Where(x => x.Char == cbs[0].Char && searchRectangle.Contains(x.R));
                }
                List <Pdf.CharBox> tcbs = new List <Pdf.CharBox>();
                foreach (Pdf.CharBox tcb0 in tcb0s)
                {
                    tcbs.Clear();
                    tcbs.Add(tcb0);
                    for (int i = 1; i < cbs.Count; i++)
                    {
                        PointF p;
                        if (pt.PositionDeviationIsAbsolute)
                        {
                            p = new PointF(tcb0.R.X + cbs[i].Rectangle.X - cbs[0].Rectangle.X, tcb0.R.Y + cbs[i].Rectangle.Y - cbs[0].Rectangle.Y);
                        }
                        else
                        {
                            p = new PointF(tcbs[i - 1].R.X + cbs[i].Rectangle.X - cbs[i - 1].Rectangle.X, tcbs[i - 1].R.Y + cbs[i].Rectangle.Y - cbs[i - 1].Rectangle.Y);
                        }
                        foreach (Pdf.CharBox bt in PdfCharBoxs.Where(x => x.Char == cbs[i].Char))
                        {
                            if (Math.Abs(bt.R.X - p.X) <= pt.PositionDeviation && Math.Abs(bt.R.Y - p.Y) <= pt.PositionDeviation)
                            {
                                tcbs.Add(bt);
                                break;
                            }
                        }
                        if (tcbs.Count - 1 < i)
                        {
                            break;
                        }
                    }
                    if (tcbs.Count == cbs.Count)
                    {
                        SizeF      shift   = new SizeF(tcbs[0].R.X - cbs[0].Rectangle.X, tcbs[0].R.Y - cbs[0].Rectangle.Y);
                        RectangleF actualR = new RectangleF(rectangle.X + shift.Width, rectangle.Y + shift.Height, rectangle.Width, rectangle.Height);
                        if (        //check that the found rectangle contains only the anchor's boxes
                            (pt.IgnoreOtherCharsInRectangle || PdfCharBoxs.FirstOrDefault(x => actualR.Contains(x.R) && !tcbs.Contains(x) && (!pt.IgnoreInvisibleChars || !Pdf.InvisibleCharacters.Contains(x.Char))) == null) &&
                            !findNext(actualR.Location)
                            )
                        {
                            return(true);
                        }
                    }
                }
            }
                return(false);

            case Template.Anchor.Types.OcrText:
            {
                Template.Anchor.OcrText ot = (Template.Anchor.OcrText)a;
                List <Template.Anchor.OcrText.CharBox> cbs = ot.CharBoxs;
                if (cbs.Count < 1)
                {
                    int w = (int)(ActiveTemplateBitmap.Width * Settings.Constants.Pdf2ImageResolutionRatio - rectangle.Width);
                    int h = (int)(ActiveTemplateBitmap.Height * Settings.Constants.Pdf2ImageResolutionRatio - rectangle.Height);
                    for (int i = 0; i < w; i++)
                    {
                        for (int j = 0; j < h; j++)
                        {
                            RectangleF actualR = new RectangleF(i, j, rectangle.Width, rectangle.Height);
                            if (ActiveTemplateOcrCharBoxs.FirstOrDefault(x => actualR.Contains(x.R)) == null &&
                                !findNext(actualR.Location)
                                )
                            {
                                return(true);
                            }
                        }
                    }
                    return(false);
                }
                List <Ocr.CharBox>        searchRectangleOcrCharBoxs;
                IEnumerable <Ocr.CharBox> tcb0s;
                if (ot.OcrEntirePage)
                {
                    searchRectangleOcrCharBoxs = ActiveTemplateOcrCharBoxs;
                    if (ot.SearchRectangleMargin < 0)
                    {
                        tcb0s = searchRectangleOcrCharBoxs.Where(x => x.Char == cbs[0].Char);
                    }
                    else
                    {
                        tcb0s = searchRectangleOcrCharBoxs.Where(x => x.Char == cbs[0].Char && searchRectangle.Contains(x.R));
                    }
                }
                else if (ot.SearchRectangleMargin < 0)
                {
                    searchRectangleOcrCharBoxs = ActiveTemplateOcrCharBoxs;
                    tcb0s = searchRectangleOcrCharBoxs.Where(x => x.Char == cbs[0].Char);
                }
                else
                {
                    //RectangleF contaningRectangle = searchRectangle;
                    //for (int i = 1; i < ot.CharBoxs.Count; i++)
                    //    contaningRectangle = RectangleF.Union(contaningRectangle, getSearchRectangle(ot.CharBoxs[i].Rectangle.GetSystemRectangleF(), a.SearchRectangleMargin));
                    //searchRectangleOcrCharBoxs = Ocr.This.GetCharBoxs(GetRectangleFromActiveTemplateBitmap(contaningRectangle.X / Settings.Constants.Pdf2ImageResolutionRatio, contaningRectangle.Y / Settings.Constants.Pdf2ImageResolutionRatio, contaningRectangle.Width / Settings.Constants.Pdf2ImageResolutionRatio, contaningRectangle.Height / Settings.Constants.Pdf2ImageResolutionRatio));
                    //PointF searchRectanglePosition = new PointF(contaningRectangle.X < 0 ? 0 : contaningRectangle.X, contaningRectangle.Y < 0 ? 0 : contaningRectangle.Y);
                    //searchRectangleOcrCharBoxs.ForEach(x => { x.R.X += contaningRectangle.X; x.R.Y += contaningRectangle.Y; });
                    //RectangleF mainElementSearchRectangle = new RectangleF(searchRectangle.X - searchRectanglePosition.X, searchRectangle.Y - searchRectanglePosition.Y, searchRectangle.Width, searchRectangle.Height);
                    //tcb0s = searchRectangleOcrCharBoxs.Where(x => x.Char == cbs[0].Char && contaningRectangle.Contains(x.R));
                    using (Bitmap b = GetRectangleFromActiveTemplateBitmap(searchRectangle.X / Settings.Constants.Pdf2ImageResolutionRatio, searchRectangle.Y / Settings.Constants.Pdf2ImageResolutionRatio, searchRectangle.Width / Settings.Constants.Pdf2ImageResolutionRatio, searchRectangle.Height / Settings.Constants.Pdf2ImageResolutionRatio))
                    {
                        if (b == null)
                        {
                            return(false);
                        }
                        searchRectangleOcrCharBoxs = Ocr.This.GetCharBoxs(b, PageCollection.ActiveTemplate.TesseractPageSegMode);
                    }
                    PointF searchRectanglePosition = new PointF(searchRectangle.X < 0 ? 0 : searchRectangle.X, searchRectangle.Y < 0 ? 0 : searchRectangle.Y);
                    searchRectangleOcrCharBoxs.ForEach(x => { x.R.X += searchRectanglePosition.X; x.R.Y += searchRectanglePosition.Y; });
                    tcb0s = searchRectangleOcrCharBoxs.Where(x => x.Char == cbs[0].Char && searchRectangle.Contains(x.R));
                }
                List <Ocr.CharBox> tcbs = new List <Ocr.CharBox>();
                foreach (Ocr.CharBox tcb0 in tcb0s)
                {
                    tcbs.Clear();
                    tcbs.Add(tcb0);
                    for (int i = 1; i < cbs.Count; i++)
                    {
                        PointF p;
                        if (ot.PositionDeviationIsAbsolute)
                        {
                            p = new PointF(tcb0.R.X + cbs[i].Rectangle.X - cbs[0].Rectangle.X, tcb0.R.Y + cbs[i].Rectangle.Y - cbs[0].Rectangle.Y);
                        }
                        else
                        {
                            p = new PointF(tcbs[i - 1].R.X + cbs[i].Rectangle.X - cbs[i - 1].Rectangle.X, tcbs[i - 1].R.Y + cbs[i].Rectangle.Y - cbs[i - 1].Rectangle.Y);
                        }
                        foreach (Ocr.CharBox bt in searchRectangleOcrCharBoxs.Where(x => x.Char == cbs[i].Char))
                        {
                            if (Math.Abs(bt.R.X - p.X) <= ot.PositionDeviation && Math.Abs(bt.R.Y - p.Y) <= ot.PositionDeviation)
                            {
                                tcbs.Add(bt);
                                break;
                            }
                        }
                        if (tcbs.Count - 1 < i)
                        {
                            break;
                        }
                    }
                    if (tcbs.Count == cbs.Count)
                    {
                        SizeF      shift   = new SizeF(tcbs[0].R.X - cbs[0].Rectangle.X, tcbs[0].R.Y - cbs[0].Rectangle.Y);
                        RectangleF actualR = new RectangleF(rectangle.X + shift.Width, rectangle.Y + shift.Height, rectangle.Width, rectangle.Height);
                        if (        //check that the found rectangle contains only the anchor's boxes
                            searchRectangleOcrCharBoxs.FirstOrDefault(x => actualR.Contains(x.R) && !tcbs.Contains(x)) == null &&
                            !findNext(actualR.Location)
                            )
                        {
                            return(true);
                        }
                    }
                }
            }
                return(false);

            case Template.Anchor.Types.ImageData:
            {
                Template.Anchor.ImageData idv = (Template.Anchor.ImageData)a;
                Point     searchRectanglePosition;
                ImageData id0;
                if (idv.SearchRectangleMargin < 0)
                {
                    id0 = ActiveTemplateImageData;
                    searchRectanglePosition = new Point(0, 0);
                }
                else
                {
                    searchRectanglePosition = new Point(searchRectangle.X < 0 ? 0 : (int)searchRectangle.X, searchRectangle.Y < 0 ? 0 : (int)searchRectangle.Y);
                    using (Bitmap b = GetRectangleFromActiveTemplateBitmap(searchRectangle.X / Settings.Constants.Pdf2ImageResolutionRatio, searchRectangle.Y / Settings.Constants.Pdf2ImageResolutionRatio, searchRectangle.Width / Settings.Constants.Pdf2ImageResolutionRatio, searchRectangle.Height / Settings.Constants.Pdf2ImageResolutionRatio))
                    {
                        if (b == null)
                        {
                            return(false);
                        }
                        id0 = new ImageData(b);
                    }
                }
                Point?p_ = idv.Image.FindWithinImage(id0, idv.BrightnessTolerance, idv.DifferentPixelNumberTolerance, idv.FindBestImageMatch);
                if (p_ == null)
                {
                    return(false);
                }
                Point p = (Point)p_;
                return(!findNext(new PointF(searchRectanglePosition.X + p.X, searchRectanglePosition.Y + p.Y)));
            }

            case Template.Anchor.Types.CvImage:
            {
                Template.Anchor.CvImage civ = (Template.Anchor.CvImage)a;
                Point   searchRectanglePosition;
                CvImage ci0;
                if (civ.SearchRectangleMargin < 0)
                {
                    ci0 = ActiveTemplateCvImage;
                    searchRectanglePosition = new Point(0, 0);
                }
                else
                {
                    searchRectanglePosition = new Point(searchRectangle.X < 0 ? 0 : (int)searchRectangle.X, searchRectangle.Y < 0 ? 0 : (int)searchRectangle.Y);
                    using (Bitmap b = GetRectangleFromActiveTemplateBitmap(searchRectangle.X / Settings.Constants.Pdf2ImageResolutionRatio, searchRectangle.Y / Settings.Constants.Pdf2ImageResolutionRatio, searchRectangle.Width / Settings.Constants.Pdf2ImageResolutionRatio, searchRectangle.Height / Settings.Constants.Pdf2ImageResolutionRatio))
                    {
                        if (b == null)
                        {
                            return(false);
                        }
                        ci0 = new CvImage(b);
                    }
                }
                if (civ.FindBestImageMatch)
                {
                    //CvImage.Match m = civ.Image.FindFirstMatchWithinImage(ci0, civ.Threshold, civ.ScaleDeviation, PageCollection.ActiveTemplate.CvImageScalePyramidStep);
                    CvImage.Match m = civ.Image.FindBestMatchWithinImage(ci0, civ.Threshold, civ.ScaleDeviation, PageCollection.ActiveTemplate.CvImageScalePyramidStep);
                    if (m == null)
                    {
                        return(false);
                    }
                    Point p = m.Rectangle.Location;
                    return(!findNext(new PointF(searchRectanglePosition.X + p.X, searchRectanglePosition.Y + p.Y)));
                }
                else
                {        //!!!this returns rather the first match than the best match
                    bool found = false;
                    civ.Image.FindMatchesWithinImage(ci0, civ.Threshold, civ.ScaleDeviation, PageCollection.ActiveTemplate.CvImageScalePyramidStep,
                                                     (CvImage.Match m) =>
                        {
                            found = !findNext(new PointF(searchRectanglePosition.X + m.Rectangle.X, searchRectanglePosition.Y + m.Rectangle.Y));
                            return(!found);
                        }
                                                     );
                    return(found);
                }
            }

            default:
                throw new Exception("Unknown option: " + a.Type);
            }
        }