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
@@ -72,8 +72,8 @@ namespace Rays
72
72
  RawFont::RawFont (const char* name, coord size)
73
73
  {
74
74
  self->font = name
75
- ? CTFontCreateWithName(cfstring(name).get(), size, NULL)
76
- : CTFontCreateUIFontForLanguage(kCTFontSystemFontType, size, NULL);
75
+ ? CTFontCreateWithName(cfstring(name).get(), size, NULL)
76
+ : CTFontCreateUIFontForLanguage(kCTFontSystemFontType, size, NULL);
77
77
  }
78
78
 
79
79
  RawFont::~RawFont ()
@@ -1,7 +1,7 @@
1
1
  // -*- c++ -*-
2
2
  #pragma once
3
- #ifndef __RAYS_SRC_OSX_HELPER_H__
4
- #define __RAYS_SRC_OSX_HELPER_H__
3
+ #ifndef __RAYS_SRC_IOS_HELPER_H__
4
+ #define __RAYS_SRC_IOS_HELPER_H__
5
5
 
6
6
 
7
7
  #include <memory>
@@ -0,0 +1,23 @@
1
+ // -*- mode: c++ -*-
2
+ #pragma once
3
+ #ifndef __RAYS_SRC_OSX_BITMAP_H__
4
+ #define __RAYS_SRC_OSX_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 <Cocoa/Cocoa.h>
@@ -26,14 +26,14 @@ namespace Rays
26
26
  if (cs.is_alpha_first())
27
27
  {
28
28
  info |= cs.is_premult()
29
- ? kCGImageAlphaPremultipliedFirst
30
- : kCGImageAlphaFirst;
29
+ ? kCGImageAlphaPremultipliedFirst
30
+ : kCGImageAlphaFirst;
31
31
  }
32
32
  else if (cs.is_alpha_last())
33
33
  {
34
34
  info |= cs.is_premult()
35
- ? kCGImageAlphaPremultipliedLast
36
- : kCGImageAlphaLast;
35
+ ? kCGImageAlphaPremultipliedLast
36
+ : kCGImageAlphaLast;
37
37
  }
38
38
  else if (cs.is_skip_first())
39
39
  info |= kCGImageAlphaNoneSkipFirst;
@@ -174,6 +174,27 @@ namespace Rays
174
174
  return bmp;
175
175
  }
176
176
 
177
+ void
178
+ Bitmap_draw_image (
179
+ Bitmap* bitmap, CGImageRef image,
180
+ coord x, coord y, coord width, coord height)
181
+ {
182
+ if (width == 0 || height == 0) return;
183
+
184
+ if (!bitmap || !image)
185
+ argument_error(__FILE__, __LINE__);
186
+
187
+ CGContextRef context = bitmap->self->get_context();
188
+ if (!context)
189
+ rays_error(__FILE__, __LINE__, "getting CGContext failed.");
190
+
191
+ if (width < 0) width = (coord) CGImageGetWidth(image);
192
+ if (height < 0) height = (coord) CGImageGetHeight(image);
193
+ CGContextDrawImage(context, CGRectMake(x, y, width, height), image);
194
+
195
+ Bitmap_set_modified(bitmap);
196
+ }
197
+
177
198
  void
178
199
  Bitmap_draw_string (
179
200
  Bitmap* bitmap, const RawFont& font, const char* str, coord x, coord y)
@@ -184,6 +205,7 @@ namespace Rays
184
205
  if (*str == '\0') return;
185
206
 
186
207
  font.draw_string(bitmap->self->get_context(), bitmap->height(), str, x, y);
208
+
187
209
  Bitmap_set_modified(bitmap);
188
210
  }
189
211
 
@@ -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
 
@@ -0,0 +1,452 @@
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
+ }
24
+
25
+ - (id) init
26
+ {
27
+ self = [super init];
28
+ if (self)
29
+ {
30
+ session = nil;
31
+ queue = nil;
32
+ image = nil;
33
+ }
34
+ return self;
35
+ }
36
+
37
+ - (void) dealloc
38
+ {
39
+ [self stop];
40
+ [self clearImage];
41
+
42
+ if (queue)
43
+ {
44
+ dispatch_release(queue);
45
+ queue = nil;
46
+ }
47
+
48
+ [super dealloc];
49
+ }
50
+
51
+ - (dispatch_queue_t) getQueue
52
+ {
53
+ if (!queue)
54
+ {
55
+ auto name = Xot::stringf(
56
+ "org.xord.RaysVideoInputQueue_%d",
57
+ video_input_queue_index++);
58
+ queue = dispatch_queue_create(name, DISPATCH_QUEUE_SERIAL);
59
+ }
60
+ return queue;
61
+ }
62
+
63
+ - (BOOL) start: (AVCaptureDevice*) device
64
+ preset: (AVCaptureSessionPreset) preset
65
+ {
66
+ if (!device) return NO;
67
+
68
+ [self stop];
69
+
70
+ AVCaptureSession* sess = [[[AVCaptureSession alloc] init] autorelease];
71
+ if (preset != nil)
72
+ sess.sessionPreset = preset;
73
+
74
+ //device.activeVideoMinFrameDuration = CMTimeMake(1, 30);
75
+
76
+ NSError* error = nil;
77
+ AVCaptureDeviceInput* input = [[[AVCaptureDeviceInput alloc]
78
+ initWithDevice: device error: &error]
79
+ autorelease];
80
+ if (!input || error || ![sess canAddInput: input])
81
+ return NO;
82
+
83
+ AVCaptureVideoDataOutput* output =
84
+ [[[AVCaptureVideoDataOutput alloc] init] autorelease];
85
+ output.videoSettings = @{
86
+ (NSString*) kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32BGRA)
87
+ };
88
+ output.alwaysDiscardsLateVideoFrames = YES;
89
+ [output setSampleBufferDelegate: self queue: [self getQueue]];
90
+ if (![sess canAddOutput: output])
91
+ return NO;
92
+
93
+ [sess addInput: input];
94
+ [sess addOutput: output];
95
+ [sess startRunning];
96
+
97
+ session = [sess retain];
98
+ return YES;
99
+ }
100
+
101
+ - (void) captureOutput: (AVCaptureOutput*) output
102
+ didOutputSampleBuffer: (CMSampleBufferRef) sampleBuffer
103
+ fromConnection: (AVCaptureConnection*) connection
104
+ {
105
+ CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
106
+ if (!pixelBuffer) return;
107
+
108
+ CIImage* ciImage = [CIImage imageWithCVPixelBuffer: pixelBuffer];
109
+ if (!ciImage) return;
110
+
111
+ CIContext* context = [CIContext contextWithOptions: nil];
112
+ size_t width = CVPixelBufferGetWidth(pixelBuffer);
113
+ size_t height = CVPixelBufferGetHeight(pixelBuffer);
114
+ CGRect rect = CGRectMake(0, 0, width, height);
115
+ CGImageRef cgImage = [context createCGImage: ciImage fromRect: rect];
116
+
117
+ dispatch_async(dispatch_get_main_queue(), ^{
118
+ [self clearImage];
119
+ image = cgImage;
120
+ });
121
+ }
122
+
123
+ - (void) stop
124
+ {
125
+ if (!session) return;
126
+
127
+ [session stopRunning];
128
+ [session release];
129
+ session = nil;
130
+ }
131
+
132
+ - (BOOL) isActive
133
+ {
134
+ return session != nil;
135
+ }
136
+
137
+ - (void) clearImage
138
+ {
139
+ if (!image) return;
140
+
141
+ CGImageRelease(image);
142
+ image = nil;
143
+ }
144
+
145
+ - (CGImageRef) getImage
146
+ {
147
+ return image;
148
+ }
149
+
150
+ @end// VideoInput
151
+
152
+
153
+ namespace Rays
154
+ {
155
+
156
+
157
+ struct Camera::Data
158
+ {
159
+
160
+ String device_name;
161
+
162
+ int min_width = -1, min_height = -1;
163
+
164
+ bool resize = false, crop = false;
165
+
166
+ mutable Image image;
167
+
168
+ VideoInput* video_input = nil;
169
+
170
+ AVCaptureSessionPreset get_preset (AVCaptureDevice* device)
171
+ {
172
+ int w = min_width, h = min_height;
173
+ if (w > 0 && h > 0)
174
+ {
175
+ #define SUPPORT(x) \
176
+ [device supportsAVCaptureSessionPreset: AVCaptureSessionPreset##x]
177
+
178
+ if (w <= 320 && h <= 240 && SUPPORT(320x240))
179
+ return AVCaptureSessionPreset320x240;
180
+
181
+ if (w <= 352 && h <= 288 && SUPPORT(352x288))
182
+ return AVCaptureSessionPreset352x288;
183
+
184
+ if (w <= 640 && h <= 480 && SUPPORT(640x480))
185
+ return AVCaptureSessionPreset640x480;
186
+
187
+ if (w <= 960 && h <= 540 && SUPPORT(960x540))
188
+ return AVCaptureSessionPreset960x540;
189
+
190
+ if (/*w <= 1280 && h <= 720 &&*/ SUPPORT(1280x720))
191
+ return AVCaptureSessionPreset1280x720;
192
+
193
+ //if (w <= 1920 && h <= 1080 && SUPPORT(1920x1080))
194
+ // return AVCaptureSessionPreset1920x1080;
195
+
196
+ //if (SUPPORT(3840x2160))
197
+ // return AVCaptureSessionPreset3840x2160;
198
+
199
+ #undef SUPPORT
200
+ }
201
+
202
+ return nil;
203
+ }
204
+
205
+ void update_image_from_video_input () const
206
+ {
207
+ if (!video_input) return;
208
+
209
+ CGImageRef cgImage = [video_input getImage];
210
+ if (!cgImage) return;
211
+
212
+ coord draw_x, draw_y, draw_width, draw_height;
213
+ int bitmap_width, bitmap_height;
214
+ get_draw_bounds(
215
+ &draw_x, &draw_y, &draw_width, &draw_height,
216
+ &bitmap_width, &bitmap_height,
217
+ cgImage);
218
+
219
+ if (
220
+ !image ||
221
+ image.bitmap().width() != bitmap_width ||
222
+ image.bitmap().height() != bitmap_height)
223
+ {
224
+ image = Image(Bitmap(bitmap_width, bitmap_height));
225
+ }
226
+
227
+ Bitmap_draw_image(
228
+ &image.bitmap(), cgImage,
229
+ draw_x, draw_y, draw_width, draw_height);
230
+
231
+ [video_input clearImage];
232
+ }
233
+
234
+ void get_draw_bounds (
235
+ coord* draw_x, coord* draw_y, coord* draw_width, coord* draw_height,
236
+ int* bitmap_width, int* bitmap_height,
237
+ CGImageRef image) const
238
+ {
239
+ int image_width = (int) CGImageGetWidth(image);
240
+ int image_height = (int) CGImageGetHeight(image);
241
+ float image_ratio = (float) image_width / (float) image_height;
242
+
243
+ if (resize && min_width > 0 && min_height > 0)
244
+ {
245
+ float min_size_ratio = (float) min_width / (float) min_height;
246
+ if (image_ratio > min_size_ratio)
247
+ {
248
+ *draw_width = min_height * image_ratio;
249
+ *draw_height = min_height;
250
+ }
251
+ else
252
+ {
253
+ *draw_width = min_width;
254
+ *draw_height = min_width / image_ratio;
255
+ }
256
+ }
257
+ else if (resize && min_width > 0)
258
+ {
259
+ *draw_width = min_width;
260
+ *draw_height = min_width / image_ratio;
261
+ }
262
+ else if (resize && min_height > 0)
263
+ {
264
+ *draw_width = min_height * image_ratio;
265
+ *draw_height = min_height;
266
+ }
267
+ else
268
+ {
269
+ *draw_width = image_width;
270
+ *draw_height = image_height;
271
+ }
272
+
273
+ *draw_x = 0;
274
+ *draw_y = 0;
275
+ *bitmap_width = *draw_width;
276
+ *bitmap_height = *draw_height;
277
+
278
+ if (crop && min_width > 0)
279
+ {
280
+ *draw_x = min_width / 2 - *draw_width / 2;
281
+ *bitmap_width = min_width;
282
+ }
283
+ else if (crop && min_height > 0)
284
+ {
285
+ *draw_y = min_height / 2 - *draw_height / 2;
286
+ *bitmap_height = min_height;
287
+ }
288
+ }
289
+
290
+ };// Camera::Data
291
+
292
+
293
+ static NSArray<AVCaptureDevice*>*
294
+ get_video_devices ()
295
+ {
296
+ NSMutableArray<AVCaptureDevice*>* devices = [NSMutableArray array];
297
+ for (AVCaptureDevice* d in AVCaptureDevice.devices)
298
+ {
299
+ if ([d hasMediaType: AVMediaTypeVideo])
300
+ [devices addObject: d];
301
+ }
302
+ return devices;
303
+ }
304
+
305
+ static AVCaptureDevice*
306
+ get_default_video_device ()
307
+ {
308
+ AVCaptureDevice* device =
309
+ [AVCaptureDevice defaultDeviceWithMediaType: AVMediaTypeVideo];
310
+ if (!device)
311
+ rays_error(__FILE__, __LINE__, "Default camera device is not found.");
312
+
313
+ return device;
314
+ }
315
+
316
+ static AVCaptureDevice*
317
+ get_video_device (const char* name)
318
+ {
319
+ if (!name || *name == 0)
320
+ return get_default_video_device();
321
+
322
+ for (AVCaptureDevice* d in get_video_devices())
323
+ {
324
+ if (strcmp(name, d.localizedName.UTF8String) == 0)
325
+ return d;
326
+ }
327
+
328
+ rays_error(__FILE__, __LINE__, "Camera device '%s' is not found.", name);
329
+ return nil;
330
+ }
331
+
332
+ std::vector<String>
333
+ get_camera_device_names ()
334
+ {
335
+ std::vector<String> names;
336
+ for (AVCaptureDevice* d in get_video_devices())
337
+ names.emplace_back(d.localizedName.UTF8String);
338
+ return names;
339
+ }
340
+
341
+
342
+ Camera::Camera (
343
+ const char* device_name,
344
+ int min_width, int min_height, bool resize, bool crop)
345
+ {
346
+ if (device_name)
347
+ self->device_name = device_name;
348
+
349
+ self->min_width = min_width;
350
+ self->min_height = min_height;
351
+ self->resize = resize;
352
+ self->crop = crop;
353
+ }
354
+
355
+ Camera::~Camera ()
356
+ {
357
+ stop();
358
+ }
359
+
360
+ bool
361
+ Camera::start ()
362
+ {
363
+ if (!self->video_input) self->video_input = [[VideoInput alloc] init];
364
+
365
+ AVCaptureDevice* device = get_video_device(self->device_name.c_str());
366
+ return [self->video_input start: device preset: self->get_preset(device)];
367
+ }
368
+
369
+ void
370
+ Camera::stop ()
371
+ {
372
+ if (!self->video_input) return;
373
+
374
+ [self->video_input stop];
375
+ [self->video_input release];
376
+ self->video_input = nil;
377
+ }
378
+
379
+ bool
380
+ Camera::is_active () const
381
+ {
382
+ return self->video_input && [self->video_input isActive];
383
+ }
384
+
385
+ void
386
+ Camera::set_min_width (int width)
387
+ {
388
+ self->min_width = width;
389
+ }
390
+
391
+ int
392
+ Camera::min_width () const
393
+ {
394
+ return self->min_width;
395
+ }
396
+
397
+ void
398
+ Camera::set_min_height (int height)
399
+ {
400
+ self->min_height = height;
401
+ }
402
+
403
+ int
404
+ Camera::min_height () const
405
+ {
406
+ return self->min_height;
407
+ }
408
+
409
+ void
410
+ Camera::set_resize (bool resize)
411
+ {
412
+ self->resize = resize;
413
+ }
414
+
415
+ bool
416
+ Camera::is_resize () const
417
+ {
418
+ return self->resize;
419
+ }
420
+
421
+ void
422
+ Camera::set_crop (bool crop)
423
+ {
424
+ self->crop = crop;
425
+ }
426
+
427
+ bool
428
+ Camera::is_crop () const
429
+ {
430
+ return self->crop;
431
+ }
432
+
433
+ const Image*
434
+ Camera::image () const
435
+ {
436
+ self->update_image_from_video_input();
437
+ return self->image ? &self->image : NULL;
438
+ }
439
+
440
+ Camera::operator bool () const
441
+ {
442
+ return true;
443
+ }
444
+
445
+ bool
446
+ Camera::operator ! () const
447
+ {
448
+ return !operator bool();
449
+ }
450
+
451
+
452
+ }// Rays