I have the following line of code which takes my HttpPostedFileBase and converts it to an image.
I have messed around with Encoder Parameteres to try and resize the image but can't seem to do this.
What is the best way to resize the image to 250x250?
I would also prefer it to take the middle of the image as 250x250 rectangle rather than somewhere random.
What is the most space efficent way to convert and save the image as it will be going in the database?
Please note that model.Image is of type HttpPostedFileBase.
var image = Image.FromStream(model.Image.InputStream, true, true);
ImageCodecInfo jpgInfo = ImageCodecInfo.GetImageEncoders()
.Where(codecInfo => codecInfo.MimeType == "image/jpeg").First();
using (EncoderParameters encParams = new EncoderParameters(1))
{
encParams.Param[0] = new EncoderParameter(Encoder.Quality, (long)50);
//quality should be in the range [0..100]
using (var ms = new MemoryStream())
{
// Convert Image to byte[]
image.Save(ms, ImageFormat.Jpeg);
byte[] imageBytes = ms.ToArray();
// Convert byte[] to Base64 String
string base64String = Convert.ToBase64String(imageBytes);
image64 = base64String;
}
}
The best way is to use an established library like ImageResizer; that way, you avoid re-inventing the wheel. If you are concerned about space efficiency (file size), use the JPEG format with maximum compression. Note that using JPEG's lossy encoding will drastically reduce image quality. If you want to use a lossless encoding, try PNG. Compressing PNG images is quite difficult in .NET, in my experience. I searched in vain awhile back for a single library that would do it and all I found were thick-client Windows applications.
Related
I've got a bunch of images stored on disk, with the mimetype of the image stored in a database. If I want to save the image to disk I can use Image.Save(string) (or the Async version) without needing to know the MimeType of the image.
However, if I want to save to a stream (for example, Response.Body) then I have to use Image.Save(Stream, IImageEncoder).
How do I get the IImageEncoder I need to save to the stream (without just declaring that "All my images ar png/jpeg/bmp" and using e.g. JpegEncoder)?
ImageSharp can already tell you the mimetype of the input image. With your code if the
mimetype doesn't match the input stream then the decode will fail.
(Image Image, IImageFormat Format) imf = await Image.LoadWithFormatAsync(file.OnDiskFilename);
using Image img = imf.Image;
img.Save(Response.Body, imf.Format);
What we are missing however in the current API v1.0.1 is the ability to save asynchronously while passing the format. We need to add that.
It took a bit of messing about, but I've figured it out:
var file = ... // From DB
ImageFormatManager ifm = Configuration.Default.ImageFormatsManager;
IImageFormat format = ifm.FindFormatByMimeType(file.MimeType);
IImageDecoder decoder = ifm.FindDecoder(format);
IImageEncoder encoder = ifm.FindEncoder(format);
using Image img = await Image.LoadAsync(file.OnDiskFilename, decoder);
// Do what you want with the Image, e.g.: img.Mutate(i => i.Resize(width.Value, height.Value));
Response.ContentType = format.DefaultMimeType; // In case the stored mimetype was something weird
await img.SaveAsync(Response.Body, encoder);
(Although I'm happy to be shown a better way)
We have a system that provides images in 8-bit grayscale either tiff or jpg formats. However, the component we have to process the images expects image to be in 8-bit jpg format.
When I use .Net to save the tiff images as jpg it convets it to 24-bit image.
Is there a way, hopefully simple and fast, to convert 8-bit grayscale tiff images to equivalent jpg?
I tried and tried just to conclude that I'm sorry: .Net library's Bitmap class DOES NOT save JPEG as 8bpp even when explicitly stated and data is in grayscale.
(note: although stated in some places, JPEG format DOES support 8bpp).
At Convert an image to grayscale you may find code snipet to convert to grayscale any Image.
Using that code, I was able to save a 8bpp grayscale Image instance with '.jpeg' extension, but stating ImageFormat.Gif... that's a cheat...
My findings show as solution an entirely different approach.
The FreeImage library offers powerful APIs, including the feature needed to solve your problem.
It's home page is at http://freeimage.sourceforge.net/faq.html
But, I could not easily compile it in my Win2008 + VS 2010 machine.
One ought to sweat a lot to make it run on modern environments.
Some hints on how to accomplish that are found at http://www.sambeauvois.be/blog/2010/05/freeimage-and-x64-projects-yes-you-can/
Good luck!
Image img = Image.FromFile(filePathOriginal);
Bitmap bmp = ConvertTo8bpp(img);
EncoderParameters parameters = new EncoderParameters();
parameters.Param[0] = new EncoderParameter(Encoder.ColorDepth, 8);
bmp.Save(filePathNew, jpgCodec, parameters);
bmp.Dispose();
img.Dispose();
...
private static Bitmap ConvertTo8bpp(Image img) {
var bmp = new Bitmap(img.Width, img.Height, System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
using (var gr = Graphics.FromImage(bmp))
{
gr.DrawImage(img, new Rectangle(0, 0, img.Width, img.Height));
}
return bmp;
}
I have array of image bytes and I would like to set resolution. Original image can be JPEG, PNG, BMP. Output - PNG. I am using ImageMagic to convert image and do some manipulations.
using (var image = this.Convert(originalImage, height, width))
using (var stream = new MemoryStream())
{
image.Quality = 90;
image.Write(stream, MagickFormat.Png);
return stream.GetBuffer();
}
I tryed to modify image.GetExifProfile, but has no success (at least for PNG images).
I can't use any comandline tool (like ImageMagic or ExifTool) here.
There are 3 exiff tags I need to modify
XResolution
YResolution
ResolutionUnit
I can successfully achieve this with bitmap, but it also resource overhead (need to create MemoryStream ...).
I have found some Pdf specification, but it will consume time to make it all work.
Does any can point me to right direction?
Thanks.
I have a winform C# desktop application.
I have a constant stream of jpegs coming in.
I am comparing the current image with the previous 1.
By using a 3rd party tool - Emgu - I can create a new image that contains just the differences.
I then convert that image to a memory stream and then to a byte array.
In the receiving application I take this byte array and load the image via a memory stream using these bytes.
The trouble is that the image degrades quite a lot.
If I save the image to the hard drive before converting it to a memory stream on the client side the quality of the image is good.
The problem lies when i load it as a memory stream.
I encode it as jpeg.
If I encode it as a PNG before sending to the server the quality is good again.
The trouble with encoding to PNG the size in the byte array shoots up.
What my intention was all along was to reduce the number of bytes I have to upload to improve response time.
Am I doing something wrong or can this not be done?
This is my code:
Bitmap imgContainingDifference
= GetDiffFromEmgu(CurrentJpegImage, PreviousJpegImage);
using (System.IO.MemoryStream msIn = new System.IO.MemoryStream())
{
holding.Save(msIn, System.Drawing.Imaging.ImageFormat.Jpeg);
data = msIn.ToArray();
}
//test here
using (System.IO.MemoryStream msOut = new System.IO.MemoryStream(_data))
{
Bitmap testIMG = (Bitmap)Image.FromStream(msOut);
}
//result is image is poor/degrades
If I do this instead:
using (System.IO.MemoryStream msIn = new System.IO.MemoryStream())
{
holding.Save(msIn, System.Drawing.Imaging.ImageFormat.Png);
data = msIn.ToArray();
}
using (System.IO.MemoryStream msOut = new System.IO.MemoryStream(_data))
{
Bitmap testIMG = (Bitmap)Image.FromStream(msOut);
}
//Image is good BUT the size of the byte array is
//10 times the size of the CurrentFrame right at the start.
This is what the image looks like when using the kid suggestion from :
I have now tried using a encoder from the kind suggestion from #MagnatLU and I also get the same quality of image if I use FreeImage.Net.
You can set JPEG compression level when encoding your file to value that is the best empirical tradeoff between quality and size.
I have a cannon digital camera and I set it to take pictures with superfine quality and it outputs a .jpg file 3 mega in size.
If I load it like this in ASP.NET(this is useful to change it's dpi resolution or crop it or whaterver)
imgPicture = Image.FromFile(Config.WorkDirectory + this.TempPhotoName);
bmpPicture = new Bitmap(imgPicture);
and then I save it again like this:
bmpModified.Save(Config.WorkDirectory + this.TempPhotoName,System.Drawing.Imaging.ImageFormat.Jpeg);
it outputs a jpg that is only 700KB or so in size. There is a loss of quality.
I also tried saving it like this:
bmpPicture.Save(Config.WorkDirectory + this.TempPhotoName, codecJpeg, encparams);
where codecJpeg is
ImageCodecInfo codecJpeg = this.getEncoderInfo("image/jpeg");
private ImageCodecInfo getEncoderInfo(string mimeType)
{
// Get image codecs for all image formats
ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();
// Find the correct image codec
for (int i = 0; i < codecs.Length; i++)
if (codecs[i].MimeType == mimeType)
return codecs[i];
return null;
}
and encparams:
EncoderParameters encparams = new EncoderParameters(1);
encparams.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 97L);
This way the size(and I suspect also the quality) is maintained but I am inputing the quality by hand.
I want to ask:
Is there a way to save the image with the same quality as it was loaded without hardcoding the quality value?
Thank you in advance
So it sounds like you know how to set the quality, you really just need to know how to fetch the quality from the original image?
I suspect that Image.PropertyItems is your friend, if the quality is in the metadata to start with. (I don't know if there's even a standard scale for quality within JPEG encoders.)
EDIT: I've just checked, and a jpeg I downloaded didn't have any tags for quality.
One option might be to work out how big the file should end up to have roughly the same quality, and then save it several times, doing a binary search to work out the most appropriate quality. Icky, but it might just work.
I have a sneaking suspicion that there isn't a way to just preserve the original quality setting, although I don't have very good grounds for that suspicion...
Read here how to save image without re-encoding image: How-to: Re-encode a JPEG Image with Metadata.
However, if you do cropping or another image manipulation it impossible to do it without quality loss (well technically it is possible to do loss-less crop, if you work with boundaries that multiply of 16, but AFAIK it is cannot be done with libraries available in .net).
You must use the additional parameters which tell GDI+ to detect the color scheme.
For instance:
using (var img = Image.FromStream(fileupload.InputStream, true,true))
{
img.Save(fileOnDisk, ImageFormat.Jpeg);
}
using (var img = Image.FromFile("yourimage", true))
{
img.Save(fileOnDisk, ImageFormat.Jpeg);
}