1

I have a user gallery at the site and it is possible for visitors to upload some images. After upload image should be resized to some predefined presets. In addition original image should be saved too. All works fine for png and bmp image formats. But if I upload gif format or jpeg with a predominance of one color uploaded original image seems to be compressed.

For example:

Original:
Original image

Uploaded:
Uploaded image

I thorougly searched in google and found some examples how to upload image right. At the end I have written the next method:

void UploadImagePreset(Image image, ImageFormat imgFormat, string imgPath)
{
    using (var uploadStream = imageUploader.CreateUploadStream(imagePath))
    {
        var newWidth = image.Width;
        var newHeight = image.Height;
        using (var outBitmap = new Bitmap(newWidth, newHeight))
        {
            using (var outGraph = Graphics.FromImage(outBitmap))
            {
                outGraph.CompositingQuality = CompositingQuality.HighQuality;
                outGraph.SmoothingMode = SmoothingMode.HighQuality;
                outGraph.PixelOffsetMode = PixelOffsetMode.HighQuality;
                outGraph.InterpolationMode = InterpolationMode.HighQualityBicubic;

                var imageRect = new Rectangle(0, 0, newWidth, newHeight);
                outGraph.DrawImage(image, imageRect);

                outBitmap.Save(uploadStream, imgFormat);
            }
        }
    }
}

But it did not help. Uploaded image was the same as described above. I have tryied to specify qaulity of the results image like this:

var encoderParameters = new EncoderParameters();
var encoderParameter = new EncoderParameter(Encoder.Quality, 100);
encoderParameters.Param[0] = encoderParameter;
var encoder = ImageCodecInfo.GetImageEncoders()
    .Where(e => e.FormatID == imgFormat.Guid)
    .FirstOrDefault();
outBitmap.Save(uploadStream, encoder, encoderParameters);

It does not work too. In addition when I upload jpeg image exception occurs.

Is any way to upload image without compressing or resizing? I have spent some hours trying solve this issue and stuck on it.

cramopy
  • 3,459
  • 6
  • 28
  • 42
  • It's not clear - what's doing the uploading? If it's just from a browser with no extra client code, you should be getting the exact file that's on the client - at which point your problem has *nothing* to do with uploading (or ASP.NET), and is *just* to do with resizing. – Jon Skeet Nov 17 '11 at 17:55
  • I use FileUpload control without any extra client code – Igor Blinnikov Nov 17 '11 at 17:58
  • Right, so first validate that if you save out the uploaded file - without processing it *at all* - you end up with the exact same file. When you've proved that to yourself, you can take the upload part out of the equation. Narrow the problem down to as small an area as possible. – Jon Skeet Nov 17 '11 at 17:59

2 Answers2

7

You are passing the uploaded image through the Image class - this is a new image, based on the passed in stream.

This is then saved using some default parameters, which would no longer reflect the original image.

You should simply save the incoming stream directly to disk - this will result in an exact copy of the original image.

Like this (.NET 4.0):

using (var uploadStream = imageUploader.CreateUploadStream(imagePath))
{
   using(var fileStream = new FileStream(imgPath, FileMode.Create))
   {
       uploadStream.CopyTo(fileStream);
   }
}

Or (pre .NET 4.0):

using (var uploadStream = imageUploader.CreateUploadStream(imagePath))
{
    using(var fileStream = new FileStream(imgPath, FileMode.Create))
    {
        byte[] buffer = new byte[32768];
        int read;
        while ((read = uploadStream.Read(buffer, 0, buffer.Length)) > 0)
        {
            fileStream.Write(buffer, 0, read);
        }
    }
}

Adapted from this answer.

Community
  • 1
  • 1
Oded
  • 489,969
  • 99
  • 883
  • 1,009
  • I use .Net 3.5. Stream class has no CopyTo method in this version of framework. – Igor Blinnikov Nov 17 '11 at 18:40
  • @IgorBlinnikov - See this for another option: http://stackoverflow.com/questions/230128/best-way-to-copy-between-two-stream-instances-c-sharp – Oded Nov 17 '11 at 18:42
  • Thank you, Oded. Your answer was very helpful. Problem was that I first of all created Image object from Stream and then saved Stream. Manipulating with Stream object adds noise to result image even if I save original Stream, but not Image object. Saving Stream to file directly after uploading (before creating Image object) solves my issue. – Igor Blinnikov Nov 17 '11 at 19:00
  • I have a `HttpFileCollection` (files[0]) that I'm trying to upload (framework 4.0), but I don't understood how to implement the first **using** `using (var uploadStream = imageUploader.CreateUploadStream(imagePath))` and you are using **imagePath** then **imgPath** they aren't the same? – Michel Ayres Jun 16 '15 at 21:59
  • @Oded I just posted a [question](http://stackoverflow.com/questions/30889838/image-loss-quality-after-upload-via-httppostedfile-saveasimgpath) about my problem, if you could take a look that would be amazing! – Michel Ayres Jun 17 '15 at 11:10
1

I suggest using Image Codecs (Your second example) for lossless image compression.

With a small modification of code i suggest that you try this :

Bitmap bm = (Bitmap)Image.FromFile(filePath); 
ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders(); 
ImageCodecInfo codecInfo = null; 
foreach (ImageCodecInfo codec in codecs)
{ 
    if (codec.MimeType == "image/jpeg") 
        codecInfo = codec; 
}
EncoderParameters ep = new EncoderParameters(); 
ep.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, (long)100); 
bm.Save("C:\\quality" + x.ToString() + ".jpg", codecInfo, ep);

Hope this will help.

cramopy
  • 3,459
  • 6
  • 28
  • 42
Haythem Tlili
  • 566
  • 3
  • 10