beebul
beebul

Reputation: 1003

Image uploading / Setting DPI but ensuring file-size <=200k

I have a form (using MVC2) which has an image-upload script, but the rules for the final image stored on the server are pretty strict. I can force the file to the dimensions I want but it always ends up exceeding the file-size required... so I can allow a sub-200k image but once my code has processed it ends up slightly bigger.

These are the rules I have to adhere to:

This is what I have currently:

[HttpPost]
public ActionResult ImageUpload(HttpPostedFileBase fileBase)
{
    ImageService imageService = new ImageService();

    if (fileBase != null  && fileBase.ContentLength > 0 && fileBase.ContentLength < 204800 && fileBase.ContentType.Contains("image/"))
    {
            string profileUploadPath = "~/Resources/images";

            Path.GetExtension(fileBase.ContentType);
            var newGuid = Guid.NewGuid();
            var extension = Path.GetExtension(fileBase.FileName);

            if (extension.ToLower() != ".jpg" && extension.ToLower() != ".gif") // only allow these types
            {
                return View("WrongFileType", extension);
            }

            EncoderParameters encodingParameters = new EncoderParameters(1);
            encodingParameters.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 70L); // Set the JPG Quality percentage

            ImageCodecInfo jpgEncoder = imageService.GetEncoderInfo("image/jpeg");
            var uploadedimage = Image.FromStream(fileBase.InputStream, true, true);

            Bitmap originalImage = new Bitmap(uploadedimage);
            Bitmap newImage = new Bitmap(originalImage, 274, 354);

            Graphics g = Graphics.FromImage(newImage);
            g.InterpolationMode = InterpolationMode.HighQualityBilinear;
            g.DrawImage(originalImage, 0, 0, newImage.Width, newImage.Height);

            var streamLarge = new MemoryStream();
            newImage.Save(streamLarge, jpgEncoder, encodingParameters);

            var fileExtension = Path.GetExtension(extension);
            var ImageName = newGuid + fileExtension;

            newImage.Save(Server.MapPath(profileUploadPath) + ImageName);
            //newImage.WriteAllBytes(Server.MapPath(profileUploadPath) + ImageName, streamLarge.ToArray());

            originalImage.Dispose();
            newImage.Dispose();
            streamLarge.Dispose();

            return View("Success");
        }
    return View("InvalidImage");
}

Just to add: The images are going off to print on a card so the DPI is important. But I realise that 200k is not a lot for a printed image.. none of these are my business rules! As it stands with this code an image uploaded that is pretty much 200k, ends up costing 238k(ish)

Upvotes: 1

Views: 3117

Answers (3)

Tom Chantler
Tom Chantler

Reputation: 14941

It's very difficult to calculate the size of a jpeg in advance. Having said that, you don't need to compress it much.

Let's just look at some metrics:

274 * 354 = 96996 pixels. If you have 8 bits per pixel and 3 colour channels (i.e. 24bit colour) then you have:

274* 354 * 8 * 3 = 2,327,904 bits = 290988 bytes = 284.17 kb.

200 / 284.17 ~ 0.70.

You only need to reduce it to 70% of its original size.

Sadly, it's at this point we get to the limit of my knowledge in this area! But I reckon that by saving as a jpeg it will be in the right size range anyway, even if saving at the highest quality setting.

I would guess at setting the quality to 70 and see what happens.

EDIT: DPI settings

Apparently you only need to change the EXIF data. See this answer: https://stackoverflow.com/a/4427411/234415

Upvotes: 3

Mark Ransom
Mark Ransom

Reputation: 308206

You should experiment with the JPEG quality setting. You currently have it set to 90, 80 might be sufficient and will result in a smaller file.

Upvotes: 2

Guffa
Guffa

Reputation: 700362

I see some problems with the code:

  • You are using GetThumbnailImage to create a thumbnail, but that is not intended for such large thumbnails. It works up to about 120x120 pixels. If the image has an embedded thumbnail, that will be used instead of scaling down the full image, so you will be scaling up a smaller image, with obvious quality problems.
  • You are saving the thumbnail to a memory stream, which you then just throw away.
  • You are saving the thumbnail to file without specifying the encoder, which means that it will either be saved as a low compressed JPEG image or a PNG image, that's why you get a larger file size.
  • You never dispose the uploadedImage object.

Note: The resolution (PPI/DPI) has no relevance when you display images on the web.

Upvotes: 1

Related Questions