Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c# saving very large bitmaps as jpegs (or any other compressed format)

I am currently handling very large images, which are basically generated by stitching together many smaller images (e.g. panorama or photo mosaic software). In order to avoid out-of-memory exceptions (in memory are only "maps" of how to arrange the smaller images), I wrote some code saving these images line by line as bitmaps using BinaryWriter and LockBits. So far, so good.

The problem is now that I would like to save these images as Jpegs (or PNGs) as well. Since I am pretty new to c# I can only think of two ways for now:

1) Similar to the bitmap saving procedure. Generating some jpeg header and saving the big images line by line, compressing them somehow before. I have no idea how to perform the compression though.

2) Streaming the already saved bitmap into the memory and saving it as encoded jpeg.

Since the second approach seemed easier, I tried something like this:

FileStream fsr =
    new FileStream("input.bmp", FileMode.Open, FileAccess.Read);
FileStream fsw =
    new FileStream("output.jpg", FileMode.CreateNew, FileAccess.Write);

EncoderParameters encoderParameters = new EncoderParameters(1);
encoderParameters.Param[0] =
    new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 80L);

Bitmap bmp = new Bitmap(fsr);
bmp.Save(fsw, GetEncoder(ImageFormat.Jpeg), encoderParameters);
bmp.Dispose();

The problem is now that the save-method tries to completely load the bitmap into memory first, causing an out-of-memory exception.

I would be more than happy for any suggestions on how to solve or circumvent this problem!

like image 381
mgulde Avatar asked Nov 23 '11 19:11

mgulde


1 Answers

Note that JPEG compression has some important non-trivial drawbacks :

1) JPEG is lossy, so you will not regenerate the same image. This might be perfectly acceptable, but if you need to exactly regenerate source image, then PNG is the way to go.

2) JPEG is aligned on 8-pixels boundaries. If you stich together images which sizes are not multiple of 8, either in width or height, you will get some strong artefacts at image boundaries

Considering your use case, i would rather recommend to not stitch images together, and use a standard compression algorithm, such as PNG or Zlib, on each smaller image. You can still store the resulting compressed streams into a single file. The advantage is that you can then directly "jump" at the position of the small image you want to extract, which will save * a lot * of memory.

The disadvantage is that you cannot "visually preview" all the smaller images into a big single one (you will need to create a program for this usage).

like image 94
Cyan Avatar answered Sep 25 '22 14:09

Cyan