0

I have an MVC application where you can upload a picture and it gets resized to max. 50KB. I do the resizing in a while loop but the problem is when i decrease the width and height of the picture the file size increases. At a certain point the size gets smaller but at the cost of quality

    Request.InputStream.Position = 0;
    string Data = new System.IO.StreamReader(Request.InputStream).ReadToEnd();
    var Base64 = Data.Split(',')[1];
    var BitmapBytes = Convert.FromBase64String(Base64);
    var Bmp = new Bitmap(new MemoryStream(BitmapBytes));

    while (BitmapBytes.Length > 51200)
    {
        int Schritte = 20; //I tested here also with 300
        int maxWidth = Bmp.Width;
        maxWidth = maxWidth - Schritte;
        int maxHeight = Bmp.Height;
        maxHeight = maxHeight - Schritte;
        Bmp = ScaleImage(Bmp, maxWidth, maxHeight);
        var base64 = ReturnImageAsBase64(Bmp);
        BitmapBytes = Convert.FromBase64String(base64);
    }

The Code to resize:

public static Bitmap ScaleImage(Image image, int maxWidth, int maxHeight)
{
    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);

    Bitmap newImage = new Bitmap(newWidth, newHeight);
    using (Graphics gr = Graphics.FromImage(newImage))
    {
        gr.SmoothingMode = SmoothingMode.HighQuality;
        gr.InterpolationMode = InterpolationMode.HighQualityBicubic;
        gr.PixelOffsetMode = PixelOffsetMode.HighQuality;
        gr.DrawImage(image, new Rectangle(0, 0, newWidth, newHeight));
     }
     return newImage;
}

I start with a Size of 66964 Bytes. After the first turn in the loop its 85151 Bytes and this although the width was reduced by 300 pixel and the height by 420 pixel.

Lexu
  • 579
  • 1
  • 5
  • 14
  • 1
    I would say that is a Problem of your Pixelformat. If you have for example a Bitmap with 1bpp (black or white) and draw that to your newImage in ScaleImage, the newImage is created with the default Pixelformat which is likely with Colors so you end up with 24bpp which results in a much higher Memory size. – Thomas Voß Aug 10 '16 at 09:00

1 Answers1

0

From my comment earlier:

I would say that is a Problem of your Pixelformat. If you have for example a Bitmap with 1bpp (black or white) and draw that to your newImage in ScaleImage, the newImage is created with the default Pixelformat which is likely with Colors so you end up with 24bpp which results in a much higher Memory size.

Try changing:

Bitmap newImage = new Bitmap(newWidth, newHeight);

to

Bitmap newImage = new Bitmap(newWidth, newHeight, image.PixelFormat);

Edit: As the use of indexed PixelFormats seem to be impossible to create a graphics object from, there seems to be no easy solution on this.

To explain the reason for the bigger Image size:

Original Image: Color lookup table:

1 = Red   = 255,  0,0
2 = Black =   0,  0,0
3 = Green =   0,255,0
...

         Column    
    Row  1  2  3  4
      1  1  1  1  1
      2  1  1  1  1
      3  2  2  2  2
      4  3  3  3  3

Here you have 16 Bytes for 16 Pixels and 12 Bytes for the lookup table (one byte for the index number and three bytes for the RGB channels for each color) So the total size of the Image is 28 Bytes

In the newImage there is no lookup table so each Pixel has the full RGB information:

         Column    
    Row  1            2            3            4
      1  (255,  0,0)  (255,  0,0)  (255,  0,0)  (255,  0,0)
      2  (255,  0,0)  (255,  0,0)  (255,  0,0)  (255,  0,0)
      3  (  0,  0,0)  (  0,  0,0)  (  0,  0,0)  (  0,  0,0)
      4  (  0,255,0)  (  0,255,0)  (  0,255,0)  (  0,255,0)

So the size of the newImage is 3*16=48 Bytes

Thomas Voß
  • 1,145
  • 8
  • 20
  • This throws an exception just in the next line where I create a new Graphic. (A graphic object cannot be created from an image that has an indexed pixel format.) – Lexu Aug 10 '16 at 09:09
  • That seems to be a limitation of the Graphics class. See here: http://stackoverflow.com/questions/17313285/graphics-on-indexed-image – Thomas Voß Aug 10 '16 at 09:29
  • But that perfectly explains what happens: Your original image is has a color lookup table and the pixels only point to the lookupentry for the color. In the new image the color is stored once per pixel so you retrive a bigger size for the image. – Thomas Voß Aug 10 '16 at 09:33
  • I changed the code so that it adds the BPP after the resizing, but I still get the same problem. I posted another question where I added some examples: https://stackoverflow.com/questions/38872777/c-sharp-picture-resizing-causing-unnormal-huge-quality-loss-compared-to-other – Lexu Aug 10 '16 at 11:57
  • Please don't forget to vote if you feel that the answer is correct. – Thomas Voß Aug 11 '16 at 04:18