'System.Runtime.InteropServices.ExternalException' - c#

I keep getting this error of 'System.Runtime.InteropServices.ExternalException' on line 70 "img3.Save(finalImage, System.Drawing.Imaging.ImageFormat.Jpeg);". Originally I had a program that stitched two photos together that worked fine, but I wanted the two images to be the same size (300 pixles by 300 pixles) so I inserted a method:
public static Image resizeImage(Image imgToResize, Size size)
{
return (Image)(new Bitmap(imgToResize, size));
}
and in my CombineImages method put:
img = resizeImage(img, new Size(300, 300));
but now I am getting an error. Here is my code:
private void cmdCombine_Click(object sender, EventArgs e)
{
//Change the path to location where your images are stored.
DirectoryInfo directory = new DirectoryInfo(#"C:\Users\Elder Zollinger\Desktop\Images");
if (directory != null)
{
FileInfo[] files = directory.GetFiles();
CombineImages(files);
}
}
private void CombineImages(FileInfo[] files)
{
//change the location to store the final image.
string finalImage = #"C:\Users\Elder Zollinger\Desktop\Images\Final.jpg";
List<int> imageHeights = new List<int>();
int nIndex = 0;
int width = 0;
foreach (FileInfo file in files)
{
Image img = Image.FromFile(file.FullName);
img = resizeImage(img, new Size(300, 300));
imageHeights.Add(img.Height);
width += img.Width;
img.Dispose();
}
imageHeights.Sort();
int height = imageHeights[imageHeights.Count - 1];
Bitmap img3 = new Bitmap(width, height);
Graphics g = Graphics.FromImage(img3);
g.Clear(SystemColors.AppWorkspace);
foreach (FileInfo file in files)
{
Image img = Image.FromFile(file.FullName);
if (nIndex == 0)
{
g.DrawImage(img, new Point(0, 0));
nIndex++;
width = img.Width;
}
else
{
g.DrawImage(img, new Point(width, 0));
width += img.Width;
}
img.Dispose();
}
g.Dispose();
img3.Save(finalImage, System.Drawing.Imaging.ImageFormat.Jpeg);
img3.Dispose();
imageLocation.Image = Image.FromFile(finalImage);
}
public static Image resizeImage(Image imgToResize, Size size)
{
return (Image)(new Bitmap(imgToResize, size));
}
}
}

It is likely that the image format of the uploaded image cannot be converted directly to Jpeg. One thing we do when resizing is actually draw the image to a new Graphics instance as follows. Note that the first 2 lines attempt to get the pixel and image formats directly from the original image instance - you may have issues with CMYK and images with a transparency layer (GIF/PNG).
var pixelFormat = imgToResize.PixelFormat;
var imageFormat = imgToResize.RawFormat;
Bitmap b = new Bitmap(newWidth.Value, newHeight.Value, pixelFormat);
Graphics g = Graphics.FromImage(b);
g.SmoothingMode = SmoothingMode.AntiAlias;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
g.DrawImage(imgToResize, (float)-0.5, (float)-0.5, newWidth.Value + 1, newHeight.Value + 1);
g.Dispose();
b.Save(stream, imageFormat);

Related

C# Bitmap Draw Image is Scaling

My setup takes .png images (with transparency) and stacks these images as layers on top of each other to form one image. The first batch I did worked perfectly. This second batch for some reason is scaling all of the images.
All of the images are 2000px x 2000px (I have individually checked each one and I can also see that Windows Explorer recognizes all of their dimensions.
All images are *.png files with transparent backgrounds.
In the Merge() function: I checked to see what the output width and height (and same of the image object) were and every single time they all came out to be 2000 (which is what it should be).
Below is a screen shot of the actual output vs what it should be. Again, I did this with different images (all 2000px x 2000px) and it worked perfectly. I'm not sure what is going on here.
public static Bitmap TestIt()
{
List<string> list = new List<string>
{
Path.Combine(dir, "body1.png"),
Path.Combine(dir, "head5.png"),
Path.Combine(dir, "legs2.png"),
Path.Combine(dir, "background2.png")
};
//Get List of Bitmaps from URLs
List<Bitmap> bitmaps = ConvertUrlsToBitmaps(list);
if (bitmaps.Any())
{
return Merge(bitmaps);
}
else
{
return null;
}
}
private static Bitmap Merge(List<Bitmap> images)
{
Bitmap bitmap = null;
var width = 0;
var height = 0;
try
{
// Get max width and height of the image
foreach (var image in images)
{
width = image.Width > width ? image.Width : width;
height = image.Height > height ? image.Height : height;
}
// merge images
bitmap = new Bitmap(width, height);
using (var g = Graphics.FromImage(bitmap))
{
foreach (var image in images)
{
g.DrawImage(image, 0, 0);
}
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
return bitmap;
}
private static List<Bitmap> ConvertUrlsToBitmaps(List<string> imageUrls)
{
List<Bitmap> bitmapList = new List<Bitmap>();
try
{
foreach (string imgUrl in imageUrls)
{
Bitmap bmp = (Bitmap)Image.FromFile(imgUrl);
bitmapList.Add(bmp);
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
return bitmapList;
}
Alright...I solved it.
I added a Rectangle object that will identify both position and size.
Then I forced the drawImage function to draw according to position and size
Here's the update
private static Bitmap Merge(List<Bitmap> images)
{
Bitmap bitmap = null;
var width = 0;
var height = 0;
try
{
// Get max width and height of the image
foreach (var image in images)
{
width = image.Width > width ? image.Width : width;
height = image.Height > height ? image.Height : height;
}
// merge images
bitmap = new Bitmap(width, height);
//*** Added a Rectangle object that will identify starting position and size
Rectangle rect = new Rectangle(new Point(0, 0), new Size(width, height));
using (var g = Graphics.FromImage(bitmap))
{
foreach (var image in images)
{
//*** Force the system to draw the image at location AND size
g.DrawImage(image, rect);
}
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
return bitmap;
}

Split bitmap into pieces and save

I load image from disc:
var img = Image.FromFile("foo");
var bmp = new Bitmap(img);
I wrote method to split image into pieces:
public static IEnumerable<Bitmap> VerticalSplit(this Bitmap src, int pixels)
{
var bmps = new List<Bitmap>();
for (int i = 0; i < src.Width; i+=pixels)
{
var dst = new Bitmap(pixels, src.Height);
using (var grD = Graphics.FromImage(dst))
{
grD.DrawImage(src, new Rectangle(i, 0, pixels, src.Height), new Rectangle(0,0,pixels,src.Height), GraphicsUnit.Pixel);
bmps.Add(dst);
}
}
return bmps;
}
And this is the usage:
var parts = bmp.VerticalSplit(10);
for (int i = 0; i < parts.Count(); i++)
{
parts[i].Save(#"output/" + i + ".jpg");
}
The problem is that every image except 1 is blank. Why does that happen?
See DrawImage, which has a signature of:
public void DrawImage (System.Drawing.Image image,
System.Drawing.Rectangle destRect, System.Drawing.Rectangle srcRect,
System.Drawing.GraphicsUnit srcUnit);
Note that the second parameter is "destRect", and the third parameter is "srcRect". Your code has the destination and source rectangles BACKWARDS.
Change:
grD.DrawImage(src, new Rectangle(i, 0, pixels, src.Height), new Rectangle(0,0,pixels,src.Height), GraphicsUnit.Pixel);
To:
grD.DrawImage(src, new Rectangle(0,0,pixels,src.Height), new Rectangle(i, 0, pixels, src.Height), GraphicsUnit.Pixel);

Add text to image using AForge.Video.FFMEG in C#

Using AForge.Video.FFMPEG I am able to create video from Images.
string[] files;
string folderPath = #"FolderPath";
files = Directory.GetFiles(folderPath).OrderBy(c => c).ToArray();
VideoFileWriter writer = new VideoFileWriter();
writer.Open(#"C:folder\new.mp4", imageWidth, imageHeight, 10, VideoCodec.MPEG4);
for (int j = 0; j < files.Length; j++)
{
string fileName = files[j];
BitmapSource imageBitMap = new BitmapImage(new Uri(fileName, UriKind.RelativeOrAbsolute));
imageBitMap.Freeze();
int stride = imageBitMap.PixelWidth * ((imageBitMap.Format.BitsPerPixel + 7) / 8);
byte[] ImageInBits = new byte[imageBitMap.PixelWidth * imageBitMap.PixelHeight];
imageBitMap.CopyPixels(ImageInBits, stride, 0);
Bitmap image = new Bitmap(imageWidth, imageHeight, stride, PixelFormat.Format8bppIndexed, Marshal.UnsafeAddrOfPinnedArrayElement(ImageInBits, 0));
writer.WriteVideoFrame(image);
image.Dispose();
}
I am trying to add text/String to input image using
private Bitmap WriteString(Bitmap bmp)
{
RectangleF rectf = new RectangleF(70, 90, 90, 50);
Bitmap tempBitmap = new Bitmap(bmp.Width, bmp.Height);
Graphics g = Graphics.FromImage(tempBitmap);
g.DrawImage(bmp, 0, 0);
g.SmoothingMode = SmoothingMode.AntiAlias;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
g.DrawString("yourText", new Font("Tahoma", 8), Brushes.Red, rectf);
g.Flush();
return bmp;
}
like
Bitmap image = new Bitmap(imageWidth, imageHeight, stride, PixelFormat.Format8bppIndexed, Marshal.UnsafeAddrOfPinnedArrayElement(ImageInBits, 0));
Bitmap outputBitmap=WriteString(image);
writer.WriteVideoFrame(outputBitmap);
How can I write a string to Image?
Is there any way to add subtitle to AForge.Video.FFMEG to image before creating video?
private Bitmap WriteString(Bitmap bmp) {
Bitmap tempBitmap = new Bitmap(bmp.Width, bmp.Height); << create new
..draw on copy..
return bmp; <<< return original
}
Seems to be the wrong.

Compressing large image to small format

I have images stored in DB as binary, to show them I want to compress them to smaller images (4000 x 3000) to (400 x 300), which basicly works however the images look awefull, can somebody point me to the right direction?
I am using now:
System.IO.MemoryStream myMemStream = new System.IO.MemoryStream(bytes);
System.Drawing.Image fullsizeImage = System.Drawing.Image.FromStream(myMemStream);
Type typeoff = fullsizeImage.GetType();
double height = fullsizeImage.Height;
double width = Convert.ToDouble(fullsizeImage.Width);
double aspect = setWidth / width;
setHeight = Convert.ToInt32(aspect * height);
System.Drawing.Image newImage = fullsizeImage.GetThumbnailImage(Convert.ToInt32(setWidth), setHeight, null, IntPtr.Zero);
System.IO.MemoryStream myResult = new System.IO.MemoryStream();
using (System.IO.MemoryStream imageMemStream = new System.IO.MemoryStream(bytes))
{
using (Bitmap bitmap = new Bitmap(imageMemStream))
{
ImageFormat imageFormat = bitmap.RawFormat;
if (bitmap.RawFormat.Equals(System.Drawing.Imaging.ImageFormat.Jpeg))
{
newImage.Save(myResult, System.Drawing.Imaging.ImageFormat.Jpeg);
}
if (bitmap.RawFormat.Equals(System.Drawing.Imaging.ImageFormat.Gif))
{
newImage.Save(myResult, System.Drawing.Imaging.ImageFormat.Gif);
}
if (bitmap.RawFormat.Equals(System.Drawing.Imaging.ImageFormat.Bmp))
{
newImage.Save(myResult, System.Drawing.Imaging.ImageFormat.Bmp);
}
if (bitmap.RawFormat.Equals(System.Drawing.Imaging.ImageFormat.Png))
{
newImage.Save(myResult, System.Drawing.Imaging.ImageFormat.Png);
}
if (bitmap.RawFormat.Equals(System.Drawing.Imaging.ImageFormat.Icon))
{
newImage.Save(myResult, System.Drawing.Imaging.ImageFormat.Icon);
}
}
}
_bytes = myResult.ToArray(); //Returns a new byte array.
Have been looking to this but have no idea yet how to implenet ths with my binary in and output:
Bitmap image = new Bitmap(fullsizeImage, Convert.ToInt32(newWidth), setHeight);
using (Graphics gr = Graphics.FromImage(image))
{
gr.SmoothingMode = SmoothingMode.HighQuality;
gr.InterpolationMode = InterpolationMode.HighQualityBicubic;
gr.PixelOffsetMode = PixelOffsetMode.HighQuality;
gr.DrawImage(fullsizeImage, new Rectangle(0, 0, Convert.ToInt32(newWidth), setHeight));
_bytes = gr.T.ToArray();
}
Probebly I do something wrong but have no idea where to look to do this right, have not much experience in image compression.
Any help would be appriciated
UPDATE
trying to get out of the Image the mime type but not very lucky to get it, using this and cant find any other, code has a null return.
public byte[] imageToByteArray(System.Drawing.Image newImage)
{
System.IO.MemoryStream ms = new System.IO.MemoryStream();
ImageFormat format = newImage.RawFormat;
if (ImageCodecInfo.GetImageDecoders().FirstOrDefault(c => c.FormatID == format.Guid) != null)
{
ImageCodecInfo codec = ImageCodecInfo.GetImageDecoders().FirstOrDefault(c => c.FormatID == format.Guid);
string mimeType = codec.MimeType;
}
newImage.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
return ms.ToArray();
You can use this function to create the reduced Images:
public static Image ShrinkImage(Image original, int scale)
{
Bitmap bmp = new Bitmap(original.Width / scale, original.Height / scale,
original.PixelFormat);
using (Graphics G = Graphics.FromImage(bmp))
{
G.InterpolationMode = InterpolationMode.HighQualityBicubic;
G.SmoothingMode = SmoothingMode.HighQuality;
Rectangle srcRect = new Rectangle(0,0,original.Width, original.Height);
Rectangle destRect = new Rectangle(0,0,bmp.Width, bmp.Height);
G.DrawImage(original, destRect, srcRect, GraphicsUnit.Pixel);
bmp.SetResolution( original.HorizontalResolution, original.VerticalResolution);
}
return (Image)bmp;
}
Note that it can only work with real Bitmap Images, not with Icons; but it makes little sense trying to reduce icons anyway!
Also note that you may or may not want to change the Dpi of the new Images. In the code I don't but maybe you want to scale it up or set it to a fixed value..
Don't forget to Dispose of your Images, when you're done with them!

Merging 2 images using C#

I want to merge two pictures in my C# program.
the first one is any picture in grayscale mode, and the second one is like in this picture:
Both of the pictures/images have the same size, and this is my code:
Bitmap first = new Bitmap (picturebox1.image);
Bitmap second = new Bitmap (picturebox2.image);
Bitmap result = new Bitmap (first.width, first.height);
Graphics g = Graphics.FromImage(result);
g.DrawImageUnscaled(first, 0, 0);
g.Flush();
g.DrawImageUnscaled(second, 0, 0);
g.Flush();
picturebox3.image = result;
I can join those picture, but the result has smaller size than the two originals (both pictures have same size). Could anyone give me some suggestions?
Additionally, I want the result picture has condition like this :
if the edge pixel in 2nd picture dropped to the bright side at the 1st one, it will be dark, otherwise when the edge dropped to the dark side, it will be bright (seem glow).
so the text will be semi transparent.
Here's an example of the results I want.
Could anyone give some suggestions please?
It was for joining
Bitmap first = new Bitmap (picturebox1.Image);
Bitmap second = new Bitmap (picturebox2.Image);
Bitmap result = new Bitmap (first.Width+first.Width, first.Height);
Graphics g = Graphics.FromImage(result);
g.DrawImageUnscaled(first, 0, 0);
g.DrawImageUnscaled(second,first.Width, 0);
Try this for merging one on top another . set alpha by yourself ( red: U can use BitMap.MakeTransParent if u not want alpha)
public Bitmap SetImageOpacity(Image image, float opacity)
{
try
{
//create a Bitmap the size of the image provided
Bitmap bmp = new Bitmap(image.Width, image.Height);
//create a graphics object from the image
using (Graphics gfx = Graphics.FromImage(bmp))
{
//create a color matrix object
ColorMatrix matrix = new ColorMatrix();
//set the opacity
matrix.Matrix33 = opacity;
//create image attributes
ImageAttributes attributes = new ImageAttributes();
//set the color(opacity) of the image
attributes.SetColorMatrix(matrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
//now draw the image
gfx.DrawImage(image, new Rectangle(0, 0, bmp.Width, bmp.Height), 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, attributes);
}
return bmp;
}
catch (Exception ex)
{
return null;
}
}
private void button1_Click(object sender, EventArgs e)
{
Bitmap first = new Bitmap(pictureBox1.Image);
Bitmap second = SetImageOpacity(pictureBox2.Image, 0.5f);
//Bitmap result = new Bitmap(first.Width, first.Height);
//fix :
Bitmap result = new Bitmap(Math.Max(first.Width,second.Width), Math.Max(first.Height,second.Height));
Console.WriteLine(first.Width);
Graphics g = Graphics.FromImage(result);
g.DrawImageUnscaled(first, 0, 0);
g.DrawImageUnscaled(second, 0, 0);
pictureBox3.Image = result;
result.Save("result.jpg" );
}
}
}
And Coming For watermark why not you want to use Drawstring with alpha
here is article for all these http://www.codeproject.com/Articles/5034/How-to-implement-Alpha-blending
You need to include the System.Drawing.Imaging namespace to make this code work.
Go through following code:
private void CombineImages(FileInfo[] files)
{
//change the location to store the final image.
string finalImage = #"C:\\MyImages\\FinalImage.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 img3 = new Bitmap(width, height);
Graphics g = Graphics.FromImage(img3);
g.Clear(SystemColors.AppWorkspace);
foreach (FileInfo file in files)
{
Image img = Image.FromFile(file.FullName);
if (nIndex == 0)
{
g.DrawImage(img, new Point(0, 0));
nIndex++;
width = img.Width;
}
else
{
g.DrawImage(img, new Point(width, 0));
width += img.Width;
}
img.Dispose();
}
g.Dispose();
img3.Save(finalImage, System.Drawing.Imaging.ImageFormat.Jpeg);
img3.Dispose();
imageLocation.Image = Image.FromFile(finalImage);
}
Follow Link:
http://www.niteshluharuka.com/2012/08/combine-several-images-to-form-a-single-image-using-c/
This codeproject article shows how to watermark an image with text as well as another image.
In summary, what you have to do is draw your watermark image over the image with the desired transparency.

Categories