gphoto4ruby 0.1.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.
@@ -0,0 +1,49 @@
1
+ GPhoto2::Camera
2
+ Класс для управления камерами, подключенными через usb-порты к компьютеру.
3
+ Следует написать require "gphoto4ruby"
4
+
5
+ GPhoto2::Camera.ports() -> Array
6
+ Метод класса. Возвращает массив, содержащий пути (path) usb-портов, к которым подключены камеры, если камер более одной.
7
+
8
+ GPhoto2::Camera.new() -> GPhoto2::Camera
9
+ Конструктор класса. Создает объект для управления первой авто-определенной камерой (обычно это камера, которая была подключена последней).
10
+
11
+ GPhoto2::Camera.new(port) -> GPhoto2::Camera
12
+ Конструктор класса. Создает объект для управления камерой, подключенной к заданному порту. Актуально при подключении более одной камеры.
13
+ port (String) -- путь (path) порта с камерой. Следует использовать элементы массива, возвращаемого методом класса GPhoto2::Camera.ports
14
+ Пример:
15
+ cams = Array.new
16
+ GPhoto2::Camera.ports.each do |port|
17
+ cams.push(GPhoto2::Camera.new(port))
18
+ end
19
+
20
+ configs() -> Array
21
+ Метод объекта. Возвращает массив с именами (name) доступных для изменения настроек камеры.
22
+
23
+ [config_name] -> String или Float
24
+ Метод объекта. Возвращает значение настройки с именем config_name.
25
+ config_name (String или Symbol) -- имя (name) настройки камеры. Следует использовать элементы массива, возвращаемые методом configs().
26
+ Пример:
27
+ cam[:focallength] -> 10.5
28
+ cam["f-number"] -> "f/4"
29
+ cam[cam.configs[0]]
30
+
31
+ [config_name, directive] -> Array
32
+ Метод объекта. Возвращает информацию о настройке в зависимости от директивы directive.
33
+ config_name (String или Symbol) -- имя (name) настройки камеры. Следует использовать элементы массива, возвращаемые методом configs().
34
+ directive (Symbol) -- указывает на информацию, которую следует выдать
35
+ :all -- возвращается массив с допустимыми значениями настройки.
36
+ Пример:
37
+ cam["exptime", :all] -> ["0.002", "0.003", ...]
38
+
39
+ [config_name] = value -> String или Float
40
+ Метод объекта. Изменяет значение указанной настройки на новое.
41
+ config_name (String или Symbol) -- имя (name) настройки камеры. Следует использовать элементы массива, возвращаемые методом configs().
42
+ value (String или Float) -- новое значение настройки. Следует использовать элементы массива, возвращаемые методом [] с директивой :all.
43
+ Пример:
44
+ cam[:exptime] = "0.010" -> "0.010"
45
+ cam["f-number"] = cam["f-number", :all][3]
46
+
47
+ capture() -> GPhoto2::Camera
48
+ Метод объекта. Посылает сигнал на камеру для съемки изображения.
49
+
data/ext/extconf.rb ADDED
@@ -0,0 +1,8 @@
1
+ require "mkmf"
2
+
3
+ dir_config("gphoto4ruby", "/usr/local")
4
+ if have_library("gphoto2")
5
+ create_makefile("gphoto4ruby")
6
+ else
7
+ raise "You need gphoto2 installed to compile and use this library"
8
+ end
data/ext/gphoto4ruby.c ADDED
@@ -0,0 +1,459 @@
1
+ /**
2
+ *
3
+ * Copyright 2008 neq4 company <http://neq4.com>
4
+ * Author: Sergey Kruk <sergey.kruk@gmail.com>
5
+ *
6
+ * This file is part of GPhoto4Ruby.
7
+ *
8
+ * GPhoto4Ruby is free software: you can redistribute it and/or
9
+ * modify it under the terms of the GNU Lesser General Public
10
+ * License as published by the Free Software Foundation, either
11
+ * version 3 of the License, or (at your option) any later version.
12
+ *
13
+ * GPhoto4Ruby is distributed in the hope that it will be useful,
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ * GNU General Public License for more details.
17
+ *
18
+ * You should have received a copy of the GNU General Public License
19
+ * along with GPhoto4Ruby. If not, see <http://www.gnu.org/licenses/>.
20
+ *
21
+ */
22
+
23
+ #include <stdlib.h>
24
+ #include <stdio.h>
25
+ #include <string.h>
26
+ #include <gphoto2/gphoto2.h>
27
+ #include <ruby.h>
28
+ #include "gphoto4ruby.h"
29
+
30
+
31
+ static VALUE rb_mGPhoto2;
32
+ static VALUE rb_cGPhoto2Camera;
33
+ static VALUE rb_cGPhoto2Exception;
34
+ static VALUE rb_cGPhoto2ConfigurationError;
35
+ static VALUE rb_cGPhoto2ProgrammerError;
36
+
37
+ static void rb_raise_gp_result(int retval) {
38
+ rb_raise(rb_cGPhoto2Exception, "LibGPhoto2 function returned: %s", gp_result_as_string(retval));
39
+ }
40
+
41
+ static void rb_raise_programmer_error(const char* fName) {
42
+ rb_raise(rb_cGPhoto2ProgrammerError, "Program was not supposed to get here. Function: %s", fName);
43
+ }
44
+
45
+ static VALUE getRadio(CameraWidget *cc) {
46
+ int retval;
47
+ const char *val;
48
+ retval = gp_widget_get_value(cc, &val);
49
+ if (retval == GP_OK) {
50
+ return rb_str_new2(val);
51
+ } else {
52
+ rb_raise_gp_result(retval);
53
+ return Qnil;
54
+ }
55
+ }
56
+
57
+ static VALUE listRadio(CameraWidget *cc) {
58
+ int retval, i, choicesTotal;
59
+ const char *choice;
60
+ VALUE arr;
61
+
62
+ choicesTotal = gp_widget_count_choices(cc);
63
+ arr = rb_ary_new();
64
+ for (i = 0; i < choicesTotal; i++) {
65
+ retval = gp_widget_get_choice(cc, i, &choice);
66
+ if (retval == GP_OK) {
67
+ rb_ary_push(arr, rb_str_new2(choice));
68
+ } else {
69
+ rb_raise_gp_result(retval);
70
+ return Qnil;
71
+ }
72
+ }
73
+ return arr;
74
+
75
+ static VALUE setRadio(GPhoto2Camera *c, VALUE newVal) {
76
+ int retval, i, choicesTotal;
77
+ const char *choice;
78
+ const char *val;
79
+
80
+ Check_Type(newVal, T_STRING);
81
+ val = RSTRING(newVal)->ptr;
82
+
83
+ choicesTotal = gp_widget_count_choices(c->childConfig);
84
+ for (i = 0; i < choicesTotal; i++) {
85
+ gp_widget_get_choice(c->childConfig, i, &choice);
86
+ if (strcmp(choice, val) == 0) {
87
+ retval = gp_widget_set_value(c->childConfig, val);
88
+ if (retval == GP_OK) {
89
+ retval = gp_camera_set_config(c->camera, c->config, c->context);
90
+ if (retval == GP_OK) {
91
+ return newVal;
92
+ }
93
+ }
94
+ }
95
+ }
96
+ if (retval != GP_OK) {
97
+ rb_raise_gp_result(retval);
98
+ } else {
99
+ rb_raise(rb_cGPhoto2ConfigurationError, "Value '%s' is not allowed", val);
100
+ }
101
+ return Qnil;
102
+ }
103
+
104
+ static VALUE getRange(CameraWidget *cc) {
105
+ int retval;
106
+ float val;
107
+ retval = gp_widget_get_value(cc, &val);
108
+ if (retval == GP_OK) {
109
+ return rb_float_new(val);
110
+ } else {
111
+ rb_raise_gp_result(retval);
112
+ return Qnil;
113
+ }
114
+ }
115
+
116
+ static VALUE listRange(CameraWidget *cc) {
117
+ int retval;
118
+ float min, max, inc, i;
119
+ VALUE arr;
120
+
121
+ retval = gp_widget_get_range(cc, &min, &max, &inc);
122
+ if ((retval == GP_OK) && (inc > 0)) {
123
+ arr = rb_ary_new();
124
+ for (i = min; i <= max; i = i + inc) {
125
+ rb_ary_push(arr, rb_float_new(i));
126
+ }
127
+ return arr;
128
+ } else if (retval != GP_OK) {
129
+ rb_raise_gp_result(retval);
130
+ } else {
131
+ return rb_ary_new();
132
+ }
133
+ return Qnil;
134
+ }
135
+
136
+ static VALUE setRange(GPhoto2Camera *c, VALUE newNum) {
137
+ int retval;
138
+ float min, max, inc, i;
139
+ float val;
140
+
141
+ Check_Type(newNum, T_FLOAT);
142
+ val = NUM2DBL(newNum);
143
+
144
+ retval = gp_widget_get_range(c->childConfig, &min, &max, &inc);
145
+ if ((retval == GP_OK) && (val >= min) && (val <= max) && (inc > 0)) {
146
+ for (i = min; i <= max; i = i + inc) {
147
+ if ((val >= i) && (val <= (i+inc))) {
148
+ if ((val - i) > (inc / 2.0)) {
149
+ val = i + inc;
150
+ } else {
151
+ val = i;
152
+ }
153
+ retval = gp_widget_set_value(c->childConfig, &val);
154
+ if (retval == GP_OK) {
155
+ retval = gp_camera_set_config(c->camera, c->config, c->context);
156
+ if (retval == GP_OK) {
157
+ return rb_float_new(val);
158
+ }
159
+ }
160
+ }
161
+ }
162
+ }
163
+ if (retval != GP_OK) {
164
+ rb_raise_gp_result(retval);
165
+ } else {
166
+ rb_raise(rb_cGPhoto2ConfigurationError, "Value has to be in range: %f .. %f", min, max);
167
+ }
168
+ return Qnil;
169
+ }
170
+
171
+ static void populateWithConfigs(CameraWidget *cc, VALUE arr) {
172
+ int retval, i, childrenTotal;
173
+ const char *name;
174
+ CameraWidget *child;
175
+ CameraWidgetType widgettype;
176
+
177
+ retval = gp_widget_get_type(cc, &widgettype);
178
+ if (retval == GP_OK) {
179
+ switch (widgettype) {
180
+ case GP_WIDGET_RADIO:
181
+ case GP_WIDGET_RANGE:
182
+ retval = gp_widget_get_name(cc, &name);
183
+ if (retval == GP_OK) {
184
+ rb_ary_push(arr, rb_str_new2(name));
185
+ }
186
+ break;
187
+ case GP_WIDGET_WINDOW:
188
+ case GP_WIDGET_SECTION:
189
+ childrenTotal = gp_widget_count_children(cc);
190
+ for (i = 0; i < childrenTotal; i ++) {
191
+ retval = gp_widget_get_child(cc, i, &child);
192
+ if (retval == GP_OK) {
193
+ populateWithConfigs(child, arr);
194
+ }
195
+ }
196
+ break;
197
+ }
198
+ }
199
+ if (retval != GP_OK) {
200
+ rb_raise_gp_result(retval);
201
+ }
202
+ }
203
+
204
+ static void camera_mark(GPhoto2Camera *c) {
205
+ }
206
+
207
+ static void camera_free(GPhoto2Camera *c) {
208
+ int retval;
209
+ retval = gp_camera_exit(c->camera, c->context);
210
+ retval = gp_widget_free(c->config);
211
+ retval = gp_camera_free(c->camera);
212
+ free(c->context);
213
+ free(c);
214
+ }
215
+
216
+ static VALUE camera_allocate(VALUE klass) {
217
+ int retval;
218
+ GPhoto2Camera *c;
219
+ c = (GPhoto2Camera*) malloc(sizeof(GPhoto2Camera));
220
+ c->context = gp_context_new();
221
+ retval = gp_camera_new(&(c->camera));
222
+ if (retval == GP_OK) {
223
+ retval = gp_camera_get_config(c->camera, &(c->config), c->context);
224
+ if (retval == GP_OK) {
225
+ return Data_Wrap_Struct(klass, camera_mark, camera_free, c);
226
+ }
227
+ }
228
+ rb_raise_gp_result(retval);
229
+ return Qnil;
230
+ }
231
+
232
+ static VALUE camera_initialize(int argc, VALUE *argv, VALUE self) {
233
+ switch (argc) {
234
+ case 0:
235
+ return self;
236
+ break;
237
+ case 1:
238
+ Check_Type(argv[0], T_STRING);
239
+ int retval, portIndex;
240
+ GPPortInfoList *portInfoList;
241
+ GPPortInfo p;
242
+ GPhoto2Camera *c;
243
+
244
+ Data_Get_Struct(self, GPhoto2Camera, c);
245
+
246
+ retval = gp_port_info_list_new(&portInfoList);
247
+ if (retval == GP_OK) {
248
+ retval = gp_port_info_list_load(portInfoList);
249
+ if (retval == GP_OK) {
250
+ portIndex = gp_port_info_list_lookup_path(portInfoList, RSTRING(argv[0])->ptr);
251
+ if (portIndex >= 0) {
252
+ retval = gp_port_info_list_get_info(portInfoList, portIndex, &p);
253
+ if (retval == GP_OK) {
254
+ retval = gp_camera_set_port_info(c->camera, p);
255
+ if (retval == GP_OK) {
256
+ return self;
257
+ }
258
+ }
259
+ } else {
260
+ rb_raise_gp_result(portIndex);
261
+ return Qnil;
262
+ }
263
+ }
264
+ }
265
+ rb_raise_gp_result(retval);
266
+ return Qnil;
267
+ default:
268
+ rb_raise(rb_eArgError, "Wrong number of arguments (%d for 0 or 1)", argc);
269
+ return Qnil;
270
+ }
271
+ }
272
+
273
+ static VALUE camera_class_ports(VALUE klass) {
274
+ int retval, i, portsTotal;
275
+ GPPortInfoList *portInfoList;
276
+ GPPortInfo p;
277
+ VALUE arr;
278
+
279
+ retval = gp_port_info_list_new(&portInfoList);
280
+ if (retval == GP_OK) {
281
+ retval = gp_port_info_list_load(portInfoList);
282
+ if (retval == GP_OK) {
283
+ portsTotal = gp_port_info_list_count(portInfoList);
284
+ arr = rb_ary_new();
285
+ for(i = 0; i < portsTotal; i++) {
286
+ retval = gp_port_info_list_get_info(portInfoList, i, &p);
287
+ if ((retval == GP_OK) && (strlen(p.path) > 4) && (strncmp(p.path, "usb:", 4) == 0)) {
288
+ rb_ary_push(arr, rb_str_new2(p.path));
289
+ }
290
+ }
291
+ retval = gp_port_info_list_free(portInfoList);
292
+ if (retval == GP_OK) {
293
+ return arr;
294
+ }
295
+ }
296
+ }
297
+ rb_raise_gp_result(retval);
298
+ return Qnil;
299
+ }
300
+
301
+ static VALUE camera_capture(VALUE self) {
302
+ int retval;
303
+ GPhoto2Camera *c;
304
+
305
+ Data_Get_Struct(self, GPhoto2Camera, c);
306
+
307
+ retval = gp_camera_capture(c->camera, GP_CAPTURE_IMAGE, &(c->filepath), c->context);
308
+ if (retval == GP_OK) {
309
+ // printf("captured: %s/%s\n", c->filepath.folder, c->filepath.name);
310
+ return self;
311
+ } else {
312
+ rb_raise_gp_result(retval);
313
+ return Qnil;
314
+ }
315
+ }
316
+
317
+ static VALUE camera_get_configs(VALUE self) {
318
+ GPhoto2Camera *c;
319
+ VALUE arr = rb_ary_new();
320
+
321
+ Data_Get_Struct(self, GPhoto2Camera, c);
322
+
323
+ populateWithConfigs(c->config, arr);
324
+
325
+ return arr;
326
+ }
327
+
328
+ static VALUE camera_get_value(int argc, VALUE *argv, VALUE self) {
329
+ int retval;
330
+ const char *name;
331
+ GPhoto2Camera *c;
332
+ CameraWidgetType widgettype;
333
+ VALUE str, dir;
334
+
335
+ switch (argc) {
336
+ case 1:
337
+ str = argv[0];
338
+ break;
339
+ case 2:
340
+ str = argv[0];
341
+ dir = argv[1];
342
+ break;
343
+ default:
344
+ rb_raise(rb_eArgError, "Wrong number of arguments (%d for 1 or 2)", argc);
345
+ return Qnil;
346
+ }
347
+
348
+ switch (TYPE(str)) {
349
+ case T_STRING:
350
+ name = RSTRING(str)->ptr;
351
+ break;
352
+ case T_SYMBOL:
353
+ name = rb_id2name(rb_to_id(str));
354
+ break;
355
+ default:
356
+ rb_raise(rb_eTypeError, "Not valid parameter type");
357
+ return Qnil;
358
+ }
359
+
360
+ Data_Get_Struct(self, GPhoto2Camera, c);
361
+
362
+ retval = gp_widget_get_child_by_name(c->config, name, &(c->childConfig));
363
+ if (retval == GP_OK) {
364
+ retval = gp_widget_get_type(c->childConfig, &widgettype);
365
+ if (retval == GP_OK) {
366
+ switch (widgettype) {
367
+ case GP_WIDGET_RADIO:
368
+ if (argc == 1) {
369
+ return getRadio(c->childConfig);
370
+ } else if (strcmp(rb_id2name(rb_to_id(dir)), "all") == 0) {
371
+ return listRadio(c->childConfig);
372
+ } else {
373
+ rb_raise(rb_cGPhoto2ConfigurationError, "Second parameter not valid");
374
+ return Qnil;
375
+ }
376
+ break;
377
+ case GP_WIDGET_RANGE:
378
+ if (argc == 1) {
379
+ return getRange(c->childConfig);
380
+ } else if (strcmp(rb_id2name(rb_to_id(dir)), "all") == 0) {
381
+ return listRange(c->childConfig);
382
+ } else {
383
+ rb_raise(rb_cGPhoto2ConfigurationError, "Second parameter not valid");
384
+ return Qnil;
385
+ }
386
+ break;
387
+ default:
388
+ rb_raise(rb_cGPhoto2ConfigurationError, "Not supported yet");
389
+ return Qnil;
390
+ }
391
+ }
392
+ }
393
+ if (retval != GP_OK) {
394
+ rb_raise_gp_result(retval);
395
+ } else {
396
+ rb_raise_programmer_error("camera_get_value");
397
+ }
398
+ return Qnil;
399
+ }
400
+
401
+ static VALUE camera_set_value(VALUE self, VALUE str, VALUE newVal) {
402
+ int retval;
403
+ const char *name;
404
+ GPhoto2Camera *c;
405
+ CameraWidgetType widgettype;
406
+
407
+ switch (TYPE(str)) {
408
+ case T_STRING:
409
+ name = RSTRING(str)->ptr;
410
+ break;
411
+ case T_SYMBOL:
412
+ name = rb_id2name(rb_to_id(str));
413
+ break;
414
+ default:
415
+ rb_raise(rb_eTypeError, "Not valid parameter type");
416
+ return Qnil;
417
+ }
418
+
419
+ Data_Get_Struct(self, GPhoto2Camera, c);
420
+
421
+ retval = gp_widget_get_child_by_name(c->config, name, &(c->childConfig));
422
+ if (retval == GP_OK) {
423
+ retval = gp_widget_get_type(c->childConfig, &widgettype);
424
+ if (retval == GP_OK) {
425
+ switch (widgettype) {
426
+ case GP_WIDGET_RADIO:
427
+ return setRadio(c, newVal);
428
+ break;
429
+ case GP_WIDGET_RANGE:
430
+ return setRange(c, newVal);
431
+ break;
432
+ default:
433
+ rb_raise(rb_cGPhoto2ConfigurationError, "Cannot access this setting");
434
+ return Qnil;
435
+ }
436
+ }
437
+ }
438
+ if (retval != GP_OK) {
439
+ rb_raise_gp_result(retval);
440
+ } else {
441
+ rb_raise_programmer_error("camera_set_value");
442
+ }
443
+ return Qnil;
444
+ }
445
+
446
+ void Init_gphoto4ruby() {
447
+ rb_mGPhoto2 = rb_define_module("GPhoto2");
448
+ rb_cGPhoto2Camera = rb_define_class_under(rb_mGPhoto2, "Camera", rb_cObject);
449
+ rb_cGPhoto2Exception = rb_define_class_under(rb_mGPhoto2, "Exception", rb_eStandardError);
450
+ rb_cGPhoto2ConfigurationError = rb_define_class_under(rb_mGPhoto2, "ConfigurationError", rb_eStandardError);
451
+ rb_cGPhoto2ProgrammerError = rb_define_class_under(rb_mGPhoto2, "ProgrammerError", rb_eStandardError);
452
+ rb_define_alloc_func(rb_cGPhoto2Camera, camera_allocate);
453
+ rb_define_module_function(rb_cGPhoto2Camera, "ports", camera_class_ports, 0);
454
+ rb_define_method(rb_cGPhoto2Camera, "initialize", camera_initialize, -1);
455
+ rb_define_method(rb_cGPhoto2Camera, "configs", camera_get_configs, 0);
456
+ rb_define_method(rb_cGPhoto2Camera, "[]", camera_get_value, -1);
457
+ rb_define_method(rb_cGPhoto2Camera, "[]=", camera_set_value, 2);
458
+ rb_define_method(rb_cGPhoto2Camera, "capture", camera_capture, 0);
459
+ }