Resizing High Quality images for web - c#

Hi Guys I am resizing Images in C# and saving them as .png.
public static Bitmap resize(int x, int y, Image p)
{
Bitmap Img = new Bitmap(x,y);
using (Graphics gr = Graphics.FromImage(Img))
{
gr.SmoothingMode = SmoothingMode.HighQuality;
gr.InterpolationMode = InterpolationMode.HighQualityBicubic;
gr.PixelOffsetMode = PixelOffsetMode.HighQuality;
gr.DrawImage(p, new Rectangle(0, 0, x, y));
}
return Img;
}
The problem is that when a user uploads a high quality image such as Images from high end smartphones such as galaxys, iphones etc the filesize of the resulting resized image is quite high.
I have constructed a table of resized images file size and pixel size.
1) Img1 1280 * 666px => 458 kb
2) Img1 300 * 399px => 221kb
3) Img2 1280 * 1444px => 2.08mb
4) Img2 300 * 451px => 327kb
I know I have interpolation and smoothing set to high quality for example purposes and saving images as .png to preserve transparency. But what setting should I change to obtain a Image of reasonable quality and filesize ideal for HTML pages. My end goal is making a compromise between Image quality and FileSize. So please point me to to some link demonstrating Filsesize vs Quality comparison for quality of resized images so that I can make the choice myself.

There is one option you can play with, the PixelFormat.
using (Bitmap bmp = new Bitmap(x, y,
System.Drawing.Imaging.PixelFormat.Format32bppArgb))
{
using (Graphics gr = Graphics.FromImage(bmp))
{
gr.SmoothingMode = SmoothingMode.HighQuality;
gr.InterpolationMode = InterpolationMode.HighQualityBicubic;
gr.PixelOffsetMode = PixelOffsetMode.HighQuality;
gr.DrawImage(src, new Rectangle(0, 0, x, y));
}
}
Use 32 bit Argb only if you need the alpha channel (e.g. the image is transparent). You can also query the img.PixelFormat to see if the image even contains an alpha channel!
In this case you don't have to save it as PNG and can go with JPG which will result in lot smaller files!
Normal jpg usually use Format24bppRgb.

Use JPEG instead and adjust the compression for the quality you need.

Related

C#.Net How do I resize pixel art without it becoming blurry?

So I've made a function that can create pixel art from an image by finding and setting the average colour in a grid with dimensions specified by the user. But while the new picture looks like pixel art, each "pixel" is a grid of actual pixels of the same colour. My resize function below divides the height and width of the image by the number of smaller pixels in the grid. And I'm stumped on why it turns out blurry after changing the interpolation mode and all that. Any help is greatly appreciated.
Original:
face
Face after going through my function, but still full size:
pixel art
Pixel art after being resized by the below function: blurry
If I upload the blurry picture to a program like Piskel.com, I can see the pixel size is accurate, so I don't think the problem is in the ratio.
Edit: The resized picture should look exactly like the pixel art one
public static Bitmap Resize(Bitmap bmp, int scaleFactor)
{
//Where bmp is mypic.Image as a bitmap, scaleFactor is what I want to scale down by
int newWidth = bmp.Width / scaleFactor;
int newHeight = bmp.Height / scaleFactor;
Bitmap newImage = new Bitmap(newWidth, newHeight);
using (var graphics = Graphics.FromImage(newImage))
{
graphics.InterpolationMode = InterpolationMode.NearestNeighbor;
graphics.PixelOffsetMode = PixelOffsetMode.Half;
graphics.DrawImage(bmp, 0, 0, newWidth, newHeight);
}
return newImage;
}

Create multiple bitmap objects fast

What's the fastest way to create 500+ Bitmaps from 500+ different image files? They need to be HQ resized and converted to the pixel format Format32bppPArgb for faster painting.
I'm creating each Bitmap as follows:
Bitmap resized;
using (Bitmap original = new Bitmap(pathToFile))
{
resized = new Bitmap(width, height, PixelFormat.Format32bppPArgb);
resized.SetResolution(original.HorizontalResolution, original.VerticalResolution);
using (Graphics g = Graphics.FromImage(resized))
{
g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
g.DrawImage(original, 0, 0, width, height);
}
}
I'm running a new BackgroundWorker to handle each Bitmap creation, which speeds up the process substantially, but I'm still looking for more speed (without sacrificing image quality). Pre-sizing images is not a possibility for what I'm trying to do.
Any help would be greatly appreciated. :)

Create a bitmap in c# with specific pixelformat from an image without loading the image

sorry if this question is silly, i'm just starting with C#
I have an image in disk which I know the path. The image is 20000x10000 aprox in size and around 400MB in size (i know this looking at the image)
I need to load it in the code and resize it since the progam dies if I try to put in a picture box 400m of image, but if I do
Bitmap b0 = new Bitmap(pathImage);
int newWidth = (int)(b0.Width * escala);
int newHeight = (int)(b0.Height * escala);
// Convert other formats (including CMYK) to RGB.
Bitmap newImage = new Bitmap(newWidth, newHeight, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
// Draws the image in the specified size with quality mode set to HighQuality
using (Graphics graphics = Graphics.FromImage(newImage))
{
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.DrawImage(b0, 0, 0, newWidth, newHeight);
}
But when I do Bitmap b0 = new Bitmap(pathImage); it just dies since 20000x10000x32 it's too much for my poor memory.
The problem is that if not specified, c# just uses as pixel format Format32bppArgb but I want Format1bppIndexed, and the only way i've found to change the format is with the constructor
Bitmap(
int width,
int height,
int stride,
PixelFormat format,
IntPtr scan0
)
But for this constructor I need to know the size of the image, which in the code I don't know because it dies before the code can get it and know the size...
I'm lost. Any ideas?
EDIT:
Doing this
int width;
int height;
Image tif;
using (FileStream file = new FileStream(rutaImagenEntrada, FileMode.Open, FileAccess.ReadWrite))
{
using ( tif = Image.FromStream(stream: file,
useEmbeddedColorManagement: false,
validateImageData: false))
{
width = (int)tif.PhysicalDimension.Width;
height = (int)tif.PhysicalDimension.Height;
}
file.Close();
}
I get the size of the image I cannot load, and can create a bitmap with the pixelformat and size that i wanted, BUT everyway I try to upload it doesn't work, it still crashes on me.
I've tried using graphics .draw(tiff...) and tiff.getThumbnail(new size...) and it just dies on me.
It targets x86 and the .Net 3.5 since those are the requirements of the client...
Any ideas?
If FileStream works to open the file, you might want to give some of the other constructors of Bitmap a try, in particular Bitmap(Stream).
If that doesn't help, you might try loading the raw bmp data, creating a Bitmap with the format you want and copying the data into the Bitmap manually (I'm not familiar with C# Bitmaps, but there should be some way of accessing the data).
Hope this helps.

Possible to reproduce the "resize image" quality of Paint.NET?

I have been having a tough time creating a thumbnail that is not horrible quality. So far the best code i've come up with is:
Bitmap bmp = new Bitmap(width, height);
Graphics graphic = Graphics.FromImage(bmp);
graphic.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphic.SmoothingMode = SmoothingMode.HighQuality;
graphic.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphic.CompositingQuality = CompositingQuality.HighQuality;
graphic.DrawImage(photo, 0, 0, width, height);
return imageToByteArray(bmp);
Which produces this gem:
If I resize the same image in Paint.NET i get this:
Which is WAY better. Everything I've found on line points me to some variation of the code I have above. I know Paint.NET was open source at one point. Does anyone know what magic they were doing to create such nice resize functionality and if that functionality can be reproduced in C#?
UPDATE:
The original image from this example was a jpg
GIFs
I recalled reading that .NET has issues with palette-based formats, like GIF, so I dug up a few articles.
This article describes how to quantize (pick an optimum palette) to improve quality: http://msdn.microsoft.com/en-us/library/aa479306.aspx, as does this (badly formatted) article.
In brief, I believe GDI+ picks a non-optimum palette when performing the resize.
PNGs
PNGs are palette-based, so they may be prone to the same issues as GIFs. I'm not sure if it matters that the palette can be much larger.
JPEG-friendly example
This code should work fine on JPEGs (but does not render GIFs smoothly). If you try it and it pixelates a JPEG, then there is probably something else going on.
private static byte[] GetScaledImage( byte[] inputBytes, int width, int height ) {
Image img = null;
using( MemoryStream ms = new MemoryStream() ) {
ms.Write( inputBytes, 0, inputBytes.Length );
img = Image.FromStream( ms );
}
using( MemoryStream ms = new MemoryStream() ) {
using( Image newImg = new Bitmap( width, height ) ) {
using( Graphics g = Graphics.FromImage( newImg ) ) {
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.DrawImage( img, 0, 0, width, height );
newImg.Save( ms, img.RawFormat );
return ms.GetBuffer();
}
}
}
}
since Bitmap(int,int) is effectively Bitmap(int,int,PixelFormat.Format32bppArgb) I think the problem is in source image. Try to create another intermediate copy of the image of the same size as source image if using palette, then use that 32bppArgb image source for your resize function.

Best options for image resizing

I have to resize images exceeding a max size. Different methods I tried so far are not good enough:
System.Drawing.Image.GetThumbnailImage generates very poor quality images in general.
Playing with options like this one I can generate better images in quality but heavier than the original one.
Probably the second option (or something similar) is the best option and I would need to resize using the proper options.
Any advice?
EDIT
My option 2 was generating heavier images for some specific pictures. In general is working as expected so I'd say this is solved.
Try something like this:
public Bitmap Resize(Bitmap originalImage, int newWidth)
{
int newHeight = (int)Math.Round(originalImage.Height * (decimal)newWidth / originalImage.Width, 0);
var destination = new Bitmap(newWidth, newHeight);
using (Graphics g = Graphics.FromImage(destination))
{
g.SmoothingMode = SmoothingMode.AntiAlias;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
g.DrawImage(originalImage, 0, 0, newWidth, newHeight);
}
return destination;
}
I would go with using the WPF libs instead of the GDI+ libs. The WPF libs perform faster and I think they yield better results compared to the GDI+ libs.
Check out these excellent posts from Bertrand Le Roy.
Resizing images from the server using WPF/WIC instead of GDI+
Server-side resizing with WPF: now with JPG
The fastest way to resize images from ASP.NET. And it’s (more) supported-ish
Create a new Bitmap object, then using the Graphics object, re-draw the old image into the new image's buffer at the increased/decreased size based on the resize engine you want.
// inImage is your original
Bitmap outImage = new Bitmap(newWid, newHei);
Graphics gfx = Graphics.FromImage(outImage);
gfx.InterpolationMode = InterpolationMode.HighQualityBicubic;
gfx.DrawImage(inImage,
new Rectangle(0, 0, newWid, new Hei),
new Rectangle(0, 0, inImage.Width, inImage.Height),
GraphicsUnit.Pixel);

Categories

Resources