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.
-
What have you tries, show us your issue, tried using filestream? then you stream it of the disk and not the memory, it will be much slower than just pushing it to memory and handling it there. The size in memory shoud be roughly width*height*4channels*8bit = total bits in memory for a bitmap. a 41mp image (lumia 1020) should be about 150MB in memory which is totally acceptable, leaving me to think it is the code for cropping that you tried that hogs memory. – Thomas Andreè Wang Jun 25 '15 at 05:04
-
Is this for an Windows 8 mobile phone app? what is the image size estimate? – n00b Jun 25 '15 at 05:16
3 Answers
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

- 191,897
- 31
- 273
- 432
-
-
There is a .Net implementation, maintained by @dlemstra on SO who may be able to advise further... http://magick.codeplex.com – Mark Setchell Jun 25 '15 at 10:36
-
Or, I presume that C# must have something like a `system()` function for spawning command-line programs... – Mark Setchell Jun 25 '15 at 10:43
-
The .Net framework allows you to run commands, but not available for isolated applications like windows phone apps. The .Net implementation can work – n00b Jun 25 '15 at 10:55
-
For vips, try `vips extract area ....`, you should see a large drop in memory use. The `im_` prefix is for the old vips7 API, the new vips8 API does automatic image streaming. I see: `$ vips im_extract_area big.jpg x.jpg 8000 50 1000 1000 --vips-leak memory: high-water mark 235.11 MB $ vips extract_area big.jpg x.jpg 8000 50 1000 1000 --vips-leak memory: high-water mark 22.64 MB` – jcupitt Jun 25 '15 at 14:17
-
@user894763 Thank you for your advice - I wish the `vips` documentation was better. It is really hard to find anything and it takes ages to work out how commands work and which variants will work best... are there any good examples anywhere? – Mark Setchell Jun 25 '15 at 14:28
-
Oh dear, the docs have been rewritten for vips8: http://www.vips.ecs.soton.ac.uk/supported/current/doc/html/libvips/index.html is that any better? There's an alphabetic index, a thematic index, and a function list with a quick summary of each operator. – jcupitt Jun 25 '15 at 16:34
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

- 1,832
- 14
- 25
-
The vips jpeg decoder will decompress on demand, so if you only need a chunk at the top of the file it'll only decode the top of the file. If you ask for a chunk at the bottom, it will decompress the whole thing but will only save the bottom part to memory, it'll discard the unwanted part. – jcupitt Jun 25 '15 at 14:19
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/

- 17,993
- 23
- 107
- 210