Skip to content
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

Question about saving and re-opening an image from a memory array #494

Closed
aferrero2707 opened this issue Jul 28, 2016 · 6 comments
Closed
Labels

Comments

@aferrero2707
Copy link

In my photoflow editor I am internally building a pre-computed pyramid of zoom levels whenever I open an image from disk, to speed-up rendering of scaled-down previews.

Currently I am writing each level into a RAW disk buffer, which I re-open with vips_rawload().
For next version, I would like to limit the disk usage and use memory buffers for not-so-large images, and only revert to disk buffers whenever the image would be too large to be kept into RAM.

The solution seems to be simple: use vips_image_write_to_memory() to save the data, and re-open the memory array with either vips_image_new_from_memory() or vips_image_new_from_memory_copy().

The _copy() version has the advantage to avoid any risk of freeing the memory while it is still in use, however it requires a temporary double-allocation of the pixel array which I would like to avoid.

So I was thinking about a way to use vips_image_new_from_memory() and still let VIPS manage the freeing of the memory buffer when it is not needed anymore. One solution I could figure out is to attach the memory array to the image itself as a metadata blob. In this case, the blob would then be deallocated together with the image, right? Would this be a safe and efficient solution?

Thanks!

@jcupitt
Copy link
Member

jcupitt commented Jul 28, 2016

You could also use the close signal on the image to free the memory, that might be easier.

http://www.vips.ecs.soton.ac.uk/supported/current/doc/html/libvips/VipsObject.html#VipsObject-postclose

Actually, you can do it even more simply: just make a memory image with vips_image_new_memory(), then write to that.

http://www.vips.ecs.soton.ac.uk/supported/current/doc/html/libvips/VipsImage.html#vips-image-new-memory

Something like:

VImage mem = VImage::new_memory();
x.write(mem);

Now mem is a memory buffer containing the contents of x.

Your "disc for large files, mem for small files" code might be something like:

VImage cache;

if (is_a_huge_file(x))
  cache = VImage::new_temp_file("%s.v");
else
  cache = VImage::new_memory();

x.write(cache);

You can use an env var to say where new_temp_file should make the temporary file:

http://www.vips.ecs.soton.ac.uk/supported/current/doc/html/libvips/VipsImage.html#vips-image-new-temp-file

@jcupitt
Copy link
Member

jcupitt commented Jul 28, 2016

Oh I forgot, sorry, .write() used to keep a ref to the source image, so you couldn't really use it like this. 8.4 and later make it only keep a ref if the image you are writing to needs it, which a memory or disc image won't.

Anyway, for 8.3 and earlier, yes, you need to make a memory buffer and free it, as you said. From 8.4, you can just use .write(), it's much neater.

@aferrero2707
Copy link
Author

If I understand correctly, you propose the following:

  • write a callback to free the memory array:

    void free_mem_array (VipsObject *object, gpointer user_data)
    {
    if( user_data ) free( user_data );
    }

  • register the callback:

    VipsImage* img = vips_image_new_from_memory( ... );
    g_signal_connect( img, "postclose", G_CALLBACK(free_mem_array), mem_array );

Is that correct?

@jcupitt
Copy link
Member

jcupitt commented Jul 28, 2016

Yes, exactly. This is how vips_malloc() works:

https://github.com/jcupitt/libvips/blob/master/libvips/iofuncs/memory.c#L130

@aferrero2707
Copy link
Author

I did a quick test, and it works like a charm. Thanks again!

@jcupitt
Copy link
Member

jcupitt commented Jul 28, 2016

Good stuff, I'll close.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants