/// <summary> /// Places the given color on the image /// </summary> public void Place(RGB color, int startX, int startY, ref ImageData imageData) { // find the next coordinates Pixel p; if (Queue.Count == 0) p = imageData.Image[startY * imageData.Width + startX]; else p = placeImpl(color); Debug.Assert(p.Empty); p.Empty = false; p.Color = color; // adjust the queue changeQueue(p); }
static void Main(string[] args) { Console.WriteLine("RGB image generator\n"); if (!parseArgs(args)) { printArgsHelp(); Console.WriteLine("Press ENTER to exit."); Console.ReadLine(); return; } System.Diagnostics.Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.BelowNormal; DateTime start = DateTime.Now; Console.WriteLine("Running the precalculations and eating up your memory."); // create every color once, and randomize their order List<RGB> colors = new List<RGB>(Width * Height); for (int r = 0; r < NumColors; r++) for (int g = 0; g < NumColors; g++) for (int b = 0; b < NumColors; b++) colors.Add(new RGB { R = (byte)(r * 255 / (NumColors - 1)), G = (byte)(g * 255 / (NumColors - 1)), B = (byte)(b * 255 / (NumColors - 1)) }); colors.Sort(Sorter); Debug.Assert(colors.Count == Width * Height); Pixel[] img = new Pixel[Width * Height]; ImageData imageData = new ImageData { Image = img, Height = Height, Width = Width }; HashSet<int> weights = new HashSet<int>(); Debug.Assert(NeighX.Length == NeighY.Length); for (int y = 0; y < Height; y++) { for (int x = 0; x < Width; x++) { int weight; do { weight = RndGen.Next(); } while (!weights.Add(weight)); imageData.Image[y * Width + x] = new Pixel { X = x, Y = y, Empty = true, QueueIndex = -1, Weight = weight }; } } for (int y = 0; y < Height; y++) { for (int x = 0; x < Width; x++) { imageData.Image[y * Width + x].Neighbors = Enumerable.Range(0, NeighX.Length).Select(n => { int y2 = y + NeighY[n]; if (y2 < 0 || y2 == Height) return null; int x2 = x + NeighX[n]; if (x2 < 0 || x2 == Width) return null; return img[y2 * Width + x2]; }).Where(p => p != null).ToArray(); } } Dictionary<long, int> checkpoints = Enumerable.Range(1, NumFrames).ToDictionary(i => (long)i * colors.Count / NumFrames - 1, i => i - 1); Thread pngThread = null; // loop through all colors that we want to place for (int i = 0, l = colors.Count; i < l; i++) { // give progress report if (i % 1024 == 0) { Algorithm.Queue.Compress(); Console.WriteLine("{0:P}, queue is size {1}", (double)i / Width / Height, Algorithm.Queue.Count); } // run the algorithm Algorithm.Place(colors[i], StartX, StartY, ref imageData); // save a checkpoint, if needed int chkidx; if (checkpoints.TryGetValue(i, out chkidx)) { // create an image Bitmap image = new Bitmap(Width, Height, PixelFormat.Format24bppRgb); BitmapData idata = image.LockBits(new Rectangle(0, 0, Width, Height), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb); byte[] ibytes = new byte[idata.Stride * idata.Height]; int stride = idata.Stride; for (int y = 0; y < Height; y++) { for (int x = 0; x < Width; x++) { RGB color = img[y * Width + x].Color; ibytes[y * stride + x * 3 + 2] = color.R; ibytes[y * stride + x * 3 + 1] = color.G; ibytes[y * stride + x * 3 + 0] = color.B; } } Marshal.Copy(ibytes, 0, idata.Scan0, ibytes.Length); image.UnlockBits(idata); // use one thread for png compression if (pngThread != null) pngThread.Join(); pngThread = new Thread(new ThreadStart(delegate { image.Save(string.Format("result{0:D5}.png", chkidx), ImageFormat.Png); image.Dispose(); })); pngThread.Start(); } } Debug.Assert(Algorithm.Queue.Count == 0); // wait for final image pngThread.Join(); Bitmap image2 = (Bitmap)Bitmap.FromFile(string.Format("result{0:D5}.png", NumFrames - 1)); HashSet<RGB> ch = new HashSet<RGB>(); for (int y = 0; y < Height; y++) { for (int x = 0; x < Width; x++) { Color pix = image2.GetPixel(x, y); if (!ch.Add(new RGB { R = pix.R, G = pix.G, B = pix.B })) { Console.WriteLine("Color {0}/{1}/{2} is added more that once!!!", pix.R, pix.G, pix.B); } } } image2.Dispose(); Console.WriteLine("DONE!! It took this long: {0}", DateTime.Now.Subtract(start)); Console.WriteLine("pres ENTER to exit"); Console.ReadLine(); }