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.
- checksums.yaml +4 -4
- data/.rubocop_todo.yml +1 -1
- data/.travis.yml +1 -6
- data/CHANGELOG.md +11 -0
- data/README.md +38 -37
- data/TODO +1 -1
- data/VERSION +1 -1
- data/example/connection.rb +17 -0
- data/example/progress.rb +30 -0
- data/lib/vips.rb +64 -4
- data/lib/vips/connection.rb +46 -0
- data/lib/vips/gobject.rb +9 -1
- data/lib/vips/gvalue.rb +13 -4
- data/lib/vips/image.rb +213 -112
- data/lib/vips/methods.rb +330 -40
- data/lib/vips/object.rb +123 -5
- data/lib/vips/operation.rb +156 -80
- data/lib/vips/region.rb +2 -2
- data/lib/vips/source.rb +89 -0
- data/lib/vips/sourcecustom.rb +90 -0
- data/lib/vips/target.rb +87 -0
- data/lib/vips/targetcustom.rb +78 -0
- data/lib/vips/version.rb +1 -1
- data/ruby-vips.gemspec +3 -1
- metadata +14 -6
data/lib/vips/image.rb
CHANGED
@@ -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
|
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
|
-
|
521
|
-
|
627
|
+
raise Vips::Error if Vips::vips_image_get(self, name, gvalue) != 0
|
628
|
+
result = gvalue.get
|
629
|
+
gvalue.unset
|
522
630
|
|
523
|
-
|
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
|
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::
|
1440
|
+
# require 'vips'; Vips::Yard.generate
|
1332
1441
|
# ^D
|
1333
1442
|
# ```
|
1334
1443
|
|
1335
|
-
|
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
|
-
|
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
|
-
|
1355
|
-
|
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
|
-
|
1409
|
-
|
1410
|
-
|
1411
|
-
|
1412
|
-
|
1413
|
-
|
1414
|
-
|
1415
|
-
|
1416
|
-
|
1417
|
-
|
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 "#{
|
1423
|
-
print
|
1424
|
-
print ", " if
|
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
|
-
|
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 |
|
1435
|
-
|
1436
|
-
|
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 |
|
1439
|
-
|
1440
|
-
|
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[:
|
1536
|
+
print gtype_to_ruby(required_output.first[:gtype])
|
1448
1537
|
else
|
1449
1538
|
print "Array<"
|
1450
|
-
print required_output.map
|
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
|
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
|
-
|
1468
|
-
|
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
|
-
|
1471
|
-
|
1472
|
-
|
1473
|
-
|
1474
|
-
|
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
|
-
|
1479
|
-
|
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
|
-
|
1482
|
-
|
1578
|
+
generate_operation(introspect) if introspect
|
1579
|
+
end
|
1483
1580
|
|
1484
|
-
|
1485
|
-
|
1486
|
-
puts ""
|
1581
|
+
Vips::vips_type_map gtype, generate_class, nil
|
1582
|
+
end
|
1487
1583
|
|
1488
|
-
|
1584
|
+
puts "module Vips"
|
1585
|
+
puts " class Image"
|
1586
|
+
puts ""
|
1489
1587
|
|
1490
|
-
|
1491
|
-
|
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
|