public static void SetToGrayscale(this LocklessBitmap bitmap) { for (int y = 0; y < bitmap.Height; y++) { for (int x = 0; x < bitmap.Width; x++) { int grayscale = bitmap.GetGrayscale(x, y); bitmap.SetPixel(x, y, Color.FromArgb(bitmap.GetPixel(x, y).A, grayscale, grayscale, grayscale)); } } }
public static void Blacken(this LocklessBitmap bitmap, byte threshold) { for (int y = 0; y < bitmap.Height; y++) { int x = 0; while (x <= bitmap.Width - 1 && bitmap.GetGrayscale(x, y) <= threshold) { bitmap.SetPixel(x, y, Color.FromArgb(bitmap.GetPixel(x, y).A, 0, 0, 0)); x++; } x = bitmap.Width - 1; while (x >= 0 && bitmap.GetGrayscale(x, y) <= threshold) { bitmap.SetPixel(x, y, Color.FromArgb(bitmap.GetPixel(x, y).A, 0, 0, 0)); x--; } } for (int x = 0; x < bitmap.Width; x++) { int y = 0; while (y <= bitmap.Height - 1 && bitmap.GetGrayscale(x, y) <= threshold) { bitmap.SetPixel(x, y, Color.FromArgb(bitmap.GetPixel(x, y).A, 0, 0, 0)); y++; } y = bitmap.Height - 1; while (y >= 0 && bitmap.GetGrayscale(x, y) <= threshold) { bitmap.SetPixel(x, y, Color.FromArgb(bitmap.GetPixel(x, y).A, 0, 0, 0)); y--; } } }
public static string Measure(LocklessBitmap bitmap, float[] perf, byte threshold) { int width = bitmap.Width; int height = bitmap.Height; int xMin = width / 8; int xMax = width - xMin; int yMin = height / 8; int yMax = height - yMin; Rectangle[] areas = new Rectangle[] { new Rectangle(xMin, 0, xMax - xMin, yMin), new Rectangle(xMax, yMin, xMin, yMax - yMin), new Rectangle(xMin, yMax, xMax - xMin, yMin), new Rectangle(0, yMin, xMin, yMax - yMin) }; int[] rotation = new int[] { 0, -90, 180, +90 }; int[] antiRotation = new int[] { 0, +90, 180, -90 }; LocklessBitmap[] bitmaps = new LocklessBitmap[] { bitmap.Copy(areas[(int)Side.Top]).Rotate(rotation[(int)Side.Top]), bitmap.Copy(areas[(int)Side.Right]).Rotate(rotation[(int)Side.Right]), bitmap.Copy(areas[(int)Side.Bottom]).Rotate(rotation[(int)Side.Bottom]), bitmap.Copy(areas[(int)Side.Left]).Rotate(rotation[(int)Side.Left]) }; int[] edges = new int[] { 0, 0, 0, 0 }; float[][] perforations = new float[4][]; Dictionary <int, float>[] teeth = new Dictionary <int, float> [4]; Dictionary <int, float>[] holes = new Dictionary <int, float> [4]; for (int i = (int)Side.Top; i <= (int)Side.Left; i++) { LocklessBitmap b = bitmaps[i]; teeth[i] = new Dictionary <int, float>(); holes[i] = new Dictionary <int, float>(); perforations[i] = new float[0]; for (int y = 0; y < b.Height; y++) { for (int x = 0; x < b.Width; x++) { b.SetPixel(x, y, b.GetGrayscale(x, y) <= threshold ? Color.Black : Color.White); } } bool removed = true; while (removed) { removed = false; for (int y = 1; y < b.Height - 1; y++) { for (int x = 1; x < b.Width - 1; x++) { Color otherColor = b.IsColor(x, y, Color.Black) ? Color.White : Color.Black; int otherCount = 0; for (int dx = -1; dx <= +1; dx++) { for (int dy = -1; dy <= +1; dy++) { if (!(dx == 0 && dy == 0)) { if (b.IsColor(x + dx, y + dy, otherColor)) { otherCount++; } } } } if (otherCount >= 6) { b.SetPixel(x, y, otherColor); removed = true; } } } } int y1, y2; y1 = 0; while (y1 < b.Height && b.IsColor(0, y1, b.Width - 1, y1, Color.Black, 0.90F)) { y1++; } if (!(y1 > 0 && y1 < b.Height)) { continue; // Not found the upper bound, so continue with the next side } y2 = y1; while (y2 < b.Height && !b.IsColor(0, y2, b.Width - 1, y2, Color.White, 1)) { y2++; } if (!(y2 > y1 && y2 < b.Height)) { continue; // Not found the lower bound, so continue with the next side } for (int x = 1; x < b.Width - 1; x++) // Iterate from +1 to Width-2 because of the pixel removal !!! { for (int y = y2; y > y1; y--) { if (!b.IsColor(x, y, Color.White)) { for (int yy = y; yy > y1; yy--) { b.SetPixel(x, yy, Color.Black); } break; } } } perforations[i] = new float[b.Width - 2]; float[] perfs = perforations[i]; for (int x = 1; x < b.Width - 1; x++) // Iterate from +1 to Width-2 because of the pixel removal which not done at the side !!! { for (int y = y1; y <= y2; y++) { if (b.IsColor(x, y, Color.White)) { perfs[x - 1] = y; break; } else { b.SetPixel(x, y, Color.LightGray); } } } for (int m = 1; m <= 25; m++) { if (m % 2 == 0) { for (int p = 1; p < perfs.Length - 1; p++) { perfs[p] = (perfs[p - 1] + perfs[p] + perfs[p + 1]) / 3; } } else { for (int p = perfs.Length - 2; p >= 1; p--) { perfs[p] = (perfs[p - 1] + perfs[p] + perfs[p + 1]) / 3; } } } teeth[i] = new Dictionary <int, float>(); holes[i] = new Dictionary <int, float>(); for (int p = 1; p < perfs.Length - 1; p++) { if (perfs[p] < perfs[p - 1] && perfs[p] < perfs[p + 1]) { teeth[i].Add(p, perfs[p]); } if (perfs[p] > perfs[p - 1] && perfs[p] > perfs[p + 1]) { holes[i].Add(p, perfs[p]); } } for (int x = 1; x < b.Width - 1; x++) { int y = (int)perfs[x - 1]; b.SetPixels(x, y - 1, x, y + 1, Color.Blue); } edges[i] = y1; } int widthInPixels = 0; int heightInPixels = 0; int top = edges[(int)Side.Top]; int right = edges[(int)Side.Right] != 0 ? bitmap.Width - edges[(int)Side.Right] - 1 : 0; int bottom = edges[(int)Side.Bottom] != 0 ? bitmap.Height - edges[(int)Side.Bottom] - 1 : 0; int left = edges[(int)Side.Left]; if (left != 0 && right != 0) { widthInPixels = right - left; } if (top != 0 && bottom != 0) { heightInPixels = bottom - top; } for (int i = (int)Side.Top; i <= (int)Side.Left; i++) { bitmaps[i] = bitmap.Copy(areas[i]).Rotate(rotation[i]); LocklessBitmap b = bitmaps[i]; b.SetToGrayscale(); int thickness = 0; if (edges[i] != 0) { b.SetPixels(0, edges[i] - thickness, b.Width - 1, edges[i] + thickness, Color.Red); } if (teeth[i].Count() != 0) { foreach (KeyValuePair <int, float> t in teeth[i]) { int y = (int)Math.Round((double)t.Value); b.SetPixels(t.Key - thickness, 0, t.Key + thickness, y, Color.Yellow); } } if (holes[i].Count() != 0) { foreach (KeyValuePair <int, float> h in holes[i]) { int y = (int)Math.Round((double)h.Value); b.SetPixels(h.Key - thickness, y, h.Key + thickness, b.Height - 1, Color.Blue); } } if (perforations[i].Length != 0) { for (int x = 1; x < b.Width - 1; x++) { int y = (int)Math.Round((double)perforations[i][x - 1]); b.SetPixels(x, y - thickness, x, y + thickness, Color.Magenta); } } bitmap.Copy(bitmaps[i].Rotate(antiRotation[i]), areas[i]); } float[] sizes = new float[4] { 0, 0, 0, 0 }; for (int i = (int)Side.Top; i <= (int)Side.Left; i++) { if (teeth[i].Count >= 5 && holes[i].Count >= 5) { int teethFirst = teeth[i].First().Key; int teethLast = teeth[i].Last().Key; int teethPixels = teethLast - teethFirst; float teethSize = 20F / perf[i] * (teeth[i].Count() - 1); int holesFirst = holes[i].First().Key; int holesLast = holes[i].Last().Key; int holesPixels = holesLast - holesFirst; float holesSize = 20F / perf[i] * (holes[i].Count() - 1); float areaSizeInMillimetersBasedOnTeeth = (float)areas[i].Width / teethPixels * teethSize; float areaSizeInMillimetersBasedOnHoles = (float)areas[i].Width / holesPixels * holesSize; int sizeInPixels = (i == 0 || i == 2 ? widthInPixels : heightInPixels); float stampSizeTeeth = (float)sizeInPixels / areas[i].Width * areaSizeInMillimetersBasedOnTeeth; float stampSizeHoles = (float)sizeInPixels / areas[i].Width * areaSizeInMillimetersBasedOnHoles; sizes[i] = (stampSizeTeeth + stampSizeHoles) / 2; } } float horizontal = sizes[(int)Side.Top] != 0 && sizes[(int)Side.Bottom] != 0 ? (sizes[(int)Side.Top] + sizes[(int)Side.Bottom]) / 2 : (sizes[(int)Side.Top] != 0 ? sizes[(int)Side.Top] : sizes[(int)Side.Bottom]); float vertical = sizes[(int)Side.Right] != 0 && sizes[(int)Side.Left] != 0 ? (sizes[(int)Side.Right] + sizes[(int)Side.Left]) / 2 : (sizes[(int)Side.Right] != 0 ? sizes[(int)Side.Right] : sizes[(int)Side.Left]); string size = string.Format( "{0} × {1} {2} {3} · {4} × {5} · {6}", Math.Round(horizontal, 1), Math.Round(vertical, 1), char.ConvertFromUtf32(0x2190), Math.Round(sizes[(int)Side.Top], 1), Math.Round(sizes[(int)Side.Bottom], 1), Math.Round(sizes[(int)Side.Right], 1), Math.Round(sizes[(int)Side.Left], 1) ); return(size); }