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

add something like mutable #79

Open
jcupitt opened this issue Apr 11, 2024 · 1 comment
Open

add something like mutable #79

jcupitt opened this issue Apr 11, 2024 · 1 comment

Comments

@jcupitt
Copy link
Member

jcupitt commented Apr 11, 2024

The ruby-vips binding has a nice feature for encapsulating destructive operations, like metadata change or the draw operations:

https://www.libvips.org/2021/03/08/ruby-vips-mutate.html

tldr: you can write eg.:

z = x.mutate do |y|
  1000.times do 
    y.draw_circle! Array.new(3) {rand(255)},
      rand(y.width), rand(y.height), rand(100), fill: true
  end
end
  1. mutate takes an image (x in this case) and makes an instance of a class called MutableImage
  2. This constructor runs copy() to make a private copy of the underlying vips image, and subclasses Image, adding a few new methods such as draw_circle! (ruby uses the ! suffix on method names to indicate destructive operations)
  3. mutate executes the block after, passing in the mutable image (y in this case)
  4. draw_circle! modifies the image you give it by erm drawing a circle ... the first time this happens, libvips will force the iamge into memory, ie. allocate a huge ram buffer and render the image into that
  5. Now the 1000 circles are drawn directly into memory with no copying and no chance of side effects
  6. Finally, the mutable block ends, and mutate uses the modified vips image to build a new instance of the Image class
  7. And this new Image instance is returned (and assigned to z in this code)

So this scheme automates the copying that lua-vips requires right now before you can use destructive operations like metadata changes, or line or circle draw. It has locks to prevent things like set or remove being used on a non-mutable image, so it's always safe.

You see a nice speedup too: that code is more than 10x faster and needs less than 1/10th the memory compared to ruby-vips without mutate.

This would be a nice thing to add to lua-vips. You could perhaps use anonymous functions, so the code above might be:

z = x:mutate(function (y)
  for i = 1, 1000 do
    y:draw_circle(... stuff)
  end
end)

You'd need to add a new mutable image class and some locks to gate access to set, remove, draw_circle, etc.

@jcupitt
Copy link
Member Author

jcupitt commented Apr 11, 2024

For reference, the ruby-vips mutable image class is here:

https://github.com/libvips/ruby-vips/blob/master/lib/vips/mutableimage.rb

And here's the mutate method:

https://github.com/libvips/ruby-vips/blob/master/lib/vips/image.rb#L800-L819

The thing to call libvips operations has a few ifs for enforcing mutability.

https://github.com/libvips/ruby-vips/blob/master/lib/vips/operation.rb

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

No branches or pull requests

1 participant