rays 0.1.13 → 0.1.18

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/.doc/ext/rays/camera.cpp +171 -0
  3. data/.doc/ext/rays/color.cpp +2 -3
  4. data/.doc/ext/rays/color_space.cpp +22 -14
  5. data/.doc/ext/rays/font.cpp +30 -0
  6. data/.doc/ext/rays/image.cpp +1 -1
  7. data/.doc/ext/rays/native.cpp +4 -4
  8. data/.doc/ext/rays/painter.cpp +83 -0
  9. data/.doc/ext/rays/point.cpp +14 -0
  10. data/.doc/ext/rays/polygon.cpp +33 -7
  11. data/.doc/ext/rays/polyline.cpp +12 -6
  12. data/.doc/ext/rays/rays.cpp +105 -1
  13. data/LICENSE +21 -0
  14. data/Rakefile +3 -0
  15. data/VERSION +1 -1
  16. data/ext/rays/bitmap.cpp +1 -1
  17. data/ext/rays/camera.cpp +186 -0
  18. data/ext/rays/color.cpp +2 -3
  19. data/ext/rays/color_space.cpp +22 -14
  20. data/ext/rays/extconf.rb +1 -1
  21. data/ext/rays/font.cpp +35 -2
  22. data/ext/rays/image.cpp +2 -2
  23. data/ext/rays/native.cpp +4 -4
  24. data/ext/rays/painter.cpp +94 -3
  25. data/ext/rays/point.cpp +16 -0
  26. data/ext/rays/polygon.cpp +34 -6
  27. data/ext/rays/polyline.cpp +11 -5
  28. data/ext/rays/rays.cpp +105 -1
  29. data/include/rays/camera.h +74 -0
  30. data/include/rays/color_space.h +4 -2
  31. data/include/rays/defs.h +33 -0
  32. data/include/rays/exception.h +6 -2
  33. data/include/rays/image.h +1 -1
  34. data/include/rays/painter.h +38 -0
  35. data/include/rays/polygon.h +35 -1
  36. data/include/rays/polyline.h +7 -1
  37. data/include/rays/ruby/camera.h +41 -0
  38. data/include/rays/ruby/rays.h +8 -0
  39. data/lib/rays.rb +2 -2
  40. data/lib/rays/camera.rb +24 -0
  41. data/lib/rays/image.rb +1 -1
  42. data/lib/rays/painter.rb +23 -1
  43. data/lib/rays/polygon.rb +8 -0
  44. data/rays.gemspec +2 -2
  45. data/src/color_space.cpp +2 -2
  46. data/src/image.cpp +1 -1
  47. data/src/ios/bitmap.h +23 -0
  48. data/src/ios/bitmap.mm +32 -11
  49. data/src/ios/camera.mm +517 -0
  50. data/src/ios/font.mm +2 -2
  51. data/src/ios/helper.h +2 -2
  52. data/src/osx/bitmap.h +23 -0
  53. data/src/osx/bitmap.mm +28 -10
  54. data/src/osx/camera.mm +452 -0
  55. data/src/osx/font.mm +2 -2
  56. data/src/painter.cpp +100 -10
  57. data/src/polygon.cpp +203 -37
  58. data/src/polyline.cpp +4 -2
  59. data/src/polyline.h +3 -1
  60. data/test/test_font.rb +5 -0
  61. data/test/test_painter.rb +65 -5
  62. data/test/test_painter_shape.rb +48 -3
  63. data/test/test_point.rb +8 -0
  64. data/test/test_polyline.rb +26 -0
  65. metadata +20 -9
@@ -4,7 +4,10 @@
4
4
  #define __RAYS_RUBY_RAYS_H__
5
5
 
6
6
 
7
+ #include <rucy/rucy.h>
7
8
  #include <rucy/module.h>
9
+ #include <rucy/extension.h>
10
+ #include <rays/rays.h>
8
11
 
9
12
 
10
13
  namespace Rays
@@ -18,4 +21,9 @@ namespace Rays
18
21
  }// Rays
19
22
 
20
23
 
24
+ RUCY_DECLARE_CONVERT_TO(Rays::CapType)
25
+
26
+ RUCY_DECLARE_CONVERT_TO(Rays::JoinType)
27
+
28
+
21
29
  #endif//EOH
@@ -10,6 +10,7 @@ require 'rays/color'
10
10
  require 'rays/color_space'
11
11
  require 'rays/matrix'
12
12
 
13
+ require 'rays/painter'
13
14
  require 'rays/polyline'
14
15
  require 'rays/polygon'
15
16
  require 'rays/polygon_line'
@@ -17,5 +18,4 @@ require 'rays/bitmap'
17
18
  require 'rays/image'
18
19
  require 'rays/font'
19
20
  require 'rays/shader'
20
-
21
- require 'rays/painter'
21
+ require 'rays/camera'
@@ -0,0 +1,24 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+
4
+ require 'xot/block_util'
5
+ require 'rays/ext'
6
+
7
+
8
+ module Rays
9
+
10
+
11
+ class Camera
12
+
13
+ def initialize (
14
+ min_width = -1, min_height = -1,
15
+ device_name: nil, resize: true, crop: true, &block)
16
+
17
+ setup device_name, min_width, min_height, resize, crop
18
+ Xot::BlockUtil.instance_eval_or_block_call self, &block if block
19
+ end
20
+
21
+ end# Camera
22
+
23
+
24
+ end# Rays
@@ -24,7 +24,7 @@ module Rays
24
24
  end
25
25
 
26
26
  def bounds ()
27
- Bounds.new 0, 0, *size
27
+ Bounds.new 0, 0, width, height
28
28
  end
29
29
 
30
30
  end# Image
@@ -1,6 +1,7 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
3
 
4
+ require 'xot/const_symbol_accessor'
4
5
  require 'xot/universal_accessor'
5
6
  require 'xot/block_util'
6
7
  require 'rays/ext'
@@ -73,6 +74,14 @@ module Rays
73
74
  draw_ellipse args, center, radius, hole, from, to
74
75
  end
75
76
 
77
+ def curve (*args, loop: false)
78
+ draw_curve args, loop
79
+ end
80
+
81
+ def bezier (*args, loop: false)
82
+ draw_bezier args, loop
83
+ end
84
+
76
85
  def color= (fill, stroke = nil)
77
86
  self.fill fill
78
87
  self.stroke stroke
@@ -87,8 +96,21 @@ module Rays
87
96
  set_shader shader
88
97
  end
89
98
 
99
+ const_symbol_accessor :stroke_cap, {
100
+ butt: CAP_BUTT,
101
+ round: CAP_ROUND,
102
+ square: CAP_SQUARE
103
+ }
104
+
105
+ const_symbol_accessor :stroke_join, {
106
+ miter: JOIN_MITER,
107
+ round: JOIN_ROUND,
108
+ square: JOIN_SQUARE
109
+ }
110
+
90
111
  universal_accessor :background, :fill, :stroke, :color,
91
- :stroke_width, :nsegment, :shader, :clip, :font
112
+ :stroke_width, :stroke_cap, :stroke_join, :miter_limit,
113
+ :nsegment, :shader, :clip, :font
92
114
 
93
115
  private
94
116
 
@@ -44,6 +44,14 @@ module Rays
44
44
  create_ellipse args, center, radius, hole, from, to, nsegment
45
45
  end
46
46
 
47
+ def self.curve (*args, loop: false)
48
+ create_curve args, loop
49
+ end
50
+
51
+ def self.bezier (*args, loop: false)
52
+ create_bezier args, loop
53
+ end
54
+
47
55
  end# Polygon
48
56
 
49
57
 
@@ -28,8 +28,8 @@ Gem::Specification.new do |s|
28
28
  s.platform = Gem::Platform::RUBY
29
29
  s.required_ruby_version = '~> 2'
30
30
 
31
- s.add_runtime_dependency 'xot', '~> 0.1'
32
- s.add_runtime_dependency 'rucy', '~> 0.1'
31
+ s.add_runtime_dependency 'xot', '~> 0.1.16'
32
+ s.add_runtime_dependency 'rucy', '~> 0.1.18'
33
33
 
34
34
  s.files = `git ls-files`.split $/
35
35
  s.executables = s.files.grep(%r{^bin/}) {|f| File.basename f}
@@ -55,7 +55,7 @@ namespace Rays
55
55
  32, 32, 32, // RGB(A) float
56
56
  32, 32, 32, // BGR(A) float
57
57
  };
58
- if (type_ < 0 || COLORSPACE_LAST <= type_) return BPPS[COLORSPACE_UNKNOWN];
58
+ if (type_ < 0 || COLORSPACE_MAX <= type_) return BPPS[COLORSPACE_UNKNOWN];
59
59
  return BPPS[type_];
60
60
  }
61
61
 
@@ -78,7 +78,7 @@ namespace Rays
78
78
  96, 128, 128, // RGB(A) float
79
79
  96, 128, 128, // BGR(A) float
80
80
  };
81
- if (type_ < 0 || COLORSPACE_LAST <= type_) return BPPS[COLORSPACE_UNKNOWN];
81
+ if (type_ < 0 || COLORSPACE_MAX <= type_) return BPPS[COLORSPACE_UNKNOWN];
82
82
  return BPPS[type_];
83
83
  }
84
84
 
@@ -1,4 +1,4 @@
1
- #include "rays/image.h"
1
+ #include "image.h"
2
2
 
3
3
 
4
4
  #include <math.h>
@@ -0,0 +1,23 @@
1
+ // -*- mode: c++ -*-
2
+ #pragma once
3
+ #ifndef __RAYS_SRC_IOS_BITMAP_H__
4
+ #define __RAYS_SRC_IOS_BITMAP_H__
5
+
6
+
7
+ #import <CoreGraphics/CGImage.h>
8
+ #include "../bitmap.h"
9
+
10
+
11
+ namespace Rays
12
+ {
13
+
14
+
15
+ void Bitmap_draw_image (
16
+ Bitmap* bitmap, CGImageRef image,
17
+ coord x = 0, coord y = 0, coord width = -1, coord height = -1);
18
+
19
+
20
+ }// Rays
21
+
22
+
23
+ #endif//EOH
@@ -1,5 +1,5 @@
1
1
  // -*- objc -*-
2
- #import "../bitmap.h"
2
+ #import "bitmap.h"
3
3
 
4
4
 
5
5
  #import <ImageIO/CGImageDestination.h>
@@ -27,14 +27,14 @@ namespace Rays
27
27
  if (cs.is_alpha_first())
28
28
  {
29
29
  info |= cs.is_premult()
30
- ? kCGImageAlphaPremultipliedFirst
31
- : kCGImageAlphaFirst;
30
+ ? kCGImageAlphaPremultipliedFirst
31
+ : kCGImageAlphaFirst;
32
32
  }
33
33
  else if (cs.is_alpha_last())
34
34
  {
35
35
  info |= cs.is_premult()
36
- ? kCGImageAlphaPremultipliedLast
37
- : kCGImageAlphaLast;
36
+ ? kCGImageAlphaPremultipliedLast
37
+ : kCGImageAlphaLast;
38
38
  }
39
39
  else if (cs.is_skip_first())
40
40
  info |= kCGImageAlphaNoneSkipFirst;
@@ -175,6 +175,27 @@ namespace Rays
175
175
  return bmp;
176
176
  }
177
177
 
178
+ void
179
+ Bitmap_draw_image (
180
+ Bitmap* bitmap, CGImageRef image,
181
+ coord x, coord y, coord width, coord height)
182
+ {
183
+ if (width == 0 || height == 0) return;
184
+
185
+ if (!bitmap || !image)
186
+ argument_error(__FILE__, __LINE__);
187
+
188
+ CGContextRef context = bitmap->self->get_context();
189
+ if (!context)
190
+ rays_error(__FILE__, __LINE__, "getting CGContext failed.");
191
+
192
+ if (width < 0) width = (coord) CGImageGetWidth(image);
193
+ if (height < 0) height = (coord) CGImageGetHeight(image);
194
+ CGContextDrawImage(context, CGRectMake(x, y, width, height), image);
195
+
196
+ Bitmap_set_modified(bitmap);
197
+ }
198
+
178
199
  void
179
200
  Bitmap_draw_string (
180
201
  Bitmap* bitmap, const RawFont& font, const char* str, coord x, coord y)
@@ -185,6 +206,7 @@ namespace Rays
185
206
  if (*str == '\0') return;
186
207
 
187
208
  font.draw_string(bitmap->self->get_context(), bitmap->height(), str, x, y);
209
+
188
210
  Bitmap_set_modified(bitmap);
189
211
  }
190
212
 
@@ -247,11 +269,7 @@ namespace Rays
247
269
  if (!bmp)
248
270
  rays_error(__FILE__, __LINE__, "invalid bitmap.");
249
271
 
250
- CGContextRef context = bmp.self->get_context();
251
- if (!context)
252
- rays_error(__FILE__, __LINE__, "creating CGContext failed.");
253
-
254
- CGContextDrawImage(context, CGRectMake(0, 0, width, height), image);
272
+ Bitmap_draw_image(&bmp, image);
255
273
  return bmp;
256
274
  }
257
275
 
@@ -329,7 +347,10 @@ namespace Rays
329
347
  Bitmap::operator bool () const
330
348
  {
331
349
  return
332
- self->width > 0 && self->height > 0 && self->color_space && self->pixels;
350
+ self->width > 0 &&
351
+ self->height > 0 &&
352
+ self->color_space &&
353
+ self->pixels;
333
354
  }
334
355
 
335
356
  bool
@@ -0,0 +1,517 @@
1
+ // -*- mode: objc -*-
2
+ #import "rays/camera.h"
3
+
4
+
5
+ #import <AVFoundation/AVFoundation.h>
6
+ #include "rays/exception.h"
7
+ #include "bitmap.h"
8
+
9
+
10
+ static int video_input_queue_index = 0;
11
+
12
+
13
+ @interface VideoInput : NSObject <AVCaptureVideoDataOutputSampleBufferDelegate>
14
+ @end
15
+
16
+
17
+ @implementation VideoInput
18
+
19
+ {
20
+ AVCaptureSession* session;
21
+ dispatch_queue_t queue;
22
+ CGImageRef image;
23
+ AVCaptureVideoOrientation orientation;
24
+ }
25
+
26
+ - (id) init
27
+ {
28
+ self = [super init];
29
+ if (self)
30
+ {
31
+ session = nil;
32
+ queue = nil;
33
+ image = nil;
34
+ orientation = AVCaptureVideoOrientationPortrait;
35
+ }
36
+ return self;
37
+ }
38
+
39
+ - (void) dealloc
40
+ {
41
+ [self stop];
42
+ [self clearImage];
43
+
44
+ if (queue)
45
+ {
46
+ dispatch_release(queue);
47
+ queue = nil;
48
+ }
49
+
50
+ [super dealloc];
51
+ }
52
+
53
+ - (dispatch_queue_t) getQueue
54
+ {
55
+ if (!queue)
56
+ {
57
+ auto name = Xot::stringf(
58
+ "org.xord.RaysVideoInputQueue_%d",
59
+ video_input_queue_index++);
60
+ queue = dispatch_queue_create(name, DISPATCH_QUEUE_SERIAL);
61
+ }
62
+ return queue;
63
+ }
64
+
65
+ - (BOOL) start: (AVCaptureDevice*) device
66
+ preset: (AVCaptureSessionPreset) preset
67
+ {
68
+ if (!device) return NO;
69
+
70
+ [self stop];
71
+ [self updateOrientation];
72
+
73
+ AVCaptureSession* sess = [[[AVCaptureSession alloc] init] autorelease];
74
+ if (preset != nil)
75
+ sess.sessionPreset = preset;
76
+
77
+ //device.activeVideoMinFrameDuration = CMTimeMake(1, 30);
78
+
79
+ NSError* error = nil;
80
+ AVCaptureDeviceInput* input = [[[AVCaptureDeviceInput alloc]
81
+ initWithDevice: device error: &error]
82
+ autorelease];
83
+ if (!input || error || ![sess canAddInput: input])
84
+ return NO;
85
+
86
+ AVCaptureVideoDataOutput* output =
87
+ [[[AVCaptureVideoDataOutput alloc] init] autorelease];
88
+ output.videoSettings = @{
89
+ (NSString*) kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32BGRA)
90
+ };
91
+ output.alwaysDiscardsLateVideoFrames = YES;
92
+ [output setSampleBufferDelegate: self queue: [self getQueue]];
93
+ if (![sess canAddOutput: output])
94
+ return NO;
95
+
96
+ [sess addInput: input];
97
+ [sess addOutput: output];
98
+
99
+ AVCaptureConnection* connection =
100
+ [output connectionWithMediaType: AVMediaTypeVideo];
101
+ if (connection)
102
+ {
103
+ if (connection.isVideoOrientationSupported)
104
+ [connection setVideoOrientation: orientation];
105
+
106
+ if (connection.isVideoMirroringSupported)
107
+ {
108
+ [connection setVideoMirrored:
109
+ device.position == AVCaptureDevicePositionFront];
110
+ }
111
+ }
112
+
113
+ [sess startRunning];
114
+
115
+ session = [sess retain];
116
+ return YES;
117
+ }
118
+
119
+ - (void) updateOrientation
120
+ {
121
+ assert(NSThread.isMainThread);
122
+
123
+ switch (UIApplication.sharedApplication.statusBarOrientation)
124
+ {
125
+ case UIInterfaceOrientationPortraitUpsideDown:
126
+ orientation = AVCaptureVideoOrientationPortraitUpsideDown;
127
+ break;
128
+
129
+ case UIInterfaceOrientationLandscapeLeft:
130
+ orientation = AVCaptureVideoOrientationLandscapeLeft;
131
+ break;
132
+
133
+ case UIInterfaceOrientationLandscapeRight:
134
+ orientation = AVCaptureVideoOrientationLandscapeRight;
135
+ break;
136
+
137
+ default:
138
+ orientation = AVCaptureVideoOrientationPortrait;
139
+ break;
140
+ }
141
+ }
142
+
143
+ - (void) captureOutput: (AVCaptureOutput*) output
144
+ didOutputSampleBuffer: (CMSampleBufferRef) sampleBuffer
145
+ fromConnection: (AVCaptureConnection*) connection
146
+ {
147
+ [connection setVideoOrientation: orientation];
148
+
149
+ CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
150
+ if (!pixelBuffer) return;
151
+
152
+ CIImage* ciImage = [CIImage imageWithCVPixelBuffer: pixelBuffer];
153
+ if (!ciImage) return;
154
+
155
+ CIContext* context = [CIContext contextWithOptions: nil];
156
+ size_t width = CVPixelBufferGetWidth(pixelBuffer);
157
+ size_t height = CVPixelBufferGetHeight(pixelBuffer);
158
+ CGRect rect = CGRectMake(0, 0, width, height);
159
+ CGImageRef cgImage = [context createCGImage: ciImage fromRect: rect];
160
+
161
+ dispatch_async(dispatch_get_main_queue(), ^{
162
+ [self clearImage];
163
+ image = cgImage;
164
+
165
+ [self updateOrientation];
166
+ });
167
+ }
168
+
169
+ - (void) stop
170
+ {
171
+ if (!session) return;
172
+
173
+ [session stopRunning];
174
+ [session release];
175
+ session = nil;
176
+ }
177
+
178
+ - (BOOL) isActive
179
+ {
180
+ return session != nil;
181
+ }
182
+
183
+ - (void) clearImage
184
+ {
185
+ if (!image) return;
186
+
187
+ CGImageRelease(image);
188
+ image = nil;
189
+ }
190
+
191
+ - (CGImageRef) getImage
192
+ {
193
+ return image;
194
+ }
195
+
196
+ @end// VideoInput
197
+
198
+
199
+ namespace Rays
200
+ {
201
+
202
+
203
+ struct Camera::Data
204
+ {
205
+
206
+ String device_name;
207
+
208
+ int min_width = -1, min_height = -1;
209
+
210
+ bool resize = false, crop = false;
211
+
212
+ mutable Image image;
213
+
214
+ VideoInput* video_input = nil;
215
+
216
+ AVCaptureSessionPreset get_preset (AVCaptureDevice* device)
217
+ {
218
+ int w = min_width, h = min_height;
219
+ if (w > 0 && h > 0)
220
+ {
221
+ #define SUPPORT(x) \
222
+ [device supportsAVCaptureSessionPreset: AVCaptureSessionPreset##x]
223
+
224
+ //if (w <= 320 && h <= 240 && SUPPORT(320x240))
225
+ // return AVCaptureSessionPreset320x240;
226
+
227
+ if (w <= 352 && h <= 288 && SUPPORT(352x288))
228
+ return AVCaptureSessionPreset352x288;
229
+
230
+ if (w <= 640 && h <= 480 && SUPPORT(640x480))
231
+ return AVCaptureSessionPreset640x480;
232
+
233
+ //if (w <= 960 && h <= 540 && SUPPORT(960x540))
234
+ // return AVCaptureSessionPreset960x540;
235
+
236
+ if (w <= 1280 && h <= 720 && SUPPORT(1280x720))
237
+ return AVCaptureSessionPreset1280x720;
238
+
239
+ if (/*w <= 1920 && h <= 1080 &&*/ SUPPORT(1920x1080))
240
+ return AVCaptureSessionPreset1920x1080;
241
+
242
+ //if (SUPPORT(3840x2160))
243
+ // return AVCaptureSessionPreset3840x2160;
244
+
245
+ #undef SUPPORT
246
+ }
247
+
248
+ return nil;
249
+ }
250
+
251
+ void update_image_from_video_input () const
252
+ {
253
+ if (!video_input) return;
254
+
255
+ CGImageRef cgImage = [video_input getImage];
256
+ if (!cgImage) return;
257
+
258
+ coord draw_x, draw_y, draw_width, draw_height;
259
+ int bitmap_width, bitmap_height;
260
+ get_draw_bounds(
261
+ &draw_x, &draw_y, &draw_width, &draw_height,
262
+ &bitmap_width, &bitmap_height,
263
+ cgImage);
264
+
265
+ if (
266
+ !image ||
267
+ image.bitmap().width() != bitmap_width ||
268
+ image.bitmap().height() != bitmap_height)
269
+ {
270
+ image = Image(Bitmap(bitmap_width, bitmap_height));
271
+ }
272
+
273
+ Bitmap_draw_image(
274
+ &image.bitmap(), cgImage,
275
+ draw_x, draw_y, draw_width, draw_height);
276
+
277
+ [video_input clearImage];
278
+ }
279
+
280
+ void get_draw_bounds (
281
+ coord* draw_x, coord* draw_y, coord* draw_width, coord* draw_height,
282
+ int* bitmap_width, int* bitmap_height,
283
+ CGImageRef image) const
284
+ {
285
+ int image_width = (int) CGImageGetWidth(image);
286
+ int image_height = (int) CGImageGetHeight(image);
287
+ float image_ratio = (float) image_width / (float) image_height;
288
+
289
+ if (resize && min_width > 0 && min_height > 0)
290
+ {
291
+ float min_size_ratio = (float) min_width / (float) min_height;
292
+ if (image_ratio > min_size_ratio)
293
+ {
294
+ *draw_width = min_height * image_ratio;
295
+ *draw_height = min_height;
296
+ }
297
+ else
298
+ {
299
+ *draw_width = min_width;
300
+ *draw_height = min_width / image_ratio;
301
+ }
302
+ }
303
+ else if (resize && min_width > 0)
304
+ {
305
+ *draw_width = min_width;
306
+ *draw_height = min_width / image_ratio;
307
+ }
308
+ else if (resize && min_height > 0)
309
+ {
310
+ *draw_width = min_height * image_ratio;
311
+ *draw_height = min_height;
312
+ }
313
+ else
314
+ {
315
+ *draw_width = image_width;
316
+ *draw_height = image_height;
317
+ }
318
+
319
+ *draw_x = 0;
320
+ *draw_y = 0;
321
+ *bitmap_width = *draw_width;
322
+ *bitmap_height = *draw_height;
323
+
324
+ if (crop && min_width > 0)
325
+ {
326
+ *draw_x = min_width / 2 - *draw_width / 2;
327
+ *bitmap_width = min_width;
328
+ }
329
+ else if (crop && min_height > 0)
330
+ {
331
+ *draw_y = min_height / 2 - *draw_height / 2;
332
+ *bitmap_height = min_height;
333
+ }
334
+ }
335
+
336
+ };// Camera::Data
337
+
338
+
339
+ static NSArray<AVCaptureDevice*>*
340
+ get_video_devices ()
341
+ {
342
+ #if 0
343
+ AVCaptureDeviceDiscoverySession* discoverySession =
344
+ [AVCaptureDeviceDiscoverySession
345
+ discoverySessionWithDeviceTypes: @[
346
+ AVCaptureDeviceTypeBuiltInTripleCamera,
347
+ AVCaptureDeviceTypeBuiltInDualWideCamera,
348
+ AVCaptureDeviceTypeBuiltInDualCamera,
349
+ AVCaptureDeviceTypeBuiltInUltraWideCamera,
350
+ AVCaptureDeviceTypeBuiltInTelephotoCamera,
351
+ AVCaptureDeviceTypeBuiltInWideAngleCamera
352
+ ]
353
+ mediaType: AVMediaTypeVideo
354
+ position: AVCaptureDevicePositionUnspecified];
355
+ NSArray<AVCaptureDevice*>* devices = discoverySession.devices;
356
+ for (AVCaptureDevice* d in devices)
357
+ {
358
+ printf("%s\n", d.localizedName.UTF8String);
359
+ }
360
+ #endif
361
+ NSMutableArray<AVCaptureDevice*>* devices = [NSMutableArray array];
362
+ for (AVCaptureDevice* d in AVCaptureDevice.devices)
363
+ {
364
+ if ([d hasMediaType: AVMediaTypeVideo])
365
+ [devices addObject: d];
366
+ }
367
+ return devices;
368
+ }
369
+
370
+ static AVCaptureDevice*
371
+ get_default_video_device ()
372
+ {
373
+ AVCaptureDevice* device =
374
+ [AVCaptureDevice defaultDeviceWithMediaType: AVMediaTypeVideo];
375
+ if (!device)
376
+ rays_error(__FILE__, __LINE__, "Default camera device is not found.");
377
+
378
+ return device;
379
+ }
380
+
381
+ static AVCaptureDevice*
382
+ get_video_device (const char* name)
383
+ {
384
+ if (!name || *name == 0)
385
+ return get_default_video_device();
386
+
387
+ for (AVCaptureDevice* d in get_video_devices())
388
+ {
389
+ if (strcmp(name, d.localizedName.UTF8String) == 0)
390
+ return d;
391
+ }
392
+
393
+ rays_error(__FILE__, __LINE__, "Camera device '%s' is not found.", name);
394
+ return nil;
395
+ }
396
+
397
+ std::vector<String>
398
+ get_camera_device_names ()
399
+ {
400
+ std::vector<String> names;
401
+ for (AVCaptureDevice* d in get_video_devices())
402
+ names.emplace_back(d.localizedName.UTF8String);
403
+ return names;
404
+ }
405
+
406
+
407
+ Camera::Camera (
408
+ const char* device_name,
409
+ int min_width, int min_height, bool resize, bool crop)
410
+ {
411
+ if (device_name)
412
+ self->device_name = device_name;
413
+
414
+ self->min_width = min_width;
415
+ self->min_height = min_height;
416
+ self->resize = resize;
417
+ self->crop = crop;
418
+ }
419
+
420
+ Camera::~Camera ()
421
+ {
422
+ stop();
423
+ }
424
+
425
+ bool
426
+ Camera::start ()
427
+ {
428
+ if (!self->video_input) self->video_input = [[VideoInput alloc] init];
429
+
430
+ AVCaptureDevice* device = get_video_device(self->device_name.c_str());
431
+ return [self->video_input start: device preset: self->get_preset(device)];
432
+ }
433
+
434
+ void
435
+ Camera::stop ()
436
+ {
437
+ if (!self->video_input) return;
438
+
439
+ [self->video_input stop];
440
+ [self->video_input release];
441
+ self->video_input = nil;
442
+ }
443
+
444
+ bool
445
+ Camera::is_active () const
446
+ {
447
+ return self->video_input && [self->video_input isActive];
448
+ }
449
+
450
+ void
451
+ Camera::set_min_width (int width)
452
+ {
453
+ self->min_width = width;
454
+ }
455
+
456
+ int
457
+ Camera::min_width () const
458
+ {
459
+ return self->min_width;
460
+ }
461
+
462
+ void
463
+ Camera::set_min_height (int height)
464
+ {
465
+ self->min_height = height;
466
+ }
467
+
468
+ int
469
+ Camera::min_height () const
470
+ {
471
+ return self->min_height;
472
+ }
473
+
474
+ void
475
+ Camera::set_resize (bool resize)
476
+ {
477
+ self->resize = resize;
478
+ }
479
+
480
+ bool
481
+ Camera::is_resize () const
482
+ {
483
+ return self->resize;
484
+ }
485
+
486
+ void
487
+ Camera::set_crop (bool crop)
488
+ {
489
+ self->crop = crop;
490
+ }
491
+
492
+ bool
493
+ Camera::is_crop () const
494
+ {
495
+ return self->crop;
496
+ }
497
+
498
+ const Image*
499
+ Camera::image () const
500
+ {
501
+ self->update_image_from_video_input();
502
+ return self->image ? &self->image : NULL;
503
+ }
504
+
505
+ Camera::operator bool () const
506
+ {
507
+ return true;
508
+ }
509
+
510
+ bool
511
+ Camera::operator ! () const
512
+ {
513
+ return !operator bool();
514
+ }
515
+
516
+
517
+ }// Rays