ffi-gphoto2 0.5.1 → 0.8.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 +5 -5
- data/.travis.yml +11 -0
- data/CHANGELOG.md +44 -0
- data/README.md +22 -12
- 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 +9 -8
- data/lib/ffi/gphoto2.rb +14 -4
- 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.rb +21 -1
- data/lib/ffi/gphoto2_port/gp_port.rb +17 -0
- data/lib/ffi/gphoto2_port/gp_port_info_list.rb +1 -1
- data/lib/ffi/gphoto2_port/gp_port_serial_parity.rb +6 -0
- data/lib/ffi/gphoto2_port/gp_port_settings.rb +11 -0
- data/lib/ffi/gphoto2_port/gp_port_settings_serial.rb +12 -0
- data/lib/ffi/gphoto2_port/gp_port_settings_usb.rb +15 -0
- data/lib/ffi/gphoto2_port/gp_port_settings_usb_disk_direct.rb +8 -0
- data/lib/ffi/gphoto2_port/gp_port_settings_usb_scsi.rb +8 -0
- data/lib/gphoto2.rb +24 -4
- data/lib/gphoto2/camera.rb +10 -2
- data/lib/gphoto2/camera/capture.rb +22 -0
- data/lib/gphoto2/camera/configuration.rb +2 -1
- data/lib/gphoto2/camera/event.rb +3 -6
- data/lib/gphoto2/camera_abilities.rb +9 -0
- data/lib/gphoto2/camera_abilities_list.rb +1 -1
- data/lib/gphoto2/camera_file.rb +26 -8
- 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_list.rb +1 -1
- data/lib/gphoto2/camera_widgets/camera_widget.rb +3 -7
- 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.rb +61 -0
- data/lib/gphoto2/port_info.rb +0 -4
- data/lib/gphoto2/port_info_list.rb +1 -1
- 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/port_spec.rb +22 -0
- 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 +54 -24
@@ -0,0 +1,30 @@
|
|
1
|
+
module GPhoto2
|
2
|
+
class FileCameraFileInfo < CameraFileInfo
|
3
|
+
# @return [Integer, nil]
|
4
|
+
def width
|
5
|
+
fetch(:width)
|
6
|
+
end
|
7
|
+
|
8
|
+
# @return [Integer, nil]
|
9
|
+
def height
|
10
|
+
fetch(:height)
|
11
|
+
end
|
12
|
+
|
13
|
+
# @return [Boolean, nil]
|
14
|
+
def readable?
|
15
|
+
permissions = fetch(:permissions)
|
16
|
+
(permissions & CameraFilePermissions[:read]) != 0 if permissions
|
17
|
+
end
|
18
|
+
|
19
|
+
# @return [Boolean, nil]
|
20
|
+
def deletable?
|
21
|
+
permissions = fetch(:permissions)
|
22
|
+
(permissions & CameraFilePermissions[:delete]) != 0 if permissions
|
23
|
+
end
|
24
|
+
|
25
|
+
# @return [Time, nil] the last modification time
|
26
|
+
def mtime
|
27
|
+
Time.at(ptr[:mtime]) if has_field?(:mtime)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/gphoto2/camera_list.rb
CHANGED
@@ -70,7 +70,7 @@ module GPhoto2
|
|
70
70
|
map
|
71
71
|
end
|
72
72
|
|
73
|
-
# @
|
73
|
+
# @return [String]
|
74
74
|
def to_s
|
75
75
|
value.to_s
|
76
76
|
end
|
@@ -93,9 +93,7 @@ module GPhoto2
|
|
93
93
|
end
|
94
94
|
|
95
95
|
def get_name
|
96
|
-
str = FFI::MemoryPointer.new(:string)
|
97
96
|
str_ptr = FFI::MemoryPointer.new(:pointer)
|
98
|
-
str_ptr.write_pointer(str)
|
99
97
|
|
100
98
|
rc = gp_widget_get_name(ptr, str_ptr)
|
101
99
|
GPhoto2.check!(rc)
|
@@ -113,11 +111,9 @@ module GPhoto2
|
|
113
111
|
end
|
114
112
|
|
115
113
|
def get_label
|
116
|
-
str = FFI::MemoryPointer.new(:string)
|
117
114
|
str_ptr = FFI::MemoryPointer.new(:pointer)
|
118
|
-
str_ptr.write_pointer(str)
|
119
115
|
|
120
|
-
rc =
|
116
|
+
rc = gp_widget_get_label(ptr, str_ptr)
|
121
117
|
GPhoto2.check!(rc)
|
122
118
|
|
123
119
|
str_ptr = str_ptr.read_pointer
|
@@ -131,7 +127,7 @@ module GPhoto2
|
|
131
127
|
end
|
132
128
|
|
133
129
|
def get_child(index)
|
134
|
-
widget_ptr = FFI::MemoryPointer.new(
|
130
|
+
widget_ptr = FFI::MemoryPointer.new(:pointer)
|
135
131
|
rc = gp_widget_get_child(ptr, index, widget_ptr)
|
136
132
|
GPhoto2.check!(rc)
|
137
133
|
widget = FFI::GPhoto2::CameraWidget.new(widget_ptr.read_pointer)
|
@@ -8,9 +8,7 @@ module GPhoto2
|
|
8
8
|
protected
|
9
9
|
|
10
10
|
def get_value
|
11
|
-
val = FFI::MemoryPointer.new(:string)
|
12
11
|
val_ptr = FFI::MemoryPointer.new(:pointer)
|
13
|
-
val_ptr.write_pointer(val)
|
14
12
|
|
15
13
|
rc = gp_widget_get_value(ptr, val_ptr)
|
16
14
|
GPhoto2.check!(rc)
|
@@ -34,9 +32,7 @@ module GPhoto2
|
|
34
32
|
end
|
35
33
|
|
36
34
|
def get_choice(i)
|
37
|
-
val = FFI::MemoryPointer.new(:string)
|
38
35
|
val_ptr = FFI::MemoryPointer.new(:pointer)
|
39
|
-
val_ptr.write_pointer(val)
|
40
36
|
|
41
37
|
rc = gp_widget_get_choice(ptr, i, val_ptr)
|
42
38
|
GPhoto2.check!(rc)
|
@@ -3,9 +3,7 @@ module GPhoto2
|
|
3
3
|
protected
|
4
4
|
|
5
5
|
def get_value
|
6
|
-
val = FFI::MemoryPointer.new(:string)
|
7
6
|
val_ptr = FFI::MemoryPointer.new(:pointer)
|
8
|
-
val_ptr.write_pointer(val)
|
9
7
|
|
10
8
|
rc = gp_widget_get_value(ptr, val_ptr)
|
11
9
|
GPhoto2.check!(rc)
|
@@ -15,7 +13,7 @@ module GPhoto2
|
|
15
13
|
end
|
16
14
|
|
17
15
|
def set_value(text)
|
18
|
-
val = FFI::MemoryPointer.from_string(text)
|
16
|
+
val = FFI::MemoryPointer.from_string(text.to_s)
|
19
17
|
rc = gp_widget_set_value(ptr, val)
|
20
18
|
GPhoto2.check!(rc)
|
21
19
|
end
|
data/lib/gphoto2/entry.rb
CHANGED
@@ -20,9 +20,7 @@ module GPhoto2
|
|
20
20
|
private
|
21
21
|
|
22
22
|
def get_name
|
23
|
-
name = FFI::MemoryPointer.new(:string)
|
24
23
|
ptr = FFI::MemoryPointer.new(:pointer)
|
25
|
-
ptr.write_pointer(name)
|
26
24
|
|
27
25
|
rc = gp_list_get_name(@camera_list.ptr, @index, ptr)
|
28
26
|
GPhoto2.check!(rc)
|
@@ -32,9 +30,7 @@ module GPhoto2
|
|
32
30
|
end
|
33
31
|
|
34
32
|
def get_value
|
35
|
-
value = FFI::MemoryPointer.new(:string)
|
36
33
|
ptr = FFI::MemoryPointer.new(:pointer)
|
37
|
-
ptr.write_pointer(value)
|
38
34
|
|
39
35
|
rc = gp_list_get_value(@camera_list.ptr, @index, ptr)
|
40
36
|
GPhoto2.check!(rc)
|
data/lib/gphoto2/port.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
module GPhoto2
|
2
|
+
class Port
|
3
|
+
include FFI::GPhoto2Port
|
4
|
+
include GPhoto2::Struct
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@ptr = new
|
8
|
+
end
|
9
|
+
|
10
|
+
# @param [PortInfo] info
|
11
|
+
# @return [PortInfo]
|
12
|
+
def info=(info)
|
13
|
+
set_info(info)
|
14
|
+
info
|
15
|
+
end
|
16
|
+
|
17
|
+
# @return [void]
|
18
|
+
def open
|
19
|
+
_open
|
20
|
+
end
|
21
|
+
|
22
|
+
# @return [void]
|
23
|
+
def close
|
24
|
+
_close
|
25
|
+
end
|
26
|
+
|
27
|
+
# @return [void]
|
28
|
+
def reset
|
29
|
+
_reset
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def new
|
35
|
+
ptr = FFI::MemoryPointer.new(:pointer)
|
36
|
+
rc = gp_port_new(ptr)
|
37
|
+
GPhoto2.check!(rc)
|
38
|
+
FFI::GPhoto2Port::GPPort.new(ptr.read_pointer)
|
39
|
+
end
|
40
|
+
|
41
|
+
def _open
|
42
|
+
rc = gp_port_open(ptr)
|
43
|
+
GPhoto2.check!(rc)
|
44
|
+
end
|
45
|
+
|
46
|
+
def _close
|
47
|
+
rc = gp_port_close(ptr)
|
48
|
+
GPhoto2.check!(rc)
|
49
|
+
end
|
50
|
+
|
51
|
+
def _reset
|
52
|
+
rc = gp_port_reset(ptr)
|
53
|
+
GPhoto2.check!(rc)
|
54
|
+
end
|
55
|
+
|
56
|
+
def set_info(port_info)
|
57
|
+
rc = gp_port_set_info(ptr, port_info.ptr)
|
58
|
+
GPhoto2.check!(rc)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
data/lib/gphoto2/port_info.rb
CHANGED
@@ -44,9 +44,7 @@ module GPhoto2
|
|
44
44
|
end
|
45
45
|
|
46
46
|
def get_name
|
47
|
-
name = FFI::MemoryPointer.new(:string)
|
48
47
|
name_ptr = FFI::MemoryPointer.new(:pointer)
|
49
|
-
name_ptr.write_pointer(name)
|
50
48
|
|
51
49
|
rc = gp_port_info_get_name(ptr, name_ptr)
|
52
50
|
GPhoto2.check!(rc)
|
@@ -56,9 +54,7 @@ module GPhoto2
|
|
56
54
|
end
|
57
55
|
|
58
56
|
def get_path
|
59
|
-
path = FFI::MemoryPointer.new(:string)
|
60
57
|
path_ptr = FFI::MemoryPointer.new(:pointer)
|
61
|
-
path_ptr.write_pointer(path)
|
62
58
|
|
63
59
|
rc = gp_port_info_get_path(ptr, path_ptr)
|
64
60
|
GPhoto2.check!(rc)
|
data/lib/gphoto2/version.rb
CHANGED
@@ -34,5 +34,28 @@ module GPhoto2
|
|
34
34
|
expect(abilities[key]).to eq(value)
|
35
35
|
end
|
36
36
|
end
|
37
|
+
|
38
|
+
describe '#operations' do
|
39
|
+
context 'when no or one operation is supported' do
|
40
|
+
it 'returns a bit field of supported operations' do
|
41
|
+
abilities = CameraAbilities.new(camera_abilities_list, index)
|
42
|
+
allow(abilities).to receive(:[]).and_return(:none)
|
43
|
+
expect(abilities.operations).to eq(0)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context 'when multiple operations are supported' do
|
48
|
+
it 'returns a bit field of supported operations' do
|
49
|
+
abilities = CameraAbilities.new(camera_abilities_list, index)
|
50
|
+
|
51
|
+
capture_image = FFI::GPhoto2::CameraOperation[:capture_image]
|
52
|
+
config = FFI::GPhoto2::CameraOperation[:config]
|
53
|
+
operations = capture_image | config
|
54
|
+
|
55
|
+
allow(abilities).to receive(:[]).and_return(operations)
|
56
|
+
expect(abilities.operations).to eq(0x11)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
37
60
|
end
|
38
61
|
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'ostruct'
|
3
|
+
|
4
|
+
module GPhoto2
|
5
|
+
describe FileCameraFileInfo do
|
6
|
+
it_behaves_like CameraFileInfo
|
7
|
+
|
8
|
+
let(:camera_file_info_file) do
|
9
|
+
OpenStruct.new(
|
10
|
+
fields: 0xff,
|
11
|
+
status: :not_downloaded,
|
12
|
+
size: 7355608,
|
13
|
+
type: 'image/jpeg',
|
14
|
+
width: 4928,
|
15
|
+
height: 3264,
|
16
|
+
permissions: 0xff,
|
17
|
+
mtime: Time.at(1467863342)
|
18
|
+
)
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '#width' do
|
22
|
+
it 'returns the width of the file' do
|
23
|
+
info = FileCameraFileInfo.new(camera_file_info_file)
|
24
|
+
expect(info.width).to eq(4928)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe '#height' do
|
29
|
+
it 'returns the height of the file' do
|
30
|
+
info = FileCameraFileInfo.new(camera_file_info_file)
|
31
|
+
expect(info.height).to eq(3264)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe '#readable?' do
|
36
|
+
it 'returns whether the file is readable' do
|
37
|
+
info = FileCameraFileInfo.new(camera_file_info_file)
|
38
|
+
expect(info.readable?).to be(true)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe '#deletable?' do
|
43
|
+
it 'returns whether the file is deletable' do
|
44
|
+
info = FileCameraFileInfo.new(camera_file_info_file)
|
45
|
+
expect(info.deletable?).to be(true)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe '#mtime' do
|
50
|
+
it 'returns the last modification time of the file' do
|
51
|
+
info = FileCameraFileInfo.new(camera_file_info_file)
|
52
|
+
expect(info.mtime).to eq(Time.at(1467863342))
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -75,5 +75,22 @@ module GPhoto2
|
|
75
75
|
expect(file.size).to eq(data_and_size.last)
|
76
76
|
end
|
77
77
|
end
|
78
|
+
|
79
|
+
describe '#info' do
|
80
|
+
context 'the file is a preview' do
|
81
|
+
it 'returns nil' do
|
82
|
+
file = CameraFile.new(camera)
|
83
|
+
expect(file.info).to be(nil)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
context 'the file is a file' do
|
88
|
+
it 'it returns an instance of FileCameraFileInfo' do
|
89
|
+
file = CameraFile.new(camera, folder, name)
|
90
|
+
allow(file).to receive(:get_info).and_return(FileCameraFileInfo.new(nil))
|
91
|
+
expect(file.info).to be_kind_of(FileCameraFileInfo)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
78
95
|
end
|
79
96
|
end
|
data/spec/gphoto2/camera_spec.rb
CHANGED
@@ -126,18 +126,24 @@ module GPhoto2
|
|
126
126
|
let(:operations) { FFI::GPhoto2::CameraOperation[:capture_image] }
|
127
127
|
|
128
128
|
before do
|
129
|
-
allow(camera).to receive_message_chain(:abilities, :
|
129
|
+
allow(camera).to receive_message_chain(:abilities, :operations).and_return(operations)
|
130
|
+
end
|
131
|
+
|
132
|
+
context 'when the camera has the ability to perform an operation' do
|
133
|
+
it 'returns true' do
|
134
|
+
expect(camera.can?(:capture_image)).to be(true)
|
135
|
+
end
|
130
136
|
end
|
131
137
|
|
132
138
|
context 'when the camera does not have the ability perform an operation' do
|
133
|
-
it '
|
139
|
+
it 'returns false' do
|
134
140
|
expect(camera.can?(:capture_audio)).to be(false)
|
135
141
|
end
|
136
142
|
end
|
137
143
|
|
138
|
-
context '
|
139
|
-
it 'returns
|
140
|
-
expect(camera.can?(:
|
144
|
+
context 'an invalid operation is given' do
|
145
|
+
it 'returns false' do
|
146
|
+
expect(camera.can?(:dance)).to be(false)
|
141
147
|
end
|
142
148
|
end
|
143
149
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module GPhoto2
|
4
|
+
describe Port do
|
5
|
+
before do
|
6
|
+
allow_any_instance_of(Port).to receive(:new)
|
7
|
+
end
|
8
|
+
|
9
|
+
describe '#info=' do
|
10
|
+
let(:port) { Port.new }
|
11
|
+
|
12
|
+
before do
|
13
|
+
allow(port).to receive(:set_info)
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'returns the input value' do
|
17
|
+
info = double(:port_info)
|
18
|
+
expect(port.info = info).to eq(info)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe GPhoto2 do
|
4
|
+
describe '.check!' do
|
5
|
+
context 'the return code is not GP_OK' do
|
6
|
+
it 'raises GPhoto2::Error with a message and error code' do
|
7
|
+
code = -1
|
8
|
+
message = "Unspecified error (#{code})"
|
9
|
+
|
10
|
+
expect { GPhoto2.check!(code) }.to raise_error do |e|
|
11
|
+
expect(e).to be_kind_of(GPhoto2::Error)
|
12
|
+
expect(e.message).to eq(message)
|
13
|
+
expect(e.code).to eq(code)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -19,6 +19,19 @@ module GPhoto2
|
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
|
+
describe '#trigger' do
|
23
|
+
let(:camera) { Camera.new(model, port) }
|
24
|
+
|
25
|
+
before do
|
26
|
+
allow(camera).to receive(:trigger_capture)
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'saves the camera configuration' do
|
30
|
+
expect(camera).to receive(:save)
|
31
|
+
camera.trigger
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
22
35
|
describe '#preview' do
|
23
36
|
let(:camera) { Camera.new(model, port) }
|
24
37
|
let(:file) { double('camera_file') }
|
@@ -65,29 +65,37 @@ module GPhoto2
|
|
65
65
|
end
|
66
66
|
|
67
67
|
describe '#[]=' do
|
68
|
-
let(:
|
69
|
-
window = double('camera_widget')
|
70
|
-
expect(window).to receive(:value=).with(400)
|
71
|
-
window
|
72
|
-
end
|
68
|
+
let(:camera) { Camera.new(model, port) }
|
73
69
|
|
74
|
-
|
75
|
-
|
76
|
-
allow(camera).to receive(:[]).and_return(window)
|
77
|
-
camera
|
78
|
-
end
|
70
|
+
context 'when the specified key is valid' do
|
71
|
+
let(:window) { double('camera_widget', :value= => 400) }
|
79
72
|
|
80
|
-
|
81
|
-
|
82
|
-
|
73
|
+
before do
|
74
|
+
allow(camera).to receive(:[]).and_return(window)
|
75
|
+
end
|
76
|
+
|
77
|
+
it "sets a widget's value" do
|
78
|
+
camera['iso'] = 400
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'marks the camera as dirty' do
|
82
|
+
camera['iso'] = 400
|
83
|
+
expect(camera).to be_dirty
|
84
|
+
end
|
83
85
|
|
84
|
-
|
85
|
-
|
86
|
-
|
86
|
+
it 'returns the passed value' do
|
87
|
+
expect(camera['iso'] = 400).to eq(400)
|
88
|
+
end
|
87
89
|
end
|
88
90
|
|
89
|
-
|
90
|
-
|
91
|
+
context 'when the specified key is invalid' do
|
92
|
+
before do
|
93
|
+
allow(camera).to receive(:[]).and_return(nil)
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'raises an ArgumentError' do
|
97
|
+
expect { camera['flavor'] = 'strawberry' }.to raise_error(ArgumentError)
|
98
|
+
end
|
91
99
|
end
|
92
100
|
end
|
93
101
|
|