ruby-vips 2.0.16 → 2.0.17

Sign up to get free protection for your applications and to get access to all the features.
@@ -14,6 +14,9 @@ module Vips
14
14
 
15
15
  attach_function :vips_image_copy_memory, [:pointer], :pointer
16
16
 
17
+ attach_function :vips_image_set_progress, [:pointer, :bool], :void
18
+ attach_function :vips_image_set_kill, [:pointer, :bool], :void
19
+
17
20
  attach_function :vips_filename_get_filename, [:string], :pointer
18
21
  attach_function :vips_filename_get_options, [:string], :pointer
19
22
 
@@ -22,6 +25,11 @@ module Vips
22
25
  attach_function :vips_foreign_find_load_buffer, [:pointer, :size_t], :string
23
26
  attach_function :vips_foreign_find_save_buffer, [:string], :string
24
27
 
28
+ if Vips::at_least_libvips?(8, 9)
29
+ attach_function :vips_foreign_find_load_source, [:pointer], :string
30
+ attach_function :vips_foreign_find_save_target, [:string], :string
31
+ end
32
+
25
33
  attach_function :vips_image_write_to_memory,
26
34
  [:pointer, SizeStruct.ptr], :pointer
27
35
 
@@ -109,7 +117,7 @@ module Vips
109
117
 
110
118
  unless Image::complex? image.format
111
119
  if image.bands % 2 != 0
112
- raise Error, "not an even number of bands"
120
+ raise Vips::Error, "not an even number of bands"
113
121
  end
114
122
 
115
123
  unless Image::float? image.format
@@ -290,11 +298,50 @@ module Vips
290
298
  # @return [Image] the loaded image
291
299
  def self.new_from_buffer data, option_string, **opts
292
300
  loader = Vips::vips_foreign_find_load_buffer data, data.bytesize
293
- raise Vips::Error if loader == nil
301
+ raise Vips::Error if loader.nil?
294
302
 
295
303
  Vips::Operation.call loader, [data], opts, option_string
296
304
  end
297
305
 
306
+ # Create a new {Image} from a source. Load options may be passed as
307
+ # strings or appended as a hash. For example:
308
+ #
309
+ # ```
310
+ # source = Vips::Source.new_from_file("k2.jpg")
311
+ # image = Vips::Image.new_from_source source, "shrink=2"
312
+ # ```
313
+ #
314
+ # or alternatively:
315
+ #
316
+ # ```
317
+ # image = Vips::Image.new_from_source source, "", shrink: 2
318
+ # ```
319
+ #
320
+ # The options available depend on the file format. Try something like:
321
+ #
322
+ # ```
323
+ # $ vips jpegload_source
324
+ # ```
325
+ #
326
+ # at the command-line to see the available options. Not all loaders
327
+ # support load from source, but at least JPEG, PNG and
328
+ # TIFF images will work.
329
+ #
330
+ # Loading is fast: only enough data is read to be able to fill
331
+ # out the header. Pixels will only be read and decompressed when they are
332
+ # needed.
333
+ #
334
+ # @param source [Vips::Source] the source to load from
335
+ # @param option_string [String] load options as a string
336
+ # @macro vips.loadopts
337
+ # @return [Image] the loaded image
338
+ def self.new_from_source source, option_string, **opts
339
+ loader = Vips::vips_foreign_find_load_source source
340
+ raise Vips::Error if loader.nil?
341
+
342
+ Vips::Operation.call loader, [source], opts, option_string
343
+ end
344
+
298
345
  def self.matrix_from_array width, height, array
299
346
  ptr = FFI::MemoryPointer.new :double, array.length
300
347
  ptr.write_array_of_double array
@@ -454,7 +501,7 @@ module Vips
454
501
  option_string = Vips::p2str(Vips::vips_filename_get_options format_string)
455
502
  saver = Vips::vips_foreign_find_save_buffer filename
456
503
  if saver == nil
457
- raise Vips::Error, "No known saver for '#{filename}'."
504
+ raise Vips::Error, "No known buffer saver for '#{filename}'."
458
505
  end
459
506
 
460
507
  buffer = Vips::Operation.call saver, [self], opts, option_string
@@ -465,6 +512,44 @@ module Vips
465
512
  return buffer
466
513
  end
467
514
 
515
+ # Write this image to a target. Save options may be encoded in
516
+ # the format_string or given as a hash. For example:
517
+ #
518
+ # ```ruby
519
+ # target = Vips::Target.new_to_file "k2.jpg"
520
+ # image.write_to_target target, ".jpg[Q=90]"
521
+ # ```
522
+ #
523
+ # or equivalently:
524
+ #
525
+ # ```ruby
526
+ # image.write_to_target target, ".jpg", Q: 90
527
+ # ```
528
+ #
529
+ # The full set of save options depend on the selected saver. Try
530
+ # something like:
531
+ #
532
+ # ```
533
+ # $ vips jpegsave_target
534
+ # ```
535
+ #
536
+ # to see all the available options for JPEG save.
537
+ #
538
+ # @param target [Vips::Target] the target to write to
539
+ # @param format_string [String] save format plus string options
540
+ # @macro vips.saveopts
541
+ def write_to_target target, format_string, **opts
542
+ filename = Vips::p2str(Vips::vips_filename_get_filename format_string)
543
+ option_string = Vips::p2str(Vips::vips_filename_get_options format_string)
544
+ saver = Vips::vips_foreign_find_save_target filename
545
+ if saver == nil
546
+ raise Vips::Error, "No known target saver for '#{filename}'."
547
+ end
548
+
549
+ Vips::Operation.call saver, [self, target], opts, option_string
550
+ write_gc
551
+ end
552
+
468
553
  # Write this image to a large memory buffer.
469
554
  #
470
555
  # @return [String] the pixels as a huge binary string
@@ -479,6 +564,28 @@ module Vips
479
564
  ptr.get_bytes 0, len[:value]
480
565
  end
481
566
 
567
+ # Turn progress signalling on and off.
568
+ #
569
+ # If this is on, the most-downstream image from this image will issue
570
+ # progress signals.
571
+ #
572
+ # @see Object#signal_connect
573
+ # @param state [Boolean] progress signalling state
574
+ def set_progress state
575
+ Vips::vips_image_set_progress self, state
576
+ end
577
+
578
+ # Kill computation of this time.
579
+ #
580
+ # Set true to stop computation of this image. You can call this from a
581
+ # progress handler, for example.
582
+ #
583
+ # @see Object#signal_connect
584
+ # @param kill [Boolean] stop computation
585
+ def set_kill kill
586
+ Vips::vips_image_set_kill self, kill
587
+ end
588
+
482
589
  # Get the `GType` of a metadata field. The result is 0 if no such field
483
590
  # exists.
484
591
  #
@@ -517,10 +624,11 @@ module Vips
517
624
  end
518
625
 
519
626
  gvalue = GObject::GValue.alloc
520
- result = Vips::vips_image_get self, name, gvalue
521
- raise Vips::Error if result != 0
627
+ raise Vips::Error if Vips::vips_image_get(self, name, gvalue) != 0
628
+ result = gvalue.get
629
+ gvalue.unset
522
630
 
523
- gvalue.get
631
+ result
524
632
  end
525
633
 
526
634
  # Get the names of all fields on an image. Use this to loop over all
@@ -565,6 +673,7 @@ module Vips
565
673
  gvalue.init gtype
566
674
  gvalue.set value
567
675
  Vips::vips_image_set self, name, gvalue
676
+ gvalue.unset
568
677
  end
569
678
 
570
679
  # Set the value of a metadata item on an image. The metadata item must
@@ -1065,7 +1174,7 @@ module Vips
1065
1174
  GObject::GValue.from_nick Vips::BLEND_MODE_TYPE, x
1066
1175
  end
1067
1176
 
1068
- Vips::Image.composite([self] + overlay, mode, opts)
1177
+ Vips::Image.composite([self] + overlay, mode, **opts)
1069
1178
  end
1070
1179
 
1071
1180
  # Return the coordinates of the image maximum.
@@ -1315,29 +1424,26 @@ module Vips
1315
1424
  # @param opts [Hash] Set of options
1316
1425
  # @return [Vips::Image] Output image
1317
1426
  def scaleimage **opts
1318
- Vips::Image.scale self, opts
1427
+ Vips::Image.scale self, **opts
1319
1428
  end
1320
1429
  end
1321
1430
  end
1322
1431
 
1323
1432
  module Vips
1324
- # This method generates yard comments for all the dynamically bound
1433
+ # This module generates yard comments for all the dynamically bound
1325
1434
  # vips operations.
1326
1435
  #
1327
1436
  # Regenerate with something like:
1328
1437
  #
1329
1438
  # ```
1330
1439
  # $ ruby > methods.rb
1331
- # require 'vips'; Vips::generate_yard
1440
+ # require 'vips'; Vips::Yard.generate
1332
1441
  # ^D
1333
1442
  # ```
1334
1443
 
1335
- def self.generate_yard
1336
- # these have hand-written methods, see above
1337
- no_generate = ["scale", "bandjoin", "composite", "ifthenelse"]
1338
-
1444
+ module Yard
1339
1445
  # map gobject's type names to Ruby
1340
- map_go_to_ruby = {
1446
+ MAP_GO_TO_RUBY = {
1341
1447
  "gboolean" => "Boolean",
1342
1448
  "gint" => "Integer",
1343
1449
  "gdouble" => "Float",
@@ -1345,116 +1451,99 @@ module Vips
1345
1451
  "gchararray" => "String",
1346
1452
  "VipsImage" => "Vips::Image",
1347
1453
  "VipsInterpolate" => "Vips::Interpolate",
1454
+ "VipsConnection" => "Vips::Connection",
1455
+ "VipsSource" => "Vips::Source",
1456
+ "VipsTarget" => "Vips::Target",
1457
+ "VipsSourceCustom" => "Vips::SourceCustom",
1458
+ "VipsTargetCustom" => "Vips::TargetCustom",
1348
1459
  "VipsArrayDouble" => "Array<Double>",
1349
1460
  "VipsArrayInt" => "Array<Integer>",
1350
1461
  "VipsArrayImage" => "Array<Image>",
1351
1462
  "VipsArrayString" => "Array<String>",
1352
1463
  }
1353
1464
 
1354
- generate_operation = lambda do |gtype, nickname, op|
1355
- op_flags = op.get_flags
1356
- return if (op_flags & OPERATION_DEPRECATED) != 0
1357
- return if no_generate.include? nickname
1358
-
1359
- description = Vips::vips_object_get_description op
1360
-
1361
- # find and classify all the arguments the operator can take
1362
- required_input = []
1363
- optional_input = []
1364
- required_output = []
1365
- optional_output = []
1366
- member_x = nil
1367
- op.argument_map do |pspec, argument_class, _argument_instance|
1368
- arg_flags = argument_class[:flags]
1369
- next if (arg_flags & ARGUMENT_CONSTRUCT) == 0
1370
- next if (arg_flags & ARGUMENT_DEPRECATED) != 0
1371
-
1372
- name = pspec[:name].tr("-", "_")
1373
- # 'in' as a param name confuses yard
1374
- name = "im" if name == "in"
1375
- gtype = pspec[:value_type]
1376
- fundamental = GObject::g_type_fundamental gtype
1377
- type_name = GObject::g_type_name gtype
1378
- if map_go_to_ruby.include? type_name
1379
- type_name = map_go_to_ruby[type_name]
1380
- end
1381
- if fundamental == GObject::GFLAGS_TYPE ||
1382
- fundamental == GObject::GENUM_TYPE
1383
- type_name = "Vips::" + type_name[/Vips(.*)/, 1]
1384
- end
1385
- blurb = GObject::g_param_spec_get_blurb pspec
1386
- value = {
1387
- name: name,
1388
- flags: arg_flags,
1389
- gtype: gtype,
1390
- type_name: type_name,
1391
- blurb: blurb
1392
- }
1393
-
1394
- if (arg_flags & ARGUMENT_INPUT) != 0
1395
- if (arg_flags & ARGUMENT_REQUIRED) != 0
1396
- # note the first required input image, if any ... we
1397
- # will be a method of this instance
1398
- if !member_x && gtype == Vips::IMAGE_TYPE
1399
- member_x = value
1400
- else
1401
- required_input << value
1402
- end
1403
- else
1404
- optional_input << value
1405
- end
1406
- end
1465
+ # these have hand-written methods, see above
1466
+ NO_GENERATE = ["scale", "bandjoin", "composite", "ifthenelse"]
1407
1467
 
1408
- # MODIFY INPUT args count as OUTPUT as well
1409
- if (arg_flags & ARGUMENT_OUTPUT) != 0 ||
1410
- ((arg_flags & ARGUMENT_INPUT) != 0 &&
1411
- (arg_flags & ARGUMENT_MODIFY) != 0)
1412
- if (arg_flags & ARGUMENT_REQUIRED) != 0
1413
- required_output << value
1414
- else
1415
- optional_output << value
1416
- end
1417
- end
1468
+ # these are aliased (appear under several names)
1469
+ ALIAS = ["crop"]
1470
+
1471
+ # turn a gtype into a ruby type name
1472
+ def self.gtype_to_ruby gtype
1473
+ fundamental = GObject::g_type_fundamental gtype
1474
+ type_name = GObject::g_type_name gtype
1475
+
1476
+ if MAP_GO_TO_RUBY.include? type_name
1477
+ type_name = MAP_GO_TO_RUBY[type_name]
1478
+ end
1479
+
1480
+ if fundamental == GObject::GFLAGS_TYPE ||
1481
+ fundamental == GObject::GENUM_TYPE
1482
+ type_name = "Vips::" + type_name[/Vips(.*)/, 1]
1418
1483
  end
1419
1484
 
1485
+ type_name
1486
+ end
1487
+
1488
+ def self.generate_operation introspect
1489
+ return if (introspect.flags & OPERATION_DEPRECATED) != 0
1490
+ return if NO_GENERATE.include? introspect.name
1491
+
1492
+ method_args = introspect.method_args
1493
+ required_output = introspect.required_output
1494
+ optional_input = introspect.optional_input
1495
+ optional_output = introspect.optional_output
1496
+
1420
1497
  print "# @!method "
1421
- print "self." unless member_x
1422
- print "#{nickname}("
1423
- print required_input.map { |x| x[:name] }.join(", ")
1424
- print ", " if required_input.length > 0
1498
+ print "self." unless introspect.member_x
1499
+ print "#{introspect.name}("
1500
+ print method_args.map{ |x| x[:yard_name] }.join(", ")
1501
+ print ", " if method_args.length > 0
1425
1502
  puts "**opts)"
1426
1503
 
1427
- puts "# #{description.capitalize}."
1504
+ puts "# #{introspect.description.capitalize}."
1505
+
1506
+ method_args.each do |details|
1507
+ yard_name = details[:yard_name]
1508
+ gtype = details[:gtype]
1509
+ blurb = details[:blurb]
1428
1510
 
1429
- required_input.each do |arg|
1430
- puts "# @param #{arg[:name]} [#{arg[:type_name]}] #{arg[:blurb]}"
1511
+ puts "# @param #{yard_name} [#{gtype_to_ruby(gtype)}] #{blurb}"
1431
1512
  end
1432
1513
 
1433
1514
  puts "# @param opts [Hash] Set of options"
1434
- optional_input.each do |arg|
1435
- puts "# @option opts [#{arg[:type_name]}] :#{arg[:name]} " +
1436
- "#{arg[:blurb]}"
1515
+ optional_input.each do |arg_name, details|
1516
+ yard_name = details[:yard_name]
1517
+ gtype = details[:gtype]
1518
+ blurb = details[:blurb]
1519
+
1520
+ puts "# @option opts [#{gtype_to_ruby(gtype)}] :#{yard_name} " +
1521
+ "#{blurb}"
1437
1522
  end
1438
- optional_output.each do |arg|
1439
- print "# @option opts [#{arg[:type_name]}] :#{arg[:name]}"
1440
- puts " Output #{arg[:blurb]}"
1523
+ optional_output.each do |arg_name, details|
1524
+ yard_name = details[:yard_name]
1525
+ gtype = details[:gtype]
1526
+ blurb = details[:blurb]
1527
+
1528
+ print "# @option opts [#{gtype_to_ruby(gtype)}] :#{yard_name}"
1529
+ puts " Output #{blurb}"
1441
1530
  end
1442
1531
 
1443
1532
  print "# @return ["
1444
1533
  if required_output.length == 0
1445
1534
  print "nil"
1446
1535
  elsif required_output.length == 1
1447
- print required_output.first[:type_name]
1536
+ print gtype_to_ruby(required_output.first[:gtype])
1448
1537
  else
1449
1538
  print "Array<"
1450
- print required_output.map { |x| x[:type_name] }.join(", ")
1539
+ print required_output.map{ |x| gtype_to_ruby(x[:gtype]) }.join(", ")
1451
1540
  print ">"
1452
1541
  end
1453
1542
  if optional_output.length > 0
1454
1543
  print ", Hash<Symbol => Object>"
1455
1544
  end
1456
1545
  print "] "
1457
- print required_output.map { |x| x[:blurb] }.join(", ")
1546
+ print required_output.map{ |x| x[:blurb] }.join(", ")
1458
1547
  if optional_output.length > 0
1459
1548
  print ", " if required_output.length > 0
1460
1549
  print "Hash of optional output items"
@@ -1464,30 +1553,42 @@ module Vips
1464
1553
  puts ""
1465
1554
  end
1466
1555
 
1467
- generate_class = lambda do |gtype, _|
1468
- nickname = Vips::nickname_find gtype
1556
+ def self.generate
1557
+ alias_gtypes = {}
1558
+ ALIAS.each do |name|
1559
+ gtype = Vips::type_find "VipsOperation", name
1560
+ alias_gtypes[gtype] = name
1561
+ end
1469
1562
 
1470
- if nickname
1471
- begin
1472
- # can fail for abstract types
1473
- op = Vips::Operation.new nickname
1474
- rescue Vips::Error
1475
- nil
1563
+ generate_class = lambda do |gtype, _|
1564
+ if alias_gtypes.key? gtype
1565
+ name = alias_gtypes[gtype]
1566
+ else
1567
+ name = Vips::nickname_find gtype
1476
1568
  end
1477
1569
 
1478
- generate_operation.(gtype, nickname, op) if op
1479
- end
1570
+ if name
1571
+ begin
1572
+ # can fail for abstract types
1573
+ introspect = Vips::Introspect.get_yard name
1574
+ rescue Vips::Error
1575
+ nil
1576
+ end
1480
1577
 
1481
- Vips::vips_type_map gtype, generate_class, nil
1482
- end
1578
+ generate_operation(introspect) if introspect
1579
+ end
1483
1580
 
1484
- puts "module Vips"
1485
- puts " class Image"
1486
- puts ""
1581
+ Vips::vips_type_map gtype, generate_class, nil
1582
+ end
1487
1583
 
1488
- generate_class.(GObject::g_type_from_name("VipsOperation"), nil)
1584
+ puts "module Vips"
1585
+ puts " class Image"
1586
+ puts ""
1489
1587
 
1490
- puts " end"
1491
- puts "end"
1588
+ generate_class.(GObject::g_type_from_name("VipsOperation"), nil)
1589
+
1590
+ puts " end"
1591
+ puts "end"
1592
+ end
1492
1593
  end
1493
1594
  end