ffi-gphoto2 0.5.1 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.travis.yml +11 -0
- data/CHANGELOG.md +20 -0
- data/README.md +19 -10
- data/examples/autofocus.rb +21 -0
- data/examples/capture.rb +8 -0
- data/examples/continuous_burst.rb +27 -0
- data/examples/list_config.rb +1 -0
- data/examples/list_files.rb +52 -0
- data/ffi-gphoto2.gemspec +3 -3
- data/lib/ffi/gphoto2.rb +10 -1
- data/lib/ffi/gphoto2/camera_abilities_list.rb +1 -1
- data/lib/ffi/gphoto2/camera_file_info.rb +10 -0
- data/lib/ffi/gphoto2/camera_file_info_audio.rb +11 -0
- data/lib/ffi/gphoto2/camera_file_info_fields.rb +14 -0
- data/lib/ffi/gphoto2/camera_file_info_file.rb +15 -0
- data/lib/ffi/gphoto2/camera_file_info_preview.rb +13 -0
- data/lib/ffi/gphoto2/camera_file_permissions.rb +9 -0
- data/lib/ffi/gphoto2/camera_file_status.rb +7 -0
- data/lib/ffi/gphoto2/camera_list.rb +1 -1
- data/lib/ffi/gphoto2/camera_widget.rb +1 -1
- data/lib/ffi/gphoto2_port/gp_port_info_list.rb +1 -1
- data/lib/gphoto2.rb +23 -2
- data/lib/gphoto2/camera.rb +9 -1
- data/lib/gphoto2/camera/capture.rb +22 -0
- data/lib/gphoto2/camera/configuration.rb +1 -0
- data/lib/gphoto2/camera/event.rb +3 -6
- data/lib/gphoto2/camera_abilities.rb +9 -0
- data/lib/gphoto2/camera_file.rb +25 -7
- data/lib/gphoto2/camera_file_info/camera_file_info.rb +52 -0
- data/lib/gphoto2/camera_file_info/file_camera_file_info.rb +30 -0
- data/lib/gphoto2/camera_widgets/camera_widget.rb +2 -6
- data/lib/gphoto2/camera_widgets/radio_camera_widget.rb +0 -4
- data/lib/gphoto2/camera_widgets/text_camera_widget.rb +1 -3
- data/lib/gphoto2/entry.rb +0 -4
- data/lib/gphoto2/port_info.rb +0 -4
- data/lib/gphoto2/version.rb +1 -1
- data/spec/gphoto2/camera_abilities_spec.rb +23 -0
- data/spec/gphoto2/camera_file_info/file_camera_file_info_spec.rb +56 -0
- data/spec/gphoto2/camera_file_spec.rb +17 -0
- data/spec/gphoto2/camera_spec.rb +11 -5
- data/spec/gphoto2_spec.rb +18 -0
- data/spec/support/shared_examples/camera/capture_examples.rb +13 -0
- data/spec/support/shared_examples/camera/configuration_examples.rb +26 -18
- data/spec/support/shared_examples/camera_file_info_examples.rb +42 -0
- metadata +29 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 39745534e29e0571decd8eda706d74278a146cc1
|
4
|
+
data.tar.gz: 83c84f47474b4bd940748b11f4b65769db508550
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 287d38fca23d5e76207ea9f4e93d89ee4856f4c30a7deb198c5c2dc305d1eae171b881b3427671c10d623d605ffa877e9708a1db4efbc72ceb19fe0bc3c2589b
|
7
|
+
data.tar.gz: 8e69d5a190b2db161ce6d8be0bdb153282d7407955b8ce98a8b0269ecc544b63d2ac7b3bf0a2ffcf22631f23e75694bf15d1f0d7441d8124753b8a4a4f7f83bf
|
data/.travis.yml
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
sudo: required
|
2
|
+
dist: trusty
|
3
|
+
language: ruby
|
4
|
+
rvm:
|
5
|
+
- 2.3.1
|
6
|
+
before_install:
|
7
|
+
- gem install bundler -v 1.12.5
|
8
|
+
- sudo apt-get -qq update
|
9
|
+
- sudo apt-get install libgphoto2-6 libgphoto2-port10
|
10
|
+
- sudo ln -s /usr/lib/x86_64-linux-gnu/libgphoto2.so{.6,}
|
11
|
+
- sudo ln -s /usr/lib/x86_64-linux-gnu/libgphoto2_port.so{.10,}
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
## HEAD
|
4
|
+
|
5
|
+
## 0.6.0
|
6
|
+
|
7
|
+
* [FIX] Use the correct default filename when a `CameraFile` is a preview.
|
8
|
+
* [ADD] Add `CameraFileInfo` and related operations. `CameraFile#info` only
|
9
|
+
supports files.
|
10
|
+
* [FIX] `CameraWidget#label` calls the correct widget label function.
|
11
|
+
* [FIX] `Camera#[]=` raises an `ArgumentError` when passed an invalid key
|
12
|
+
instead of failing on `nil`.
|
13
|
+
* [ADD] Add `CameraAbilities#operations` to always return an `Integer`.
|
14
|
+
libgphoto2 does not stay in the defined enum set of `CameraOperations`;
|
15
|
+
therefore, it is treated as an integer bit field instead.
|
16
|
+
* [CHANGE] Errors are thrown as `GPhoto2::Error` rather than `RuntimeError`.
|
17
|
+
Use `#message` and `#code` to extract the the GPhoto2 error message and
|
18
|
+
return code, respectively.
|
19
|
+
* [ADD] `Camera#trigger` for trigger capture.
|
20
|
+
* [FIX] `TextCameraWidget` values can by any object that implements `#to_s`.
|
data/README.md
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
# ffi-gphoto2
|
2
2
|
|
3
|
-
|
3
|
+
|
4
|
+
[](https://badge.fury.io/rb/ffi-gphoto2)
|
5
|
+
[](https://travis-ci.org/zaeleus/ffi-gphoto2)
|
6
|
+
|
7
|
+
**ffi-gphoto2** provides an FFI for common functions in [libgphoto2][gphoto].
|
4
8
|
It also includes a facade to interact with the library in a more
|
5
9
|
idiomatic Ruby way.
|
6
10
|
|
@@ -34,9 +38,17 @@ camera = cameras.first
|
|
34
38
|
# ...or more conveniently
|
35
39
|
camera = GPhoto2::Camera.first
|
36
40
|
|
37
|
-
#
|
41
|
+
# search by model name
|
38
42
|
camera = GPhoto2::Camera.where(model: /nikon/i).first
|
39
43
|
|
44
|
+
# the above examples require the camera be manually closed when done
|
45
|
+
camera.close
|
46
|
+
|
47
|
+
# pass a block to automatically close the camera
|
48
|
+
GPhoto2::Camera.first do |camera|
|
49
|
+
# ...
|
50
|
+
end
|
51
|
+
|
40
52
|
# check camera abilities (see `FFI::GPhoto2::CameraOperation.symbols`)
|
41
53
|
camera.can? :capture_image
|
42
54
|
# => true
|
@@ -97,14 +109,11 @@ file.save
|
|
97
109
|
|
98
110
|
# ...and then delete it from the camera
|
99
111
|
file.delete
|
100
|
-
|
101
|
-
# close the camera
|
102
|
-
camera.finalize
|
103
112
|
```
|
104
113
|
|
105
|
-
More examples can be found in [`examples/`][
|
106
|
-
generated using the `rake yard` task or [browsed online][
|
114
|
+
More examples can be found in [`examples/`][examples]. YARD documentation can be
|
115
|
+
generated using the `rake yard` task or [browsed online][rubydoc].
|
107
116
|
|
108
|
-
[
|
109
|
-
[
|
110
|
-
[
|
117
|
+
[gphoto]: http://www.gphoto.org/
|
118
|
+
[examples]: https://github.com/zaeleus/ffi-gphoto2/tree/master/examples
|
119
|
+
[rubydoc]: http://www.rubydoc.info/gems/ffi-gphoto2/frames
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'gphoto2'
|
2
|
+
|
3
|
+
# Capture an image only after successfully autofocusing.
|
4
|
+
#
|
5
|
+
# Typically, if the camera fails to autofocus, updating the `autofocusdrive`
|
6
|
+
# key will throw an "Unspecified error (-1)". This catches the exception and
|
7
|
+
# continues to autofocus until it is successful.
|
8
|
+
|
9
|
+
GPhoto2::Camera.first do |camera|
|
10
|
+
begin
|
11
|
+
camera.update(autofocusdrive: true)
|
12
|
+
rescue GPhoto2::Error
|
13
|
+
puts "autofocus failed... retrying"
|
14
|
+
camera.reload
|
15
|
+
retry
|
16
|
+
ensure
|
17
|
+
camera.update(autofocusdrive: false)
|
18
|
+
end
|
19
|
+
|
20
|
+
camera.capture
|
21
|
+
end
|
data/examples/capture.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'gphoto2'
|
2
|
+
|
3
|
+
# This example is limited to Nikon cameras with a continuous burst mode.
|
4
|
+
|
5
|
+
# The number of frames to capture.
|
6
|
+
N = 3
|
7
|
+
|
8
|
+
GPhoto2::Camera.first do |camera|
|
9
|
+
# Set the camera to continuous burst mode.
|
10
|
+
camera.update(capturemode: 'Burst', burstnumber: N)
|
11
|
+
|
12
|
+
# Use `#trigger` instead of `#capture` so the data remains in the camera
|
13
|
+
# buffer.
|
14
|
+
camera.trigger
|
15
|
+
|
16
|
+
# Wait for the camera to process all the images.
|
17
|
+
queue = N.times.map do
|
18
|
+
event = camera.wait_for(:file_added)
|
19
|
+
|
20
|
+
# The event data contains a `CameraFile` when the `:file_added` event is
|
21
|
+
# triggered.
|
22
|
+
event.data
|
23
|
+
end
|
24
|
+
|
25
|
+
# Save all the images to the current working directory.
|
26
|
+
queue.each(&:save)
|
27
|
+
end
|
data/examples/list_config.rb
CHANGED
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'gphoto2'
|
2
|
+
|
3
|
+
# Recursively list folder contents with extended metadata.
|
4
|
+
|
5
|
+
MAGNITUDES = %w[bytes KiB MiB GiB].freeze
|
6
|
+
|
7
|
+
# @param [Integer] size filesize in bytes
|
8
|
+
# @param [Integer[ precision
|
9
|
+
# @return [String]
|
10
|
+
def format_filesize(size, precision = 1)
|
11
|
+
n = 0
|
12
|
+
|
13
|
+
while size >= 1024.0 && n < MAGNITUDES.size
|
14
|
+
size /= 1024.0
|
15
|
+
n += 1
|
16
|
+
end
|
17
|
+
|
18
|
+
"%.#{precision}f %s" % [size, MAGNITUDES[n]]
|
19
|
+
end
|
20
|
+
|
21
|
+
# @param [CameraFolder] folder a root directory
|
22
|
+
def visit(folder)
|
23
|
+
files = folder.files
|
24
|
+
|
25
|
+
puts "#{folder.path} (#{files.size} files)"
|
26
|
+
|
27
|
+
files.each do |file|
|
28
|
+
info = file.info
|
29
|
+
|
30
|
+
name = file.name
|
31
|
+
# Avoid using `File#size` here to prevent having to load the data along
|
32
|
+
# with it.
|
33
|
+
size = format_filesize(info.size)
|
34
|
+
mtime = info.mtime.utc.iso8601
|
35
|
+
|
36
|
+
if info.has_field?(:width) && info.has_field?(:height)
|
37
|
+
dimensions = "#{info.width}x#{info.height}"
|
38
|
+
else
|
39
|
+
dimensions = '-'
|
40
|
+
end
|
41
|
+
|
42
|
+
puts "#{name.ljust(30)} #{size.rjust(12)} #{dimensions.rjust(12)} #{mtime}"
|
43
|
+
end
|
44
|
+
|
45
|
+
puts
|
46
|
+
|
47
|
+
folder.folders.each { |child| visit(child) }
|
48
|
+
end
|
49
|
+
|
50
|
+
GPhoto2::Camera.first do |camera|
|
51
|
+
visit(camera.filesystem)
|
52
|
+
end
|
data/ffi-gphoto2.gemspec
CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
|
|
9
9
|
spec.homepage = 'https://github.com/zaeleus/ffi-gphoto2'
|
10
10
|
|
11
11
|
spec.authors = ['Michael Macias']
|
12
|
-
spec.email = ['
|
12
|
+
spec.email = ['zaeleus@gmail.com']
|
13
13
|
|
14
14
|
spec.version = GPhoto2::VERSION
|
15
15
|
spec.license = 'MIT'
|
@@ -24,8 +24,8 @@ Gem::Specification.new do |spec|
|
|
24
24
|
|
25
25
|
spec.add_development_dependency 'bundler', '~> 1.3'
|
26
26
|
spec.add_development_dependency 'rake'
|
27
|
-
spec.add_development_dependency 'rspec', '~> 3.
|
28
|
-
spec.add_development_dependency 'yard', '~> 0.
|
27
|
+
spec.add_development_dependency 'rspec', '~> 3.5.0'
|
28
|
+
spec.add_development_dependency 'yard', '~> 0.9.0'
|
29
29
|
|
30
30
|
spec.add_dependency 'ffi', '~> 1.9.0'
|
31
31
|
end
|
data/lib/ffi/gphoto2.rb
CHANGED
@@ -11,7 +11,10 @@ module FFI
|
|
11
11
|
require 'ffi/gphoto2/camera_driver_status'
|
12
12
|
require 'ffi/gphoto2/camera_event_type'
|
13
13
|
require 'ffi/gphoto2/camera_file_access_type'
|
14
|
+
require 'ffi/gphoto2/camera_file_info_fields'
|
14
15
|
require 'ffi/gphoto2/camera_file_operation'
|
16
|
+
require 'ffi/gphoto2/camera_file_permissions'
|
17
|
+
require 'ffi/gphoto2/camera_file_status'
|
15
18
|
require 'ffi/gphoto2/camera_file_type'
|
16
19
|
require 'ffi/gphoto2/camera_folder_operation'
|
17
20
|
require 'ffi/gphoto2/camera_operation'
|
@@ -23,10 +26,14 @@ module FFI
|
|
23
26
|
require 'ffi/gphoto2/camera_abilities'
|
24
27
|
require 'ffi/gphoto2/camera_abilities_list'
|
25
28
|
require 'ffi/gphoto2/camera_file'
|
29
|
+
require 'ffi/gphoto2/camera_file_info_audio'
|
30
|
+
require 'ffi/gphoto2/camera_file_info_file'
|
31
|
+
require 'ffi/gphoto2/camera_file_info_preview'
|
32
|
+
require 'ffi/gphoto2/camera_file_info'
|
26
33
|
require 'ffi/gphoto2/camera_file_path'
|
34
|
+
require 'ffi/gphoto2/entry'
|
27
35
|
require 'ffi/gphoto2/camera_list'
|
28
36
|
require 'ffi/gphoto2/camera_widget'
|
29
|
-
require 'ffi/gphoto2/entry'
|
30
37
|
require 'ffi/gphoto2/gp_context'
|
31
38
|
|
32
39
|
# gphoto2/gphoto2-abilities-list.h
|
@@ -47,10 +54,12 @@ module FFI
|
|
47
54
|
attach_function :gp_camera_get_config, [Camera.by_ref, :pointer, GPContext.by_ref], :int
|
48
55
|
attach_function :gp_camera_set_config, [Camera.by_ref, CameraWidget.by_ref, GPContext.by_ref], :int
|
49
56
|
attach_function :gp_camera_capture, [Camera.by_ref, CameraCaptureType, CameraFilePath.by_ref, GPContext.by_ref], :int, blocking: true
|
57
|
+
attach_function :gp_camera_trigger_capture, [Camera.by_ref, GPContext.by_ref], :int, blocking: true
|
50
58
|
attach_function :gp_camera_capture_preview, [Camera.by_ref, CameraFile.by_ref, GPContext.by_ref], :int, blocking: true
|
51
59
|
attach_function :gp_camera_wait_for_event, [Camera.by_ref, :int, :pointer, :pointer, GPContext.by_ref], :int
|
52
60
|
attach_function :gp_camera_folder_list_files, [Camera.by_ref, :string, CameraList.by_ref, GPContext.by_ref], :int
|
53
61
|
attach_function :gp_camera_folder_list_folders, [Camera.by_ref, :string, CameraList.by_ref, GPContext.by_ref], :int
|
62
|
+
attach_function :gp_camera_file_get_info, [Camera.by_ref, :string, :string, CameraFileInfo.by_ref, GPContext.by_ref], :int
|
54
63
|
attach_function :gp_camera_file_get, [Camera.by_ref, :string, :string, CameraFileType, CameraFile.by_ref, GPContext.by_ref], :int, blocking: true
|
55
64
|
attach_function :gp_camera_file_delete, [Camera.by_ref, :string, :string, GPContext.by_ref], :int
|
56
65
|
|
@@ -5,7 +5,7 @@ module FFI
|
|
5
5
|
class CameraAbilitiesList < FFI::ManagedStruct
|
6
6
|
# libgphoto2/gphoto2-abilities-list.c
|
7
7
|
layout :count, :int,
|
8
|
-
:abilities,
|
8
|
+
:abilities, CameraAbilities.by_ref
|
9
9
|
|
10
10
|
def self.release(ptr)
|
11
11
|
FFI::GPhoto2.gp_abilities_list_free(ptr)
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module FFI
|
2
|
+
module GPhoto2
|
3
|
+
# gphoto2/gphoto2-filesys.h
|
4
|
+
CameraFileInfoFields = enum :none, 0,
|
5
|
+
:type, 1 << 0,
|
6
|
+
:size, 1 << 2,
|
7
|
+
:width, 1 << 3,
|
8
|
+
:height, 1 << 4,
|
9
|
+
:permissions, 1 << 5,
|
10
|
+
:status, 1 << 6,
|
11
|
+
:mtime, 1 << 7,
|
12
|
+
:all, 0xff
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module FFI
|
2
|
+
module GPhoto2
|
3
|
+
class CameraFileInfoFile < FFI::Struct
|
4
|
+
# gphoto2/gphoto2-filesys.h
|
5
|
+
layout :fields, CameraFileInfoFields,
|
6
|
+
:status, CameraFileStatus,
|
7
|
+
:size, :uint64,
|
8
|
+
:type, [:char, 64],
|
9
|
+
:width, :uint32,
|
10
|
+
:height, :uint32,
|
11
|
+
:permissions, CameraFilePermissions,
|
12
|
+
:mtime, :time_t
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module FFI
|
2
|
+
module GPhoto2
|
3
|
+
class CameraFileInfoPreview < FFI::Struct
|
4
|
+
# gphoto2/gphoto2-filesys.h
|
5
|
+
layout :fields, CameraFileInfoFields,
|
6
|
+
:status, CameraFileStatus,
|
7
|
+
:size, :uint64,
|
8
|
+
:type, [:char, 64],
|
9
|
+
:width, :uint32,
|
10
|
+
:height, :uint32
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
data/lib/gphoto2.rb
CHANGED
@@ -17,6 +17,9 @@ require 'gphoto2/camera_widgets/text_camera_widget'
|
|
17
17
|
require 'gphoto2/camera_widgets/toggle_camera_widget'
|
18
18
|
require 'gphoto2/camera_widgets/window_camera_widget'
|
19
19
|
|
20
|
+
require 'gphoto2/camera_file_info/camera_file_info'
|
21
|
+
require 'gphoto2/camera_file_info/file_camera_file_info'
|
22
|
+
|
20
23
|
require 'gphoto2/camera/capture'
|
21
24
|
require 'gphoto2/camera/configuration'
|
22
25
|
require 'gphoto2/camera/event'
|
@@ -39,6 +42,24 @@ require 'gphoto2/port_result'
|
|
39
42
|
require 'gphoto2/version'
|
40
43
|
|
41
44
|
module GPhoto2
|
45
|
+
# A runtime error for unsuccessful return codes.
|
46
|
+
class Error < RuntimeError
|
47
|
+
# @return [Integer]
|
48
|
+
attr_reader :code
|
49
|
+
|
50
|
+
# @param [String] message
|
51
|
+
# @param [Integer] code
|
52
|
+
def initialize(message, code)
|
53
|
+
super(message)
|
54
|
+
@code = code
|
55
|
+
end
|
56
|
+
|
57
|
+
# @return [String]
|
58
|
+
def to_s
|
59
|
+
"#{super} (#{code})"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
42
63
|
# @return [Logger]
|
43
64
|
def self.logger
|
44
65
|
@logger ||= Logger.new(STDERR)
|
@@ -46,10 +67,10 @@ module GPhoto2
|
|
46
67
|
|
47
68
|
# @param [Integer] rc
|
48
69
|
# @return [void]
|
49
|
-
# @raise
|
70
|
+
# @raise [GPhoto2::Error] when the return code is not {FFI::GPhoto2Port::GP_OK}
|
50
71
|
def self.check!(rc)
|
51
72
|
logger.debug "#{caller.first} => #{rc}" if ENV['DEBUG']
|
52
73
|
return if rc >= FFI::GPhoto2Port::GP_OK
|
53
|
-
raise
|
74
|
+
raise Error.new(PortResult.as_string(rc), rc)
|
54
75
|
end
|
55
76
|
end
|