Trim JPG without loading everything into memory
How can I crop a large JPG and extract a small portion? The problem is that the underlying JPGs are so big that I can't load the whole thing into memory. I used convert.exe from ImageMagick but it doesn't work as expected on all Windows versions and I prefer some kind of C # method instead of a standalone exe.
source to share
I found a command line solution that does not depend on external libraries, jpegtran .
You can have jpegtran.exe next to your main exe and call it using these options:
jpegtran -crop WxH+X+Y input_file output_file
Download jpegtran from here: http://jpegclub.org/jpegtran/
source to share
There are several possibilities. You can use stream
which is part of ImageMagick or vips
. Let's do it first stream
.
I can make a large (10,000x5,000) JPEG like this:
convert -size 10000x5000 xc:blue BigBoy.jpg
then use stream
to extract a 1,000x1,000 chunk from offset 8000 + 50
stream -extract 1000x1000+8000+50 BigBoy.jpg extract.rgb
and the file extraact.rgb
is 3,000,000 bytes in size, i.e. 1000x1000 with 3 bytes / pixel.
If I do this with time -l
, you can see that 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
Then you can convert this extract.rgb
to JPEG withconvert
convert -size 1000x1000 -depth 8 extract.rgb chunk.jpg
I am not an expert on vips
, but you can succeed with this command which also shows peak memory usage with a flag --vips-leak
at the end
vips extract_area BigBoy.jpg SmallBoy.jpg 8000 50 1000 1000 --vips-leak
memory: high-water mark 8.72 MB
source to share
All Jpeg decoders I've seen dump the Jpeg into memory first and then start decoding. This is due to the nature of the Jpeg format, which is different from Bitmap, you cannot calculate the file location for the pixel.
If you choose not to load into memory, you have many files that make 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
source to share