System.Drawing.Imaging.Encoder.Quality file size changing strangely - c#

I am trying out working with images and i came up to some strange behavior when using Encoder.Quality
I am having code like this:
try
{
Image myImage = Image.FromStream(file.OpenReadStream());
string final = "";
MemoryStream ts = new MemoryStream();
SaveJpeg(ts, myImage, 100);
final += (ts.Capacity * 0.0009765625).ToString("0") + ", ";
for (int i = 0; i <= 10; i++)
{
MemoryStream testStream = new MemoryStream();
SaveJpeg(testStream, myImage, i * 10);
final += (testStream.Capacity * 0.0009765625).ToString("0") + ", ";
}
return Json(final);
}
catch (Exception ex)
{
return View("Error", ex.ToString());
}
public static void SaveJpeg(string path, Image img, int quality)
{
if (quality < 0)
quality = 0;
if (quality > 100)
quality = 100;
// Encoder parameter for image quality
EncoderParameter qualityParam = new EncoderParameter(Encoder.Quality, quality);
// JPEG image codec
ImageCodecInfo jpegCodec = GetEncoderInfo("image/jpeg");
EncoderParameters encoderParams = new EncoderParameters(1);
encoderParams.Param[0] = qualityParam;
img.Save(path, jpegCodec, encoderParams);
}
public static void SaveJpeg(Stream stream, Image img, int quality)
{
if (quality < 0)
quality = 0;
if (quality > 100)
quality = 100;
// Encoder parameter for image quality
EncoderParameter qualityParam = new EncoderParameter(Encoder.Quality, quality);
// JPEG image codec
ImageCodecInfo jpegCodec = GetEncoderInfo("image/jpeg");
EncoderParameters encoderParams = new EncoderParameters(1);
encoderParams.Param[0] = qualityParam;
img.Save(stream, jpegCodec, encoderParams);
}
/// <summary>
/// Returns the image codec with the given mime type
/// </summary>
private static 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;
}
It is asp.net core but i think that dosn't matter.
What matters here is that file i upload is "jpg" and it's size is 201kb but output from this code is 512, 29, 41, 53, 128, 128, 128, 128, 128, 128, 256, 512, (first number is quality 100, others are 0, 10, 20... 100)
When i store it into MemoryStream without changing quality i get same file size as my file.
Here i have two questions.
Is quality level 90-100 somehow "enchancing" image quality?
Why is image size from level 40-90 all same size, does it make any difference?

Related

PDFium Saving pdf as image specify color depth

I am trying to export pdfs as jpeg using pdfium viewer. How can I specify the color depth of the jpeg image? Do I have to edit the stream using System.Drawing.Imaging or can does anyone know of a way to do it with pdfium? https://github.com/pvginkel/PdfiumViewer is what I am using to render the pdf and create the image.
using (var document = PdfiumViewer.PdfDocument.Load(file.ToString()))
{
for (int page = 0; page < document.PageCount; page++)
{
var image = document.Render(page, 2550, 3300, 72, 72, false);
image.Save(filepath + "\\" + filename + "-" + (page + 1) + ".jpg", ImageFormat.Jpeg);
}
}
Have to set the image encoder properties to change them. This is showing from bump to tiff but explains what I was looking for.
using System;
using System.Drawing;
using System.Drawing.Imaging;
class Example_SetColorDepth
{
public static void Main()
{
Bitmap myBitmap;
ImageCodecInfo myImageCodecInfo;
Encoder myEncoder;
EncoderParameter myEncoderParameter;
EncoderParameters myEncoderParameters;
// Create a Bitmap object based on a BMP file.
myBitmap = new Bitmap(#"C:\Documents and Settings\All Users\Documents\My Music\music.bmp");
// Get an ImageCodecInfo object that represents the TIFF codec.
myImageCodecInfo = GetEncoderInfo("image/tiff");
// Create an Encoder object based on the GUID
// for the ColorDepth parameter category.
myEncoder = Encoder.ColorDepth;
// Create an EncoderParameters object.
// An EncoderParameters object has an array of EncoderParameter
// objects. In this case, there is only one
// EncoderParameter object in the array.
myEncoderParameters = new EncoderParameters(1);
// Save the image with a color depth of 24 bits per pixel.
myEncoderParameter =
new EncoderParameter(myEncoder, 24L);
myEncoderParameters.Param[0] = myEncoderParameter;
myBitmap.Save("Shapes24bpp.tiff", myImageCodecInfo, myEncoderParameters);
}
private static ImageCodecInfo GetEncoderInfo(String mimeType)
{
int j;
ImageCodecInfo[] encoders;
encoders = ImageCodecInfo.GetImageEncoders();
for(j = 0; j < encoders.Length; ++j)
{
if(encoders[j].MimeType == mimeType)
return encoders[j];
}
return null;
}
}

Loaded bitmap differs from saved one in jpeg (c#)

I'm using following methods to load bitmap from jpeg file (JpegToBitmap):
private static Bitmap JpegToBitmap(string fileName)
{
FileStream jpg = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
JpegBitmapDecoder ldDecoder = new JpegBitmapDecoder(jpg, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
BitmapFrame lfFrame = ldDecoder.Frames[0];
Bitmap lbmpBitmap = new Bitmap(lfFrame.PixelWidth, lfFrame.PixelHeight);
Rectangle lrRect = new Rectangle(0, 0, lbmpBitmap.Width, lbmpBitmap.Height);
BitmapData lbdData = lbmpBitmap.LockBits(lrRect, ImageLockMode.WriteOnly, (lfFrame.Format.BitsPerPixel == 24 ? PixelFormat.Format24bppRgb : PixelFormat.Format32bppArgb));
lfFrame.CopyPixels(System.Windows.Int32Rect.Empty, lbdData.Scan0, lbdData.Height * lbdData.Stride, lbdData.Stride);
lbmpBitmap.UnlockBits(lbdData);
return lbmpBitmap;
}
And to save bitmap to jpeg file:
private static void SaveToJpeg(Bitmap bitmap, string filePath)
{
EncoderParameters encoderParameters = new EncoderParameters(1);
encoderParameters.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 100L);
bitmap.Save(filePath, GetEncoder(ImageFormat.Jpeg), encoderParameters);
}
public static ImageCodecInfo GetEncoder(ImageFormat format)
{
ImageCodecInfo[] codecs = ImageCodecInfo.GetImageDecoders();
foreach (ImageCodecInfo codec in codecs)
{
if (codec.FormatID == format.Guid)
{
return codec;
}
}
return null;
}
Bitmap pixels differs just a little bit, but this difference is significant for me:
Screenshot of values in matrix of colors of bitmap before save
Screenshot of values in same matrix of colors of bitmap after load
This matrixes are just 2-d arrays of Color got by standart bitmap.GetPixel(x,y) in a loop.
public ColorMatrix(Bitmap bitmap, int currHeight, int currWidth)
{
matrix = new Color[8, 8];
for (int y = 0; y < 8; y++)
{
for (int x = 0; x < 8; x++)
{
matrix[y, x] = bitmap.GetPixel(x + currWidth, y + currHeight);
}
}
}
So, the question is: How can i load saved bitmap (in jpeg/png or whatever format) correctly?
There are three reasons:
JPEG encoding and decoding processes use floating point arithmetic on integer input.
The Cb and Cr components are often subsampled relative to the Y component during compression.
During the quantization (fancy word for integer division) phase, DCT coefficients are usually discarded.

How to edit/ reduce/ resize image C#?

In my project, I need to resize the image (e.g.1080 to 720), reduce the file size (may be resolution, 0-100) which is uploaded by client, so that they can then download it.
I can reduce the file size (by resolution) in C#, but not scale and resize. Can anyone tell me how to do that, even using APIs or frameworks.
My reduce resolution code in C#: (from this post)
public static void Saveimage(string path, Image img, int quality)
{
if (quality < 0 || quality > 100)
throw new ArgumentOutOfRangeException("quality must be between 0 and 100.");
// Encoder parameter for image quality
EncoderParameter qualityParam = new EncoderParameter(Encoder.Quality, quality);
string imageType = GetImageFormat(img);
ImageCodecInfo imageCodec = GetEncoderInfo(imageType);
EncoderParameters encoderParams = new EncoderParameters(1);
encoderParams.Param[0] = qualityParam;
img.Save(path, imageCodec, encoderParams);
}
private static 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;
}
public static string GetImageFormat(Image img)
{
if (img.RawFormat.Equals(System.Drawing.Imaging.ImageFormat.Jpeg))
return "image/jpeg";
if (img.RawFormat.Equals(System.Drawing.Imaging.ImageFormat.Png))
return "image/png";
if (img.RawFormat.Equals(System.Drawing.Imaging.ImageFormat.Tiff))
return "image/tiff";
else
return "image/jpeg";
}
Call:
Saveimage(#"C:\mypath", myImage, 1);

My image is not compressing

Loading code from filesystem:
System.Drawing.Image image = System.Drawing.Image.FromFile(<location of original image>););
Loading code from browser request:
var memoryStream = new MemoryStream();
using (memoryStream)
{
System.Web.HttpContext.Current.Request.Files[upload].InputStream.CopyTo(memoryStream);
memoryStream.ToArray();
}
byte[] bytes = memoryStream.GetBuffer();
// Get the image from the server
System.Drawing.Image image = new System.Drawing.Bitmap( System.Web.HttpContext.Current.Request.Files[upload].InputStream );
Resize image call:
System.Drawing.Image image = this.ResizeImage(
image,
originalImagePath,
ImageSizeType.Original,
null,
null)
Save image call:
image.Save(<location to save>);
The code that doesn't compress the image:
private System.Drawing.Image ResizeImage(System.Drawing.Image image, string filePath, string sizeType, int? _width, int? height )
{
...
System.Drawing.Bitmap b = new System.Drawing.Bitmap(width, resizeHeight);
b.SetResolution(72, 72);
System.Drawing.Graphics g = System.Drawing.Graphics.FromImage((System.Drawing.Image)b);
g.CompositingQuality = CompositingQuality.HighSpeed;
//g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.InterpolationMode = InterpolationMode.Low;
g.SmoothingMode = SmoothingMode.HighSpeed;
g.DrawImage(image, 0, 0, width, resizeHeight);
g.Dispose();
return (System.Drawing.Image)b;
}
No matter what I do to this image, when it saves, it saves at a really high kb.
For example... a jpg of 1024 x 768 # 300kb becomes 600 x 400 # 800kb
What am I doing wrong?
As Magnus rightly said, the drawing to the canvas makes no difference to size... of file...
It was the save file part that was being all noob... This is what it should be:
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;
}
...
if( mimeType.ToLower() == "image/jpeg")
{
ImageCodecInfo jpgEncoder = this.GetEncoderInfo("image/jpeg")
System.Drawing.Imaging.Encoder myEncoder = System.Drawing.Imaging.Encoder.Quality;
EncoderParameters myEncoderParameters = new EncoderParameters(1);
EncoderParameter myEncoderParameter = new EncoderParameter(myEncoder, 80L);
myEncoderParameters.Param[0] = myEncoderParameter;
image.Save(systemFilePath, jpgEncoder, myEncoderParameters);
}
else
{
image.Save(systemFilePath);
}

save pictures to harddrive

I'm trying to resize and safe a picture I've done some research and tried to get sommething working. Almost everythin works but the saving gaves me an invalid argument exception.
This is what I have:
private void ResizeImage(Image image)
{
int maxWidth = 100;
int maxHeight = 100;
int imageWidth = image.Size.Width;
int imageHeight = image.Size.Height;
double maxRatio = (double)maxWidth / (double)maxHeight;
double picRatio = (double)imageWidth / (double)imageHeight;
Image newImage = null;
if (maxRatio > picRatio && imageWidth > maxWidth)
{
newImage = new Bitmap(image, new System.Drawing.Size(Convert.ToInt32(maxWidth / picRatio), maxHeight));
}
else if (maxRatio < picRatio && imageHeight > maxHeight)
{
newImage = new Bitmap(image, new System.Drawing.Size(maxWidth, Convert.ToInt32(maxHeight / picRatio)));
}
// Encoder parameter for image quality
EncoderParameter qualityParam = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality,1);
// Jpeg image codec
ImageCodecInfo jpegCodec = this.getEncoderInfo("image/jpeg");
if(jpegCodec != null){
EncoderParameters encoderParams = new EncoderParameters(1);
encoderParams.Param[0] = qualityParam;
newImage.Save(#".\temp\pdf\photos\test.jpg",jpegCodec,encoderParams);
}
}
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;
}
But when I try to run it, it gives me an invalid argument exception on newImage.save()
According to MSDN, encoder quality parameter should be a 64-bit (long) value. Change this line:
var qualityParam = new EncoderParameter(Encoder.Quality, 1);
to
var qualityParam = new EncoderParameter(Encoder.Quality, 1L);

Categories

Resources