rays 0.1.13 → 0.1.18

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.
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