/// <summary>
        /// Draws a magnified version of the highlighted label for easier positioning.
        /// </summary>
        private static void DrawMagnifiedRectangle(Bitmap bmp, Rectangle labelRectangle, byte whiteThreshold, int magnifiedYMarginTop, int magnifiedYMarginBottom)
        {
            const int margin    = 5;
            var       bmpWidth  = bmp.Width;
            var       bmpHeight = bmp.Height;
            int       pixelSize = Math.Min(10, bmpWidth / (labelRectangle.Width + 2 * margin)); // cap magnifying

            labelRectangle.Inflate(margin, margin);
            var magnifiedWidth     = labelRectangle.Width * pixelSize;
            var magnifiedHeight    = labelRectangle.Height * pixelSize;
            var magnifiedRectangle = new Rectangle((bmpWidth - magnifiedWidth) / 2, magnifiedYMarginTop == -1 ? bmpHeight - magnifiedHeight - magnifiedYMarginBottom : magnifiedYMarginTop, magnifiedWidth, magnifiedHeight);

            var bmpData = bmp.LockBits(new Rectangle(0, 0, bmpWidth, bmpHeight), ImageLockMode.ReadWrite, bmp.PixelFormat);
            var bytes   = bmp.PixelFormat == PixelFormat.Format32bppArgb ? 4 : 3;

            unsafe
            {
                var scan0Bmp = (byte *)bmpData.Scan0.ToPointer();
                for (int x = Math.Max(0, -labelRectangle.X); x < labelRectangle.Width; x++)
                {
                    var xBmp = x + labelRectangle.X;
                    if (xBmp >= bmpWidth)
                    {
                        break;
                    }
                    bool inXBorder = x < margin || x >= labelRectangle.Width - margin;
                    for (int y = Math.Max(0, -labelRectangle.Y); y < labelRectangle.Height; y++)
                    {
                        var yBmp = y + labelRectangle.Y;
                        if (yBmp >= bmpHeight)
                        {
                            break; // it gets only bigger
                        }
                        bool  inBorder = inXBorder || y < margin || y >= labelRectangle.Height - margin;
                        byte *px       = scan0Bmp + yBmp * bmpData.Stride + xBmp * bytes;
                        var   b        = px[0];
                        var   g        = px[1];
                        var   r        = px[2];
                        if (!inBorder)
                        {
                            if (ArkOcr.HslLightness(r, g, b) < whiteThreshold)
                            {
                                b /= 2;
                                g /= 2;
                                r /= 2;
                            }
                            else
                            {
                                b = 255; //(byte)(255 - (255 - b) / 2);
                                g = 255; //(byte)(255 - (255 - g) / 2);
                                r = 255; //(byte)(255 - (255 - r) / 2);
                            }
                            //var pxLightness = (byte)(ArkOCR.HslLightness(r, g, b) < whiteThreshold ? 0 : 255);
                        }

                        var xEnd = magnifiedRectangle.X + (x + 1) * pixelSize;
                        var yEnd = magnifiedRectangle.Y + (y + 1) * pixelSize;

                        for (int xm = magnifiedRectangle.X + x * pixelSize; xm < xEnd; xm++)
                        {
                            for (int ym = magnifiedRectangle.Y + y * pixelSize; ym < yEnd; ym++)
                            {
                                byte *mPx = scan0Bmp + ym * bmpData.Stride + xm * bytes;
                                mPx[0] = b;
                                mPx[1] = g;
                                mPx[2] = r;
                            }
                        }
                    }
                }
            }
            bmp.UnlockBits(bmpData);
        }
        /// <summary>
        /// Redraws the screenShot
        /// </summary>
        /// <param name="highlightIndex">Which of the labels should be highlighted, -1 for none.</param>
        /// <param name="showLabels">Show set label rectangles.</param>
        /// <param name="whiteThreshold">Preview of white-Threshold. -1 to disable.</param>
        /// <param name="manualRectangle">draw a custom rectangle</param>
        private void RedrawScreenshot(int highlightIndex = -1, bool showLabels = true, int whiteThreshold = -1, Rectangle manualRectangle = default)
        {
            if (_screenshot == null ||
                OCRDebugLayoutPanel.Controls.Count == 0 ||
                !(OCRDebugLayoutPanel.Controls[OCRDebugLayoutPanel.Controls.Count - 1] is PictureBox p)
                )
            {
                return;
            }

            _redrawingDebouncer.Cancel();

            Bitmap b = new Bitmap((whiteThreshold >= 0 ? ArkOcr.RemovePixelsUnderThreshold(ArkOcr.GetGreyScale(_screenshot), (byte)whiteThreshold, true) : _screenshot));

            if (showLabels || !manualRectangle.IsEmpty)
            {
                using (Graphics g = Graphics.FromImage(b))
                    using (Pen penW = new Pen(Color.White, 2))
                        using (Pen penY = new Pen(Color.Yellow, 2))
                            using (Pen penB = new Pen(Color.Black, 2))
                            {
                                penW.Alignment = System.Drawing.Drawing2D.PenAlignment.Inset;
                                penY.Alignment = System.Drawing.Drawing2D.PenAlignment.Inset;
                                penB.Alignment = System.Drawing.Drawing2D.PenAlignment.Inset;

                                if (!manualRectangle.IsEmpty)
                                {
                                    var rec = manualRectangle;
                                    rec.Inflate(2, 2);
                                    g.DrawRectangle(penY, rec);
                                    rec.Inflate(2, 2);
                                    g.DrawRectangle(penB, rec);
                                }
                                else
                                {
                                    for (int r = 0; r < ArkOcr.Ocr.ocrConfig.labelRectangles.Length; r++)
                                    {
                                        var rec = ArkOcr.Ocr.ocrConfig.labelRectangles[r];
                                        rec.Inflate(2, 2);
                                        g.DrawRectangle(r == highlightIndex ? penY : penW, rec);
                                        rec.Inflate(2, 2);
                                        g.DrawRectangle(penB, rec);
                                    }
                                }
                            }

                var magnifiedRectangle = highlightIndex != -1
                    ? ArkOcr.Ocr.ocrConfig.labelRectangles[highlightIndex]
                    : !manualRectangle.IsEmpty
                        ? manualRectangle
                        : Rectangle.Empty;

                if (!magnifiedRectangle.IsEmpty)
                {
                    var       currentWhiteThreshold = Properties.Settings.Default.OCRWhiteThreshold;
                    var       magnifiedMarginBottom = -1;
                    var       magnifiedMarginTop    = -1;
                    const int recMargin             = 30;

                    if (magnifiedRectangle.Y - OCRDebugLayoutPanel.VerticalScroll.Value >
                        OCRDebugLayoutPanel.Height / 2)
                    {
                        magnifiedMarginTop = recMargin + OCRDebugLayoutPanel.VerticalScroll.Value;
                    }
                    else
                    {
                        magnifiedMarginBottom = OCRDebugLayoutPanel.Height < b.Height
                            ? b.Height - OCRDebugLayoutPanel.Height + recMargin - OCRDebugLayoutPanel.VerticalScroll.Value
                            : recMargin;
                    }

                    DrawMagnifiedRectangle(b, magnifiedRectangle, currentWhiteThreshold, magnifiedMarginTop, magnifiedMarginBottom);
                }
            }

            Bitmap disp = (Bitmap)p.Image; // take pointer to old image to dispose it soon

            p.Image = b;
            if (disp != null && disp != _screenshot)
            {
                disp.Dispose();
            }
        }