Working with Diff Image (Deltas) in Picturebox Control - c#

I create a picture box and on the first request to my server retrieve the full desktop and display it. On every subsequent request, I'm only getting the diff'ed image which is transparent everywhere except where there are changes.
How can I "overlay" these two images together? Or otherwise combine them in my picture box?
Thank you!

Try this:
for (var x = 0; x < sourceBitmap.Width; x++)
{
for (var y = 0; y < sourceBitmap.Height; y++)
{
var pixelColor = sourceBitmap.GetPixel(x, y);
// copy all non-transparent pixels
if (pixelColor.A != Byte.MaxValue)
{
destinationBitmap.SetPixel(x, y, pixelColor);
}
}
}
I'm assuming both sourceBitmap and destinationBitmap are System.Drawing.Bitmap objects. Source bitmap would be the one you're displaying in the picture box, but don't use the one that is returned by pictureBox.Image property, create a copy with Clone() method and then do a swap, or you'll get an exception.
If this method is too slow, you can try using direct memory access to manipulate bitmap data, using LockBits and UnlockBits methods on Bitmap objects.

Related

How to loop through all pixels of an image in a windows phone 8 app

I'm actually trying to loop through all pixels of an image in a windows phone 8 application.
Basically, in a Class Library I use this kind of "unsafe code".
unsafe {
byte* prSrc = (byte*)(void*)d;
byte* prDest = (byte*)(void*)s;
for(int y = 0; y < bitmap.height; y++)
{
for(int x = 0; x < bitmap.width; x++)
{
// do some work here
}
}
}
But in Windows Phone 8 it is not possible. Do you have a workaround or something like that ?
Thanks a lot for your help.
On Windows Phone, images can be manipulated via the WriteableBitmap class.
The WriteableBitmap class has a Pixels property that is an array containing every pixel of the image in ARGB32 format (premultiplied RGB).
The simplest way to loop and read/write on every pixel is to use WriteableBitmapEx (open source library that you can install via NuGet).
Then you can use the ForEach extension method, like this:
WriteableBitmap writeableBmp = new WriteableBitmap(myImage, null);
writeableBmp.ForEach((x, y, color) =>
{
// Read and write on the color object
return color;
});
Have a look at the msdn sample for the WriteableBitmap.PixelBuffer property

How to save a bitmap as an png in console application of c#

I am doing a console application in c#. In this app, I have to create a bitmap of png type and it has to to be stored in some defined path (say C: or D: drive).
In a windows application I have the below code to create a bitmap and it will be shown in a picture box.
void CreateBitmap()
{
System.Drawing.Bitmap flag = new System.Drawing.Bitmap(10, 10);
for( int x = 0; x < flag.Height; ++x )
for( int y = 0; y < flag.Width; ++y )
flag.SetPixel(x, y, Color.White);
for( int x = 0; x < flag.Height; ++x )
flag.SetPixel(x, x, Color.Red);
pictureBox1.Image = flag;
}
How can I create and store this in a specified path using a console application?
I have changed my code as below but still error exists:
static void CreatePng(string[] binvalues)
{
String aName = System.Reflection.Assembly.GetExecutingAssembly().Location;
String aPath = System.IO.Path.GetDirectoryName(aName);
string[] ExecDirectories = System.IO.Directory.GetDirectories(aPath);
System.Drawing.Bitmap flag = new System.Drawing.Bitmap(10, 10);
for (int x = 0; x < flag.Height; ++x)
for (int y = 0; y < flag.Width; ++y)
flag.SetPixel(x, y, Color.White);
for (int x = 0; x < flag.Height; ++x)
flag.SetPixel(x, x, Color.Red);
flag.Save(aPath, System.Drawing.Imaging.ImageFormat.Png);
}
It is showing run-time error in last line where flag.save seems something wrong?
Use the same code, and instead of assigning to a PictureBox, call the Save() method on the bitmap:
flag.Save("yourpath", System.Drawing.Imaging.ImageFormat.Png);
Note that you may have to add a reference to System.Drawing in your console application, as it is not there by default.
Now, I've never done this myself using C# so someone more inclined could possibly help but here's what I was able to find out.
1) You need to have your image data stored in a Bitmap. From the looks of things you're doing this already with flag
2) You need to call the save() function on the Bitmap:
flag.Save(filename, ImageFormat.Png);
3) filename would be a String that you define. This is fairly easy as you could simply have the application prompt the user to enter a path and save it.
Questions?
Disclaimer: I received my info from this page. There is a lot of discussion on the "proper" way to save a png you can dig from.
Use this:
flag.Save(filename, System.Drawing.Imaging.ImageFormat.Png);
You don't need to add the image to a PictureBox. You have a console application and PictureBox is a visual control.
For future questions it would be nice if you spent a minimum amount of time of searching SO or other sources for an answer first
The question is not tagged correctly. If you want to save a System.Drawing.Bitmap it can not be tagged BitmapImage as this is for WPF only. I changed this.
You can try below code-:
public bool ResizeImage(string OriginalFilepath, string NewFilepath)
{
Bitmap original = (Bitmap)Image.FromFile(OriginalFilepath);
Bitmap resized = new Bitmap(original, new Size(Width,Height));
resized.Save(NewFilepath.png);
}

Why isn't my image loading?

private void LoadImageList()
{
string filepath = Application.StartupPath + #"\Content\Textures\Tiles\PlatformTiles.png";
Bitmap tileSheet = new Bitmap(filepath);
int tilecount = 0;
for (int y = 0; y < tileSheet.Height / TileGrid.TileHeight; y++)
{
for (int x = 0; x < tileSheet.Width / TileGrid.TileWidth; x++)
{
Bitmap newBitmap = tileSheet.Clone(
new System.Drawing.Rectangle(
x * TileGrid.TileWidth,
y * TileGrid.TileHeight,
TileGrid.TileWidth,
TileGrid.TileHeight),
System.Drawing.Imaging.PixelFormat.DontCare);
imgListTiles.Images.Add(newBitmap);
string itemName = "";
if (tilecount == 0)
{
itemName = "Empty";
}
if (tilecount == 1)
{
itemName = "White";
}
listTiles.Items.Add(new ListViewItem(itemName, tilecount++));
}
}
}
All I did was update PlatformTiles.png with a newer one and the next time I ran the program it doesn't load. I placed a breakpoint at int tilecount = 0; and it doesn't ever reach it. Every thing after it doesn't load either. Any ideas?
Is that Bitmap referring to System.Drawing.Bitmap? If so your code has a memory leak. You're creating hundreds (thousands?) of Bitmap objects without disposing them. Each Bitmap object encapsulates a GDI Bitmap surface which must be explicitly disposed. Use a C# using(Bitmap bmp) { } block to ensure they're disposed when they fall out of scope, or ensure that you dispose of the bitmaps when the parent class object is disposed.
This may be related to your problem (generally it's a bad idea to create too many bitmaps in case you hit the GDI Object limit).
I got rid of the string and replaced filepatth, Bitmap tileSheet = new Bitmap(filepath);, with the path of the image on my hard-drive and it worked. Solution, but could use some explaining.
If the file is part of your content project and it's Build Action is set to Compile, the file that's in that folder at run time does not have a .png extension so the Bitmap will never be created. Content assets have a .xnb extension as they've been compiled to a binary format. Change the Build Action to None and the Copy to Output Direction to Copy if newer

Displaying moving pieces in my chess game lags, what can I do about it?

First time I ever ask a question here so correct me if I´m doing it wrong.
Picture of my chess set:
Every time I move a piece it lags for about 1 second. Every piece and tile has an Image and there is exactly 96 Images. Every time I move a piece it clears everything with black and then update the graphics.
In the early stages of the chess I didn't have any Images and used different colors instead and only a few pieces there was no noticeable lag and the piece moved in an instant.
public void updateGraphics(PaintEventArgs e, Graphics g, Bitmap frame)
{
g = Graphics.FromImage(frame);
g.Clear(Color.Black);
colorMap(g);
g.Dispose();
e.Graphics.DrawImageUnscaled(frame, 0, 0);
}
The function colorMap(g) looks like this:
private void colorMap(Graphics g)
{
for (int y = 0; y < SomeInts.amount; y++)
{
for (int x = 0; x < SomeInts.amount; x++)
{
//Tiles
Bundle.tile[x, y].colorBody(g, x, y);
//Pieces
player1.colorAll(g);
player2.colorAll(g);
}
}
}
The colorAll function executes every pieces colorBody(g) function which look like this:
public void colorBody(Graphics g)
{
//base.colorBody() does the following: body = new Rectangle(x * SomeInts.size + SomeInts.size / 4, y * SomeInts.size + SomeInts.size / 4, size, size);
base.colorBody();
if (team == 1)
{
//If its a white queen
image = Image.FromFile("textures/piece/white/queen.png");
}
if (team == 2)
{
//If its a black queen
image = Image.FromFile("textures/piece/black/queen.png");
}
g.DrawImage(image, body);
}
and finaly the function that moves the piece:
public void movePiece(MouseEventArgs e)
{
for (int y = 0; y < SomeInts.amount; y++)
{
for (int x = 0; x < SomeInts.amount; x++)
{
if (Bundle.tile[x, y].body.Contains(e.Location))
{
//Ignore this
for (int i = 0; i < queens.Count; i++)
{
Queen temp = queens.ElementAt<Queen>(i);
temp.move(x, y);
}
//Relevant
player1.move(x, y);
player2.move(x, y);
}
}
}
}
Thank you for reading all this! I could make a link to the whole program if my coding examples is not enough.
You're calling Image.FromFile in every refresh, for every image - effectively reloading every image file every time from disk.
Have you considered loading the images once, and storing the resulting Images somewhere useful? (say, an array, Image[2,6] would be adequate)
Why do you redraw the board each time? Can't you just leave the board where it is and display an image with transparent background over it? That way you have one image as a background (the board), plus 64 smaller images placed over the board in a grid and just change the image being displayed on each move.
That way, you can let windows handle the drawing...
Also, load the images of the pieces at the start of the application.
In addition to not calling Image.FromFile() inside updateGraphics() (which is definitely your biggest issue), you shouldn't be attempting to redraw the entire board every on every call to updateGraphics() - most of the time, only a small portion of the board will be invalidated.
The PaintEventArgs contains an parameter, ClipRectangle, which specifies which portion of the board needs redrawing. See if you can't figure out which tiles intersect with that rectangle, and only redraw those tiles :)
Hint: Write a function Point ScreenToTileCoords(Point) which takes a screen coordinate and returns which board-tile is at that coordinate. Then the only tiles you need to redraw are
Point upperLeftTileToBeDrawn = ScreenToTileCoords(e.ClipRectangle.Left, e.ClipRectangle.Top);
Point lowerRightTileToBeDrawn = ScreenToTileCoords(e.ClipRectangle.Right - 1, e.ClipRectangle.Bottom- 1);
Also, make sure your control is double-buffered, to avoid tearing. This is much simpler than #Steve B's link in the comments above states; assuming this is a UserControl, simply set
this.DoubleBuffered = true;
Well, what about this:
Do not clear the whole board but only those parts that need to be cleared.
Alternative:
Update to WPF - it moves drawing to the graphics card - and just move pieces around, in a smart way (i.e. have a control / object for every piece).

How can I get a convert a Graphics object to a Bitmap (or access it as a Bitmap)

I know the whole
Bitmap bmp = new Bitmap(100,100) ;
Graphics graphics = Graphics.FromImage(bmp) ;
But that is not what I need to do. Essentially what I am trying to do is slightly modify how something is draw on the screen (it is a rectangle with a line in the middle). I need to change the background of the rectangle (which I could do with a pixel comparison or other similar method).
If I could somehow turn it into a bitmap. There is no way (that I can tell to get/set/modify) the graphics object on the pixel level.
Bob Powell has written an excellent article about accessing image bits directly.
https://web.archive.org/web/20141229164101/http://bobpowell.net/lockingbits.aspx
Once you've used the Graphics, just save the Bitmap - the changes made with the graphics are made to the bitmap.
You could do this using a for loop like so:
for(int i = 0; i < bmp.Width; i++)
{
for(int j = 0; j < bmp.Height; j++)
{
var pixel = bmp.GetPixel(i, j);
//do stuff with pixel here :)
}
}
EDIT: After seeing Tilak's comment, if performance is an issue for you then he is right! (Thanks, I did not know about LockBits! +1) Some examples can be found on the MS BitmapData Class page. However, if this seems complicated the above method should do the trick :)

Categories