-
Notifications
You must be signed in to change notification settings - Fork 62
Method listing supported "foreign" extensions #269
-
This is a feature request.
Would it be possible to add class method to Vips
that would return an array of supported file formats akin to $ vips -l foreign
does? Having such introspection would allow to programmatically decide if for example Vips supports any given format for transformation operation.
If there already exists a way how to get list of Vips' supported extensions, I'm all ears.
Beta Was this translation helpful? Give feedback.
All reactions
Replies: 7 comments
-
Hello @aleksandrs-ledovskis,
You can do this now, though it's a little painful. Have a look at:
https://github.com/libvips/ruby-vips/blob/master/lib/vips/image.rb#L1341
The generate_yard
method that makes the ruby-vips docs.
You would use GObject::g_type_from_name("VipsForeign")
to get the GType
for the base class of the file load/save operations (it's just an int), then walk all the subclasses recursively with Vips::vips_type_map
looking for non-abstract types. You can instantiate an object of that type and get the text description, a list of the arguments, and the properties of each argument.
You can get things like supported suffixes too, though you'd need to add a little more ffi for that.
Beta Was this translation helpful? Give feedback.
All reactions
-
Spent some time digging in ruby-vips
/libvips
and managed to get some PoC code
require "vips" require "set" module Vips attach_function :vips_class_find, [:string, :string], :pointer attach_function :vips_object_summary_class, [:pointer, :pointer], :void class BufStruct < FFI::Struct layout :base, :pointer, :mx, :int, :i, :int, :full, :bool, :lasti, :int, :dynamic, :bool end end nicknames = [] generate_class = lambda do |gtype, _| nickname = Vips.nickname_find(gtype) nicknames << nickname if nickname Vips.vips_type_map(gtype, generate_class, nil) end generate_class.call( GObject.g_type_from_name("VipsForeign"), nil ) extensions = Set.new nicknames.each do |nickname| foreign_class = Vips.vips_class_find("VipsForeignLoad", nickname) next if foreign_class.null? buf_struct = Vips::BufStruct.new buf_struct_string = FFI::MemoryPointer.new(:char, 2048) buf_struct[:base] = buf_struct_string buf_struct[:mx] = 2048 Vips.vips_object_summary_class(foreign_class, buf_struct.pointer) class_summary = buf_struct_string.read_string extensions.merge(class_summary.scan(/\.\w+\.?\w+/)) end puts extensions
On my machine/libvips configuration outputs:
#<Set: {".csv", ".mat", ".vips", ".img", ".hdr", ".ppm", ".pgm", ".pbm", ".pfm", ".pdf", ".svg", ".svgz", ".svg.gz", ".gif", ".png", ".jpg", ".jpeg", ".jpe", ".webp", ".tif", ".tiff"}>
I couldn't make access to foreign_class->suffs
work via FFI. There isn't existing ForeignClass
mapping in ruby-vips
and making a simplistic pointer-to-struct didn't work.
class ForeignClassStruct < FFI::Struct layout :parent, GObject::GObject::Struct, :constructed, :int, :static_object, :int, :argument_table, :pointer, :nickname, :string, :description, :string, :preclose, :int, :close, :int, :postclose, :int, :local_memory, :size_t, :priority, :int, :chars, :pointer end # Junk ForeignClassStruct.new(Vips.vips_class_find("VipsForeignLoad", "pngload"))[:nickname] ForeignClassStruct.new(Vips.vips_class_find("VipsForeignLoad", "pngload"))[:priority]
Beta Was this translation helpful? Give feedback.
All reactions
-
👍 1
-
@aleksandrs-ledovskis I am using this method here through command-line:
https://github.com/tomasc/dragonfly_libvips/blob/master/lib/dragonfly_libvips.rb#L19
But indeed, would be great to have a method of ruby-vips
that outputs such list.
Beta Was this translation helpful? Give feedback.
All reactions
-
I had a quick hack and added get_suffixes
:
$ irb
irb(main):001:0> require 'vips'
=> true
irb(main):002:0> Vips::get_suffixes
=> [".csv", ".mat", ".v", ".vips", ".ppm", ".pgm", ".pbm", ".pfm", ".hdr", ".dz", ".png", ".jpg", ".jpeg", ".jpe", ".webp", ".tif", ".tiff", ".fits", ".fit", ".fts", ".nii", ".nii.gz", ".hdr.gz", ".img", ".img.gz", ".nia", ".nia.gz", ".heic", ".gif", ".bmp"]
irb(main):003:0>
Does that look reasonable? I'll add some tests as well.
Beta Was this translation helpful? Give feedback.
All reactions
-
Fabulous!
Beta Was this translation helpful? Give feedback.
All reactions
-
@jcupitt I see that you are basing the output on VipsForeignSave
. If I compare "save" vs. "load" class extensions, there are some differences (e.g. SVG/PDFs are only supported as input and BMP as output).
As I use Vips for image processing I would be (more) interested in seeing a way to determine what extensions can be processed by Vips at the intake for purpose of populating texts visible to end-user ("Please upload image in ".jpg", ".jpeg" or ".png" formats)/doing pre-emptive validations based on file name.
@tomasc's case also seems to require both "load" and "save" extensions.
Beta Was this translation helpful? Give feedback.
All reactions
-
Hi @aleksandrs-ledovskis, yes, that's true. libvips uses the suffix to pick savers, so there's a simple relationship between filetype and extension. But loaders are picked by sniffing the first few bytes of the file, so a list of extensions won't always be complete.
I tried swapping it for VipsForeignLoad
and I see:
irb(main):004:0> Vips::get_suffixes
=> [".v", ".vips", ".ppm", ".pgm", ".pbm", ".pfm", ".png", ".exr", ".svs", ".vms",
".vmu", ".ndpi", ".scn", ".mrxs", ".svslide", ".tif", ".bif", ".jpg", ".jpeg", ".jpe",
".tiff", ".csv", ".pdf", ".svg", ".svgz", ".svg.gz", ".gif", ".mat", ".webp", ".img",
".hdr", ".fits", ".fit", ".fts", ".nii", ".nii.gz", ".hdr.gz", ".img.gz", ".nia", ".nia.gz"]
I don't know how useful that is. It's missing .ico
and .bmp
; .jpg
is there three times, etc.
If you want a list of the available loaders, just walking the types below VipsForeignLoad
might be simpler.
(libvips will load BMP, btw)
Beta Was this translation helpful? Give feedback.