gphoto4ruby 0.4.0 → 0.4.1
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.
- 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
|
|