I have a requirement wherein I need to merge two different png/jpeg images resulting into a single image using C#.Net. There will be a particular location defined on the source image wherein I need to insert another image. Can anybody suggest some links ?
This method merge two images one in the top of the other you can modify the code to meet for your needs:
public static Bitmap MergeTwoImages(Image firstImage, Image secondImage)
{
if (firstImage == null)
{
throw new ArgumentNullException("firstImage");
}
if (secondImage == null)
{
throw new ArgumentNullException("secondImage");
}
int outputImageWidth = firstImage.Width > secondImage.Width ? firstImage.Width : secondImage.Width;
int outputImageHeight = firstImage.Height + secondImage.Height + 1;
Bitmap outputImage = new Bitmap(outputImageWidth, outputImageHeight, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
using (Graphics graphics = Graphics.FromImage(outputImage))
{
graphics.DrawImage(firstImage, new Rectangle(new Point(), firstImage.Size),
new Rectangle(new Point(), firstImage.Size), GraphicsUnit.Pixel);
graphics.DrawImage(secondImage, new Rectangle(new Point(0, firstImage.Height + 1), secondImage.Size),
new Rectangle(new Point(), secondImage.Size), GraphicsUnit.Pixel);
}
return outputImage;
}
After all this, I found a new easier method try this ..
It can join multiple photos together:
public static System.Drawing.Bitmap CombineBitmap(string[] files)
{
//read all images into memory
List<System.Drawing.Bitmap> images = new List<System.Drawing.Bitmap>();
System.Drawing.Bitmap finalImage = null;
try
{
int width = 0;
int height = 0;
foreach (string image in files)
{
//create a Bitmap from the file and add it to the list
System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(image);
//update the size of the final bitmap
width += bitmap.Width;
height = bitmap.Height > height ? bitmap.Height : height;
images.Add(bitmap);
}
//create a bitmap to hold the combined image
finalImage = new System.Drawing.Bitmap(width, height);
//get a graphics object from the image so we can draw on it
using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(finalImage))
{
//set background color
g.Clear(System.Drawing.Color.Black);
//go through each image and draw it on the final image
int offset = 0;
foreach (System.Drawing.Bitmap image in images)
{
g.DrawImage(image,
new System.Drawing.Rectangle(offset, 0, image.Width, image.Height));
offset += image.Width;
}
}
return finalImage;
}
catch (Exception)
{
if (finalImage != null)
finalImage.Dispose();
//throw ex;
throw;
}
finally
{
//clean up memory
foreach (System.Drawing.Bitmap image in images)
{
image.Dispose();
}
}
}
Disclaimer: I work at Atalasoft
Our DotImage Photo SDK (which is free) can do this.
To open an image
AtalaImage botImage = new AtalaImage("bottomImage.png");
AtalaImage topImage = new AtalaImage("topImage.png");
To overlay one on top of another
Point pos = new Point(0,0); // or whatever you need
OverlayCommand cmd = new OverlayCommand(topImage, pos);
ImageResults res = cmd.Apply(botImage);
If you need the resulting image to be a different size, look at the CanvasCommand. You could also create an AtalaImage of the size you need, then overlay each image onto it.
To save
botImage.Save("newImage.png", new PngEncoder(), null);
String jpg1 = #"c:\images.jpeg";
String jpg2 = #"c:\images2.jpeg";
String jpg3 = #"c:\image3.jpg";
Image img1 = Image.FromFile(jpg1);
Image img2 = Image.FromFile(jpg2);
int width = img1.Width + img2.Width;
int height = Math.Max(img1.Height, img2.Height);
Bitmap img3 = new Bitmap(width, height);
Graphics g = Graphics.FromImage(img3);
g.Clear(Color.Black);
g.DrawImage(img1, new Point(0, 0));
g.DrawImage(img2, new Point(img1.Width, 0));
g.Dispose();
img1.Dispose();
img2.Dispose();
img3.Save(jpg3, System.Drawing.Imaging.ImageFormat.Jpeg);
img3.Dispose();
private void Merge _Click(object sender, EventArgs e)
{
}
DirectoryInfo directory=new DirectoryInfo("D:\\Images");
if(directory!=null)
{
FileInfo[]files = directory.GetFiles();
MergeImages(Image);
}
private void MergeImages(FileInfo[] Image)
{
//change the location to store the final image.
string FImage= #"D:\\Images\\FImage.jpg";
List imageHeights = new List();
int nIndex = 0;
int width = 0;
foreach (FileInfo file in files)
{
Image img = Image.FromFile(file.FullName);
imageHeights.Add(img.Height);
width += img.Width;
img.Dispose();
}
imageHeights.Sort();
int height = imageHeights[imageHeights.Count - 1];
Bitmap NewImg = new Bitmap(width, height);
Graphics Gr= Graphics.FromImage(NewImg);
Gr.Clear(SystemColors.AppWorkspace);
foreach (FileInfo file in files)
{
Image img = Image.FromFile(file.FullName);
if (nIndex == 0)
{
Gr.DrawImage(img, new Point(0, 0));
nIndex++;
width = img.Width;
}
else
{
Gr.DrawImage(img, new Point(width, 0));
width += img.Width;
}
img.Dispose();
}
Gr.Dispose();
NewImg .Save(FImage, System.Drawing.Imaging.ImageFormat.Jpeg);
NewImg .Dispose();
imageLocation.Image = Image.FromFile(FImage);
}
Related
I currently work on image processing application. I have 'Main' PictureBox as canvas. I want to insert some PictureBox into 'Main' PictureBox and merge all as one Image then save it to png. This is my code. Can anybody help me to acccomplish this task please?
Bitmap bmp = new Bitmap(pictureEdit.Width, pictureEdit.Height);
bmp = (Bitmap)pictureEdit.Image;
foreach (Control c in pictureEdit.Controls)
{
if (c is Functions.pictureEdit)
{
using (var bitmap = new Bitmap(pictureEdit.Image.Width, pictureEdit.Image.Height)) {
using (var canvas = Graphics.FromImage(bitmap)) {
canvas.DrawImage(bmp, new Rectangle(0, 0, pictureEdit.Image.Width, pictureEdit.Image.Height));
canvas.DrawImage(((Functions.pictureEdit)c).img, new Rectangle(0, 0, pictureEdit.Image.Width, pictureEdit.Image.Height));
canvas.Save();
}
bitmap.Save(#"D:\Test\new.png", System.Drawing.Imaging.ImageFormat.Png);
}
}
}
Hope you are okay with Combining images together
Following code does that
private Bitmap CombineBitmap(List lstImages, int width, int height)
{
int iTilesPerWidth = 5;
//create a bitmap to hold the combined image
Bitmap finalImage = new System.Drawing.Bitmap(width, height);
//get a graphics object from the image so we can draw on it
using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(finalImage))
{
PointF point1 = new PointF(0, 0);
int nCount = 1;
foreach (Bitmap BM in lstImages)
{
//512, 256
g.DrawImage(BM, point1);
point1.X += BM.Width;
if (nCount % iTilesPerWidth == 0)
{
point1.X = 0;
point1.Y += BM.Height;
}
nCount++;
}
}
return finalImage;
}
i want to watermark pictures with different sizes in one folder. the watermark has 3891 x 4118 pixels. the pictures i want to watermark have nearly the same size or way lower.
however, the watermark image should always have the same size on the images. therefore i take the width of image i want to watermark, multiple it by 0.2 (20%) and the height of the watermark image gets calculated by the ratio. (see code below).
after that, i resize the watermark image and put it on on the image i want to watermark. so far so good, but the problem is, that the image is way smaller than it should be. the calculation works fine, even if i say, put the image as is (3891 x 4118 pixel), it calculates it correctly, but the watermark doesn't get bigger. it stays on a size i didn't calulcate.
that's the button to load the folder.
private void DateiLaden_Click(object sender, RoutedEventArgs e)
{
FolderBrowserDialog fbd = new FolderBrowserDialog();
DialogResult result = fbd.ShowDialog();
try
{
string[] files = GetFiles(fbd.SelectedPath.ToString(), "*.jpg|*.jpeg"); //Only select JPG pictures, method below
int anzahlBilder = files.Length;
if (anzahlBilder <= 0)
{
System.Windows.Forms.MessageBox.Show("No images!");
} // if there are no images, stop processing...
else
{
var res = checkImageSize(files); //check if they have a minmal size, method below
if (res == "") //if everythings fine, continue
{
Directory.CreateDirectory(fbd.SelectedPath.ToString() + "\\watermarked"); //create new directory of the selected folder, folder so save the watermarked images
System.Drawing.Image brand = System.Drawing.Image.FromFile("../../watermark.png"); //load watermark
double imageHeightBrand = Convert.ToDouble(brand.Height); //get height (4118px)
double imageWidthBrand = Convert.ToDouble(brand.Width); //get width (3891px)
double ratioBrand = imageWidthBrand / imageHeightBrand; //get ratio (0.94487615347)
foreach (var file in files)
{
System.Drawing.Image img = System.Drawing.Image.FromFile(file); //load image to watermerk to get width and height
double imageHeightBild = Convert.ToDouble(img.Height); //height of the image to watermark
double imageWidthBild = Convert.ToDouble(img.Width); //width of the image to watermark
//Landscape
if (imageWidthBild > 640.0 && imageHeightBild > 425.0)
{
var imageWidthTmpBranding = imageWidthBild * 0.2; //the watermark width, but only 20% size of the image to watermark
var imageHeightTmpBranding = imageWidthTmpBranding / ratioBrand; //height of watermark, preserve aspect ratio
int imageWidthBranding = Convert.ToInt32(imageWidthTmpBranding); //convert in into int32 (see method below)
int imageHeightBranding = Convert.ToInt32(imageHeightTmpBranding); //convert in into int32 (see method below)
var watermark = ResizeImage(brand, imageWidthBranding, imageHeightBranding); //resize temporally the watermark image, method below
System.Drawing.Image image = System.Drawing.Image.FromFile(file); //get image to watermark
Graphics g = Graphics.FromImage(image); //load is as graphic
g.DrawImage(watermark, new System.Drawing.Point(50, 50)); //draw the watermark on it
image.Save(fbd.SelectedPath.ToString() + "\\watermarked\\" + returnOnlyImageName(file)); //save it in the folder with the same file name, see method below.
}
//Portrait
/* if(imageWidthBild > 350 && imageHeightBild > 520) {
}*/
}
}
else
{
System.Windows.Forms.MessageBox.Show(res);
}
}
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message);
}
}
"methods below"
private static string[] GetFiles(string sourceFolder, string filters)
{
return filters.Split('|').SelectMany(filter => System.IO.Directory.GetFiles(sourceFolder, filter)).ToArray();
}
private static string checkImageSize(string[] files)
{
string message = "The following pictures are too small:\n";
foreach (var file in files)
{
Bitmap img = new Bitmap(file);
var imageHeight = img.Height;
var imageWidth = img.Width;
if ((imageWidth < 640 && imageHeight < 425) || (imageWidth < 350 && imageHeight < 520))
{
message += returnOnlyImageName(file) + "\n";
}
}
if (message == "The following pictures are too small:\n")
{
return "";
}
else
{
message += "\nPlease change those pictures!";
return message;
}
}
private static string returnOnlyImageName(string file)
{
return file.Substring(file.LastIndexOf("\\")+1);
}
public static Bitmap ResizeImage(System.Drawing.Image image, int width, int height)
{
var destRect = new System.Drawing.Rectangle(0, 0, width, height);
var destImage = new Bitmap(width, height);
destImage.SetResolution(image.HorizontalResolution, image.VerticalResolution);
using (var graphics = Graphics.FromImage(destImage))
{
graphics.CompositingMode = CompositingMode.SourceCopy;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
using (var wrapMode = new ImageAttributes())
{
wrapMode.SetWrapMode(WrapMode.TileFlipXY);
graphics.DrawImage(image, destRect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, wrapMode);
}
}
return destImage;
}
and is it also anyhow possible to save all the watermarks in the bottom right corner?
thanks in regards
Here you go...
void waterMarkOnBottomRight(Image img, Image watermarkImage, string saveFileName)
{
double imageHeightBrand = Convert.ToDouble(watermarkImage.Height);
double imageWidthBrand = Convert.ToDouble(watermarkImage.Width);
double ratioBrand = imageWidthBrand / imageHeightBrand;
double imageHeightBild = Convert.ToDouble(img.Height); //height of the image to watermark
double imageWidthBild = Convert.ToDouble(img.Width);
var imageWidthTmpBranding = imageWidthBild * 0.2; //the watermark width, but only 20% size of the image to watermark
var imageHeightTmpBranding = imageWidthTmpBranding / ratioBrand; //height of watermark, preserve aspect ratio
int imageWidthBranding = Convert.ToInt32(imageWidthTmpBranding); //convert in into int32 (see method below)
int imageHeightBranding = Convert.ToInt32(imageHeightTmpBranding);
int watermarkX = (int)(imageWidthBild - imageWidthBranding); // Bottom Right
int watermarkY = (int)(imageHeightBild - imageHeightBranding);
using (Graphics g = Graphics.FromImage(img))
g.DrawImage(watermarkImage,
new Rectangle(watermarkX, watermarkY, imageWidthBranding, imageHeightBranding),
new Rectangle(0, 0, (int)imageWidthBrand, (int)imageHeightBrand),
GraphicsUnit.Pixel);
img.Save(saveFileName);
}
This one's working for landscape (width > height).
Well.. in your code, you don't have to create separate instances for images for calculating, for creating graphics, add a new bitmap and paint using graphics and all. You do anything with the image, its in the memory. And its not going to affect the watermark image on your disk.
Simple idea: I have two images that I want to merge, one is 500x500 that is transparent in the middle the other one is 150x150.
Basic idea is this: Create an empty canvas that is 500x500, position the 150x150 image in the middle of the empty canvas and then copy the 500x500 image over so that the transparent middle of it allows the 150x150 to shine through.
I know how to do it in Java, PHP and Python... I just don't have any idea what objects/classes to use in C#, a quick example of copying an images into another would suffice.
basically i use this in one of our apps:
we want to overlay a playicon over a frame of a video:
Image playbutton;
try
{
playbutton = Image.FromFile(/*somekindofpath*/);
}
catch (Exception ex)
{
return;
}
Image frame;
try
{
frame = Image.FromFile(/*somekindofpath*/);
}
catch (Exception ex)
{
return;
}
using (frame)
{
using (var bitmap = new Bitmap(width, height))
{
using (var canvas = Graphics.FromImage(bitmap))
{
canvas.InterpolationMode = InterpolationMode.HighQualityBicubic;
canvas.DrawImage(frame,
new Rectangle(0,
0,
width,
height),
new Rectangle(0,
0,
frame.Width,
frame.Height),
GraphicsUnit.Pixel);
canvas.DrawImage(playbutton,
(bitmap.Width / 2) - (playbutton.Width / 2),
(bitmap.Height / 2) - (playbutton.Height / 2));
canvas.Save();
}
try
{
bitmap.Save(/*somekindofpath*/,
System.Drawing.Imaging.ImageFormat.Jpeg);
}
catch (Exception ex) { }
}
}
This will add an image to another.
using (Graphics grfx = Graphics.FromImage(image))
{
grfx.DrawImage(newImage, x, y)
}
Graphics is in the namespace System.Drawing
After all this, I found a new easier method try this ..
It can join multiple photos together:
public static System.Drawing.Bitmap CombineBitmap(string[] files)
{
//read all images into memory
List<System.Drawing.Bitmap> images = new List<System.Drawing.Bitmap>();
System.Drawing.Bitmap finalImage = null;
try
{
int width = 0;
int height = 0;
foreach (string image in files)
{
//create a Bitmap from the file and add it to the list
System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(image);
//update the size of the final bitmap
width += bitmap.Width;
height = bitmap.Height > height ? bitmap.Height : height;
images.Add(bitmap);
}
//create a bitmap to hold the combined image
finalImage = new System.Drawing.Bitmap(width, height);
//get a graphics object from the image so we can draw on it
using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(finalImage))
{
//set background color
g.Clear(System.Drawing.Color.Black);
//go through each image and draw it on the final image
int offset = 0;
foreach (System.Drawing.Bitmap image in images)
{
g.DrawImage(image,
new System.Drawing.Rectangle(offset, 0, image.Width, image.Height));
offset += image.Width;
}
}
return finalImage;
}
catch (Exception ex)
{
if (finalImage != null)
finalImage.Dispose();
throw ex;
}
finally
{
//clean up memory
foreach (System.Drawing.Bitmap image in images)
{
image.Dispose();
}
}
}
DrawImage method of Graphics class is not creating high quality images. In this method I am splitting a master image into multiple image but the code generating first image in very low quality. But it is generating full black images for remaining height.
public static Bitmap[] Split(byte[] ByteImage)
{
// MasterImage: there is no problem in master image. it is saving it in good quality.
MemoryStream ms = new MemoryStream(ByteImage);
System.Drawing.Image MasterImage = System.Drawing.Image.FromStream(ms);
MasterImage.Save(HttpContext.Current.Server.MapPath("../../../App_Shared/Reports/Temp/MasterImage.Bmp"), ImageFormat.Bmp);
//Split master image into multiple image according to height / 1000
Int32 ImageHeight = 1000, ImageWidth = MasterImage.Width, MasterImageHeight = MasterImage.Height;
int PageCount = 0;
Int32 TotalPages = MasterImage.Height / 1000;
Bitmap[] imgs = new Bitmap[TotalPages];
for (int y = 0; y + 1000 < MasterImageHeight; y += 1000, PageCount++)
{
imgs[PageCount] = new Bitmap(ImageWidth, ImageHeight, PixelFormat.Format32bppPArgb);
using (Graphics gr = Graphics.FromImage(imgs[PageCount]))
{
gr.CompositingQuality = CompositingQuality.HighQuality;
gr.InterpolationMode = InterpolationMode.HighQualityBicubic;
gr.SmoothingMode = SmoothingMode.HighQuality;
//First image now working with this code line
gr.DrawImage(MasterImage, new System.Drawing.Rectangle(0, y, ImageWidth, ImageHeight),new System.Drawing.Rectangle(0, 0, ImageWidth, ImageHeight), GraphicsUnit.Pixel); //new System.Drawing.Rectangle(new Point(0, y), new Size(ImageWidth, ImageHeight)));
//gr.DrawImage(MasterImage, new System.Drawing.Rectangle(0, y, ImageWidth, ImageHeight)); //new System.Drawing.Rectangle(new Point(0, y), new Size(ImageWidth, ImageHeight)));
string FilePath = HttpContext.Current.Server.MapPath("../../../App_Shared/Reports/Temp/Image" + PageCount.ToString() + ".bmp");
imgs[PageCount].Save(FilePath, System.Drawing.Imaging.ImageFormat.Bmp);
//Here it is saving images. I got first image with very poor quality but remaining in total balck color.
gr.Dispose();
}
}
return imgs;
}
As #HansPassant mentioned the source and target rectangle are reversed.
You could also change the structure of your splitting a bit so it could work a bit more flexible, and it might have a better readability at a later time.
class Program
{
static IList<Bitmap> SplitImage(Bitmap sourceBitmap, int splitHeight)
{
Size dimension = sourceBitmap.Size;
Rectangle sourceRectangle = new Rectangle(0, 0, dimension.Width, splitHeight);
Rectangle targetRectangle = new Rectangle(0, 0, dimension.Width, splitHeight);
IList<Bitmap> results = new List<Bitmap>();
while (sourceRectangle.Top < dimension.Height)
{
Bitmap pageBitmap = new Bitmap(targetRectangle.Size.Width, sourceRectangle.Bottom < dimension.Height ?
targetRectangle.Size.Height
:
dimension.Height - sourceRectangle.Top, PixelFormat.Format32bppArgb);
using (Graphics g = Graphics.FromImage(pageBitmap))
{
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBilinear;
g.DrawImage(sourceBitmap, targetRectangle, sourceRectangle, GraphicsUnit.Pixel);
}
sourceRectangle.Y += sourceRectangle.Height;
results.Add(pageBitmap);
}
return results;
}
static void Main(string[] args)
{
string sourceFilename = Environment.CurrentDirectory + #"\testimage.jpg";
Bitmap sourceBitmap = (Bitmap)Image.FromFile(sourceFilename);
var images = SplitImage(sourceBitmap, 79);
int len = images.Count;
for (int x = len; --x >= 0; )
{
var bmp = images[x];
string filename = "Images-" + x + ".bmp";
bmp.Save(Environment.CurrentDirectory + #"\" + filename, ImageFormat.Bmp);
images.RemoveAt(x);
bmp.Dispose();
Console.WriteLine("Saved " + filename);
}
Console.WriteLine("Done with the resizing");
}
}
This would also dynamically size the last image in case the page is less than your specified bitmap height at the end :)
I am getting a screenshot of the computer, then setting it as a picture box by copying it and then using it but after the first time it does it, it says the picture is being used by another process but im guessing i just dungoofed.
public void UpdatePic()
{
String newtemp = System.Environment.GetFolderPath(Environment.SpecialFolder.MyPictures) + "\\screentemp.png";
if (File.Exists(newtemp)) { File.Delete(newtemp); }
File.Copy(screendirect, newtemp);
Image image = Image.FromFile(newtemp);
try
{
using (Bitmap tempBitmap = new Bitmap(image))
{
Size size = new Size(pictureBox1.Width, pictureBox1.Height);
Bitmap backgroundBitmap = new Bitmap(size.Width, size.Height);
using (Graphics g = Graphics.FromImage(backgroundBitmap))
{
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
// Get the set of points that determine our rectangle for resizing.
Point[] corners = { new Point(0, 0), new Point(backgroundBitmap.Width, 0), new Point(0, backgroundBitmap.Height)};
g.DrawImage(tempBitmap, corners);
g.Dispose();
}
pictureBox1.Image = backgroundBitmap;
}
}
finally
{
}
}