gphoto4ruby 0.4.0 → 0.4.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.rdoc +7 -0
- data/README.rdoc +28 -22
- data/Rakefile +1 -0
- data/VERSION +1 -1
- data/example.rb +2 -10
- data/ext/extconf.rb +3 -2
- data/ext/gphoto2camera.c +60 -69
- data/ext/gphoto2camera_utilities.h +1 -0
- data/ext/gphoto4ruby.c +19 -0
- metadata +3 -3
data/CHANGELOG.rdoc
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
== 0.4.1
|
2
|
+
|
3
|
+
* Fix for canon cameras to keep "capture=on" between ruby calls. Though it shows
|
4
|
+
"capture=false" but config can be refreshed with config(:no_cache)
|
5
|
+
* Added possibility and instructions for compiling gem against specified version
|
6
|
+
of libgphoto2
|
7
|
+
|
1
8
|
== 0.4.0
|
2
9
|
|
3
10
|
* Tested ruby support including 1.9.1
|
data/README.rdoc
CHANGED
@@ -17,21 +17,30 @@ calling object methods.
|
|
17
17
|
* First of all you'll need the original gphoto2 C library installed. For
|
18
18
|
installation instructions goto http://gphoto.org.
|
19
19
|
|
20
|
-
* On
|
20
|
+
* On (k)ubuntu it is:
|
21
21
|
|
22
|
-
sudo apt-get install
|
22
|
+
sudo apt-get install libgphoto2-2-dev
|
23
23
|
|
24
|
-
* On Mac OS X gphoto2 is installed through DarwinPorts
|
24
|
+
* On Mac OS X gphoto2 is installed through DarwinPorts. Or you can install it
|
25
|
+
from source
|
25
26
|
|
26
|
-
* You can install GPhoto4Ruby gem from
|
27
|
-
the following lines depending on your preferences:
|
28
|
-
|
29
|
-
sudo gem install lonelyelk-gphoto4ruby --source http://gems.github.com
|
30
|
-
|
31
|
-
<b>or</b>
|
27
|
+
* You can install GPhoto4Ruby gem from GemCutter or from RubyForge:
|
32
28
|
|
33
29
|
sudo gem install gphoto4ruby
|
34
|
-
|
30
|
+
|
31
|
+
* If you installed libgphoto2 from source you might want to use custom paths
|
32
|
+
|
33
|
+
sudo gem install -i gphoto4ruby -- --with-opt-dir=/opt-custom-prefix
|
34
|
+
|
35
|
+
* If you have more than one version of libgphoto2 installed and you want to
|
36
|
+
specify which one to use:
|
37
|
+
|
38
|
+
sudo gem install -i gphoto4ruby -- --with-gphoto2-dir=/custom-prefix --with-dldflags="-Wl,-rpath,/custom-prefix/lib"
|
39
|
+
|
40
|
+
Following code will tell you, which version of libgphoto2 you use:
|
41
|
+
|
42
|
+
GPhoto2::LIBGPHOTO2_VERSION
|
43
|
+
|
35
44
|
* Connect your digital camera through usb, locate example.rb file and run:
|
36
45
|
|
37
46
|
ruby example.rb
|
@@ -39,6 +48,11 @@ calling object methods.
|
|
39
48
|
* <b>NOTE!</b> On Mac OS X there is a process you need to kill before using
|
40
49
|
gphoto2. You can find more information on this at http://gphoto.org
|
41
50
|
|
51
|
+
* <b>NOTE!</b> For unknown reason after upgrade to Kubuntu 9.10 Canon EOS 450D
|
52
|
+
stopped capturing images. It just hangs in infinit loop. Both with my gem and
|
53
|
+
with command line gphoto2 tool. Even for (lib)gphoto2 2.4.7. You can change
|
54
|
+
configuration though. And with kubuntu 9.04 everything is ok.
|
55
|
+
|
42
56
|
== Usage
|
43
57
|
|
44
58
|
After installation of this gem rdocs are generated for you. Or you can generate
|
@@ -47,8 +61,8 @@ it manually with:
|
|
47
61
|
rake rdoc
|
48
62
|
|
49
63
|
Ruby file <b>example.rb</b> is installed along with this gem. All examples are
|
50
|
-
tested on Kubuntu 8.04 and Mac OS X 10.4.11 with digital camera Nikon DSC D80
|
51
|
-
connected through usb in PTP mode.
|
64
|
+
tested on Kubuntu 8.04-9.04 and Mac OS X 10.4.11 with digital camera Nikon DSC D80
|
65
|
+
connected through usb in PTP mode and Canon EOS 450D.
|
52
66
|
|
53
67
|
<b>example.rb:</b>
|
54
68
|
|
@@ -62,7 +76,8 @@ connected through usb in PTP mode.
|
|
62
76
|
ports.each do |port|
|
63
77
|
c = GPhoto2::Camera.new(port)
|
64
78
|
puts "camera in port: " + port
|
65
|
-
c.config.
|
79
|
+
c["capture"] = true if c.config.has_key? "capture" # canon? :)
|
80
|
+
c.config(:no_cache).each do |key, value|
|
66
81
|
puts key + " value is: " + value.to_s
|
67
82
|
puts "values available are: " + c[key, :all].inspect
|
68
83
|
end
|
@@ -85,15 +100,6 @@ connected through usb in PTP mode.
|
|
85
100
|
# save captured file in the current directory on hard drive and delete
|
86
101
|
# it from camera
|
87
102
|
cams.first.capture.save.delete
|
88
|
-
|
89
|
-
# to capture image with all attached cameras simultaneously use:
|
90
|
-
cams.each_index do |index|
|
91
|
-
if index < cams.length - 1
|
92
|
-
fork {cams[index].capture; exit!}
|
93
|
-
else
|
94
|
-
cams[index].capture
|
95
|
-
end
|
96
|
-
end
|
97
103
|
end
|
98
104
|
== Contact
|
99
105
|
|
data/Rakefile
CHANGED
@@ -28,6 +28,7 @@ begin
|
|
28
28
|
spec = Gem::Specification.new do |s|
|
29
29
|
s.name = "gphoto4ruby"
|
30
30
|
s.summary = "GPhoto4Ruby is Ruby wrapping around gphoto2 C library"
|
31
|
+
s.description = "GPhoto4Ruby is used to control PPTP cameras (the ones that can be controlled with gphoto2) using power of ruby."
|
31
32
|
|
32
33
|
s.authors = ["neq4 company", "Sergey Kruk"]
|
33
34
|
s.email = "sergey.kruk@gmail.com"
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.4.
|
1
|
+
0.4.1
|
data/example.rb
CHANGED
@@ -8,7 +8,8 @@ if ports.any?
|
|
8
8
|
ports.each do |port|
|
9
9
|
c = GPhoto2::Camera.new(port)
|
10
10
|
puts "camera in port: " + port
|
11
|
-
c.config.
|
11
|
+
c["capture"] = true if c.config.has_key? "capture" # canon? :)
|
12
|
+
c.config(:no_cache).each do |key, value|
|
12
13
|
puts key + " value is: " + value.to_s
|
13
14
|
puts "values available are: " + c[key, :all].inspect
|
14
15
|
end
|
@@ -31,13 +32,4 @@ if ports.any?
|
|
31
32
|
# save captured file in the current directory on hard drive and delete
|
32
33
|
# it from camera
|
33
34
|
cams.first.capture.save.delete
|
34
|
-
|
35
|
-
# to capture image with all attached cameras simultaneously use:
|
36
|
-
cams.each_index do |index|
|
37
|
-
if index < cams.length - 1
|
38
|
-
fork {cams[index].capture; exit!}
|
39
|
-
else
|
40
|
-
cams[index].capture
|
41
|
-
end
|
42
|
-
end
|
43
35
|
end
|
data/ext/extconf.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require "mkmf"
|
2
2
|
|
3
|
-
dir_config("
|
3
|
+
lib_gp_paths = dir_config("gphoto2")
|
4
|
+
|
4
5
|
if have_library("gphoto2")
|
5
6
|
if RUBY_VERSION =~ /1\.9/
|
6
7
|
$CPPFLAGS += " -DRUBY_19"
|
@@ -8,5 +9,5 @@ if have_library("gphoto2")
|
|
8
9
|
$CFLAGS = '-Wall ' + $CFLAGS
|
9
10
|
create_makefile("gphoto4ruby")
|
10
11
|
else
|
11
|
-
raise "You need
|
12
|
+
raise "You need libgphoto2 installed to compile and use this library"
|
12
13
|
end
|
data/ext/gphoto2camera.c
CHANGED
@@ -55,20 +55,25 @@ void camera_mark(GPhoto2Camera *c) {
|
|
55
55
|
void camera_free(GPhoto2Camera *c) {
|
56
56
|
gp_result_check(gp_camera_exit(c->camera, c->context));
|
57
57
|
gp_result_check(gp_widget_free(c->config));
|
58
|
+
gp_result_check(gp_camera_unref(c->camera));
|
58
59
|
gp_result_check(gp_camera_free(c->camera));
|
59
60
|
free(c->virtFolder);
|
61
|
+
free(c->lastName);
|
60
62
|
free(c->context);
|
61
63
|
free(c);
|
62
64
|
}
|
63
65
|
|
64
66
|
VALUE camera_allocate(VALUE klass) {
|
65
67
|
GPhoto2Camera *c;
|
66
|
-
c = (GPhoto2Camera*)
|
67
|
-
c->virtFolder = (char*)
|
68
|
+
c = (GPhoto2Camera*) ALLOC(GPhoto2Camera);
|
69
|
+
c->virtFolder = (char*) ALLOC_N(char, 1024);
|
70
|
+
c->lastName = (char*) ALLOC_N(char, 256);
|
68
71
|
strcpy(c->virtFolder, "/");
|
72
|
+
c->lastName[0] = '\0';
|
69
73
|
c->context = gp_context_new();
|
70
74
|
gp_result_check(gp_camera_new(&(c->camera)));
|
71
75
|
gp_result_check(gp_camera_get_config(c->camera, &(c->config), c->context));
|
76
|
+
gp_result_check(gp_camera_ref(c->camera));
|
72
77
|
return Data_Wrap_Struct(klass, camera_mark, camera_free, c);
|
73
78
|
}
|
74
79
|
|
@@ -217,6 +222,7 @@ VALUE camera_capture(int argc, VALUE *argv, VALUE self) {
|
|
217
222
|
gp_result_check(gp_camera_capture(c->camera, GP_CAPTURE_IMAGE, &path, c->context));
|
218
223
|
// printf("captured: %s/%s\n", path.folder, path.name);
|
219
224
|
strcpy(c->virtFolder, path.folder);
|
225
|
+
strcpy(c->lastName, path.name);
|
220
226
|
return self;
|
221
227
|
}
|
222
228
|
|
@@ -249,9 +255,9 @@ VALUE camera_capture(int argc, VALUE *argv, VALUE self) {
|
|
249
255
|
*/
|
250
256
|
VALUE camera_save(int argc, VALUE *argv, VALUE self) {
|
251
257
|
int i, count, retVal;
|
252
|
-
int newName = 0;
|
253
258
|
const char *fData, *key, *val, *name;
|
254
|
-
char *fPath, *
|
259
|
+
char *fPath, *pchNew, *pchSrc;
|
260
|
+
char *newNameStr = NULL;
|
255
261
|
char fName[100], cFileName[100], cFolderName[100];
|
256
262
|
unsigned long int fSize;
|
257
263
|
int fd;
|
@@ -268,22 +274,25 @@ VALUE camera_save(int argc, VALUE *argv, VALUE self) {
|
|
268
274
|
|
269
275
|
gp_list_new(&list);
|
270
276
|
|
271
|
-
|
277
|
+
fName[0] = '\0';
|
272
278
|
strcpy(cFolderName, c->virtFolder);
|
273
279
|
|
274
|
-
|
275
|
-
|
276
|
-
count = gp_list_count(list);
|
277
|
-
RESULT_CHECK_LIST(count, list);
|
278
|
-
if (count == 0) {
|
279
|
-
gp_list_free(list);
|
280
|
-
return self; // Nothing to save
|
280
|
+
if (strlen(c->lastName) > 0) {
|
281
|
+
strcpy(cFileName, c->lastName);
|
281
282
|
} else {
|
282
|
-
|
283
|
+
RESULT_CHECK_LIST(gp_filesystem_reset(c->camera->fs), list);
|
284
|
+
RESULT_CHECK_LIST(gp_camera_folder_list_files(c->camera, c->virtFolder, list, c->context), list);
|
285
|
+
count = gp_list_count(list);
|
286
|
+
RESULT_CHECK_LIST(count, list);
|
287
|
+
if (count == 0) {
|
288
|
+
gp_list_free(list);
|
289
|
+
return self; // Nothing to save
|
290
|
+
} else {
|
291
|
+
count -= 1;
|
292
|
+
}
|
293
|
+
RESULT_CHECK_LIST(gp_list_get_name(list, count, &name), list);
|
294
|
+
strcpy(cFileName, name);
|
283
295
|
}
|
284
|
-
RESULT_CHECK_LIST(gp_list_get_name(list, count, &name), list);
|
285
|
-
|
286
|
-
strcpy(cFileName, name);
|
287
296
|
|
288
297
|
switch(argc) {
|
289
298
|
case 0:
|
@@ -320,9 +329,6 @@ VALUE camera_save(int argc, VALUE *argv, VALUE self) {
|
|
320
329
|
}
|
321
330
|
} else if (strcmp(key, "new_name") == 0) {
|
322
331
|
newNameStr = RSTRING_PTR(rb_hash_aref(argv[0], RARRAY_PTR(arr)[i]));
|
323
|
-
if (strlen(newNameStr) > 0) {
|
324
|
-
newName = 1;
|
325
|
-
}
|
326
332
|
} else if (strcmp(key, "type") == 0) {
|
327
333
|
hVal = rb_hash_aref(argv[0], RARRAY_PTR(arr)[i]);
|
328
334
|
Check_Type(hVal, T_SYMBOL);
|
@@ -361,14 +367,18 @@ VALUE camera_save(int argc, VALUE *argv, VALUE self) {
|
|
361
367
|
gp_file_new(&file);
|
362
368
|
RESULT_CHECK_LIST_FILE(gp_camera_file_get(c->camera, cFolderName, cFileName, fileType, file, c->context), list, file);
|
363
369
|
RESULT_CHECK_LIST_FILE(gp_file_get_data_and_size(file, &fData, &fSize), list, file);
|
364
|
-
if (
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
370
|
+
if (newNameStr) {
|
371
|
+
if (strlen(newNameStr) > 0) {
|
372
|
+
strcat(fName, newNameStr);
|
373
|
+
pchNew = strrchr(newNameStr, '.');
|
374
|
+
pchSrc = strrchr(cFileName, '.');
|
375
|
+
if (pchNew == NULL) {
|
376
|
+
strcat(fName, pchSrc);
|
377
|
+
} else if (strcmp(pchNew, pchSrc) != 0) {
|
378
|
+
strcat(fName, pchSrc);
|
379
|
+
}
|
380
|
+
} else {
|
381
|
+
strcat(fName, cFileName);
|
372
382
|
}
|
373
383
|
} else {
|
374
384
|
strcat(fName, cFileName);
|
@@ -420,18 +430,22 @@ VALUE camera_delete(int argc, VALUE *argv, VALUE self) {
|
|
420
430
|
|
421
431
|
strcpy(cFolderName, c->virtFolder);
|
422
432
|
|
423
|
-
|
424
|
-
|
425
|
-
count = gp_list_count(list);
|
426
|
-
RESULT_CHECK_LIST(count, list);
|
427
|
-
if (count == 0) {
|
428
|
-
gp_list_free(list);
|
429
|
-
return self; // Nothing to delete
|
433
|
+
if (strlen(c->lastName) > 0) {
|
434
|
+
strcpy(cFileName, c->lastName);
|
430
435
|
} else {
|
431
|
-
|
436
|
+
RESULT_CHECK_LIST(gp_filesystem_reset(c->camera->fs), list);
|
437
|
+
RESULT_CHECK_LIST(gp_camera_folder_list_files(c->camera, c->virtFolder, list, c->context), list);
|
438
|
+
count = gp_list_count(list);
|
439
|
+
RESULT_CHECK_LIST(count, list);
|
440
|
+
if (count == 0) {
|
441
|
+
gp_list_free(list);
|
442
|
+
return self; // Nothing to save
|
443
|
+
} else {
|
444
|
+
count -= 1;
|
445
|
+
}
|
446
|
+
RESULT_CHECK_LIST(gp_list_get_name(list, count, &name), list);
|
447
|
+
strcpy(cFileName, name);
|
432
448
|
}
|
433
|
-
RESULT_CHECK_LIST(gp_list_get_name(list, count, &name), list);
|
434
|
-
strcpy(cFileName, name);
|
435
449
|
|
436
450
|
switch(argc) {
|
437
451
|
case 0:
|
@@ -474,8 +488,12 @@ VALUE camera_delete(int argc, VALUE *argv, VALUE self) {
|
|
474
488
|
|
475
489
|
if (one == 1) {
|
476
490
|
RESULT_CHECK_LIST(gp_camera_file_delete(c->camera, cFolderName, cFileName, c->context), list);
|
491
|
+
if (strcmp(c->lastName, cFileName) == 0) {
|
492
|
+
c->lastName[0] = '\0';
|
493
|
+
}
|
477
494
|
} else {
|
478
495
|
RESULT_CHECK_LIST(gp_camera_folder_delete_all(c->camera, cFolderName, c->context), list);
|
496
|
+
c->lastName[0] = '\0';
|
479
497
|
}
|
480
498
|
RESULT_CHECK_LIST(gp_filesystem_reset(c->camera->fs), list);
|
481
499
|
gp_list_free(list);
|
@@ -507,13 +525,8 @@ VALUE camera_delete(int argc, VALUE *argv, VALUE self) {
|
|
507
525
|
*
|
508
526
|
*/
|
509
527
|
VALUE camera_get_config(int argc, VALUE *argv, VALUE self) {
|
510
|
-
int i;
|
511
|
-
const char *key;
|
512
528
|
GPhoto2Camera *c;
|
513
|
-
|
514
|
-
VALUE arr, cfg;
|
515
|
-
|
516
|
-
cfg = rb_iv_get(self, "@configuration");
|
529
|
+
VALUE cfg = rb_iv_get(self, "@configuration");
|
517
530
|
|
518
531
|
switch (argc) {
|
519
532
|
case 1:
|
@@ -523,31 +536,8 @@ VALUE camera_get_config(int argc, VALUE *argv, VALUE self) {
|
|
523
536
|
if (strcmp(rb_id2name(rb_to_id(argv[0])), "no_cache") == 0) {
|
524
537
|
gp_widget_free(c->config);
|
525
538
|
gp_result_check(gp_camera_get_config(c->camera, &(c->config), c->context));
|
526
|
-
|
527
|
-
|
528
|
-
key = RSTRING_PTR(RARRAY_PTR(arr)[i]);
|
529
|
-
gp_result_check(gp_widget_get_child_by_name(c->config, key, &(c->childConfig)));
|
530
|
-
gp_result_check(gp_widget_get_type(c->childConfig, &widgettype));
|
531
|
-
switch (widgettype) {
|
532
|
-
case GP_WIDGET_RADIO:
|
533
|
-
rb_hash_aset(cfg, RARRAY_PTR(arr)[i], getRadio(c->childConfig));
|
534
|
-
break;
|
535
|
-
case GP_WIDGET_TEXT:
|
536
|
-
rb_hash_aset(cfg, RARRAY_PTR(arr)[i], getText(c->childConfig));
|
537
|
-
break;
|
538
|
-
case GP_WIDGET_RANGE:
|
539
|
-
rb_hash_aset(cfg, RARRAY_PTR(arr)[i], getRange(c->childConfig));
|
540
|
-
break;
|
541
|
-
case GP_WIDGET_TOGGLE:
|
542
|
-
rb_hash_aset(cfg, RARRAY_PTR(arr)[i], getToggle(c->childConfig));
|
543
|
-
break;
|
544
|
-
case GP_WIDGET_DATE:
|
545
|
-
rb_hash_aset(cfg, RARRAY_PTR(arr)[i], getDate(c->childConfig));
|
546
|
-
break;
|
547
|
-
default:
|
548
|
-
break;
|
549
|
-
}
|
550
|
-
}
|
539
|
+
rb_funcall(cfg, rb_intern("replace"), 1, rb_hash_new());
|
540
|
+
populateWithConfigs(c->config, cfg);
|
551
541
|
} else {
|
552
542
|
rb_raise(rb_cGPhoto2ConfigurationError, "Unknown directive '%s'", rb_id2name(rb_to_id(argv[0])));
|
553
543
|
return Qnil;
|
@@ -1166,7 +1156,7 @@ VALUE camera_wait(int argc, VALUE *argv, VALUE self) {
|
|
1166
1156
|
}
|
1167
1157
|
|
1168
1158
|
Data_Get_Struct(self, GPhoto2Camera, c);
|
1169
|
-
ce = (GPhoto2CameraEvent*)
|
1159
|
+
ce = (GPhoto2CameraEvent*) ALLOC(GPhoto2CameraEvent);
|
1170
1160
|
|
1171
1161
|
// RESULT_CHECK_EVENT(gp_filesystem_reset(c->camera->fs), ce);
|
1172
1162
|
RESULT_CHECK_EVENT(gp_camera_wait_for_event(c->camera, to, &(ce->type), &evtData, c->context), ce);
|
@@ -1176,6 +1166,7 @@ VALUE camera_wait(int argc, VALUE *argv, VALUE self) {
|
|
1176
1166
|
case GP_EVENT_FOLDER_ADDED:
|
1177
1167
|
ce->path = (CameraFilePath*)evtData;
|
1178
1168
|
strcpy(c->virtFolder, ce->path->folder);
|
1169
|
+
strcpy(c->lastName, ce->path->name);
|
1179
1170
|
break;
|
1180
1171
|
case GP_EVENT_UNKNOWN:
|
1181
1172
|
break;
|
data/ext/gphoto4ruby.c
CHANGED
@@ -21,15 +21,34 @@
|
|
21
21
|
*/
|
22
22
|
|
23
23
|
#include <ruby.h>
|
24
|
+
#include <gphoto2/gphoto2-version.h>
|
24
25
|
#include "gphoto2camera_event.h"
|
25
26
|
#include "gphoto2camera_utilities.h"
|
26
27
|
#include "gphoto2camera.h"
|
27
28
|
|
28
29
|
void Init_gphoto4ruby() {
|
30
|
+
const char **v = gp_library_version(GP_VERSION_SHORT);
|
31
|
+
char libGPVersion[256];
|
32
|
+
int i;
|
33
|
+
|
34
|
+
strcpy(libGPVersion, v[0]);
|
35
|
+
for (i = 1; v[i] != NULL; i++) {
|
36
|
+
if (v[i+1] != NULL) {
|
37
|
+
strcat(libGPVersion, v[i]);
|
38
|
+
strcat(libGPVersion, ", ");
|
39
|
+
} else {
|
40
|
+
strcat(libGPVersion, v[i]);
|
41
|
+
}
|
42
|
+
}
|
43
|
+
|
29
44
|
/*
|
30
45
|
* Module contains camera class definition and some exceptions.
|
31
46
|
*/
|
32
47
|
rb_mGPhoto2 = rb_define_module("GPhoto2");
|
48
|
+
/*
|
49
|
+
* Version of libgphoto used by gem
|
50
|
+
*/
|
51
|
+
rb_define_const(rb_mGPhoto2, "LIBGPHOTO2_VERSION", rb_str_new2(libGPVersion));
|
33
52
|
/*
|
34
53
|
* GPhoto2::Camera object is a Ruby wrapping aroung gphoto2 C library.
|
35
54
|
*/
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gphoto4ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- neq4 company
|
@@ -10,11 +10,11 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2009-
|
13
|
+
date: 2009-11-06 00:00:00 +03:00
|
14
14
|
default_executable:
|
15
15
|
dependencies: []
|
16
16
|
|
17
|
-
description:
|
17
|
+
description: GPhoto4Ruby is used to control PPTP cameras (the ones that can be controlled with gphoto2) using power of ruby.
|
18
18
|
email: sergey.kruk@gmail.com
|
19
19
|
executables: []
|
20
20
|
|