Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

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

Method listing supported "foreign" extensions #186

Closed
aleksandrs-ledovskis opened this issue Oct 25, 2018 · 7 comments
Closed

Method listing supported "foreign" extensions #186

aleksandrs-ledovskis opened this issue Oct 25, 2018 · 7 comments

Comments

@aleksandrs-ledovskis
Copy link

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.

@jcupitt
Copy link
Member

jcupitt commented Oct 25, 2018

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.

@aleksandrs-ledovskis
Copy link
Author

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]

@tomasc
Copy link

tomasc commented Feb 10, 2019

@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.

jcupitt added a commit to libvips/libvips that referenced this issue Feb 23, 2019
Add vips_foreign_get_suffixes(), get an array of all the filename suffixes that
libvips recognises.

See libvips/ruby-vips#186
jcupitt added a commit that referenced this issue Feb 23, 2019
Get a list of all the filename suffixes that libvips supports.

See #186
@jcupitt
Copy link
Member

jcupitt commented Feb 23, 2019

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.

@tomasc
Copy link

tomasc commented Feb 23, 2019

Fabulous!

jcupitt added a commit to libvips/pyvips that referenced this issue Feb 23, 2019
Add get_suffixes(), a thing to get all the filename suffixes supported
by libvips. See libvips/ruby-vips#186

Also, some smalll cleanups.
@aleksandrs-ledovskis
Copy link
Author

@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.

@jcupitt
Copy link
Member

jcupitt commented Feb 24, 2019

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)

kleisauke added a commit to kleisauke/net-vips that referenced this issue Mar 14, 2019
Add Base.GetSuffixes(), a thing to get all the filename suffixes supported
by libvips. See: libvips/ruby-vips#186

Also, some unit test cleanups.
kleisauke added a commit to kleisauke/net-vips that referenced this issue Apr 6, 2019
Add Base.GetSuffixes(), a thing to get all the filename suffixes supported
by libvips. See: libvips/ruby-vips#186

Also, some unit test cleanups.
@jcupitt jcupitt closed this as completed Jan 31, 2021
@libvips libvips locked and limited conversation to collaborators Jan 31, 2021

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Projects
None yet
Development

No branches or pull requests

3 participants