-
Notifications
You must be signed in to change notification settings - Fork 24
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
*save gets really slow after composite-ing lots of images #59
Comments
ah, and the result on my machine (virtualized) is:
[snip, it almost linearly increases by each run]
|
Hello, that's right, as the pipeline gets longer it'll run more slowly, since it's joining more images. Most libvips images are not real images, they are just tiny scraps of code and data that get joined together. This is why it uses little memory and can process huge images. When you execute: $x = Vips\Image::newFromFile("x.jpg");
$x = $x->invert(); It's not actually processing any pixels. The load will check the image header and set up things like with and height, but it will not decompress anything, just attach a function to When you finally execute: $x->writeToBuffer(".jpg"); The final write will pull pixels through the pipeline in (usually) 128 x 128 pixels chunks. The decode, invert and recode will all execute at the same time and the work will be spread over your available cores. In your case, you want to reuse results from one pipeline computation (the save) in the next (the next composite). You need to keep a copy of the complete intermediate image in memory. The simplest way is to use $base = $frame[0];
for ($i = 1; i < $n_frames; $i++) {
// this will make a new pipeline section from base, but will not do any computation
$base = $base->composite($frame[$i], 2);
// this will allocate a new area of memory, then render the image into it
// the previous memory image will be GCd away soon, hopefully
$base = $base->copyMemory();
// save this intermediate
$my_image_string = $base->writeToBuffer(".tif");
} https://jcupitt.github.io/php-vips/docs/classes/Jcupitt.Vips.Image.html#method_copyMemory Stepping back, I'm not certain that this is necessary. Each frame of the gif loader output is already a composite of every previous frame, so I think you can just pull single frames out and save them. Or I'm missing something! |
More background: libvips has quite a lot of machinery to try to cache and reuse results within pipelines. For example, suppose you have something like: $a = $a->invert();
$r, $g, $b = $a->bandsplit();
$r += $g;
$b = $r->bandjoin([$g, $b]);
$b->writeToFile(...); (not legal php, I know) ie. a pipeline that splits an image up, processes, and rejoins, you might think there's a danger that the It starts to get harder when there are area operations, like convolution. libvips tries to optimise these cases by reordering computation so that the largest areas are computed first and there's the most likelihood of finding a buffer to reuse. Operations with small value results, like image average or image histogram, are memoised. Before adding any operation to a pipeline, libvips searches the last 1,000 operations and simply reuses the result of the previous invocation. This is safe, because libvips images are immutable. This has the extra effect of common-subexpression elimination. If you have: $c = $a->add(2);
$b = $b->add($a->add(2))->add($c); The Finally, you can add explicit cache nodes to a pipeline. http://jcupitt.github.io/libvips/API/current/libvips-conversion.html#vips-tilecache https://jcupitt.github.io/php-vips/docs/classes/Jcupitt.Vips.ImageAutodoc.html#method_tilecache |
ah thanks, that explains a lot. And copyMemory makes it fast. About gif loading and composition. the single pages still have transparency in it, which is noticeable when you resize just on that. With the image from http://files.chregu.tv/animated.gif
Ends up in composite helps removing them. |
But won't composite break things like a solid object moving over a transparent background? You'll make each frame the superposition of all the previous object positions. There's something I'm not understanding about gif :( |
I'm not an gif expert either, for me, transparent just meant "take the same color as the frame before on that frame" and one should apply that during optimizing it. But I don't know exactly, the end result should be the same The problem is when I don't do composition with the background and just for example resize on such an image, one can see later the artifacts where it was transparent, since it antialiases between the transparency and eg. the blue full color (in the above example). If I composite the frame before, that doesn't happen. |
Hmm I think I found it: http://www.webreference.com/content/studio/disposal.html libvips isn't implementing the dispose stuff at the moment. I'll try to add it. I added a metadata item for |
It seems to handle dispose correctly now, or at any rate all my test gifs seem to work. You shouldn't need the composite thing any more: just load with Thank you for pushing on this -- it's good to fix up the gif loader. |
I'll close, this should be fixed in 8.6. |
Strange behaviour here, hopefully there's an easy explanation.
I load each frame of a animated gif as a vips image. Then a composite them on each other from start to end to replace the transparency with the colours from the frames before. and then I save them. But that save gets slower and slower with each image. When I don't do the composite, it's as fast as expected. The more frames it has the slower it gets.
Here's some example code which shows the behaviour:
An animated gif with lots of frames where it's especially noticeable can be found here https://liip.rokka.io/www_raw/170a46a35209b1747256224e037bceaab2049a51/animation-1.jpg
The text was updated successfully, but these errors were encountered: