ffi-gphoto2 0.5.1 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|