This code resizes an image and saves it to disk.
using (var medBitmap = new Bitmap(fullSizeImage, newImageW, newImageH))
{
medBitmap.Save(HttpContext.Current.Server.MapPath("~/Media/Items/Images/" + itemId + ".jpg"),
ImageFormat.Jpeg);
}
But if I want to use the graphics class to set the interpolation, how do I save it? The graphics class has a save method, but it doesn't take any parameters. How do I save it to disk like the bitmap? Heres a modified code snippet:
using (var medBitmap = new Bitmap(fullSizeImage, newImageW, newImageH))
{
var g = Graphics.FromImage(medBitmap);
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
//What do I do now?
medBitmap.Save(HttpContext.Current.Server.MapPath("~/Media/Items/Images/" + itemId + ".jpg"),
ImageFormat.Jpeg);
}
I just need to set the interpolation and then save it to disk.
Call DrawImage on the Graphics object to update the bitmap:
using (var medBitmap = new Bitmap(fullSizeImage, newImageW, newImageH))
{
using (var g = Graphics.FromImage(medBitmap))
{
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.DrawImage(medBitmap, 0, 0);
}
medBitmap.Save(HttpContext.Current.Server.MapPath("~/Media/Items/Images/" + itemId + ".jpg"), ImageFormat.Jpeg);
}
Create a new Bitmap with the size you want and set the interpolationMode. Then use Graphics.DrawImage to draw the full sized image into the new bitmap.
Related
I am trying to take multiple screenshots and save them to a file. However, screenshots are taken decently often, and in order to not lose any of them, my current program will simply create a new file for every screenshot. Ideally, the program would simply "append" the most recent screenshot onto a single file every time.
Here is the code:
static Rectangle bounds = Screen.GetBounds(Point.Empty);
static Size rectSize = new Size(bounds.Width, bounds.Height);
public static void takeScreenshot(string path, int iteration, string filetype)
{
using (Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height))
{
using (Graphics g = Graphics.FromImage(bitmap))
{
g.CopyFromScreen(Point.Empty, Point.Empty, new Size
(rectSize.Width * iteration, rectSize.Height));
}
bitmap.Save(path + filetype);
}
}
iteration was the amount of times the method has been called. I was trying to just shift the next screenshot over by one screenshot's width while keeping every other screenshot, but it seems to overwrite the file anyways. Is it possible to do this?
Try this..
string n = string.Format("{0:yyyy-MM-dd_hh-mm-ss-tt}", DateTime.Now);
bitmap.Save(path + n + filetype);
Like TheGeneral said, you will run out of memory quickly. And every time the file grows it has a chance of needing to be moved on disc wearing down your drives.
Also, opening and viewing huge image files can be very slow, your computer will not be able to handle it very quickly.
But here it is, maybe at least the AppendImage function could be used for something like generating particle sprite strips in games or something.
If you're appending a screenshot, I wouldn't append more than maybe 10 times, with 1080P monitor.
public enum AppendLocation
{
Before,
After
}
void AppendScreenToFile(string filename, AppendLocation appendLocation = AppendLocation.After)
{
Rectangle bounds = Screen.PrimaryScreen.Bounds;
using (Bitmap screenShot = new Bitmap(bounds.Width, bounds.Height))
{
using (Graphics g = Graphics.FromImage(screenShot))
{
g.CopyFromScreen(UpperLeftSource, Point.Empty, bounds.Size);
}
if (!File.Exists(filename))
{
screenShot.Save(filename, ImageFormat.Png);
return;
}
//Not using Image.FromFile as it blocks saving.
Image onDisc;
using (Stream fs = new FileStream(filename, FileMode.Open, FileAccess.Read))
onDisc = Image.FromStream(fs);
using (Image appended = appendLocation == AppendLocation.Before ? AppendImage(screenShot, onDisc) : AppendImage(onDisc, screenShot))
appended.Save(filename, ImageFormat.Png);
}
}
public enum AppendAxis
{
Vertical,
Horizontal
}
Bitmap AppendImage(Image image, Image append, AppendAxis axis = AppendAxis.Vertical)
{
Bitmap bitmap;
Rectangle destinationRect;
RectangleF imageBounds = new Rectangle(0, 0, image.Width, image.Height);
RectangleF appendRect = new Rectangle(0, 0, append.Width, append.Height);
pictureBox_Item4.BackgroundImage = image;
pictureBox_Item3.BackgroundImage = append;
switch (axis)
{
case AppendAxis.Vertical:
destinationRect = new Rectangle(0, image.Height, append.Width, append.Height);
bitmap = new Bitmap(image.Width, image.Height + append.Height);
break;
case AppendAxis.Horizontal:
destinationRect = new Rectangle(image.Width, 0, append.Width, append.Width);
bitmap = new Bitmap(image.Width + append.Width, image.Height);
break;
default:
throw new ArgumentException("AppendAxis is invalid.");
}
using (Graphics g = Graphics.FromImage(bitmap))
{
g.DrawImage(image, imageBounds, imageBounds, GraphicsUnit.Pixel);
g.DrawImage(append, destinationRect, appendRect, GraphicsUnit.Pixel);
return bitmap;
}
}
recently I started working on my project and unfortunately I have a problem. I want to get sqaures 5x5 from one image, count average color of them and then draw a circle to another Bitmap so I can get a result like this http://imageshack.com/a/img924/9093/ldgQAd.jpg
I have it done, but I can't save to file the Graphics object. I've tried many solutions from Stack, but none of them worked for me.
My code:
//GET IMAGE OBJECT
Image img = Image.FromFile(path);
Image newbmp = new Bitmap(img.Width, img.Height);
Size size = img.Size;
//CREATE NEW BITMAP WITH THIS IMAGE
Bitmap bmp = new Bitmap(img);
//CREATE EMPTY BITMAP TO DRAW ON IT
Graphics g = Graphics.FromImage(newbmp);
//DRAWING...
//SAVING TO FILE
Bitmap save = new Bitmap(size.Width, size.Height, g);
g.Dispose();
save.Save("file.bmp", System.Drawing.Imaging.ImageFormat.Bmp);
The file 'file.bmp' is just a blank image. What am I doing wrong?
First, your Graphics object should be created from the target bitmap.
Bitmap save = new Bitmap(size.Width, size.Height) ;
Graphics g = Graphics.FromImage(save );
Second, flush your graphics before Save()
g.Flush() ;
And last, Dispose() after Save() (or use a using block)
save.Save("file.bmp", System.Drawing.Imaging.ImageFormat.Bmp);
g.Dispose();
It should give you something like this :
Image img = Image.FromFile(path);
Size size = img.Size;
//CREATE EMPTY BITMAP TO DRAW ON IT
using (Bitmap save = new Bitmap(size.Width, size.Height))
{
using (Graphics g = Graphics.FromImage(save))
{
//DRAWING...
//SAVING TO FILE
g.Flush();
save.Save("file.bmp", System.Drawing.Imaging.ImageFormat.Bmp);
}
}
I have some images that I need to do some crude re-size work on -- For the purpose of this example lets just say I need to increase the width and height of a given image by 4 pixels.
I am unsure why the call to Graphics.DrawImage() is throwing an OOM -- Any advice here would be greatly appreciated.
class Program
{
static void Main(string[] args)
{
string filename = #"c:\testImage.png";
// Load png from stream
FileStream fs = new FileStream(filename, FileMode.Open);
Image pngImage = Image.FromStream(fs);
fs.Close();
// super-hacky resize
Graphics g = Graphics.FromImage(pngImage);
g.DrawImage(pngImage, 0, 0, pngImage.Width + 4, pngImage.Height + 4); // <--- out of memory exception?!
// save it out
pngImage.Save(filename, System.Drawing.Imaging.ImageFormat.Png);
}
}
I just had the same problem. However fixing the size of the output Graphics did not solve my problem. I realized that I tried to use a very high quality for the drawing the image which was consuming too much memory when I use the code on a lot of images.
g.CompositingQuality = CompositingQuality.HighQuality;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.SmoothingMode = SmoothingMode.HighQuality;
after commenting these lines out the code worked perfectly.
Your Graphics surface is only big enough for the original-sized image. You need to create a new image of the correct size and use it as the source of your Graphics object.
Image newImage = new Bitmap(pngImage.Width + 4, pngImage.Height+4);
Graphics g = Graphics.FromImage(newImage);
That likely will not accomplish what you'd like to do seeing as how the image is the same size as the one specified by FromImage, instead you can use the Bitmap class:
using (var bmp = new Bitmap(fileName))
{
using (var output = new Bitmap(
bmp.Width + 4, bmp.Height + 4, bmp.PixelFormat))
using (var g = Graphics.FromImage(output))
{
g.DrawImage(bmp, 0, 0, output.Width, output.Height);
output.Save(outFileName, ImageFormat.Png);
}
}
Can you try this fix?
class Program
{
static void Main(string[] args)
{
string filename = #"c:\testImage.png";
// Load png from stream
FileStream fs = new FileStream(filename, FileMode.Open);
Image pngImage = Image.FromStream(fs);
fs.Close();
// super-hacky resize
Graphics g = Graphics.FromImage(pngImage);
pngImage = pngImage.GetThumbnailImage(image.Width, image.Height, null, IntPtr.Zero);
g.DrawImage(pngImage, 0, 0, pngImage.Width + 4, pngImage.Height + 4); // <--- out of memory exception?!
// save it out
pngImage.Save(filename, System.Drawing.Imaging.ImageFormat.Png);
}
}
Inspired by this question: Help to resolve 'Out of memory' exception when calling DrawImage
I need to stretch various sized bitmaps to fill a PictureBox.
PictureBoxSizeMode.StretchImage sort of does what I need but can't think of a way to properly add text or lines to the image using this method. The image below is a 5x5 pixel Bitmap stretched to a 380x150 PictureBox.
pictureBox.SizeMode = PictureBoxSizeMode.StretchImage;
pictureBox.Image = bmp;
I tried adapting this example and this example this way
using (var bmp2 = new Bitmap(pictureBox.Width, pictureBox.Height))
using (var g = Graphics.FromImage(bmp2))
{
g.InterpolationMode = InterpolationMode.NearestNeighbor;
g.DrawImage(bmp, new Rectangle(Point.Empty, bmp2.Size));
pictureBox.Image = bmp2;
}
but get this
What am I missing?
It appears you're throwing away the bitmap (bmp2) you'd like to see in your picture box! The using block from the example you posted is used because the code no longer needs the Bitmap object after the code returns. In your example you need the Bitmap to hang around, hence no using-block on the bmp2 variable.
The following should work:
using (bmp)
{
var bmp2 = new Bitmap(pictureBox.Width, pictureBox.Height);
using (var g = Graphics.FromImage(bmp2))
{
g.InterpolationMode = InterpolationMode.NearestNeighbor;
g.DrawImage(bmp, new Rectangle(Point.Empty, bmp2.Size));
pictureBox.Image = bmp2;
}
}
The red X on white background happens when you have an exception in a paint method.
Your error is that you are trying to assign a disposed bitmap as the image source of your picturebox. The use of "using" keyword will dispose the bitmap you are using in the picturebox!
So your exception, i know, will be ObjectDisposedException :)
You should create the bitmap once and keep it until it is not needed anymore.
void ReplaceResizedPictureBoxImage(Bitmap bmp)
{
var oldBitmap = pictureBox.Image;
var bmp2 = new Bitmap(pictureBox.Width, pictureBox.Height);
using (var g = Graphics.FromImage(bmp2))
{
g.InterpolationMode = InterpolationMode.NearestNeighbor;
g.DrawImage(bmp, new Rectangle(Point.Empty, bmp2.Size));
pictureBox.Image = bmp2;
}
if (oldBitmap != null)
oldBitmap.Dispose();
}
This function will allow you to replace the old bitmap disposing the previous one, if you need to do that to release resources.
I'm really trying to nail out a little more performance out of this tidbit of code. It's not a heavly used bit of code but is used every time a new image is uploaded, and 4 times for each image (100px, 200px, 500px, 700px). So when there are any more than 2 or 3 images processing, it gets a little busy on the server. Also I'm trying to figure out how to make it correctly process images with a low resolution. Currently it just chops it off half way through, not plesent.
Examples: Original, large, xLarge
public static byte[] ResizeImageFile(byte[] imageFile, int targetSize)
{
using (System.Drawing.Image oldImage = System.Drawing.Image.FromStream(new MemoryStream(imageFile)))
{
Size newSize = CalculateDimensions(oldImage.Size, targetSize);
using (Bitmap newImage = new Bitmap(newSize.Width, newSize.Height, PixelFormat.Format32bppRgb))
{
newImage.SetResolution(oldImage.HorizontalResolution, oldImage.VerticalResolution);
using (Graphics canvas = Graphics.FromImage(newImage))
{
canvas.SmoothingMode = SmoothingMode.AntiAlias;
canvas.InterpolationMode = InterpolationMode.HighQualityBicubic;
canvas.PixelOffsetMode = PixelOffsetMode.HighQuality;
canvas.DrawImage(oldImage, new Rectangle(new Point(0, 0), newSize));
MemoryStream m = new MemoryStream();
newImage.Save(m, ImageFormat.Jpeg);
return m.GetBuffer();
}
}
}
}
private static Size CalculateDimensions(Size oldSize, int targetSize)
{
Size newSize = new Size();
if (oldSize.Width > oldSize.Height)
{
newSize.Width = targetSize;
newSize.Height = (int)(oldSize.Height * (float)targetSize / (float)oldSize.Width);
}
else
{
newSize.Width = (int)(oldSize.Width * (float)targetSize / (float)oldSize.Height);
newSize.Height = targetSize;
}
return newSize;
}
Thanks for and help!
The first thought that comes to mind is, have you thought about Multithreading it? i.e. calling this method for each image (or batch of images) in a separate thread? That way, if your server has a few cores you can get things done quicker. Just a thought...
(Threading is a great tip.)
Try to call your method with the smallest possible image as input each time, instead of the original image. If the original image is, say 2000px, then create the 700px image from it and then use your newly created 700px image to create the 500px, etc...
With the HighQualityBicubic setting I doubt that you'll notice any difference in the 100px image. (But it of course it needs to be verified.)
For completeness, here is the solution to the second part of the question which was never answered. When processing a low resolution image the image was being cut off. The solution now, seems obvious. The problem lies in this bit of code from above:
using (Bitmap newImage = new Bitmap(newSize.Width, newSize.Height,
PixelFormat.Format32bppRgb))
The problem being that I'm selecting the PixelFormat, not letting it be the format of the original image. The correct code is here:
public static byte[] ResizeImageFile(byte[] imageFile, int targetSize)
{
using (System.Drawing.Image oldImage = System.Drawing.Image.FromStream(new MemoryStream(imageFile)))
{
Size newSize = CalculateDimensions(oldImage.Size, targetSize);
using (Bitmap newImage = new Bitmap(newSize.Width, newSize.Height,
oldImage.PixelFormat))
{
newImage.SetResolution(oldImage.HorizontalResolution,
oldImage.VerticalResolution);
using (Graphics canvas = Graphics.FromImage(newImage))
{
canvas.SmoothingMode = SmoothingMode.AntiAlias;
canvas.InterpolationMode = InterpolationMode.HighQualityBicubic;
canvas.PixelOffsetMode = PixelOffsetMode.HighQuality;
canvas.DrawImage(oldImage, new Rectangle(new Point(0, 0), newSize));
MemoryStream m = new MemoryStream();
newImage.Save(m, ImageFormat.Jpeg);
return m.GetBuffer();
}
}
}
}