Cropping a JPG without loading all of it in memory

680 views Asked by At

How can I crop a big JPG and extract a small portion of it? The problem is main JPGs are so big and I can't load all of it in memory. I used convert.exe from ImageMagick, but it's not working properly on all versions of windows and I prefer some C# method instead of a standalone exe.

3

There are 3 answers

0
AVEbrahimi On BEST ANSWER

I found a command line solution which does not depend on external libraries, jpegtran.

You can have jpegtran.exe beside your main exe and call it with these parameters:

jpegtran -crop WxH+X+Y input_file output_file

Download jpegtran from here: http://jpegclub.org/jpegtran/

1
n00b On

All Jpeg decoders I have seen first dump the Jpeg into memory and then start decoding. This is because of the nature of Jpeg format which is unlike a Bitmap you can not calculate file location for a pixel.

If you decide not to load into memory, then you have numerous file seeks, which makes your decoder less memory-intensive, but more I/O intensive.

The NanoJpeg project is a good start https://github.com/Deathspike/NanoJPEG.NET/blob/master/NanoJPEG.cs

7
Mark Setchell On

There are a couple of possibilities. You could use stream which is part of ImageMagick, or vips. Let's do stream first.

I can make a large (10,000x5,000) JPEG like this:

convert -size 10000x5000 xc:blue BigBoy.jpg

then use stream like this to extract a chunk 1,000x1,000 from an offset of 8,000+50

stream -extract 1000x1000+8000+50 BigBoy.jpg extract.rgb

and the extraact.rgb file is 3000000 bytes in size, i.e. 1,000x1,000 at 3 bytes/pixel.

If I do that with time -l you can see the resident set is small despite the large image

/usr/bin/time -l stream -extract 1000x1000+8000+50 BigBoy.jpg extract.rgb
        0.81 real         0.79 user         0.01 sys
   2924544  maximum resident set size       <----- 2MB RAM ****
         0  average shared memory size
         0  average unshared data size
         0  average unshared stack size
       796  page reclaims

You can then convert that extract.rgb to JPEG with convert

convert -size 1000x1000 -depth 8 extract.rgb chunk.jpg

I am no expert on vips, but you may have some success with this command that also shows the peak memory usage with the --vips-leak flag at the end

vips extract_area BigBoy.jpg SmallBoy.jpg 8000 50 1000 1000 --vips-leak
memory: high-water mark 8.72 MB