Hello everyone, i'm fresh new here, and i already have a question regarding...well, C#.
I've made a Forms Application in which the user submits an image (bmp,png,jpg or gif), and the image suffers some byte-level modifications (obviously, i'm using the LockBits() method).
Now, after the modifications are done, the user should be able to save the image in its original format (only the least important bits of the image get modified, so the image looks pretty much like the original).
I've developed a static class called ImageTextEncoder which has a public static member ImageTextEncoder.Image, which holds the submitted bitmap.
When i call ImageTextEncoder.Image.Save(Filename,Format) (if initially the image was a Jpeg, i will save it as a jpeg, same for png, gif, etc. ), and i upload the image back, visibly it suffered nothing, but its size gets modified (example: a 700 kb JPG got down to 140 kb), AND at byte level things are altered.
IS there a way i can save the image WITHOUT losing ANYTHING ( size, byte information) . (as a note, i need a solution asap, it's been bugging my application for some days now)
Thank you very much !

Recommended Answers

All 26 Replies

if the image is a different size, its probably the compression level. when you save your bitmap, if you save it as a jpeg file, you can alter its compression methods, changing its filesize, if you just call save, it uses the default. which might be different from the source image.

No, the image does NOT change its size, not at all!
My question can be resumed to this: How can i save an image to a file, without losing its quality?

I ment size as in file size not dimensions. sorry.

// We will store the correct image codec in this object
            ImageCodecInfo iciJpegCodec = null;
            // This will specify the image quality to the encoder
            EncoderParameter epQuality = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, (int)80);//set quality here
            // Get all image codecs that are available
            ImageCodecInfo[] iciCodecs = ImageCodecInfo.GetImageEncoders();
            // Store the quality parameter in the list of encoder parameters
            EncoderParameters epParameters = new EncoderParameters(1);
            epParameters.Param[0] = epQuality;

            // Loop through all the image codecs
            for (int i = 0; i < iciCodecs.Length; i++)
            {
                // Until the one that we are interested in is found, which is image/jpeg
                if (iciCodecs[i].MimeType == "image/jpeg")
                {
                    iciJpegCodec = iciCodecs[i];
                    break;
                }
            }
         
//now save
                yourImage.Save(filepath, iciJpegCodec, epParameters);

I borrowed this code from somewhere a long time ago, i don't remember where. there are other ways. but this one always worked for me.

Thank you very much, it's great for JPG files, can i also do this for BMP,GIF,PNG ?

Ok, never mind GIF,PNG,BMP, i'm using the suggestion which you, and also microsoft http://support.microsoft.com/kb/324790 apparently gives, but my problem ain't solved - when i call the new parametrized save method, with 100 quality quoefficient, my image still gets shrinked :(.
The problem with image shrinkage is data loss - i used the least significative bits of each byte to encode some data, and that data is LOST when i save the image :(
please help !

the idea behind JPEG image compression is that it removes color differences that are not apparent by the human eye. If you really want a full quality picture you might want to always save to bmp or png24 regardless of source type.

jpeg compression looks good, and makes for a good file size, but if your goal is just to preserve bytes written into your image, you probably will loose it during the compression. Sorry. its still not clear to me what your goal is.

im not sure if this will suit u , especially i didn't understand completely
what u intend to do ..

but : what about submitting array of bytes representing the image..
and then reading them through memory stream then converting them to an image with the type u want

this is a part of code i used before for saving submitted images..

//this is a kind of encoding i used
 byte[] img = Convert.FromBase64String(s);

 MemoryStream ms = new MemoryStream(img);
       
 Bitmap bmp = new Bitmap(ms);

System.Drawing.Image.FromStream(ms);
imga.Save(file path);

im not sure if this could help
good luck

@dima shawahneh:
Already tried that, the Save method will cause my image to lose bytes.
@Diamonddrake:
I am encoding text into an image - changing the least significant bit of each of the image's bytes to "encode" the ASCII representation of a character. (example: The letter "A" is 65 in ASCII -> 01000001 in binary, so i will modify 8 of the image's bytes in order to "encode" that specific letter).
I need to save any jpeg,bmp,gif,png file and not lose ANY of the image's bytes.
(I already tried saving Jpeg as a Bitmap, while still retaining the .jpg extension , but it increases the image's byte size too much. - it saved a 700 KB jpeg to a 3 MB one)
What i need is to save the image and not loose ANY of its bytes, while also retaining its original size in bytes ( 700 KB to 3 MB = NOT GOOD)

Then don't convert the input stream in to an image. Save the raw input stream directly to a file and you will have the exact image they uploaded.

//this is a kind of encoding i used
byte[] img = Convert.FromBase64String(s);
System.IO.File.WriteAllBytes(@"C:\image.bmp", img);

You will obviously have to tweak the save location and file extension but that information needs to be gathered from the uploaded filename and whatever logic you use to determine save file names...

Ok, here's what i did:

ImageConverter img_converter = new ImageConverter();
byte[] bytes = (byte[])img_converter.ConvertTo(image, typeof(byte[]));  
File.WriteAllBytes(savefil.FileName, bytes);
//savefil is a Save File Dialog

It works ! But my original Jpeg file has 700 KB, while the new one has 2 MB ...could i further enhance this?

You ran the bytes through your converter.... In my last post I said to save the input stream directly to disk. Its hard to say whats going on here since we don't have the full code for your encoding/converting mechanisms. Are you writing the base-encoded bytes to disk and not the raw image to disk, and using your app to view the image?

Here's an idea of what's going on with my picture:

public static void EncodeText(string text)
        {
            ImageData = image.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadWrite, image.PixelFormat);
            byte* walker = (byte*)ImageData.Scan0;
            for (int h = 0; h < text.Length; h++)
            {
              //Do stuff to the image's bits.
            }
            image.UnlockBits(ImageData);
        }

So after using that method i flush down its bytes through the converter and save them to a file.
Should i be doing it some other way?

>>So after using that method i flush down its bytes through the converter and save them to a file.
So what you are saying is "after I take an original image, run the image through a converter, and save the modified image it is different than my original image". Right? If you do anything to an image other than save it you're probably going to cause some change in it.

Wherever you are getting the source image -- before you convert it, encode it, or even load it in to an Image or Bitmap class in C# you should save the raw image bytes.

I dont need the original image saved back to the hard disk, i need the modified image saved to the disk. I modify only the least significant bits of the image, so the change isn't that big to increase its size threefold.
That's where my problem is.

Ah, gotcha. Upload the source image and your project to this thread. You can do this by zipping them up and clicking on "Go Advanced" then "Manage attachments".

Sorry for being a bit paranoid, but doesn't that mean everyone will be able to download it? ^^
The nature of my project is...pseudo-commercial.

Yes, everyone can download it. Just pull out the parts of your code relevant to what you're trying to accomplish and a single image. There is all kinds of commercial code posted on the internet.....

Ok, here is my project and a JPEG image.

I used your application and made that ~700kb jpeg to a ~2.xMB jpeg just like you said. However after inspecting the 2MB file I noticed it is actually a PNG file with a JPEG extension. You can change the file extension to another image type and it will still open in photo viewers properly. I'm sure you know that PNG is a lossless format so that makes sense why the file is so big.

Something you are doing is changing the image format.

I noticed here:

case "JPEG":
                        case "JPG":
                            {
                                File.WriteAllBytes(savefil.FileName, ImageTextEncoder.ToByteArray());
                                //Works only for JPG files, though it increases their size considerably.
                            }
                            break;
                        case "BMP":
                            {
                                bm.Save(savefil.FileName, ImageFormat.MemoryBmp);
                                //Shrinks bmp's, but works.
                            }

Why dont you use:

bm.Save(savefil.FileName, ImageFormat.Jpeg);

The rest of your code is using bm.Save()

I changed the ImageFormats because the native ones didn't work.
Saving a BMP with BMP ImageFormat made the picture lose the encoded bytes. Same with GIF. So i had to find formats which preserved the encoded bytes.
As for saving BMP as a JPEG, it doesn't work...already tried.
Also, again, what can i do to save the JPG file ...without losing byte information, and without increasing its size?
Edit: Flushing the bytes to a file worked only for JPEG's, that's why i used the Save() method for the other extensions.

Well the only reason it worked was because it wasn't really a JPG at all. See if you can disable the compression for JPEG so it doesn't modify the file's contents. Beyond that i'm not sure off hand, this is getting very file-format specific.

commented: Relevant and helpful poster. Thank you ! +1

I tried saving other JPEG's, which were REALLY Jpg's ( made with digital camera), and it worked ....but there are huge changes in size ( 1.6 MB -> 7.5 ??! :( )
Do you or anyone else know how to disable JPG compression and save the file as i intend to...in respect to everything i've posted till now?
(i'm getting desperate)

your extention was jpg but the image was NOT a jpeg. extensions mean nothing. Listen.

1. If you want to preserve your changes you cannot compress it, because compression codecs change those values.

2. Saving as a BMP is uncompressed, So it will work, but the file will be big.

3. if the file is big, then its uncompressed, and your data is preserved, if the file is small, then its compressed and you WILL LOOSE YOUR CHANGES

sorry that's how Imaging works.

That is ....most unnerving.
Consequently...there's no possibility to get away with my original-sized pictures AND by low-level byte modifications?
That's. well . I'll get over it :)
If any of you guys confirm positively that in order to preserve my byte-level modifications, i have to save stuff as uncompressed...then i'll mark the thread as solved.

you could in theory take your image and load it in as a byte array, not as an image, sift through the bytes and find the start of the image data, then apply them there, but idk what the results would be. but other than that. there isn't sorry.

commented: Very relevant. +1

Ok, thank you both for sharing your knowledge with me and helping me out...cheers !

commented: you're welcome! :) Not too many people say thanks +6
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.