async-ruby-vips 1.2.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.
- checksums.yaml +7 -0
- data/Gemfile.lock +63 -0
- data/README.md +101 -0
- data/async-ruby-vips.gemspec +74 -0
- data/ext/LICENSE +20 -0
- data/ext/async_vips.c +73 -0
- data/ext/async_vips.h +11 -0
- data/ext/callback.c +119 -0
- data/ext/callback.h +9 -0
- data/ext/details.c +54 -0
- data/ext/details.h +15 -0
- data/ext/extconf.rb +18 -0
- data/ext/image.c +66 -0
- data/ext/image.h +13 -0
- data/ext/info.c +42 -0
- data/ext/info.h +8 -0
- data/ext/transform.c +396 -0
- data/ext/transform.h +11 -0
- data/ext/transform_data.c +74 -0
- data/ext/transform_data.h +34 -0
- data/ext/transform_data_fwd.h +6 -0
- data/ext/writer.c +96 -0
- data/ext/writer.h +7 -0
- data/lib/async_vips.rb +5 -0
- data/lib/async_vips/version.rb +3 -0
- metadata +125 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 2fd9bfe82936faf9228063b50fd6b2b77c6941c8
|
4
|
+
data.tar.gz: 73b4f797dd51f56737bdbc5eede0e8a21f730890
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 69c7e4a80904bd8b2b74daedc1270c59d933fecca2a1ace15d49e6e53932ff5226b8e34ce6cfe648e156f460d0ce29bae04f79e252b66c2c32edcb672ecc30d3
|
7
|
+
data.tar.gz: 605dd6ae731af3ade945dcbb47983c9351bd89569d3b5d7e8aa529fe1da9083c54611b951d615f8e736782723547471a39963d06a3a1a166499cb57d9f5f068b
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
addressable (2.3.5)
|
5
|
+
builder (3.2.2)
|
6
|
+
diff-lcs (1.2.5)
|
7
|
+
faraday (0.8.8)
|
8
|
+
multipart-post (~> 1.2.0)
|
9
|
+
git (1.2.6)
|
10
|
+
github_api (0.10.1)
|
11
|
+
addressable
|
12
|
+
faraday (~> 0.8.1)
|
13
|
+
hashie (>= 1.2)
|
14
|
+
multi_json (~> 1.4)
|
15
|
+
nokogiri (~> 1.5.2)
|
16
|
+
oauth2
|
17
|
+
hashie (2.0.5)
|
18
|
+
highline (1.6.20)
|
19
|
+
httpauth (0.2.0)
|
20
|
+
jeweler (1.8.8)
|
21
|
+
builder
|
22
|
+
bundler (~> 1.0)
|
23
|
+
git (>= 1.2.5)
|
24
|
+
github_api (= 0.10.1)
|
25
|
+
highline (>= 1.6.15)
|
26
|
+
nokogiri (= 1.5.10)
|
27
|
+
rake
|
28
|
+
rdoc
|
29
|
+
json (1.8.1)
|
30
|
+
jwt (0.1.8)
|
31
|
+
multi_json (>= 1.5)
|
32
|
+
multi_json (1.8.2)
|
33
|
+
multi_xml (0.5.5)
|
34
|
+
multipart-post (1.2.0)
|
35
|
+
nokogiri (1.5.10)
|
36
|
+
oauth2 (0.9.2)
|
37
|
+
faraday (~> 0.8)
|
38
|
+
httpauth (~> 0.2)
|
39
|
+
jwt (~> 0.1.4)
|
40
|
+
multi_json (~> 1.0)
|
41
|
+
multi_xml (~> 0.5)
|
42
|
+
rack (~> 1.2)
|
43
|
+
rack (1.5.2)
|
44
|
+
rake (10.1.1)
|
45
|
+
rdoc (3.12.2)
|
46
|
+
json (~> 1.4)
|
47
|
+
rspec (2.14.1)
|
48
|
+
rspec-core (~> 2.14.0)
|
49
|
+
rspec-expectations (~> 2.14.0)
|
50
|
+
rspec-mocks (~> 2.14.0)
|
51
|
+
rspec-core (2.14.7)
|
52
|
+
rspec-expectations (2.14.4)
|
53
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
54
|
+
rspec-mocks (2.14.4)
|
55
|
+
|
56
|
+
PLATFORMS
|
57
|
+
ruby
|
58
|
+
|
59
|
+
DEPENDENCIES
|
60
|
+
bundler (~> 1.5)
|
61
|
+
jeweler (~> 1.8)
|
62
|
+
rdoc (~> 3.12)
|
63
|
+
rspec (~> 2.14)
|
data/README.md
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
async-ruby-vips
|
2
|
+
===============
|
3
|
+
|
4
|
+
Non-blocking transformation and image writing in Ruby, powered by VIPS
|
5
|
+
|
6
|
+
## Requirements
|
7
|
+
|
8
|
+
* OS X or Linux
|
9
|
+
* MRI >= 1.9.2
|
10
|
+
* libvips 7.28.x
|
11
|
+
* libexif
|
12
|
+
|
13
|
+
## Prerequisites
|
14
|
+
* On Ubuntu, `apt-get install libvips-dev`, or follow the guidelines at: https://github.com/jcupitt/libvips
|
15
|
+
|
16
|
+
If you installed it from source, make sure:
|
17
|
+
* /usr/local/lib is on your LD_LIBRARY_PATH
|
18
|
+
* /usr/local/bin is on PATH
|
19
|
+
* /usr/local/lib/pkgconfig is on PKG_CONFIG_PATH
|
20
|
+
|
21
|
+
|
22
|
+
## Building
|
23
|
+
* bundle install # to install dependencies
|
24
|
+
* rake gemspec # to generate gemspec file
|
25
|
+
* rake build # to build the gem
|
26
|
+
* rake install # to install the gem
|
27
|
+
|
28
|
+
## Example
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
require 'rubygems'
|
32
|
+
require 'async_vips'
|
33
|
+
include AsyncVips
|
34
|
+
|
35
|
+
|
36
|
+
# Non-blocking scaling of an image:
|
37
|
+
# Allowed symbols are: :load, :scale_x, :scale_y, :save
|
38
|
+
# Wneh called, a function is invoked on a separate native thread.
|
39
|
+
# The callback-proc is invoked on a separate Ruby thread on completion.
|
40
|
+
AsyncVips.transform(:load => srcfile, :scale_x => 800, :save => dstfile) do |img|
|
41
|
+
if(img.error != nil)
|
42
|
+
puts img.error
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Set the number of operations cached by VIPS:
|
47
|
+
AsyncVips.set_cache(100)
|
48
|
+
|
49
|
+
# Get image information:
|
50
|
+
# Allowed symbols are: :load
|
51
|
+
AsyncVips.info(:load => srcfile) do |img|
|
52
|
+
puts img.src # image filepath
|
53
|
+
puts img.width # image width
|
54
|
+
puts img.height # image height
|
55
|
+
puts img.size # image size in bytes
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
## Using event machine
|
60
|
+
|
61
|
+
require 'rubygems'
|
62
|
+
require 'async_vips'
|
63
|
+
require 'eventmachine'
|
64
|
+
include AsyncVips
|
65
|
+
|
66
|
+
#puts AsyncVips::VERSION
|
67
|
+
#puts AsyncVips::LIB_VERSION
|
68
|
+
AsyncVips.set_cache(0) # sets the number of operations cached by VIPS
|
69
|
+
|
70
|
+
EM.run do
|
71
|
+
|
72
|
+
EM.add_timer(3) do
|
73
|
+
source = './images/*.JPG'
|
74
|
+
files = Dir[source]
|
75
|
+
files.each do |srcfile|
|
76
|
+
dstfile = './output/'+File.basename(srcfile)
|
77
|
+
|
78
|
+
AsyncVips.transform(:load => srcfile, :scale_x => 800, :save => dstfile) do |img|
|
79
|
+
puts img.src
|
80
|
+
if(img.error != nil)
|
81
|
+
puts img.error
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
EM.add_periodic_timer(1) do
|
89
|
+
puts "#{Time.now}"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
|
94
|
+
```ruby
|
95
|
+
|
96
|
+
|
97
|
+
## Version history
|
98
|
+
|
99
|
+
### 1.2.1 - added support for natural_orientation flag
|
100
|
+
### 1.1.0 - shrink operation
|
101
|
+
### 1.0.0 - initial release
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
# stub: async-ruby-vips 1.2.1 ruby lib
|
6
|
+
# stub: ext/extconf.rb
|
7
|
+
|
8
|
+
Gem::Specification.new do |s|
|
9
|
+
s.name = "async-ruby-vips"
|
10
|
+
s.version = "1.2.1"
|
11
|
+
|
12
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
13
|
+
s.require_paths = ["lib"]
|
14
|
+
s.authors = ["Grigoriy Chudnov"]
|
15
|
+
s.date = "2014-01-27"
|
16
|
+
s.description = "Non-blocking transformation and image writing in Ruby, powered by VIPS."
|
17
|
+
s.email = "g.chudnov@gmail.com"
|
18
|
+
s.extensions = ["ext/extconf.rb"]
|
19
|
+
s.extra_rdoc_files = [
|
20
|
+
"README.md"
|
21
|
+
]
|
22
|
+
s.files = [
|
23
|
+
"Gemfile.lock",
|
24
|
+
"README.md",
|
25
|
+
"async-ruby-vips.gemspec",
|
26
|
+
"ext/LICENSE",
|
27
|
+
"ext/async_vips.c",
|
28
|
+
"ext/async_vips.h",
|
29
|
+
"ext/callback.c",
|
30
|
+
"ext/callback.h",
|
31
|
+
"ext/details.c",
|
32
|
+
"ext/details.h",
|
33
|
+
"ext/extconf.rb",
|
34
|
+
"ext/image.c",
|
35
|
+
"ext/image.h",
|
36
|
+
"ext/info.c",
|
37
|
+
"ext/info.h",
|
38
|
+
"ext/transform.c",
|
39
|
+
"ext/transform.h",
|
40
|
+
"ext/transform_data.c",
|
41
|
+
"ext/transform_data.h",
|
42
|
+
"ext/transform_data_fwd.h",
|
43
|
+
"ext/writer.c",
|
44
|
+
"ext/writer.h",
|
45
|
+
"lib/async_vips.rb",
|
46
|
+
"lib/async_vips/version.rb"
|
47
|
+
]
|
48
|
+
s.homepage = "https://github.com/gchudnov/async-ruby-vips"
|
49
|
+
s.licenses = ["MIT"]
|
50
|
+
s.rubygems_version = "2.2.1"
|
51
|
+
s.summary = "async-ruby-vips is a ruby extension for vips that transforms images asynchronously."
|
52
|
+
|
53
|
+
if s.respond_to? :specification_version then
|
54
|
+
s.specification_version = 4
|
55
|
+
|
56
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
57
|
+
s.add_development_dependency(%q<rdoc>, ["~> 3.12"])
|
58
|
+
s.add_development_dependency(%q<bundler>, ["~> 1.5"])
|
59
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.8"])
|
60
|
+
s.add_development_dependency(%q<rspec>, ["~> 2.14"])
|
61
|
+
else
|
62
|
+
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
63
|
+
s.add_dependency(%q<bundler>, ["~> 1.5"])
|
64
|
+
s.add_dependency(%q<jeweler>, ["~> 1.8"])
|
65
|
+
s.add_dependency(%q<rspec>, ["~> 2.14"])
|
66
|
+
end
|
67
|
+
else
|
68
|
+
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
69
|
+
s.add_dependency(%q<bundler>, ["~> 1.5"])
|
70
|
+
s.add_dependency(%q<jeweler>, ["~> 1.8"])
|
71
|
+
s.add_dependency(%q<rspec>, ["~> 2.14"])
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
data/ext/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2012 Grigoriy Chudnov
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/ext/async_vips.c
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
#include "async_vips.h"
|
2
|
+
#include "transform.h"
|
3
|
+
#include "writer.h"
|
4
|
+
#include "callback.h"
|
5
|
+
#include "image.h"
|
6
|
+
#include "info.h"
|
7
|
+
|
8
|
+
VALUE mAsyncVips, eVipsError;
|
9
|
+
|
10
|
+
/* Initialize VIPS library */
|
11
|
+
void av_init()
|
12
|
+
{
|
13
|
+
VALUE argv_0 = rb_gv_get("0");
|
14
|
+
|
15
|
+
if(NIL_P(argv_0))
|
16
|
+
vips_init("");
|
17
|
+
else
|
18
|
+
vips_init(RSTRING_PTR(argv_0));
|
19
|
+
}
|
20
|
+
|
21
|
+
/* Print internal debugging information from VIPS, including memory allocation information. */
|
22
|
+
static VALUE av_debug_info(VALUE self)
|
23
|
+
{
|
24
|
+
vips_object_print_all();
|
25
|
+
return Qnil;
|
26
|
+
}
|
27
|
+
|
28
|
+
/* Set the max number of operations to keep in cache. */
|
29
|
+
static VALUE av_set_cache(VALUE self, VALUE val)
|
30
|
+
{
|
31
|
+
vips_cache_set_max(NUM2INT(val));
|
32
|
+
return Qnil;
|
33
|
+
}
|
34
|
+
|
35
|
+
/* Get the version string */
|
36
|
+
static VALUE av_version_string()
|
37
|
+
{
|
38
|
+
return rb_str_new2(vips_version_string());
|
39
|
+
}
|
40
|
+
|
41
|
+
/* Copy error from vips */
|
42
|
+
char* copy_vips_error(void)
|
43
|
+
{
|
44
|
+
char* result = NULL;
|
45
|
+
const char* err_str = vips_error_buffer();
|
46
|
+
if(err_str && strlen(err_str) > 0)
|
47
|
+
{
|
48
|
+
result = malloc(strlen(err_str) + 1);
|
49
|
+
strcpy(result, err_str);
|
50
|
+
im_error_clear();
|
51
|
+
}
|
52
|
+
|
53
|
+
return result;
|
54
|
+
}
|
55
|
+
|
56
|
+
/* Initialize extension */
|
57
|
+
void Init_async_vips_ext()
|
58
|
+
{
|
59
|
+
av_init();
|
60
|
+
|
61
|
+
mAsyncVips = rb_define_module("AsyncVips");
|
62
|
+
eVipsError = rb_define_class_under(mAsyncVips, "Error", rb_eStandardError);
|
63
|
+
|
64
|
+
rb_define_singleton_method(mAsyncVips, "debug_info", av_debug_info, 0);
|
65
|
+
rb_define_singleton_method(mAsyncVips, "set_cache", av_set_cache, 1);
|
66
|
+
rb_define_const(mAsyncVips, "LIB_VERSION", av_version_string());
|
67
|
+
|
68
|
+
//
|
69
|
+
init_async_vips_transform();
|
70
|
+
init_async_vips_image();
|
71
|
+
init_async_vips_info();
|
72
|
+
init_async_vips_event_thread();
|
73
|
+
}
|
data/ext/async_vips.h
ADDED
data/ext/callback.c
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
#include "callback.h"
|
2
|
+
#include "async_vips.h"
|
3
|
+
#include "image.h"
|
4
|
+
#include "transform_data.h"
|
5
|
+
#include <pthread.h>
|
6
|
+
|
7
|
+
|
8
|
+
typedef struct _tdata_wait_t
|
9
|
+
{
|
10
|
+
transform_data_t* tdata;
|
11
|
+
int abort;
|
12
|
+
} tdata_wait_t;
|
13
|
+
|
14
|
+
|
15
|
+
/* Queue of callbacks; each one invoked on a ruby thread */
|
16
|
+
pthread_mutex_t av_proc_mutex = PTHREAD_MUTEX_INITIALIZER;
|
17
|
+
pthread_cond_t av_proc_cond = PTHREAD_COND_INITIALIZER;
|
18
|
+
transform_data_t* av_proc_queue = NULL;
|
19
|
+
|
20
|
+
/* Push new callback to front of the queue */
|
21
|
+
static void av_proc_queue_push(transform_data_t* tdata)
|
22
|
+
{
|
23
|
+
tdata->next = av_proc_queue;
|
24
|
+
av_proc_queue = tdata;
|
25
|
+
}
|
26
|
+
|
27
|
+
/* Pop next callback from the queue; Returns NULL, when the queue is empty */
|
28
|
+
static transform_data_t* av_proc_queue_pop(void)
|
29
|
+
{
|
30
|
+
transform_data_t* tdata = av_proc_queue;
|
31
|
+
if(tdata)
|
32
|
+
{
|
33
|
+
av_proc_queue = tdata->next;
|
34
|
+
}
|
35
|
+
|
36
|
+
return tdata;
|
37
|
+
}
|
38
|
+
|
39
|
+
/* Callback executed by Ruby Thread */
|
40
|
+
static VALUE av_handle_proc(void *d)
|
41
|
+
{
|
42
|
+
transform_data_t* tdata = (transform_data_t*)d;
|
43
|
+
|
44
|
+
// Invoke callback with task argument
|
45
|
+
VALUE proc = (VALUE)tdata->proc;
|
46
|
+
VALUE img = rb_class_new_instance(0, NULL, cImage);
|
47
|
+
|
48
|
+
av_image_init(img, tdata);
|
49
|
+
rb_funcall2(proc, rb_intern("call"), 1, &img);
|
50
|
+
rb_gc_unregister_address(&tdata->proc);
|
51
|
+
|
52
|
+
av_free_transform_data(tdata);
|
53
|
+
|
54
|
+
return Qnil;
|
55
|
+
}
|
56
|
+
|
57
|
+
|
58
|
+
/* Wait until we have some callbacks to process */
|
59
|
+
static VALUE av_wait_for_tdata(void* w)
|
60
|
+
{
|
61
|
+
tdata_wait_t* waiter = (tdata_wait_t*)w;
|
62
|
+
|
63
|
+
pthread_mutex_lock(&av_proc_mutex);
|
64
|
+
while (!waiter->abort && (waiter->tdata = av_proc_queue_pop()) == NULL)
|
65
|
+
{
|
66
|
+
pthread_cond_wait(&av_proc_cond, &av_proc_mutex);
|
67
|
+
}
|
68
|
+
pthread_mutex_unlock(&av_proc_mutex);
|
69
|
+
|
70
|
+
return Qnil;
|
71
|
+
}
|
72
|
+
|
73
|
+
/* Stop waiting for callbacks */
|
74
|
+
static void av_stop_waiting_for_tdata(void* w)
|
75
|
+
{
|
76
|
+
tdata_wait_t* waiter = (tdata_wait_t*)w;
|
77
|
+
|
78
|
+
pthread_mutex_lock(&av_proc_mutex);
|
79
|
+
waiter->abort = 1;
|
80
|
+
pthread_mutex_unlock(&av_proc_mutex);
|
81
|
+
pthread_cond_signal(&av_proc_cond);
|
82
|
+
}
|
83
|
+
|
84
|
+
|
85
|
+
/* ruby event thread, waiting for processed transformations (invokes callbacks) */
|
86
|
+
static VALUE av_event_thread(void *unused)
|
87
|
+
{
|
88
|
+
tdata_wait_t waiter = { .tdata = NULL, .abort = 0 };
|
89
|
+
while (!waiter.abort)
|
90
|
+
{
|
91
|
+
rb_thread_blocking_region(av_wait_for_tdata, &waiter, av_stop_waiting_for_tdata, &waiter);
|
92
|
+
if (waiter.tdata)
|
93
|
+
{
|
94
|
+
rb_thread_create(av_handle_proc, waiter.tdata);
|
95
|
+
}
|
96
|
+
}
|
97
|
+
|
98
|
+
return Qnil;
|
99
|
+
}
|
100
|
+
|
101
|
+
/* Initialize Ruby Event Thread for invokation of user-provider callbacks */
|
102
|
+
static void av_create_event_thread(void)
|
103
|
+
{
|
104
|
+
rb_thread_create(av_event_thread, NULL);
|
105
|
+
}
|
106
|
+
|
107
|
+
/* Add the transform data to the event queue */
|
108
|
+
void av_add_to_event_queue(transform_data_t* tdata)
|
109
|
+
{
|
110
|
+
pthread_mutex_lock(&av_proc_mutex);
|
111
|
+
av_proc_queue_push(tdata);
|
112
|
+
pthread_mutex_unlock(&av_proc_mutex);
|
113
|
+
pthread_cond_signal(&av_proc_cond);
|
114
|
+
}
|
115
|
+
|
116
|
+
void init_async_vips_event_thread(void)
|
117
|
+
{
|
118
|
+
av_create_event_thread();
|
119
|
+
}
|