/// <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(); } }