How to resize an Image C#
Asked Answered
H

17

359

As Size, Width and Height are Get() properties of System.Drawing.Image;
How can I resize an Image object at run-time in C#?

Right now, I am just creating a new Image using:

// objImage is the original Image
Bitmap objBitmap = new Bitmap(objImage, new Size(227, 171));
Haemin answered 17/12, 2009 at 14:9 Comment(4)
Thats the way to do it... The overloaded constructor for Bitmap also accepts two parameters for Width and HeightOxa
You probably want to look at this stackoverflow question too: <#88253>Ingate
Not the right way... uses low-quality interpolation and can cause the original stream to stay locked for the duration of the new bitmap image... Read the image resizing pitfalls list before doing your own image resizing solution.Planter
The standard lib for image resizing can be found at imageresizing.net. Once you start addressing all the GDI bugs, it will definitely be worth your time to use a (simple) library rather than write your own.Planter
V
622

This will perform a high quality resize:

/// <summary>
/// Resize the image to the specified width and height.
/// </summary>
/// <param name="image">The image to resize.</param>
/// <param name="width">The width to resize to.</param>
/// <param name="height">The height to resize to.</param>
/// <returns>The resized image.</returns>
public static Bitmap ResizeImage(Image image, int width, int height)
{
    var destRect = new 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;
}
  • wrapMode.SetWrapMode(WrapMode.TileFlipXY) prevents ghosting around the image borders -- naïve resizing will sample transparent pixels beyond the image boundaries, but by mirroring the image we can get a better sample (this setting is very noticeable)
  • destImage.SetResolution maintains DPI regardless of physical size -- may increase quality when reducing image dimensions or when printing
  • Compositing controls how pixels are blended with the background -- might not be needed since we're only drawing one thing.
  • graphics.InterpolationMode determines how intermediate values between two endpoints are calculated
  • graphics.SmoothingMode specifies whether lines, curves, and the edges of filled areas use smoothing (also called antialiasing) -- probably only works on vectors
  • graphics.PixelOffsetMode affects rendering quality when drawing the new image

Maintaining aspect ratio is left as an exercise for the reader (actually, I just don't think it's this function's job to do that for you).

Also, this is a good article describing some of the pitfalls with image resizing. The above function will cover most of them, but you still have to worry about saving.

Venison answered 13/6, 2014 at 6:50 Comment(20)
code worked perfectly when resizing image but increased the size from 66KB to 132 KB. Hoe can I reduce itMisname
@Misname That's probably due to save quality you chose. See msdn.microsoft.com/en-us/library/bb882583(v=vs.110).aspx Try quality=90Venison
Using graphics.CompositingMode = CompositingMode.SourceCopy; seems to do bad things to transparency. Mind you, I'm using parts of this code to overlay existing images on to a base existing image, and resize at the same time.Health
Just curious, does this code maintain the original image type such as JPG, PNG, etc. or do you always get back a type of BMP? Maybe I'm confusing what the actual Bitmap type in .NET.Haerle
@Haerle You sure are. Bitmap is essentially just the name of the class, you can save it out as whatever file type you like.Venison
Using this method to resize 24bpp results in 32bpp image.Hashim
@dotNetBlackBelt You probably need to add a reference to System.Drawing and add using System.Drawing.Imaging;Venison
This will not maintain the original aspect ratio right?Palaeolithic
@KasperSkov Correct. You have to do the math beforehand.Venison
I am occasionally getting an OutOfMemory Exception on graphics.DrawImage() with the above method. Not sure why. Can't easily reproduce it and the image isn't even that big. I'm trying to shrink it down. And yes, the stream on which the image was made from is open.Rapscallion
@TudorCarean I imagine the internal representation uses much more memory than size on disk. Possibly 3 or 4 bytes per pixel (for RGBA), but I'm speculating. Could that be it? Not sure if C# limits memory usage like Java does.Venison
for those who are trying to fix the resolution of DataMatrix, the best interpolation mode is InterpolationMode.NearestNeighborMaclay
Why does this flip the image upside down on about 20% of the loaded images? I can't figure out what is so different about those 20% that makes them always flip upside down with this function. I've tried disabling all of those properties and different Wrap Modes, but it's always the same 20%.Soble
@BryanWilliams It's probably rotation info stored in the image metadata/EXIF which is getting stripped when you re-save the image.Venison
@mpen, you're absolutely right! Those that were flipped had EXIF Orientation of "Bottom-right". Thanks for your help.Soble
To fix the missing EXIF data and orientation problem, I added this: foreach (PropertyItem propertyItem in image.PropertyItems) { destImage.SetPropertyItem(propertyItem); }Soble
In .NET 6+ you will have to add the System.Drawing.Common as a NuGet package as per this threadMaintopmast
@chamara: Changing the InterpolationMode from HighQualityBicubic to NearestNeighbor produces low quality but much smaller image. I tested via resampling a 256x256 Google Maps tile. The sizes are 101KB and 33KB, respectively.Antenna
@MustafaÖzçetin That sounds like it very much depends on the image and output file format. Using HighQualityBicubic on an image with a small color palette will introduce new colors at the boundaries due to blending whereas NearestNeighbor won't. GIF and probably PNG will benefit from this, newer formats like WEBP and JPEGXL will likely see a smaller difference, but I haven't tested.Venison
GC doesn't seem to dispose of objects as needed, I also get outOfMemory exception.. ran profiler and noticed even after hitting 12GB, memory is not released, GC ran twice.Sostenuto
S
176

Not sure what is so difficult about this, do what you were doing, use the overloaded Bitmap constructor to create a re-sized image, the only thing you were missing was a cast back to the Image data type:

public static Image resizeImage(Image imgToResize, Size size)
{
    return (Image)(new Bitmap(imgToResize, size));
}

yourImage = resizeImage(yourImage, new Size(50,50));
Slut answered 15/1, 2013 at 22:2 Comment(17)
Shouldn't you dispose yourImage before assigning it to the new image?Slop
You can dispose it manually or you can let the garbage collector do it's work. No matter.Amianthus
This code gives no control over the quality of the resizing which is very important. Have a look at the answer from Mark.Amianthus
@Amianthus The garbage collector will not automatically clean up remote GDI+ objects. Disposing them is vital.Ricciardi
@ Nyerguds: Your commnent is wrong. You can optionally dispose a Bitmap manually if you want to free the memory immediately. But this is not mandatory. Bitmap is derived from Image. And Image has a finalizer which calls Dispose(). Look here: referencesource.microsoft.com/#System.Drawing/commonui/System/…Amianthus
@Amianthus it is really bad advice what you are saying. I have been working with imaging for 8 years now in scanning software, batch conversion of millions of documents and pages, and OCR and others, and not disposing of bitmaps except under the most trivial scenarios will create memory leaks, inefficient code, and software that will grind to a halt (crash, performance, and the like). You should always always notify the GC as soon as possible when you don't need something so the GC doesn't have to do so much work later, which can really affect application performance and scalability (in a big way)Claypoole
@David: What you say does not make much sense. As Image has a finalizer it is obvious that Bitmaps are collected by the garbage collector. This is it's job. If this would not work the entire .NET framework would have a severe problem. What may be the cause are 3 options: A.) You still have a reference to the bitmap and therefore it is not collected. B.) You are creating hundreds of Bitmaps in so short time that the RAM flows over before the process enters idle state and garbage collection starts. C.) You use .NET framework 2.0 which had a bug in the garbage collector (fixed in Framework 4)Amianthus
> "I have been working with imaging for 8 years now in scanning software." Well, this is your experience. I'am working on a huge software project where I cannot dispose bitmaps because I have no idea where they are still in use. I cannot explain this in detail here. But I HAVE to trust the garbage collector. And this works perfectly since I changed from Framework 2 to 4. So there is your experience versus my experience. Obviously I call Dispose whenever possible. But if not there will be no memory leak.Amianthus
Having to trust the GC because you have no other option and having the option to follow best practice (which you said you try to) are two completely different things. You are right that when there are no references to a Bitmap it will be collected - at an indeterminate time when the GC algorithm decides to do so based on generation when the finalizer is called. In your scenario maybe you are able to let the GC do its work, and I will agree that for most developers and most software it is not an issue, but that doesn't make it best practice. Most situations should call Dispose, it does matter.Claypoole
And ultimately, each situation should be looked at in its context and requirements. Many times you cannot dispose a bitmap like you said because it is used higher up the call stack. But, at some point, the application code should call dispose higher up the call chain once it is done being used to free that from memory. In my experience we work with many thousands (sometimes hundreds of thousands) of bitmaps, and often high DPI color multi-page documents (each page a bitmap) where memory pressure builds and bitmaps are created fast, and in a 32-bit env. sometimes, where this is more importantClaypoole
@Amianthus You have failed to grasp the fact that GDI+ objects are not just "memory". The GC only reclaims memory. It does not reclaim GDI+ handles. The finaliser may not be called for minutes, hours – or ever! I have been a Win32 developer for decades, and I am telling you that GDI+ objects need to be disposed when they're finished with. Trusting the GC to free plain memory is fine. Trusting it to free GDI handles can cause the entire Windows environment to stop being able to paint itself, leading to other applications displaying black rectangles instead of graphics. Ask me how I know.Ernesternesta
And this can happen no matter how much free RAM you have. GC is for RAM only. And the .NET GC is unreliable. It is not guaranteed to call the finalisers. And therefore, there is no such thing as a true "finaliser" in .net like there is in C. The .net GC is a hope and a prayer, not a guarantee. If your code is so messy as to render you unable to free bitmaps when you're done with them, refactor your code. There is no excuse for sloppy work.Ernesternesta
@Sod: Your assumption is WRONG: "The garbage collector is only for memory and not for handles"! If this would be true what a disaster would this be! The garbage collector does not even CARE if a managed objects occupies memory or has opened a native handle! The garbage collector simply calls the destructor (called finalizer in .NET) and that's IT! Then it is upon the finalizer of the object to either free the memory or release the native handle or both.Amianthus
If you would have studied the code in my third posting you would have seen what ~Image() does: SafeNativeMethods.Gdip.GdipDisposeImage(new HandleRef(this, nativeImage)); So it clearly frees native handles! I post the link once more for you: Study this: referencesource.microsoft.com/#System.Drawing/commonui/System/…Amianthus
Either way, it's a hope and a prayer, not a guarantee. And either way, your code is still sloppy. Please furnish me with the name of your product, so I can be certain never to use it by accident.Ernesternesta
Perhaps you have heard that a GC can be described as "simulating a system with infinite memory"? I disagree with that definition, but even so: Nobody ever said GC simulated a system with infinite handles. So-called "finalisers" in .net are a joke. They're so incredibly bad that Microsoft had to bring in the Dispose pattern to do the job finalisers were supposed to do. And then screwed that up too, leading to the oxymoronic void Dispose(bool disposing) { if (disposing) ... } situation we now find ourselves in.Ernesternesta
The using statement exists for a reason. And that reason is: finalisers are NOT guaranteed to be called in a timely manner; and are NOT guaranteed to be called AT ALL, PERIOD. You must Dispose() your Pens, Brushes, Bitmaps and Graphics instances when you're done with them. To just drop them on the ground when you're finished with them and trust the GC to pick up after you is simply bad practice and asking for trouble.Ernesternesta
D
51

in this question, you'll have some answers, including mine:

public Image resizeImage(int newWidth, int newHeight, string stPhotoPath)
 {
     Image imgPhoto = Image.FromFile(stPhotoPath); 

     int sourceWidth = imgPhoto.Width;
     int sourceHeight = imgPhoto.Height;

     //Consider vertical pics
    if (sourceWidth < sourceHeight)
    {
        int buff = newWidth;

        newWidth = newHeight;
        newHeight = buff;
    }

    int sourceX = 0, sourceY = 0, destX = 0, destY = 0;
    float nPercent = 0, nPercentW = 0, nPercentH = 0;

    nPercentW = ((float)newWidth / (float)sourceWidth);
    nPercentH = ((float)newHeight / (float)sourceHeight);
    if (nPercentH < nPercentW)
    {
        nPercent = nPercentH;
        destX = System.Convert.ToInt16((newWidth -
                  (sourceWidth * nPercent)) / 2);
    }
    else
    {
        nPercent = nPercentW;
        destY = System.Convert.ToInt16((newHeight -
                  (sourceHeight * nPercent)) / 2);
    }

    int destWidth = (int)(sourceWidth * nPercent);
    int destHeight = (int)(sourceHeight * nPercent);


    Bitmap bmPhoto = new Bitmap(newWidth, newHeight,
                  PixelFormat.Format24bppRgb);

    bmPhoto.SetResolution(imgPhoto.HorizontalResolution,
                 imgPhoto.VerticalResolution);

    Graphics grPhoto = Graphics.FromImage(bmPhoto);
    grPhoto.Clear(Color.Black);
    grPhoto.InterpolationMode =
        System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;

    grPhoto.DrawImage(imgPhoto,
        new Rectangle(destX, destY, destWidth, destHeight),
        new Rectangle(sourceX, sourceY, sourceWidth, sourceHeight),
        GraphicsUnit.Pixel);

    grPhoto.Dispose();
    imgPhoto.Dispose();
    return bmPhoto;
}
Digitate answered 17/12, 2009 at 14:16 Comment(5)
You forgot imgPhoto.Dispose(); the file is kept in useAnderton
This is very helpfull, and i am using this in my app. However its important to note that this algorithm does not work with transparent imagens.. It turns all transparent pixels to black. Its probably easy to fix, but its just a note for users. :)Halftimbered
Aren't you suppose to save the image? imgPhoto.Save() ?Kilmarx
@Halftimbered Can you give link on how to fix that black background for transparent doc.Evangelical
I'm getting a lot of border bleed from the background color. Using Math.Ceiling helps a bit on the destWidth and destHeight, but not enough. However, the memory performance of this is way better on Azure than the other solutions.Morph
L
33

You could try my library net-vips, the C# binding for libvips. It's a lazy, streaming, demand-driven image processing library, so it can do operations like this without needing to load the whole image.

For example, it comes with a handy image thumbnailer:

using Image image = Image.Thumbnail("image.jpg", 300, 300);
image.WriteToFile("my-thumbnail.jpg");

It also supports smart crop, a way of intelligently determining the most important part of the image and keeping it in focus while cropping the image. For example:

using Image image = Image.Thumbnail("owl.jpg", 128, crop: Enums.Interesting.Attention);
image.WriteToFile("tn_owl.jpg");

Where owl.jpg is an off-centre composition:

Owl

Gives this result:

Owl smart crop

First it shrinks the image to get the vertical axis to 128 pixels, then crops down to 128 pixels across using the attention strategy. This one searches the image for features which might catch a human eye, see Smartcrop() for details.

Levator answered 23/1, 2019 at 18:55 Comment(2)
Sorry if my question is stupid. I get a red underline under the Thumbnail portion in the "Image.Thumbnail" and under the WriteToFile part of the image.WriteToFile. Might I ask what "using ...; I should be using? I know that using NetVips; is one of them. ThanksKnisley
@Knisley using NetVips; should do the job. Did you install the NuGet package? If that doesn't work, please open a new issue on NetVips issue tracker: github.com/kleisauke/net-vips/issuesLevator
B
30

Why not use the System.Drawing.Image.GetThumbnailImage method?

public Image GetThumbnailImage(
    int thumbWidth, 
    int thumbHeight, 
    Image.GetThumbnailImageAbort callback, 
    IntPtr callbackData)

Example:

Image originalImage = System.Drawing.Image.FromStream(inputStream, true, true);
Image resizedImage = originalImage.GetThumbnailImage(newWidth, (newWidth * originalImage.Height) / originalWidth, null, IntPtr.Zero);
resizedImage.Save(imagePath, ImageFormat.Png);

Source: http://msdn.microsoft.com/en-us/library/system.drawing.image.getthumbnailimage.aspx

Byron answered 7/10, 2013 at 18:48 Comment(6)
This is not the correct way to resize an image. This pulls a thumbnail from the jpg if it exists. If it doesn't exist, you have no control over the quality or the new image. Also, this code as is has memory leaks.Claque
@Bobrot Why will this cause memory leaks?Nunley
Anything in the GDI library is still running unmanaged. Without using a using statement or disposing of the objects afterward, it can take a long long time for the system to garbage collect those objects and make the memory available again.Claque
It is as you say: It may take a long time. But this is NOT a memory leak. It WOULD be a memory leak if the memory would NEVER be freed. But this is the NORMAL behaviour of the garbage collector that it frees memory when the CPU is idle. The using() statement does not prevent memory leaks. It just frees the memory immediately while the garbage collector frees the memory when it has time to do that. That is the only difference in this specific case.Amianthus
See pitfalls of image resizing: nathanaeljones.com/blog/2009/20-image-resizing-pitfalls "Using GetThumbnailImage(). GetThumbnailImage() seems the obvious choice, and many articles recommend its use. Unfortunately, it always grabs the embedded jpeg thumbnail if present. Some photos have these, some don't - it usually depends on your camera. You'll wonder why GetThumbnailImage works good on some photo, but on others is horribly blurred. GetThumbnailImage() isn't reliable for photos larger than 10px by 10px for that reason."Duaneduarchy
I know this is really old, but any code using this will have a GDI resource leak and crash before too long.Hashum
I
12
public static Image resizeImage(Image image, int new_height, int new_width)
{
    Bitmap new_image = new Bitmap(new_width, new_height);
    Graphics g = Graphics.FromImage((Image)new_image );
    g.InterpolationMode = InterpolationMode.High;
    g.DrawImage(image, 0, 0, new_width, new_height);
    return new_image;
}
Indeterminable answered 4/10, 2015 at 11:42 Comment(1)
You forgot to dispose graphics. Seems the same principle as new Bitmap(image, width, height) with better interpolation mode. I am curious what is Default? Is it worse even thanLow?Crain
S
11

This will -

  • Resize width AND height without the need for a loop
  • Doesn't exceed the images original dimensions

//////////////

private void ResizeImage(Image img, double maxWidth, double maxHeight)
{
    double resizeWidth = img.Source.Width;
    double resizeHeight = img.Source.Height;

    double aspect = resizeWidth / resizeHeight;

    if (resizeWidth > maxWidth)
    {
        resizeWidth = maxWidth;
        resizeHeight = resizeWidth / aspect;
    }
    if (resizeHeight > maxHeight)
    {
        aspect = resizeWidth / resizeHeight;
        resizeHeight = maxHeight;
        resizeWidth = resizeHeight * aspect;
    }

    img.Width = resizeWidth;
    img.Height = resizeHeight;
}
Syndesmosis answered 13/4, 2011 at 20:2 Comment(1)
OP was asking about System.Drawing.Image, where your code will not work as the 'Width' and 'Height' properties are not settable. It will, however, work for System.Windows.Controls.Image.Philippopolis
B
9

This code is same as posted from one of above answers.. but will convert transparent pixel to white instead of black ... Thanks:)

    public Image resizeImage(int newWidth, int newHeight, string stPhotoPath)
    {
        Image imgPhoto = Image.FromFile(stPhotoPath);

        int sourceWidth = imgPhoto.Width;
        int sourceHeight = imgPhoto.Height;

        //Consider vertical pics
        if (sourceWidth < sourceHeight)
        {
            int buff = newWidth;

            newWidth = newHeight;
            newHeight = buff;
        }

        int sourceX = 0, sourceY = 0, destX = 0, destY = 0;
        float nPercent = 0, nPercentW = 0, nPercentH = 0;

        nPercentW = ((float)newWidth / (float)sourceWidth);
        nPercentH = ((float)newHeight / (float)sourceHeight);
        if (nPercentH < nPercentW)
        {
            nPercent = nPercentH;
            destX = System.Convert.ToInt16((newWidth -
                      (sourceWidth * nPercent)) / 2);
        }
        else
        {
            nPercent = nPercentW;
            destY = System.Convert.ToInt16((newHeight -
                      (sourceHeight * nPercent)) / 2);
        }

        int destWidth = (int)(sourceWidth * nPercent);
        int destHeight = (int)(sourceHeight * nPercent);


        Bitmap bmPhoto = new Bitmap(newWidth, newHeight,
                      PixelFormat.Format24bppRgb);

        bmPhoto.SetResolution(imgPhoto.HorizontalResolution,
                     imgPhoto.VerticalResolution);

        Graphics grPhoto = Graphics.FromImage(bmPhoto);
        grPhoto.Clear(Color.White);
        grPhoto.InterpolationMode =
            System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;

        grPhoto.DrawImage(imgPhoto,
            new Rectangle(destX, destY, destWidth, destHeight),
            new Rectangle(sourceX, sourceY, sourceWidth, sourceHeight),
            GraphicsUnit.Pixel);

        grPhoto.Dispose();
        imgPhoto.Dispose();

        return bmPhoto;
    }
Bewhiskered answered 8/2, 2017 at 12:28 Comment(0)
L
8

This is the code that I worked out for a specific requirement ie: the destination is always in landscape ratio. It should give you a good start.

public Image ResizeImage(Image source, RectangleF destinationBounds)
{
    RectangleF sourceBounds = new RectangleF(0.0f,0.0f,(float)source.Width, (float)source.Height);
    RectangleF scaleBounds = new RectangleF();

    Image destinationImage = new Bitmap((int)destinationBounds.Width, (int)destinationBounds.Height);
    Graphics graph = Graphics.FromImage(destinationImage);
    graph.InterpolationMode =
        System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;

    // Fill with background color
    graph.FillRectangle(new SolidBrush(System.Drawing.Color.White), destinationBounds);

    float resizeRatio, sourceRatio;
    float scaleWidth, scaleHeight;

    sourceRatio = (float)source.Width / (float)source.Height;

    if (sourceRatio >= 1.0f)
    {
        //landscape
        resizeRatio = destinationBounds.Width / sourceBounds.Width;
        scaleWidth = destinationBounds.Width;
        scaleHeight = sourceBounds.Height * resizeRatio;
        float trimValue = destinationBounds.Height - scaleHeight;
        graph.DrawImage(source, 0, (trimValue / 2), destinationBounds.Width, scaleHeight);
    }
    else
    {
        //portrait
        resizeRatio = destinationBounds.Height/sourceBounds.Height;
        scaleWidth = sourceBounds.Width * resizeRatio;
        scaleHeight = destinationBounds.Height;
        float trimValue = destinationBounds.Width - scaleWidth;
        graph.DrawImage(source, (trimValue / 2), 0, scaleWidth, destinationBounds.Height);
    }

    return destinationImage;

}
Lxx answered 27/12, 2011 at 15:17 Comment(0)
N
7

In the application I made it was necessary to create a function with multiple options. It's quite large, but it resizes the image, can keep the aspect ratio and can cut of the edges to return only the center of the image:

/// <summary>
    /// Resize image with a directory as source
    /// </summary>
    /// <param name="OriginalFileLocation">Image location</param>
    /// <param name="heigth">new height</param>
    /// <param name="width">new width</param>
    /// <param name="keepAspectRatio">keep the aspect ratio</param>
    /// <param name="getCenter">return the center bit of the image</param>
    /// <returns>image with new dimentions</returns>
    public Image resizeImageFromFile(String OriginalFileLocation, int heigth, int width, Boolean keepAspectRatio, Boolean getCenter)
    {
        int newheigth = heigth;
        System.Drawing.Image FullsizeImage = System.Drawing.Image.FromFile(OriginalFileLocation);

        // Prevent using images internal thumbnail
        FullsizeImage.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipNone);
        FullsizeImage.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipNone);

        if (keepAspectRatio || getCenter)
        {
            int bmpY = 0;
            double resize = (double)FullsizeImage.Width / (double)width;//get the resize vector
            if (getCenter)
            {
                bmpY = (int)((FullsizeImage.Height - (heigth * resize)) / 2);// gives the Y value of the part that will be cut off, to show only the part in the center
                Rectangle section = new Rectangle(new Point(0, bmpY), new Size(FullsizeImage.Width, (int)(heigth * resize)));// create the section to cut of the original image
                //System.Console.WriteLine("the section that will be cut off: " + section.Size.ToString() + " the Y value is minimized by: " + bmpY);
                Bitmap orImg = new Bitmap((Bitmap)FullsizeImage);//for the correct effect convert image to bitmap.
                FullsizeImage.Dispose();//clear the original image
                using (Bitmap tempImg = new Bitmap(section.Width, section.Height))
                {
                    Graphics cutImg = Graphics.FromImage(tempImg);//              set the file to save the new image to.
                    cutImg.DrawImage(orImg, 0, 0, section, GraphicsUnit.Pixel);// cut the image and save it to tempImg
                    FullsizeImage = tempImg;//save the tempImg as FullsizeImage for resizing later
                    orImg.Dispose();
                    cutImg.Dispose();
                    return FullsizeImage.GetThumbnailImage(width, heigth, null, IntPtr.Zero);
                }
            }
            else newheigth = (int)(FullsizeImage.Height / resize);//  set the new heigth of the current image
        }//return the image resized to the given heigth and width
        return FullsizeImage.GetThumbnailImage(width, newheigth, null, IntPtr.Zero);
    }

To make it easier to acces the function it's possible to add some overloaded functions:

/// <summary>
    /// Resize image with a directory as source
    /// </summary>
    /// <param name="OriginalFileLocation">Image location</param>
    /// <param name="heigth">new height</param>
    /// <param name="width">new width</param>
    /// <returns>image with new dimentions</returns>
    public Image resizeImageFromFile(String OriginalFileLocation, int heigth, int width)
    {
        return resizeImageFromFile(OriginalFileLocation, heigth, width, false, false);
    }

    /// <summary>
    /// Resize image with a directory as source
    /// </summary>
    /// <param name="OriginalFileLocation">Image location</param>
    /// <param name="heigth">new height</param>
    /// <param name="width">new width</param>
    /// <param name="keepAspectRatio">keep the aspect ratio</param>
    /// <returns>image with new dimentions</returns>
    public Image resizeImageFromFile(String OriginalFileLocation, int heigth, int width, Boolean keepAspectRatio)
    {
        return resizeImageFromFile(OriginalFileLocation, heigth, width, keepAspectRatio, false);
    }

Now are the last two booleans optional to set. Call the function like this:

System.Drawing.Image ResizedImage = resizeImageFromFile(imageLocation, 800, 400, true, true);
Nitrous answered 13/12, 2012 at 9:19 Comment(0)
G
7
public string CreateThumbnail(int maxWidth, int maxHeight, string path)
{

    var image = System.Drawing.Image.FromFile(path);
    var ratioX = (double)maxWidth / image.Width;
    var ratioY = (double)maxHeight / image.Height;
    var ratio = Math.Min(ratioX, ratioY);
    var newWidth = (int)(image.Width * ratio);
    var newHeight = (int)(image.Height * ratio);
    var newImage = new Bitmap(newWidth, newHeight);
    Graphics thumbGraph = Graphics.FromImage(newImage);

    thumbGraph.CompositingQuality = CompositingQuality.HighQuality;
    thumbGraph.SmoothingMode = SmoothingMode.HighQuality;
    //thumbGraph.InterpolationMode = InterpolationMode.HighQualityBicubic;

    thumbGraph.DrawImage(image, 0, 0, newWidth, newHeight);
    image.Dispose();

    string fileRelativePath = "newsizeimages/" + maxWidth + Path.GetFileName(path);
    newImage.Save(Server.MapPath(fileRelativePath), newImage.RawFormat);
    return fileRelativePath;
}

Click here http://bhupendrasinghsaini.blogspot.in/2014/07/resize-image-in-c.html

Glyndaglynias answered 15/7, 2014 at 11:21 Comment(0)
G
3

If you're working with a BitmapSource:

var resizedBitmap = new TransformedBitmap(
    bitmapSource,
    new ScaleTransform(scaleX, scaleY));

If you want finer control over quality, run this first:

RenderOptions.SetBitmapScalingMode(
    bitmapSource,
    BitmapScalingMode.HighQuality);

(Default is BitmapScalingMode.Linear which is equivalent to BitmapScalingMode.LowQuality.)

Gleam answered 18/2, 2016 at 22:12 Comment(0)
R
1

Note: this will not work with ASP.Net Core because WebImage depends on System.Web, but on previous versions of ASP.Net I used this snippet many times and was useful.

String ThumbfullPath = Path.GetFileNameWithoutExtension(file.FileName) + "80x80.jpg";
var ThumbfullPath2 = Path.Combine(ThumbfullPath, fileThumb);
using (MemoryStream stream = new MemoryStream(System.IO.File.ReadAllBytes(fullPath)))
{
      var thumbnail = new WebImage(stream).Resize(80, 80);
      thumbnail.Save(ThumbfullPath2, "jpg");
}
Rather answered 29/1, 2017 at 21:26 Comment(0)
H
1

Below function will return the new size to display the image.This may not be helpful here.But it will return resized Display Rectangle size.

 public static  class ResizeImage
{
    /// <summary>
    /// Return new resized size to display the image
    /// </summary>
    /// <param name="srcrectanle">source rectangle of image or you can pass the bitmap and set the size accrodingly</param>
    /// <param name="initSize">initial size of the page to draw image</param>
    /// <returns></returns>
    public static SizeF getResizedRectangle(RectangleF srcrectanle, SizeF initSize)
    {
        float sw = srcrectanle.Width;
        float sh = srcrectanle.Height;
        float dw = initSize.Width;
        float dh = initSize.Height;
        float finalHeight, finalWidth;
        float sourceRatio = sw / sh;
        float destRatio = dw / dh;

        if (sourceRatio >= destRatio)
        {
            finalWidth = (int)dw;
            float ratio = sw / dw;
            finalHeight = (sh / ratio);
        }
        else
        {
            finalHeight = (int)dh;
            float ratio = sh / dh;
            finalWidth = (sw / ratio);
        }
        return new SizeF(finalHeight, finalHeight);


    }
}
Hurry answered 19/6, 2021 at 7:32 Comment(3)
You are returning the value of finalHeight twice, don't you want return new SizeF(finalHeight, finalWidth)?Stake
haha that was supposed to be return new SizeF(finalHeight, finalWidth)Hurry
Looking at SizeF I see that I had that backward, should actually be: return new SizeF(finalWidth, finalHeight);Stake
F
0

Resize and save an image to fit under width and height like a canvas keeping image proportional

using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;

namespace Infra.Files
{
    public static class GenerateThumb
    {
        /// <summary>
        /// Resize and save an image to fit under width and height like a canvas keeping things proportional
        /// </summary>
        /// <param name="originalImagePath"></param>
        /// <param name="thumbImagePath"></param>
        /// <param name="newWidth"></param>
        /// <param name="newHeight"></param>
        public static void GenerateThumbImage(string originalImagePath, string thumbImagePath, int newWidth, int newHeight)
        {
            Bitmap srcBmp = new Bitmap(originalImagePath);
            float ratio = 1;
            float minSize = Math.Min(newHeight, newHeight);

            if (srcBmp.Width > srcBmp.Height)
            {
                ratio = minSize / (float)srcBmp.Width;
            }
            else
            {
                ratio = minSize / (float)srcBmp.Height;
            }

            SizeF newSize = new SizeF(srcBmp.Width * ratio, srcBmp.Height * ratio);
            Bitmap target = new Bitmap((int)newSize.Width, (int)newSize.Height);

            using (Graphics graphics = Graphics.FromImage(target))
            {
                graphics.CompositingQuality = CompositingQuality.HighSpeed;
                graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
                graphics.CompositingMode = CompositingMode.SourceCopy;
                graphics.DrawImage(srcBmp, 0, 0, newSize.Width, newSize.Height);

                using (MemoryStream memoryStream = new MemoryStream())
                {
                    target.Save(thumbImagePath);
                }
            }
        }
    }
}
Feces answered 1/2, 2017 at 20:58 Comment(0)
H
0

Use below function with below example for changing image size :

//Example : 
System.Net.Mime.MediaTypeNames.Image newImage = System.Net.Mime.MediaTypeNames.Image.FromFile("SampImag.jpg");
System.Net.Mime.MediaTypeNames.Image temImag = FormatImage(newImage, 100, 100);

//image size modification unction   
public static System.Net.Mime.MediaTypeNames.Image FormatImage(System.Net.Mime.MediaTypeNames.Image img, int outputWidth, int outputHeight)
{

    Bitmap outputImage = null;
    Graphics graphics = null;
    try
    {
         outputImage = new Bitmap(outputWidth, outputHeight, System.Drawing.Imaging.PixelFormat.Format16bppRgb555);
         graphics = Graphics.FromImage(outputImage);
         graphics.DrawImage(img, new Rectangle(0, 0, outputWidth, outputHeight),
         new Rectangle(0, 0, img.Width, img.Height), GraphicsUnit.Pixel);

         return outputImage;
     }
     catch (Exception ex)
     {
           return img;
     }
}
Henley answered 17/1, 2018 at 9:41 Comment(2)
Please consider to explain in your answer above how to use this code, what the code does, and how it solves the problem in the original question.Shirtmaker
I have added use case also. Use above functionwith bellow example. Image newImage = Image.FromFile("SampImag.jpg"); Image temImag = FormatImage(newImage, 100, 100);Henley
C
0

Adding another answer for the sake of completeness

For modern .NET core apps, using System.Drawing is not the best choice especially if you need cross-platform resizing without OS dependencies (libgdi in this case).

I've used ImageSharp library in the past (it's 100% managed code so no OS dependencies). However it uses too much memory for our use case.

That is why we switched to PhotoSauce. This library does depend on a native codec, but it is distributed nicely with the nuget-package and works cross-platform (tested on win64, linux64 various distros).

P.S. I'm not affiliated with any of the above just wanted to recommend an awesome product (PhotoSauce).

Calve answered 15/4 at 18:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.