Class: Vips::Operation
- Inherits:
-
Object
- Object
- GObject::GObject
- Object
- Vips::Operation
- Defined in:
- lib/vips/operation.rb
Defined Under Namespace
Modules: OperationLayout Classes: ManagedStruct, Struct
Instance Attribute Summary
Attributes inherited from GObject::GObject
Class Method Summary collapse
-
.call(name, supplied, optional = {}, option_string = "") ⇒ Object
This is the public entry point for the vips binding.
-
.flat_find(object, &block) ⇒ Object
Search an object for the first element to match a predicate.
-
.imageize(match_image, value) ⇒ Object
expand a constant into an image.
Instance Method Summary collapse
- #argument_map(&block) ⇒ Object
- #build ⇒ Object
-
#initialize(value) ⇒ Operation
constructor
A new instance of Operation.
-
#set(name, value, match_image, flags, gtype, destructive) ⇒ Object
set an operation argument, expanding constants and copying images as required.
Methods inherited from Object
#get, #get_pspec, #get_typeof, #get_typeof_error, print_all, #signal_connect
Methods inherited from GObject::GObject
#ffi_managed_struct, ffi_managed_struct, ffi_struct, #ffi_struct
Constructor Details
#initialize(value) ⇒ Operation
Returns a new instance of Operation.
213 214 215 216 217 218 219 220 221 222 |
# File 'lib/vips/operation.rb', line 213 def initialize value # allow init with a pointer so we can wrap the return values from # things like _build if value.is_a? String value = Vips.vips_operation_new value raise Vips::Error if value.null? end super end |
Class Method Details
.call(name, supplied, optional = {}, option_string = "") ⇒ Object
This is the public entry point for the vips binding. call will run any vips operation, for example:
out = Vips::Operation.call "black", [100, 100], {:bands => 12}
will call the C function
vips_black( &out, 100, 100, "bands", 12, NULL );
There are Image#method_missing hooks which will run call for you on Image for undefined instance or class methods. So you can also write:
out = Vips::Image.black 100, 100, bands: 12
Or perhaps:
x = Vips::Image.black 100, 100
y = x.invert
to run the vips_invert()
operator.
There are also a set of operator overloads and some convenience functions, see Image.
If the operator needs a vector constant, call will turn a scalar
into a
vector for you. So for x.linear a, b
, which calculates
x * a + b
where a
and b
are vector constants, you can write:
x = Vips::Image.black 100, 100, bands: 3
y = x.linear 1, 2
y = x.linear [1], 4
y = x.linear [1, 2, 3], 4
or any other combination. The operator overloads use this facility to support all the variations on:
x = Vips::Image.black 100, 100, bands: 3
y = x * 2
y = x + [1,2,3]
y = x % [1]
Similarly, wherever an image is required, you can use a constant. The constant will be expanded to an image matching the first input image argument. For example, you can write:
x = Vips::Image.black 100, 100, bands: 3
y = x.bandjoin 255
to add an extra band to the image where each pixel in the new band has the constant value 255.
358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 |
# File 'lib/vips/operation.rb', line 358 def self.call name, supplied, optional = {}, option_string = "" GLib.logger.debug("Vips::VipsOperation.call") { "name = #{name}, supplied = #{supplied}, " \ "optional = #{optional}, option_string = #{option_string}" } introspect = Introspect.get name required_input = introspect.required_input required_output = introspect.required_output optional_input = introspect.optional_input optional_output = introspect.optional_output destructive = introspect.destructive unless supplied.is_a? Array raise Vips::Error, "unable to call #{name}: " \ "argument array is not an array" end unless optional.is_a? Hash raise Vips::Error, "unable to call #{name}: " \ "optional arguments are not a hash" end if supplied.length != required_input.length raise Vips::Error, "unable to call #{name}: " \ "you supplied #{supplied.length} arguments, " \ "but operation needs #{required_input.length}." end # all supplied_optional keys should be in optional_input or # optional_output optional.each do |key, _value| arg_name = key.to_s unless optional_input.has_key?(arg_name) || optional_output.has_key?(arg_name) raise Vips::Error, "unable to call #{name}: " \ "unknown option #{arg_name}" end end # the first image arg is the thing we expand constants to match ... # we need to find it # # look inside array and hash arguments, since we may be passing an # array of images # # also enforce the rules around mutable and non-mutable images match_image = nil flat_find(supplied) do |value| if match_image # no non-first image arg can ever be mutable if value.is_a?(MutableImage) raise Vips::Error, "unable to call #{name}: " \ "only the first image argument can be mutable" end elsif destructive if value.is_a?(Image) raise Vips::Error, "unable to call #{name}: " \ "first image argument to a destructive " \ "operation must be mutable" elsif value.is_a?(MutableImage) match_image = value end elsif value.is_a?(MutableImage) # non destructive operation, so no mutable images raise Vips::Error, "unable to call #{name}: " \ "must not pass mutable images to " \ "non-destructive operations" elsif value.is_a?(Image) match_image = value end # keep looping false end op = Operation.new introspect.vips_name # set any string args first so they can't be overridden unless option_string.nil? if Vips.vips_object_set_from_string(op, option_string) != 0 raise Vips::Error end end # dedupe all input references here deduped_references = Set.new add_reference = lambda do |x| if x.is_a?(Vips::Image) deduped_references.merge x.references end false end # set all required inputs required_input.each_index do |i| details = required_input[i] arg_name = details[:arg_name] flags = details[:flags] gtype = details[:gtype] value = supplied[i] flat_find value, &add_reference op.set arg_name, value, match_image, flags, gtype, destructive end # set all optional inputs optional.each do |key, value| next if value.nil? arg_name = key.to_s if optional_input.has_key? arg_name details = optional_input[arg_name] flags = details[:flags] gtype = details[:gtype] flat_find value, &add_reference op.set arg_name, value, match_image, flags, gtype, destructive end end op = op.build # we need an array of references for output objects references = deduped_references.to_a # attach all input refs to output x set_reference = lambda do |x| # stop early if there are no refs to attach return true if references == [] if x.is_a? Vips::Image references.each { |i| x.references << i } end false end # get all required results result = [] required_output.each do |details| value = op.get(details[:arg_name]) flat_find value, &set_reference result << value end # fetch all optional ones optional_results = {} optional.each do |key, _value| arg_name = key.to_s if optional_output.has_key? arg_name value = op.get arg_name flat_find value, &set_reference optional_results[arg_name] = value end end result << optional_results if optional_results != {} if result.length == 1 result = result.first elsif result.length == 0 result = nil end GLib.logger.debug("Vips::Operation.call") { "result = #{result}" } Vips.vips_object_unref_outputs op result end |
.flat_find(object, &block) ⇒ Object
Search an object for the first element to match a predicate. Search inside subarrays and sub-hashes. Equlvalent to x.flatten.find{}.
243 244 245 246 247 248 249 250 251 252 253 254 |
# File 'lib/vips/operation.rb', line 243 def self.flat_find object, &block if object.respond_to? :each object.each do |x| result = flat_find x, &block return result unless result.nil? end elsif yield object return object end nil end |
.imageize(match_image, value) ⇒ Object
expand a constant into an image
257 258 259 260 261 262 263 264 265 266 267 268 269 |
# File 'lib/vips/operation.rb', line 257 def self.imageize match_image, value return value if value.is_a?(Image) || value.is_a?(MutableImage) # 2D array values become tiny 2D images # if there's nothing to match to, we also make a 2D image if (value.is_a?(Array) && value[0].is_a?(Array)) || match_image.nil? Image.new_from_array value else # we have a 1D array ... use that as a pixel constant and # expand to match match_image match_image.new_from_image value end end |
Instance Method Details
#argument_map(&block) ⇒ Object
234 235 236 237 238 239 |
# File 'lib/vips/operation.rb', line 234 def argument_map &block fn = proc do |_op, pspec, argument_class, argument_instance, _a, _b| block.call pspec, argument_class, argument_instance end Vips.vips_argument_map self, fn, nil, nil end |
#build ⇒ Object
224 225 226 227 228 229 230 231 232 |
# File 'lib/vips/operation.rb', line 224 def build op = Vips.vips_cache_operation_build self if op.null? Vips.vips_object_unref_outputs self raise Vips::Error end Operation.new op end |
#set(name, value, match_image, flags, gtype, destructive) ⇒ Object
set an operation argument, expanding constants and copying images as required
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 |
# File 'lib/vips/operation.rb', line 273 def set name, value, match_image, flags, gtype, destructive if gtype == IMAGE_TYPE value = Operation.imageize match_image, value # in non-destructive mode, make sure we have a unique copy if (flags & ARGUMENT_MODIFY) != 0 && !destructive value = value.copy.copy_memory end elsif gtype == ARRAY_IMAGE_TYPE value = value.map { |x| Operation.imageize match_image, x } end super(name, value) end |