//Draws a border on the bitmap public static PixelMatrix Border(PixelMatrix bitmap, Color color) { for (int i = 0; i < bitmap.height; i++) { bitmap.SetPixelSafe(0, i, color); bitmap.SetPixelSafe(bitmap.width - 1, i, color); } for (int i = 0; i < bitmap.width; i++) { bitmap.SetPixelSafe(i, 0, color); bitmap.SetPixelSafe(i, bitmap.height - 1, color); } return(bitmap); }
//Rotate an image by increments of 90 degrees public static PixelMatrix RotateSq(PixelMatrix original, int rotates) { //No more rotates if (rotates == 0) { return(original); } //Setup new rotated int side = Mathf.Max(original.width, original.height); PixelMatrix rotated = new PixelMatrix(side, side, Color.clear); //Rotate 90º for (int i = 0; i < original.width; i++) { int finalI = original.width - i - 1; for (int j = 0; j < original.height; j++) { rotated.SetPixelSafe(j, finalI, original.GetPixelSafe(i, j)); } } //Call new rotation rotated = RotateSq(rotated, rotates - 1); return(rotated); }
//Scan-line flood fill, much faster //https://lodev.org/cgtutor/floodfill.html#Scanline_Floodfill_Algorithm_With_Stack public static PixelMatrix FloodFillLine(PixelMatrix bmp, int x, int y, Color replacementColor) { Point pt = new Point(x, y); Color targetColor = bmp.GetPixel(pt.x, pt.y); if (targetColor == replacementColor) { return(bmp); } Stack <Point> pixels = new Stack <Point>(); pixels.Push(pt); while (pixels.Count != 0) { Point temp = pixels.Pop(); int y1 = temp.y; while (y1 >= 0 && bmp.GetPixel(temp.x, y1) == targetColor) { y1--; } y1++; bool spanLeft = false; bool spanRight = false; while (y1 < bmp.height && bmp.GetPixel(temp.x, y1) == targetColor) { bmp.SetPixelSafe(temp.x, y1, replacementColor); Color clm1 = bmp.GetPixel(temp.x - 1, y1); Color clp1 = bmp.GetPixel(temp.x + 1, y1); if (!spanLeft && temp.x > 0 && clm1 == targetColor) { pixels.Push(new Point(temp.x - 1, y1)); spanLeft = true; } else if (spanLeft && temp.x - 1 >= 0 && clm1 != targetColor) { spanLeft = false; } if (!spanRight && temp.x < bmp.width - 1 && clp1 == targetColor) { pixels.Push(new Point(temp.x + 1, y1)); spanRight = true; } else if (spanRight && temp.x < bmp.width - 1 && clp1 != targetColor) { spanRight = false; } y1++; } } return(bmp); }
//Fill Polygon //Looks much faster and quite promissing //http://alienryderflex.com/polygon_fill/ public static PixelMatrix FillPolygon(PixelMatrix original, List <Geometry.Vector2X> polygon, Color cl) { int pixelX, pixelY, swap; int i, j, nodes; int[] nodeX = new int[polygon.Count]; //Limits of polygon int IMAGE_TOP = original.height + 1, IMAGE_BOT = -1, IMAGE_RIGHT = -1, IMAGE_LEFT = original.width + 1; for (int p = 0; p < polygon.Count; p++) { if (polygon[p].value.x > IMAGE_RIGHT) { IMAGE_RIGHT = (int)polygon[p].value.x; } else if (polygon[p].value.x < IMAGE_LEFT) { IMAGE_LEFT = (int)polygon[p].value.x; } if (polygon[p].value.y < IMAGE_TOP) { IMAGE_TOP = (int)polygon[p].value.y; } else if (polygon[p].value.y > IMAGE_BOT) { IMAGE_BOT = (int)polygon[p].value.y; } } // Loop through the rows of the image. for (pixelY = IMAGE_TOP; pixelY < IMAGE_BOT; pixelY++) { // Build a list of nodes. nodes = 0; j = polygon.Count - 1; for (i = 0; i < polygon.Count; i++) { if (polygon[i].value.y < pixelY && polygon[j].value.y >= pixelY || polygon[j].value.y < pixelY && polygon[i].value.y >= pixelY) { nodeX[nodes++] = (int)(polygon[i].value.x + (pixelY - polygon[i].value.y) / (polygon[j].value.y - polygon[i].value.y) * (polygon[j].value.x - polygon[i].value.x)); } j = i; } // Sort the nodes, via a simple “Bubble” sort. i = 0; while (i < nodes - 1) { if (nodeX[i] > nodeX[i + 1]) { swap = nodeX[i]; nodeX[i] = nodeX[i + 1]; nodeX[i + 1] = swap; if (i != 0) { i--; } } else { i++; } } // Fill the pixels between node pairs. for (i = 0; i < nodes; i += 2) { if (nodeX[i] >= IMAGE_RIGHT) { break; } if (nodeX[i + 1] > IMAGE_LEFT) { if (nodeX[i] < IMAGE_LEFT) { nodeX[i] = IMAGE_LEFT; } if (nodeX[i + 1] > IMAGE_RIGHT) { nodeX[i + 1] = IMAGE_RIGHT; } for (pixelX = nodeX[i]; pixelX < nodeX[i + 1]; pixelX++) { original.SetPixelSafe(pixelX, pixelY, cl); } } } } return(original); }