Composition from multiple images using C#.NET - c#

I have a PictureBox on which images from files are painted, one on top of another (like a photoshop layering concept, if you're familiar). Being PNGs and with a opacity index, these images are perfect candidates for a image composition. But I can't figure out how to do that and save to a file.
In the following code sample, I've loaded two PNG images into bitmap objects and had them painted on the PictureBox.
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
Rectangle DesRec = new Rectangle(0, 0, pictureBox1.Width, pictureBox1.Height);
Bitmap bmp;
Rectangle SrcRec;
bmp = (Bitmap)Image.FromFile(Application.StartupPath + "\\Res\\base.png");
SrcRec = new Rectangle(0, 0, bmp.Width, bmp.Height);
e.Graphics.DrawImage(bmp, DesRec, SrcRec, GraphicsUnit.Pixel);
bmp = (Bitmap)Image.FromFile(Application.StartupPath + "\\Res\\layer1.png");
SrcRec = new Rectangle(0, 0, bmp.Width, bmp.Height);
e.Graphics.DrawImage(bmp, DesRec, SrcRec, GraphicsUnit.Pixel);
}
How do I save the composition to a file, preferably to another PNG file?

I would start drawing to an intermediate in-memory bitmap, which I would then save (and eventually draw in your picture box, if really needed). Something like this:
var bmp = new Bitmap(pictureBox1.Width, pictureBox1.Height);
using (var graphics = Graphics.FromImage(bmp))
{
// ...
graphics.DrawImage(...);
// ...
}
bmp.Save("c:\\test.png", ImageFormat.Png);

Thanks both of you. I've decided to do as Efran Cobisi suggested and changed the program so that it does the composing in memory first. Then I can use it where ever and however I want.
My new code to reflect the changes is as follows-
// Image objects to act as layers (which will hold the images to be composed)
Image Layer0 = new Bitmap(Application.StartupPath + "\\Res\\base.png");
Image Layer1 = new Bitmap(Application.StartupPath + "\\Res\\layer1.png");
//Creating the Canvas to draw on (I'll be saving/using this)
Image Canvas = new Bitmap(222, 225);
//Frame to define the dimentions
Rectangle Frame = new Rectangle(0, 0, 222, 225);
//To do drawing and stuffs
Graphics Artist = Graphics.FromImage(Canvas);
//Draw the layers on Canvas
Artist.DrawImage(Layer0, Frame, Frame, GraphicsUnit.Pixel);
Artist.DrawImage(Layer1, Frame, Frame, GraphicsUnit.Pixel);
//Free up resources when required
Artist.dispose();
//Show the Canvas in a PictureBox
pictureBox1.Image = Canvas;
//Save the Canvas image
Canvas.Save("MYIMG.PNG", ImageFormat.Png);
Apparently, the images (Canvas) are being saved with opacity index intact.

Related

Screenshot conversion into grayscale doesn't work. What causes this?

I have a Windows Forms application that takes a screenshot of a specific portion of the screen, then displays it in a picture box (pictureBox1). It works when I don't try to convert it, but I want to convert the image to grayscale or black and white. The problem is when I convert it to grayscale, it still shows the original picture in the picture box.
Here is the code when it works, without the conversion:
private void button1_Click(object sender, EventArgs e)
{
Rectangle rectangle = new Rectangle(660, 200, 600, 100);
pictureBox1.Height = rectangle.Height;
pictureBox1.Width = rectangle.Width;
imageUploader(rectangle);
}
public void imageUploader(Rectangle rectangle)
{
Bitmap bitmap = new Bitmap(rectangle.Width, rectangle.Height, PixelFormat.Format32bppArgb);
Graphics graphics = Graphics.FromImage(bitmap);
graphics.CopyFromScreen(rectangle.Left, rectangle.Top, 0, 0, bitmap.Size, CopyPixelOperation.SourceCopy);
bitmap.Save("proba.jpeg", ImageFormat.Jpeg);
pictureBox1.Image = bitmap;
}
Here is the conversion method, which I tried out:
public void toGrayscale(Bitmap bitmap)
{
Color c;
for (int y = 0; y < bitmap.Height; y++)
{
for (int x = 0; x < bitmap.Width; x++)
{
c = bitmap.GetPixel(x,y);
Color newColor = Color.FromArgb(c.R,0,0);
bitmap.SetPixel(x,y,newColor);
}
}
}
After I used this conversion (see below) the image showed up in the picture box, but it wasn't grayscale.
Here is the modified imageUploader void with the conversion:
public void imageUploader(Rectangle rectangle)
{
Bitmap bitmap = new Bitmap(rectangle.Width, rectangle.Height, PixelFormat.Format32bppArgb);
toGrayscale(bitmap);
Graphics graphics = Graphics.FromImage(bitmap);
graphics.CopyFromScreen(rectangle.Left, rectangle.Top, 0, 0, bitmap.Size, CopyPixelOperation.SourceCopy);
bitmap.Save("proba.jpeg", ImageFormat.Jpeg);
pictureBox1.Image = bitmap;
}
It appears that your issue is here:
public void imageUploader(Rectangle rectangle)
{
Bitmap bitmap = new Bitmap(rectangle.Width, rectangle.Height, PixelFormat.Format32bppArgb);
toGrayscale(bitmap);
Graphics graphics = Graphics.FromImage(bitmap);
graphics.CopyFromScreen(rectangle.Left, rectangle.Top, 0, 0, bitmap.Size, CopyPixelOperation.SourceCopy);
bitmap.Save("proba.jpeg", ImageFormat.Jpeg);
pictureBox1.Image = bitmap;
}
You're converting each pixel of the bitmap to greyscale (oddly it looks like you're only grabbing the red channel) then copying from the screen, which overwrites your conversion. To fix it, all you should need to do is move the toGreyscale after you copy from the screen, like this:
public void imageUploader(Rectangle rectangle)
{
Bitmap bitmap = new Bitmap(rectangle.Width, rectangle.Height, PixelFormat.Format32bppArgb);
Graphics graphics = Graphics.FromImage(bitmap);
graphics.CopyFromScreen(rectangle.Left, rectangle.Top, 0, 0, bitmap.Size, CopyPixelOperation.SourceCopy);
toGrayscale(bitmap); # Moved after the copy from screen
bitmap.Save("proba.jpeg", ImageFormat.Jpeg);
pictureBox1.Image = bitmap;
}
This should fix the issue.
You are converting an empty Bitmap to greyscale, then copying over the (nominally) greyscaled Bitmap with an image from the screen. Here is your code, annotated to describe what it is doing:
// This line creates an empty Bitmap.
Bitmap bitmap = new Bitmap(rectangle.Width, rectangle.Height, PixelFormat.Format32bppArgb);
// This line converts the empty Bitmap to grayscale.
toGrayscale(bitmap);
// This line creates a Graphics drawing surface from your bitmap.
Graphics graphics = Graphics.FromImage(bitmap);
// This line overwrites the image data from your bitmap with an image from the screen.
graphics.CopyFromScreen(rectangle.Left, rectangle.Top, 0, 0, bitmap.Size, CopyPixelOperation.SourceCopy);
You need to find some way to take the data you got from the screen and make it greyscale. You have not done this. You have made a greyscale image, but then you have thrown it away by writing other data on top of it. It happens that that replacement data is not greyscale.

how to draw a part of a png image c#

I'm trying to draw a part of a .png image but the code i found is not working. this is my code
//define canvas
canvas = pb.CreateGraphics();
sPicture = new Bitmap(pb.Width, pb.Height);
sCanvas = Graphics.FromImage(sPicture);
// Create a Bitmap object from a file.
Image image = Image.FromFile(#"");
// Clone a portion of the Bitmap object.
Rectangle cloneRect = new Rectangle(0, 0, 11, 6);
System.Drawing.Imaging.PixelFormat format =
image.PixelFormat;
Image cloneBitmap = image.Clone(cloneRect, format); //Error: No overload for method 'Clone' takes2 arguments
// Draw the cloned portion of the Bitmap object.
canvas.DrawImage(cloneBitmap, 0, 0);
This is for a sprite sheet and thanks.
You don't need to use Clone(), you can do this directly with Graphics.DrawImage(). It looks like you are trying to do this in WinForms. If, so handle OnPaint for the control you want to draw on. In the example below I'm drawing directly on the form.
private void Form1_Paint(object sender, PaintEventArgs e)
{
Graphics graphics = e.Graphics;
int width = 60;
int height = 60;
// Create a Bitmap object from a file.
Image sourceImage = Image.FromFile(#"C:\Users\Mike\Downloads\logo.png");
// Draw a portion of the source image.
Rectangle sourceRect = new Rectangle(0, 0, width, height);
graphics.DrawImage(sourceImage, 0, 0, sourceRect, GraphicsUnit.Pixel);
}
If you want to do this without WinForms, there is the extra step of creating the target Graphics instance.
int width = 60;
int height = 60;
// Create a Bitmap object from a file.
Image sourceImage = Image.FromFile(#"C:\Users\Mike\Downloads\logo.png");
// Create a drawing target
Bitmap bitmap = new Bitmap(width, height, sourceImage.PixelFormat);
Graphics graphics = Graphics.FromImage(bitmap);
// Draw a portion of the source image.
Rectangle sourceRect = new Rectangle(0, 0, width, height);
graphics.DrawImage(sourceImage, 0, 0, sourceRect, GraphicsUnit.Pixel);
// Save
bitmap.Save(#"C:\Users\Mike\Downloads\out.png");

how do i merge multiple images into a single image ?

I have an array of Images all of the same size . I should add them to a new image like i have shown in the picture.
Different colors represent different images.
Identify the size of final image
Create a bitmap with final height and width var bitmap = new Bitmap(width, height);
Draw each image on canvas
using (var canvas = Graphics.FromImage(bitmap))
{
canvas.InterpolationMode = InterpolationMode.HighQualityBicubic;
//Draw each image (maybe use a loop to loop over images to draw)
canvas.DrawImage(someImage, new Rectangle(0, 0, width, height), new Rectangle(0, 0, Frame.Width, Frame.Height), GraphicsUnit.Pixel);
canvas.Save();
}
Save the final image bitmap.Save("image path", ImageFormat.Jpeg);

C# Graphics shown in Form but not in Bitmap

I'm using C# and I would like to draw some polygons on a Form, then to save the graphics in a Bitmap.
Following this question answers I wrote a method in my Form class:
private void draw_pol()
{
Graphics d = this.CreateGraphics();
// drawing stuff
Bitmap bmp = new Bitmap(this.Width, this.Height, d);
bmp.Save("image.bmp");
}
In this way the Form displays correctly the graphics and the Bitmap file named "image.bmp" is created, but that file is a white image.
Why isn't the bmp file showing any image? What I'm doing wrong?
Thank you very much.
The graphics parameter you are passing to your bitmap is only used to specify the resolution of the bitmap. It does not in any way paint to the bitmap.
from MSDN:
The new Bitmap that this method creates takes its horizontal and vertical resolution from the DpiX and DpiY properties of g, respectively.
Instead, use Graphics.FromImage() to get a Graphics object you can use. Moreover, you should Dispose the Graphics object after painting. This is an ideal usage for the using statement.
Bitmap bmp = new Bitmap(this.Width, this.Height);
using (Graphics g = Graphics.FromImage(bmp))
{
//paint stuff
}
bmp.Save(yourFile);
If you also need to paint this to the form, you can easily just draw the bitmap you created:
Graphics g = this.CreateGraphics();
g.DrawImage(bmp, 0, 0);
A Graphics instance only operates on one Bitmap. It's either the one you want to save, or the one on your form.
You can for example do this to render the drawn bitmap on your form and save it afterwards:
private void DrawOnBitmap()
{
using (var bitmap = new Bitmap(this.Width, this.Height))
{
using (var bitmapGraphics = Graphics.FromImage(bitmap))
{
// Draw on the bitmap
var pen = new Pen(Color.Red);
var rect = new Rectangle(20, 20, 100, 100);
bitmapGraphics.DrawRectangle(pen, rect);
// Display the bitmap on the form
using (var formGraphics = this.CreateGraphics())
{
formGraphics.DrawImage(bitmap, new Point(0, 0));
}
// Save the bitmap
bitmap.Save("image.bmp");
}
}
}
you need a graphics object that represents the bitmap,so that you can draw on image.do lke this:
create the bitmap object
create the graphics object using Graphics.FromImage method
pass bitmap object as argument to graphics object
Bitmap bmp = new Bitmap(this.Width, this.Height, d);
bmp.Save("image.bmp");//for your need
Graphics d=Graphics.FromImage(bmp);

Resize GIF and save animation?

I'm using this code i wrote to resize my images to fit my PictureBox:
//Creates a new Bitmap as the size of the window
Bitmap bmp = new Bitmap(this.Width, this.Height);
//Creates a new graphics to handle the image that is coming from the stream
Graphics g = Graphics.FromImage((Image)bmp);
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
//Resizes the image from the stream to fit our windows
g.DrawImage(Properties.Resources.loading, 0, 0, this.Width, this.Height);
this.Image = (Image)bmp;
Works perfect !
The only problam is when im trying to resize a GIF... it resizes but i lose the animation...
Any fix for that?
You should simply set the PictureBox's SizeMode to StretchImage to make the PictureBox stretch the image for you.

Categories