public static int CountColors(this Image image) { if (image == null) { throw new ArgumentNullException("image"); } HashSet<int> colors = new HashSet<int>(); FastBitmap fastBitmap = new FastBitmap(image); fastBitmap.Lock(); // Loop through all the pixels of the image // and add the colors to the HashSet - duplicates // are automatically ignored by that collection type for (int x = 0; x < image.Width; x++) { for (int y = 0; y < image.Height; y++) { // We use ToArgb because Colors are compared on more than their ARGB values - see Color class documentation on MSDN colors.Add(fastBitmap.GetPixel(x, y).ToArgb()); } } fastBitmap.Unlock(); return colors.Count; }
public void TestFastBitmapCreation() { Bitmap bitmap = new Bitmap(64, 64); FastBitmap fastBitmap = new FastBitmap(bitmap); fastBitmap.Lock(); fastBitmap.Unlock(); // Try creating a FastBitmap with different 32bpp depths try { // ReSharper disable once ObjectCreationAsStatement new FastBitmap(new Bitmap(1, 1, PixelFormat.Format32bppArgb)); // ReSharper disable once ObjectCreationAsStatement new FastBitmap(new Bitmap(1, 1, PixelFormat.Format32bppPArgb)); // ReSharper disable once ObjectCreationAsStatement new FastBitmap(new Bitmap(1, 1, PixelFormat.Format32bppRgb)); } catch (ArgumentException) { Assert.Fail("The FastBitmap should accept any type of 32bpp pixel format bitmap"); } // Try creating a FastBitmap with a bitmap of a bit depth different from 32bpp Bitmap invalidBitmap = new Bitmap(64, 64, PixelFormat.Format4bppIndexed); // ReSharper disable once ObjectCreationAsStatement new FastBitmap(invalidBitmap); }
/// <summary> /// Locks this bitmap into memory and returns a FastBitmap that can be used to manipulate its pixels /// </summary> /// <param name="bitmap">The bitmap to lock</param> /// <returns>A locked FastBitmap</returns> public static FastBitmap FastLock(this Bitmap bitmap) { var fast = new FastBitmap(bitmap); fast.Lock(); return(fast); }
//tiles = 16 means 16 x 16 atlas public List<Bitmap> Atlas2dInto1d(Bitmap atlas2d, int tiles, int atlassizezlimit) { FastBitmap orig = new FastBitmap(); orig.bmp = atlas2d; int tilesize = atlas2d.Width / tiles; int atlasescount = Math.Max(1, (tiles * tiles * tilesize) / atlassizezlimit); List<Bitmap> atlases = new List<Bitmap>(); orig.Lock(); //256 x 1 FastBitmap atlas1d = null; for (int i = 0; i < tiles * tiles; i++) { int x = i % tiles; int y = i / tiles; int tilesinatlas = (tiles * tiles / atlasescount); if (i % tilesinatlas == 0) { if (atlas1d != null) { atlas1d.Unlock(); atlases.Add(atlas1d.bmp); } atlas1d = new FastBitmap(); atlas1d.bmp = new Bitmap(tilesize, atlassizezlimit); atlas1d.Lock(); } for (int xx = 0; xx < tilesize; xx++) { for (int yy = 0; yy < tilesize; yy++) { int c = orig.GetPixel(x * tilesize + xx, y * tilesize + yy); atlas1d.SetPixel(xx, (i % tilesinatlas) * tilesize + yy, c); } } } atlas1d.Unlock(); atlases.Add(atlas1d.bmp); orig.Unlock(); return atlases; }
public void TestSequentialFastBitmapLocking() { Bitmap bitmap = new Bitmap(64, 64); FastBitmap fastBitmap = new FastBitmap(bitmap); Assert.IsFalse(fastBitmap.Locked, "Immediately after creation, the FastBitmap.Locked property must be false"); fastBitmap.Lock(); Assert.IsTrue(fastBitmap.Locked, "After a successful call to .Lock(), the .Locked property must be true"); fastBitmap.Unlock(); Assert.IsFalse(fastBitmap.Locked, "After a successful call to .Lock(), the .Locked property must be false"); fastBitmap = new FastBitmap(bitmap); fastBitmap.Lock(); fastBitmap.Unlock(); }
public static bool CompareColors(this Image image, Image other) { if (image == null || other == null) { throw new ArgumentNullException(image == null ? "image" : "other"); } if (image.Size != other.Size) { return false; } FastBitmap fastImage = new FastBitmap(image); FastBitmap fastOther = new FastBitmap(other); try { fastImage.Lock(); fastOther.Lock(); for (int x = 0; x < image.Width; x++) { for (int y = 0; y < image.Height; y++) { // We use ToArgb because Colors are compared on more than their ARGB values - see Color class documentation on MSDN if (fastImage.GetPixel(x, y).ToArgb() != fastOther.GetPixel(x, y).ToArgb()) { return false; } } } } finally { fastImage.Unlock(); fastOther.Unlock(); } return true; }
public static Image ReplaceColor(this Image image, Color oldColor, Color newColor) { if (image == null) { throw new ArgumentNullException("image"); } Image clone = image.Clone() as Image; // If they try to replace a color with itself (sneaky, sneaky!) then just return our cloned image immediately if (oldColor.ToArgb() == newColor.ToArgb()) { return clone; } FastBitmap fastBitmap = new FastBitmap(clone); fastBitmap.Lock(); for (int x = 0; x < image.Width; x++) { for (int y = 0; y < image.Height; y++) { // We use ToArgb because Colors are compared on more than their ARGB values - see Color class documentation on MSDN if (fastBitmap.GetPixel(x, y).ToArgb() == oldColor.ToArgb()) { fastBitmap.SetPixel(x, y, newColor); } } } fastBitmap.Unlock(); return fastBitmap.Image; }
public void TestFailedSequentialFastBitmapLocking() { Bitmap bitmap = new Bitmap(64, 64); FastBitmap fastBitmap = new FastBitmap(bitmap); fastBitmap.Lock(); fastBitmap = new FastBitmap(bitmap); fastBitmap.Lock(); }
/// <summary> /// Generates a frame image with a given set of parameters. /// The seed is used to randomize the frame, and any call with the same width, height and seed will generate the same image /// </summary> /// <param name="width">The width of the image to generate</param> /// <param name="height">The height of the image to generate</param> /// <param name="seed">The seed for the image, used to seed the random number generator that will generate the image contents</param> /// <returns>An image with the passed parameters</returns> public static Bitmap GenerateRandomBitmap(int width, int height, int seed = -1) { if (seed == -1) { seed = _seedRandom.Next(); } Bitmap bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb); FastBitmap fastBitmap = new FastBitmap(bitmap); fastBitmap.Lock(); // Plot the image with random pixels now Random r = new Random(seed); for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { uint pixelColor = (uint)(r.NextDouble() * 0xFFFFFFFF); fastBitmap.SetPixel(x, y, pixelColor); } } fastBitmap.Unlock(); return bitmap; }
public void TestFastBitmapSetPixelBoundsException() { Bitmap bitmap = new Bitmap(64, 64); FastBitmap fastBitmap = new FastBitmap(bitmap); fastBitmap.Lock(); try { fastBitmap.SetPixel(-1, -1, 0); Assert.Fail("When trying to access a coordinate that is out of bounds via GetPixel, an exception must be thrown"); } catch (ArgumentOutOfRangeException) { } try { fastBitmap.SetPixel(fastBitmap.Width, 0, 0); Assert.Fail("When trying to access a coordinate that is out of bounds via GetPixel, an exception must be thrown"); } catch (ArgumentOutOfRangeException) { } try { fastBitmap.SetPixel(0, fastBitmap.Height, 0); Assert.Fail("When trying to access a coordinate that is out of bounds via GetPixel, an exception must be thrown"); } catch (ArgumentOutOfRangeException) { } fastBitmap.SetPixel(fastBitmap.Width - 1, fastBitmap.Height - 1, 0); }
public void TestFastBitmapLockingException() { Bitmap bitmap = new Bitmap(64, 64); FastBitmap fastBitmap = new FastBitmap(bitmap); fastBitmap.Lock(); fastBitmap.Lock(); }
public void TestFastBitmapLocker() { Bitmap bitmap = new Bitmap(64, 64); FastBitmap fastBitmap = new FastBitmap(bitmap); // Immediate lock and dispose fastBitmap.Lock().Dispose(); Assert.IsFalse(fastBitmap.Locked, "After disposing of the FastBitmapLocker object, the underlying fast bitmap must be unlocked"); using (var locker = fastBitmap.Lock()) { fastBitmap.SetPixel(0, 0, 0); Assert.AreEqual(fastBitmap, locker.FastBitmap, "The fast bitmap referenced in the fast bitmap locker must be the one that had the original Lock() call"); } Assert.IsFalse(fastBitmap.Locked, "After disposing of the FastBitmapLocker object, the underlying fast bitmap must be unlocked"); // Test the conditional unlocking of the fast bitmap locker by unlocking the fast bitmap before exiting the 'using' block using (fastBitmap.Lock()) { fastBitmap.SetPixel(0, 0, 0); fastBitmap.Unlock(); } }
public void TestSetPixelInt() { Bitmap bitmap1 = new Bitmap(64, 64); Bitmap bitmap2 = new Bitmap(64, 64); FastBitmap fastBitmap1 = new FastBitmap(bitmap1); fastBitmap1.Lock(); Random r = new Random(); for (int y = 0; y < bitmap1.Height; y++) { for (int x = 0; x < bitmap1.Width; x++) { int intColor = r.Next(0xFFFFFF); Color color = Color.FromArgb(intColor); fastBitmap1.SetPixel(x, y, intColor); bitmap2.SetPixel(x, y, color); } } fastBitmap1.Unlock(); AssertBitmapEquals(bitmap1, bitmap2, "Calls to FastBitmap.SetPixel() with an integer overload must be equivalent to calls to Bitmap.SetPixel() with a Color with the same ARGB value as the interger"); }
public void TestGetPixel() { Bitmap original = GenerateRandomBitmap(64, 64); Bitmap copy = original.Clone(new Rectangle(0, 0, 64, 64), original.PixelFormat); FastBitmap fastOriginal = new FastBitmap(original); fastOriginal.Lock(); for (int y = 0; y < original.Height; y++) { for (int x = 0; x < original.Width; x++) { Assert.AreEqual(fastOriginal.GetPixel(x, y).ToArgb(), copy.GetPixel(x, y).ToArgb(), "Calls to FastBitmap.GetPixel() must return the same value as returned by Bitmap.GetPixel()"); } } fastOriginal.Unlock(); }
protected override Image CreateImage() { // set design-mode properties foreach (Layer layer in this.Layers) if (layer is ImageLayer) { ImageLayer imageLayer = (ImageLayer) layer; imageLayer._site = this.Site; imageLayer._designMode = this.DesignMode; } // process layers foreach (Layer layer in this.Layers) layer.Process(); // for SizeMode = Auto, we need to calculate the output dimensions // based on the combination of all layers' dimensions int outputWidth, outputHeight; if (this.AutoSize) { Rectangle outputDimensions = Rectangle.Empty; foreach (Layer layer in this.Layers) { Rectangle? bounds = layer.Bounds; if (bounds != null) outputDimensions = Rectangle.Union(outputDimensions, bounds.Value); } outputWidth = outputDimensions.Width; outputHeight = outputDimensions.Height; } else { outputWidth = this.Width.Value; outputHeight = this.Height.Value; } if (outputWidth == 0 && outputHeight == 0) return null; // create output bitmap and lock data FastBitmap output = new FastBitmap(outputWidth, outputHeight, PixelFormat.Format24bppRgb); // lock layer bitmaps and output bitmap output.Lock(); foreach (Layer layer in this.Layers) layer.Bitmap.Lock(); // calculate colors of flattened image // 1. take offsetx, offsety into consideration // 2. calculate alpha of color (alpha, opacity, mask) // 3. mix colors of current layer and layer below for (int y = 0; y < outputHeight; ++y) { for (int x = 0; x < outputWidth; ++x) { Color c0 = Color.Transparent; foreach (Layer layer in this.Layers) { Color c1 = Color.Transparent; if (x >= layer.X && x <= layer.X + layer.Bitmap.Width - 1 && y >= layer.Y && y <= layer.Y + layer.Bitmap.Height - 1) { c1 = layer.Bitmap[x - layer.X, y - layer.Y]; } if (c1.A == 255) { c0 = c1; } else { double a = c1.A / 255.0; double tr = c1.R * a + c0.R * (1.0 - a); double tg = c1.G * a + c0.G * (1.0 - a); double tb = c1.B * a + c0.B * (1.0 - a); tr = Math.Round(tr); tg = Math.Round(tg); tb = Math.Round(tb); tr = Math.Min(tr, 255); tg = Math.Min(tg, 255); tb = Math.Min(tb, 255); c0 = Color.FromArgb((byte) tr, (byte) tg, (byte) tb); } } output[x, y] = c0; } } // unlock layer bitmaps and output bitmap foreach (Layer layer in this.Layers) layer.Bitmap.Unlock(); output.Unlock(); return output.InnerBitmap; }