Skip to content

improve gflags argument handling #421

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

Merged
merged 6 commits into from
Jul 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## master

* improve NULL pointer handling [dloebl]
* improve GFlags argument handling [jcupitt]

## Version 2.2.4 (2025-06-05)

Expand Down
44 changes: 41 additions & 3 deletions lib/vips/gvalue.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class GValue < FFI::ManagedStruct
:data, [:ulong_long, 2]

# convert an enum value (str/symb/int) into an int ready for libvips
def self.from_nick(gtype, value)
def self.enum_from_nick(gtype, value)
value = value.to_s if value.is_a? Symbol

if value.is_a? String
Expand All @@ -40,6 +40,43 @@ def self.from_nick(gtype, value)
value
end

# compatibility ... we used to call it this, perhaps someone has used this
# internal method
def self.from_nick(gtype, value)
GValue.enum_from_nick(gtype, value)
end

# convert an flags value (array[str/symb/int] | str/symb/int) into an
# int ready for libvips
def self.flags_from_nick(gtype, value)
if value.is_a? String
# libvips will parse strings like "sub|up" etc.
name = value.tr("_", "-")
value = Vips.vips_flags_from_nick "ruby-vips", gtype, name
else
value = [value] if !value.is_a? Array

# convert each item to a set of bits, OR them together
result = 0
value.map do |item|
item = item.to_s if item.is_a? Symbol
if item.is_a? String
name = item.tr("_", "-")
item = Vips.vips_flags_from_nick "ruby-vips", gtype, name
if item == -1
raise Vips::Error
end
end

result |= item
end

value = result
end

value
end

# convert an int enum back into a symbol
def self.to_nick(gtype, enum_value)
enum_name = Vips.vips_enum_nick gtype, enum_value
Expand Down Expand Up @@ -148,10 +185,11 @@ def set value
else
case fundamental
when GFLAGS_TYPE
::GObject.g_value_set_flags self, value
flags_value = GValue.flags_from_nick(self[:gtype], value)
::GObject.g_value_set_flags self, flags_value

when GENUM_TYPE
enum_value = GValue.from_nick(self[:gtype], value)
enum_value = GValue.enum_from_nick(self[:gtype], value)
::GObject.g_value_set_enum self, enum_value

when GOBJECT_TYPE
Expand Down
10 changes: 5 additions & 5 deletions lib/vips/image.rb
Original file line number Diff line number Diff line change
Expand Up @@ -114,12 +114,12 @@ def self.smap x, &block
end

def self.complex? format
format_number = GObject::GValue.from_nick BAND_FORMAT_TYPE, format
format_number = GObject::GValue.enum_from_nick BAND_FORMAT_TYPE, format
Vips.vips_band_format_iscomplex(format_number) != 0
end

def self.float? format
format_number = GObject::GValue.from_nick BAND_FORMAT_TYPE, format
format_number = GObject::GValue.enum_from_nick BAND_FORMAT_TYPE, format
Vips.vips_band_format_isfloat(format_number) != 0
end

Expand Down Expand Up @@ -380,7 +380,7 @@ def self.new_from_memory data, width, height, bands, format
size = data.bytesize
end

format_number = GObject::GValue.from_nick BAND_FORMAT_TYPE, format
format_number = GObject::GValue.enum_from_nick BAND_FORMAT_TYPE, format
vi = Vips.vips_image_new_from_memory data, size,
width, height, bands, format_number
raise Vips::Error if vi.null?
Expand All @@ -405,7 +405,7 @@ def self.new_from_memory data, width, height, bands, format
# @param format [Symbol] band format
# @return [Image] the loaded image
def self.new_from_memory_copy data, width, height, bands, format
format_number = GObject::GValue.from_nick BAND_FORMAT_TYPE, format
format_number = GObject::GValue.enum_from_nick BAND_FORMAT_TYPE, format

if data.is_a?(FFI::Pointer)
if data.size == UNKNOWN_POINTER_SIZE
Expand Down Expand Up @@ -1319,7 +1319,7 @@ def composite overlay, mode, **opts
end

mode = mode.map do |x|
GObject::GValue.from_nick Vips::BLEND_MODE_TYPE, x
GObject::GValue.enum_from_nick Vips::BLEND_MODE_TYPE, x
end

Vips::Image.composite([self] + overlay, mode, **opts)
Expand Down
1 change: 1 addition & 0 deletions lib/vips/object.rb
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ class Progress < FFI::Struct

attach_function :vips_enum_from_nick, [:string, :GType, :string], :int
attach_function :vips_enum_nick, [:GType, :int], :string
attach_function :vips_flags_from_nick, [:string, :GType, :string], :int

attach_function :vips_value_set_ref_string,
[GObject::GValue.ptr, :string], :void
Expand Down
29 changes: 29 additions & 0 deletions spec/vips_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,35 @@
expect(rot.bands).to eq(1)
end

it "can handle symbol flag arguments" do
black = Vips::Operation.call "black", [200, 200]
bytes = Vips::Operation.call "pngsave_buffer", [black], keep: :icc

expect(bytes.length).to be > 100
end

it "can handle int flag arguments" do
black = Vips::Operation.call "black", [200, 200]
bytes = Vips::Operation.call "pngsave_buffer", [black], keep: 1 << 3

expect(bytes.length).to be > 100
end

it "can handle string flag arguments" do
black = Vips::Operation.call "black", [200, 200]
bytes = Vips::Operation.call "pngsave_buffer", [black], keep: "icc"

expect(bytes.length).to be > 100
end

it "can handle array flag arguments" do
black = Vips::Operation.call "black", [200, 200]
bytes = Vips::Operation.call "pngsave_buffer", [black],
keep: [:icc, :xmp]

expect(bytes.length).to be > 100
end

it "can return optional output args" do
point = Vips::Operation.call "black", [1, 1]
test = Vips::Operation.call "embed", [point, 20, 10, 100, 100],
Expand Down