capture_camera 0.0.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/.gitignore +5 -0
- data/Gemfile +4 -0
- data/Rakefile +27 -0
- data/capture_camera.gemspec +25 -0
- data/ext/Capture.c +54 -0
- data/ext/Capture.h +11 -0
- data/ext/CapturePhoto.h +34 -0
- data/ext/CapturePhoto.m +186 -0
- data/ext/extconf.rb +12 -0
- data/lib/capture_camera/version.rb +3 -0
- data/lib/capture_camera.rb +6 -0
- data/test/CaptureTest +0 -0
- data/test/CaptureTest.h +5 -0
- data/test/CaptureTest.m +16 -0
- data/test/capture_test.rb +8 -0
- metadata +65 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
|
3
|
+
|
4
|
+
namespace :build do
|
5
|
+
desc "Build and Run Capture Test Extention"
|
6
|
+
task :capture do
|
7
|
+
base_path = File.expand_path(".", File.dirname(__FILE__))
|
8
|
+
frameworks = %W(Foundation Cocoa QTKit QuartzCore).map {|framework| "-framework #{framework}"}.join(" ")
|
9
|
+
include_path = %Q{-I #{base_path}/ext}
|
10
|
+
output_file = "#{base_path}/test/CaptureTest"
|
11
|
+
main_file = "#{base_path}/test/CaptureTest.m #{base_path}/ext/CapturePhoto.m"
|
12
|
+
|
13
|
+
system("rm #{output_file}") if File.exists?(output_file)
|
14
|
+
|
15
|
+
command = %Q{ gcc -arch x86_64 -ObjC -Wall -Wimplicit-function-declaration -lobjc #{frameworks} #{include_path} -o #{output_file} #{main_file} }
|
16
|
+
|
17
|
+
puts command, "\n"
|
18
|
+
system(command)
|
19
|
+
|
20
|
+
if File.exists?(output_file)
|
21
|
+
system("chmod +x #{output_file}")
|
22
|
+
puts "Run: #{output_file}"
|
23
|
+
puts "-----", "\n"
|
24
|
+
system("#{output_file}")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "capture_camera/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "capture_camera"
|
7
|
+
s.version = CaptureCamera::VERSION
|
8
|
+
s.authors = ["Fernando Barajas"]
|
9
|
+
s.email = ["fernyb@fernyb.net"]
|
10
|
+
s.homepage = ""
|
11
|
+
s.summary = %q{Take a photo from the macbook camera}
|
12
|
+
s.description = %q{Take a photo from the macbook camera}
|
13
|
+
|
14
|
+
s.rubyforge_project = "capture_camera"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.extensions = ["ext/extconf.rb"]
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
|
22
|
+
# specify any dependencies here; for example:
|
23
|
+
# s.add_development_dependency "rspec"
|
24
|
+
# s.add_runtime_dependency "rest-client"
|
25
|
+
end
|
data/ext/Capture.c
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
#import "Capture.h"
|
2
|
+
#import "CapturePhoto.h"
|
3
|
+
|
4
|
+
NSString * to_nsstring(VALUE string)
|
5
|
+
{
|
6
|
+
if (string == Qnil) {
|
7
|
+
return [NSString string];
|
8
|
+
}
|
9
|
+
else {
|
10
|
+
printf(StringValuePtr(string));
|
11
|
+
return [NSString stringWithCString:StringValuePtr(string) encoding:NSASCIIStringEncoding];
|
12
|
+
}
|
13
|
+
}
|
14
|
+
|
15
|
+
void Init_Capture() {
|
16
|
+
Capture = rb_define_module("Capture");
|
17
|
+
rb_define_method(Capture, "take_photo", method_take_photo, 1);
|
18
|
+
}
|
19
|
+
|
20
|
+
CGSize size_from_array(VALUE array) {
|
21
|
+
long len = RARRAY_LEN(array);
|
22
|
+
int sizeWidth = 0;
|
23
|
+
int sizeHeight = 0;
|
24
|
+
|
25
|
+
if(len == 2) {
|
26
|
+
sizeWidth = FIX2INT(rb_ary_entry(array, 0));
|
27
|
+
sizeHeight = FIX2INT(rb_ary_entry(array, 1));
|
28
|
+
} else {
|
29
|
+
rb_raise(rb_eArgError, "size wrong number of arguments (%d for 2)", len);
|
30
|
+
}
|
31
|
+
return CGSizeMake(sizeWidth, sizeHeight);
|
32
|
+
}
|
33
|
+
|
34
|
+
void method_take_photo(VALUE self, VALUE options)
|
35
|
+
{
|
36
|
+
Check_Type(options, T_HASH);
|
37
|
+
VALUE filename = rb_hash_aref(options, ID2SYM(rb_intern("filename")));
|
38
|
+
VALUE size = rb_hash_aref(options, ID2SYM(rb_intern("size")));
|
39
|
+
|
40
|
+
Check_Type(size, T_ARRAY);
|
41
|
+
|
42
|
+
NSAutoreleasePool * pool = [NSAutoreleasePool new];
|
43
|
+
CapturePhoto * camera = [[CapturePhoto alloc] init];
|
44
|
+
if([camera failedToInitialize]) {
|
45
|
+
[camera release];
|
46
|
+
} else {
|
47
|
+
[camera setFilename:to_nsstring(filename)];
|
48
|
+
[camera setSize:size_from_array(size)];
|
49
|
+
|
50
|
+
[camera begin];
|
51
|
+
[camera release];
|
52
|
+
}
|
53
|
+
[pool drain];
|
54
|
+
}
|
data/ext/Capture.h
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
#import <Foundation/Foundation.h>
|
2
|
+
#import <QTKit/QTKit.h>
|
3
|
+
#import <QuartzCore/QuartzCore.h>
|
4
|
+
#import "ruby.h"
|
5
|
+
|
6
|
+
NSString * to_nsstring(VALUE string);
|
7
|
+
|
8
|
+
VALUE Capture = Qnil;
|
9
|
+
void Init_Capture();
|
10
|
+
void method_take_photo();
|
11
|
+
CGSize size_from_array(VALUE hash);
|
data/ext/CapturePhoto.h
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
#import <Foundation/Foundation.h>
|
2
|
+
#import <Cocoa/Cocoa.h>
|
3
|
+
#import <QTKit/QTKit.h>
|
4
|
+
#import <QuartzCore/QuartzCore.h>
|
5
|
+
|
6
|
+
|
7
|
+
@interface CapturePhoto : NSObject {
|
8
|
+
CVImageBufferRef currentImage;
|
9
|
+
BOOL failedToInitialize;
|
10
|
+
|
11
|
+
QTCaptureDevice * video;
|
12
|
+
QTCaptureDecompressedVideoOutput * output;
|
13
|
+
QTCaptureInput * input;
|
14
|
+
QTCaptureSession * session;
|
15
|
+
|
16
|
+
NSInteger delay;
|
17
|
+
BOOL didTakePhoto;
|
18
|
+
|
19
|
+
NSString * filename;
|
20
|
+
CGSize size;
|
21
|
+
}
|
22
|
+
|
23
|
+
@property(readonly) BOOL failedToInitialize;
|
24
|
+
@property(assign) NSInteger delay;
|
25
|
+
@property(copy) NSString * filename;
|
26
|
+
@property(assign) CGSize size;
|
27
|
+
|
28
|
+
- (void)initVars;
|
29
|
+
- (void)begin;
|
30
|
+
- (void)photoTaken:(NSData *)imageData;
|
31
|
+
- (NSData *)dataFromImage:(NSImage *)anImage;
|
32
|
+
- (CIImage *)applyFiltersForImageBuffer:(CVImageBufferRef)imageBufferRef;
|
33
|
+
|
34
|
+
@end
|
data/ext/CapturePhoto.m
ADDED
@@ -0,0 +1,186 @@
|
|
1
|
+
#import "CapturePhoto.h"
|
2
|
+
|
3
|
+
@implementation CapturePhoto
|
4
|
+
@synthesize failedToInitialize;
|
5
|
+
@synthesize delay;
|
6
|
+
@synthesize filename, size;
|
7
|
+
|
8
|
+
- (id)init
|
9
|
+
{
|
10
|
+
self = [super init];
|
11
|
+
[self initVars];
|
12
|
+
return self;
|
13
|
+
}
|
14
|
+
|
15
|
+
- (void)initVars
|
16
|
+
{
|
17
|
+
didTakePhoto = NO;
|
18
|
+
delay = 1;
|
19
|
+
NSError * error = nil;
|
20
|
+
|
21
|
+
// Get default input device and open it
|
22
|
+
video = [QTCaptureDevice defaultInputDeviceWithMediaType:QTMediaTypeVideo];
|
23
|
+
BOOL success = [video open:&error];
|
24
|
+
|
25
|
+
if (!success || error != nil) {
|
26
|
+
NSLog(@"Error Could Not Open Device");
|
27
|
+
failedToInitialize = YES;
|
28
|
+
return;
|
29
|
+
}
|
30
|
+
|
31
|
+
input = [[QTCaptureDeviceInput alloc] initWithDevice:video];
|
32
|
+
session = [QTCaptureSession new];
|
33
|
+
success = [session addInput:input error:&error];
|
34
|
+
|
35
|
+
if (!success || error != nil) {
|
36
|
+
NSLog(@"Error could not add input into session");
|
37
|
+
failedToInitialize = YES;
|
38
|
+
return;
|
39
|
+
}
|
40
|
+
|
41
|
+
output = [QTCaptureDecompressedVideoOutput new];
|
42
|
+
[output setDelegate:self];
|
43
|
+
|
44
|
+
success = [session addOutput:output error:&error];
|
45
|
+
if (!success || error != nil) {
|
46
|
+
NSLog(@"Error session failed to add output");
|
47
|
+
failedToInitialize = YES;
|
48
|
+
return;
|
49
|
+
}
|
50
|
+
|
51
|
+
currentImage = nil;
|
52
|
+
}
|
53
|
+
|
54
|
+
- (void)photoTaken:(NSData *)imageData
|
55
|
+
{
|
56
|
+
if([self filename]) {
|
57
|
+
NSString * saveFilePath = [[NSString stringWithFormat:@"%@", [self filename]] stringByExpandingTildeInPath];
|
58
|
+
[imageData writeToFile:saveFilePath atomically:NO];
|
59
|
+
}
|
60
|
+
}
|
61
|
+
|
62
|
+
- (void)begin
|
63
|
+
{
|
64
|
+
[session startRunning];
|
65
|
+
|
66
|
+
NSDate * now = [[NSDate alloc] init];
|
67
|
+
[[NSRunLoop currentRunLoop] runUntilDate:[now dateByAddingTimeInterval:(double)delay]];
|
68
|
+
[now release];
|
69
|
+
|
70
|
+
BOOL didTake = NO;
|
71
|
+
|
72
|
+
while( didTake == NO ) {
|
73
|
+
@synchronized(self) {
|
74
|
+
didTake = didTakePhoto;
|
75
|
+
}
|
76
|
+
|
77
|
+
if( didTake == NO ) { // Wait until the photo is taken...
|
78
|
+
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow: 0.1]];
|
79
|
+
}
|
80
|
+
} // end while
|
81
|
+
|
82
|
+
// Stop the session
|
83
|
+
[session stopRunning];
|
84
|
+
}
|
85
|
+
|
86
|
+
- (void)captureOutput:(QTCaptureOutput *)captureOutput
|
87
|
+
didOutputVideoFrame:(CVImageBufferRef)videoFrame
|
88
|
+
withSampleBuffer:(QTSampleBuffer *)sampleBuffer
|
89
|
+
fromConnection:(QTCaptureConnection *)connection
|
90
|
+
{
|
91
|
+
// If we already have an image we should use that instead
|
92
|
+
if ( currentImage ) return;
|
93
|
+
|
94
|
+
// Retain the videoFrame so it won't disappear
|
95
|
+
// don't forget to release!
|
96
|
+
CVBufferRetain(videoFrame);
|
97
|
+
|
98
|
+
// The Apple docs state that this action must be synchronized
|
99
|
+
// as this method will be run on another thread
|
100
|
+
@synchronized (self) {
|
101
|
+
currentImage = videoFrame;
|
102
|
+
}
|
103
|
+
|
104
|
+
// As stated above, this method will be called on another thread, so
|
105
|
+
// we perform the selector that handles the image on the main thread
|
106
|
+
[self performSelectorOnMainThread:@selector(saveImage) withObject:nil waitUntilDone:NO];
|
107
|
+
}
|
108
|
+
|
109
|
+
- (NSData *)dataFromImage:(NSImage *)anImage
|
110
|
+
{
|
111
|
+
NSData * tiffData = [anImage TIFFRepresentation];
|
112
|
+
NSBitmapImageFileType imageType = NSJPEGFileType;
|
113
|
+
NSDictionary * imageProps = [NSDictionary dictionaryWithObject:[NSNumber numberWithFloat:0.9] forKey:NSImageCompressionFactor];
|
114
|
+
|
115
|
+
NSBitmapImageRep * imageRep = [NSBitmapImageRep imageRepWithData:tiffData];
|
116
|
+
NSData * photoData = [imageRep representationUsingType:imageType properties:imageProps];
|
117
|
+
return photoData;
|
118
|
+
}
|
119
|
+
|
120
|
+
- (CIImage *)applyFiltersForImageBuffer:(CVImageBufferRef)imageBufferRef
|
121
|
+
{
|
122
|
+
CIImage * inputImage = [CIImage imageWithCVImageBuffer:imageBufferRef];
|
123
|
+
CGRect extent = [inputImage extent];
|
124
|
+
CGSize inputImageSize = extent.size;
|
125
|
+
|
126
|
+
CGFloat targetAspectRation = [self size].width / [self size].height;
|
127
|
+
CGFloat inputAspectRation = inputImageSize.width / inputImageSize.height;
|
128
|
+
CGFloat scaleFactor;
|
129
|
+
|
130
|
+
if (inputAspectRation > targetAspectRation) {
|
131
|
+
scaleFactor = inputImageSize.height / [self size].height;
|
132
|
+
} else {
|
133
|
+
scaleFactor = inputImageSize.width / [self size].width;
|
134
|
+
}
|
135
|
+
|
136
|
+
CIFilter *scaleFilter = [CIFilter filterWithName:@"CILanczosScaleTransform"];
|
137
|
+
[scaleFilter setDefaults];
|
138
|
+
[scaleFilter setValue:inputImage forKey:@"inputImage"];
|
139
|
+
[scaleFilter setValue:[NSNumber numberWithFloat:scaleFactor] forKey:@"inputScale"];
|
140
|
+
|
141
|
+
return [scaleFilter valueForKey:@"outputImage"];
|
142
|
+
}
|
143
|
+
|
144
|
+
|
145
|
+
- (void)saveImage
|
146
|
+
{
|
147
|
+
CIImage * ciImage = [self applyFiltersForImageBuffer:currentImage];
|
148
|
+
NSCIImageRep *imageRep = [NSCIImageRep imageRepWithCIImage:ciImage];
|
149
|
+
|
150
|
+
NSImage * imageCam = [[NSImage alloc] initWithSize:[imageRep size]];
|
151
|
+
[imageCam addRepresentation:imageRep];
|
152
|
+
|
153
|
+
NSData * imageData = [self dataFromImage:imageCam];
|
154
|
+
|
155
|
+
if ( [self respondsToSelector:@selector(photoTaken:)] ) {
|
156
|
+
[self photoTaken:imageData];
|
157
|
+
}
|
158
|
+
|
159
|
+
// Clean up after us
|
160
|
+
[imageCam release];
|
161
|
+
CVBufferRelease(currentImage); // release the current from since we retained it above.
|
162
|
+
currentImage = nil;
|
163
|
+
didTakePhoto = YES; // make sure we know the photo has been taken so we can end the while loop
|
164
|
+
}
|
165
|
+
|
166
|
+
|
167
|
+
- (void)dealloc
|
168
|
+
{
|
169
|
+
[super dealloc];
|
170
|
+
|
171
|
+
// make sure we are not running
|
172
|
+
if ([session isRunning]) {
|
173
|
+
[session stopRunning];
|
174
|
+
}
|
175
|
+
// if video cam is open by the current application (which is us) then we should close it
|
176
|
+
if ([video isOpen]) {
|
177
|
+
[video close];
|
178
|
+
}
|
179
|
+
|
180
|
+
if(session) [session release];
|
181
|
+
if(video) [video release];
|
182
|
+
|
183
|
+
if(filename) [filename release];
|
184
|
+
}
|
185
|
+
|
186
|
+
@end
|
data/ext/extconf.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'mkmf'
|
2
|
+
|
3
|
+
$CFLAGS << " -ObjC "
|
4
|
+
$LDFLAGS << " -lobjc -framework Foundation -framework Cocoa -framework QTKit -framework QuartzCore"
|
5
|
+
|
6
|
+
find_header('CapturePhoto.h', '..')
|
7
|
+
|
8
|
+
extension_name = "Capture"
|
9
|
+
|
10
|
+
dir_config(extension_name)
|
11
|
+
|
12
|
+
create_makefile(extension_name)
|
data/test/CaptureTest
ADDED
Binary file
|
data/test/CaptureTest.h
ADDED
data/test/CaptureTest.m
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#import "CaptureTest.h"
|
2
|
+
#import "CapturePhoto.h"
|
3
|
+
|
4
|
+
int main() {
|
5
|
+
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
|
6
|
+
|
7
|
+
CapturePhoto * camera = [[CapturePhoto alloc] init];
|
8
|
+
[camera setFilename:@"~/Desktop/screen.jpg"];
|
9
|
+
[camera setSize:CGSizeMake(640,480)];
|
10
|
+
|
11
|
+
[camera begin];
|
12
|
+
[camera release];
|
13
|
+
|
14
|
+
[pool drain];
|
15
|
+
return 0;
|
16
|
+
}
|
metadata
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: capture_camera
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Fernando Barajas
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-04-09 00:00:00.000000000Z
|
13
|
+
dependencies: []
|
14
|
+
description: Take a photo from the macbook camera
|
15
|
+
email:
|
16
|
+
- fernyb@fernyb.net
|
17
|
+
executables: []
|
18
|
+
extensions:
|
19
|
+
- ext/extconf.rb
|
20
|
+
extra_rdoc_files: []
|
21
|
+
files:
|
22
|
+
- .gitignore
|
23
|
+
- Gemfile
|
24
|
+
- Rakefile
|
25
|
+
- capture_camera.gemspec
|
26
|
+
- ext/Capture.c
|
27
|
+
- ext/Capture.h
|
28
|
+
- ext/CapturePhoto.h
|
29
|
+
- ext/CapturePhoto.m
|
30
|
+
- ext/extconf.rb
|
31
|
+
- lib/capture_camera.rb
|
32
|
+
- lib/capture_camera/version.rb
|
33
|
+
- test/CaptureTest
|
34
|
+
- test/CaptureTest.h
|
35
|
+
- test/CaptureTest.m
|
36
|
+
- test/capture_test.rb
|
37
|
+
homepage: ''
|
38
|
+
licenses: []
|
39
|
+
post_install_message:
|
40
|
+
rdoc_options: []
|
41
|
+
require_paths:
|
42
|
+
- lib
|
43
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
44
|
+
none: false
|
45
|
+
requirements:
|
46
|
+
- - ! '>='
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '0'
|
49
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
requirements: []
|
56
|
+
rubyforge_project: capture_camera
|
57
|
+
rubygems_version: 1.8.12
|
58
|
+
signing_key:
|
59
|
+
specification_version: 3
|
60
|
+
summary: Take a photo from the macbook camera
|
61
|
+
test_files:
|
62
|
+
- test/CaptureTest
|
63
|
+
- test/CaptureTest.h
|
64
|
+
- test/CaptureTest.m
|
65
|
+
- test/capture_test.rb
|