devil 0.1.9.5-i386-mswin32
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/CHANGELOG +112 -0
- data/LICENSE +21 -0
- data/README +52 -0
- data/Rakefile +55 -0
- data/ext/devil/extconf.rb +23 -0
- data/ext/devil/ruby_devil_ext.c +9 -0
- data/ext/devil/ruby_devil_ext.h +8 -0
- data/ext/devil/ruby_il.c +546 -0
- data/ext/devil/ruby_ilu.c +228 -0
- data/lib/1.8/devil.so +0 -0
- data/lib/1.9/devil.so +0 -0
- data/lib/devil.rb +547 -0
- data/lib/devil/gosu.rb +122 -0
- data/lib/devil/version.rb +3 -0
- data/test/red.png +0 -0
- data/test/tank.png +0 -0
- data/test/test_blank.rb +21 -0
- data/test/test_blit.rb +21 -0
- data/test/test_clone_and_crop.rb +28 -0
- data/test/test_gosu_load.rb +23 -0
- data/test/test_gosu_roundtrip.rb +29 -0
- data/test/test_gosu_save.rb +26 -0
- data/test/test_gosu_show.rb +10 -0
- data/test/test_group.rb +18 -0
- data/test/test_ilut.rb +95 -0
- data/test/test_new_api.rb +28 -0
- data/test/test_profile.rb +8 -0
- data/test/test_quality.rb +9 -0
- data/test/test_scale_algos.rb +30 -0
- data/test/test_screenshot.rb +33 -0
- data/test/test_thumbnail.rb +13 -0
- data/test/texture.jpg +0 -0
- data/test/texture.png +0 -0
- data/test/texture_out1.jpg +0 -0
- data/test/texture_out2.jpg +0 -0
- data/test/thumb.png +0 -0
- metadata +101 -0
@@ -0,0 +1,228 @@
|
|
1
|
+
#include <ruby.h>
|
2
|
+
#include <IL/ilu.h>
|
3
|
+
#include "ruby_devil_ext.h"
|
4
|
+
|
5
|
+
static VALUE mILU;
|
6
|
+
|
7
|
+
static VALUE ilu_Init(VALUE obj) {
|
8
|
+
iluInit();
|
9
|
+
return Qnil;
|
10
|
+
}
|
11
|
+
|
12
|
+
static VALUE ilu_ErrorString(VALUE obj, VALUE rb_error) {
|
13
|
+
ILenum num = NUM2INT(rb_error);
|
14
|
+
const char* error = iluErrorString(num);
|
15
|
+
return rb_str_new2(error);
|
16
|
+
}
|
17
|
+
|
18
|
+
static VALUE ilu_Alienify(VALUE obj) {
|
19
|
+
ILboolean flag = iluAlienify();
|
20
|
+
return flag ? Qtrue : Qfalse;
|
21
|
+
}
|
22
|
+
|
23
|
+
static VALUE ilu_BlurAvg(VALUE obj, VALUE rb_iter) {
|
24
|
+
ILuint iter = NUM2INT(rb_iter);
|
25
|
+
ILboolean flag = iluBlurAvg(iter);
|
26
|
+
return flag ? Qtrue : Qfalse;
|
27
|
+
}
|
28
|
+
|
29
|
+
static VALUE ilu_BlurGaussian(VALUE obj, VALUE rb_iter) {
|
30
|
+
ILuint iter = NUM2INT(rb_iter);
|
31
|
+
ILboolean flag = iluBlurGaussian(iter);
|
32
|
+
return flag ? Qtrue : Qfalse;
|
33
|
+
}
|
34
|
+
|
35
|
+
static VALUE ilu_Contrast(VALUE obj, VALUE rb_cont) {
|
36
|
+
ILfloat cont = NUM2DBL(rb_cont);
|
37
|
+
ILboolean flag = iluContrast(cont);
|
38
|
+
return flag ? Qtrue : Qfalse;
|
39
|
+
}
|
40
|
+
|
41
|
+
static VALUE ilu_Equalize(VALUE obj) {
|
42
|
+
ILboolean flag = iluEqualize();
|
43
|
+
return flag ? Qtrue : Qfalse;
|
44
|
+
}
|
45
|
+
|
46
|
+
static VALUE ilu_GammaCorrect (VALUE obj, VALUE rb_gamma) {
|
47
|
+
ILfloat gamma = NUM2DBL(rb_gamma);
|
48
|
+
ILboolean flag = iluGammaCorrect(gamma);
|
49
|
+
return flag ? Qtrue : Qfalse;
|
50
|
+
}
|
51
|
+
static VALUE ilu_Negative (VALUE obj) {
|
52
|
+
ILboolean flag = iluNegative();
|
53
|
+
return flag ? Qtrue : Qfalse;
|
54
|
+
}
|
55
|
+
static VALUE ilu_Noisify (VALUE obj, VALUE rb_tolerance) {
|
56
|
+
ILclampf tolerance = NUM2DBL(rb_tolerance);
|
57
|
+
ILboolean flag = iluNoisify(tolerance);
|
58
|
+
return flag ? Qtrue : Qfalse;
|
59
|
+
}
|
60
|
+
static VALUE ilu_Pixelize (VALUE obj, VALUE rb_pix_size) {
|
61
|
+
ILuint pix = NUM2INT(rb_pix_size);
|
62
|
+
ILboolean flag = iluPixelize(pix);
|
63
|
+
return flag ? Qtrue : Qfalse;
|
64
|
+
}
|
65
|
+
static VALUE ilu_Sharpen (VALUE obj, VALUE rb_factor, VALUE rb_iter) {
|
66
|
+
ILfloat factor = NUM2DBL(rb_factor);
|
67
|
+
ILuint iter = NUM2INT(rb_iter);
|
68
|
+
ILboolean flag = iluSharpen(factor, iter);
|
69
|
+
return flag ? Qtrue : Qfalse;
|
70
|
+
}
|
71
|
+
|
72
|
+
static VALUE ilu_Scale(VALUE obj, VALUE rb_Width, VALUE rb_Height, VALUE rb_Depth) {
|
73
|
+
ILuint Width = NUM2INT(rb_Width);
|
74
|
+
ILuint Height = NUM2INT(rb_Height);
|
75
|
+
ILuint Depth = NUM2INT(rb_Depth);
|
76
|
+
ILboolean flag = iluScale(Width, Height, Depth);
|
77
|
+
return flag ? Qtrue : Qfalse;
|
78
|
+
}
|
79
|
+
|
80
|
+
static VALUE ilu_ImageParameter(VALUE obj, VALUE rb_PName, VALUE rb_Param) {
|
81
|
+
ILenum PName = NUM2INT(rb_PName);
|
82
|
+
ILenum Param = NUM2INT(rb_Param);
|
83
|
+
iluImageParameter(PName, Param);
|
84
|
+
return Qnil;
|
85
|
+
}
|
86
|
+
|
87
|
+
static VALUE ilu_BuildMipmaps(VALUE obj) {
|
88
|
+
ILboolean flag = iluBuildMipmaps();
|
89
|
+
return flag ? Qtrue : Qfalse;
|
90
|
+
}
|
91
|
+
|
92
|
+
/* functions added by banisterfiend */
|
93
|
+
static VALUE ilu_FlipImage(VALUE obj) {
|
94
|
+
ILboolean flag = iluFlipImage();
|
95
|
+
return flag ? Qtrue : Qfalse;
|
96
|
+
}
|
97
|
+
|
98
|
+
static VALUE ilu_Rotate(VALUE obj, VALUE rb_angle) {
|
99
|
+
ILfloat angle = NUM2DBL(rb_angle);
|
100
|
+
|
101
|
+
ILboolean flag = iluRotate(angle);
|
102
|
+
|
103
|
+
return flag ? Qtrue : Qfalse;
|
104
|
+
}
|
105
|
+
|
106
|
+
static VALUE ilu_Crop(VALUE obj, VALUE rb_XOff, VALUE rb_YOff, VALUE rb_ZOff, VALUE rb_width, VALUE rb_height, VALUE rb_depth)
|
107
|
+
{
|
108
|
+
ILuint XOff = NUM2INT(rb_XOff);
|
109
|
+
ILuint YOff = NUM2INT(rb_YOff);
|
110
|
+
ILuint ZOff = NUM2INT(rb_ZOff);
|
111
|
+
ILuint width = NUM2INT(rb_width);
|
112
|
+
ILuint height = NUM2INT(rb_height);
|
113
|
+
ILuint depth = NUM2INT(rb_depth);
|
114
|
+
|
115
|
+
ILboolean flag = iluCrop(XOff, YOff, ZOff, width, height, depth);
|
116
|
+
|
117
|
+
return flag ? Qtrue : Qfalse;
|
118
|
+
}
|
119
|
+
|
120
|
+
static VALUE ilu_EnlargeCanvas(VALUE obj, VALUE rb_width, VALUE rb_height, VALUE rb_depth)
|
121
|
+
{
|
122
|
+
ILuint width = NUM2INT(rb_width);
|
123
|
+
ILuint height = NUM2INT(rb_height);
|
124
|
+
ILuint depth = NUM2INT(rb_depth);
|
125
|
+
|
126
|
+
ILboolean flag = iluEnlargeCanvas(width, height, depth);
|
127
|
+
|
128
|
+
return flag ? Qtrue : Qfalse;
|
129
|
+
}
|
130
|
+
|
131
|
+
static VALUE ilu_EdgeDetectP(VALUE obj)
|
132
|
+
{
|
133
|
+
ILboolean flag = iluEdgeDetectP();
|
134
|
+
|
135
|
+
return flag ? Qtrue : Qfalse;
|
136
|
+
}
|
137
|
+
|
138
|
+
static VALUE ilu_EdgeDetectS(VALUE obj)
|
139
|
+
{
|
140
|
+
ILboolean flag = iluEdgeDetectS();
|
141
|
+
|
142
|
+
return flag ? Qtrue : Qfalse;
|
143
|
+
}
|
144
|
+
|
145
|
+
static VALUE ilu_Emboss(VALUE obj)
|
146
|
+
{
|
147
|
+
ILboolean flag = iluEmboss();
|
148
|
+
|
149
|
+
return flag ? Qtrue : Qfalse;
|
150
|
+
}
|
151
|
+
|
152
|
+
static VALUE ilu_Mirror(VALUE obj)
|
153
|
+
{
|
154
|
+
ILboolean flag = iluMirror();
|
155
|
+
|
156
|
+
return flag ? Qtrue : Qfalse;
|
157
|
+
}
|
158
|
+
|
159
|
+
static VALUE ilu_SwapColours(VALUE obj)
|
160
|
+
{
|
161
|
+
ILboolean flag = iluSwapColours();
|
162
|
+
|
163
|
+
return flag ? Qtrue : Qfalse;
|
164
|
+
}
|
165
|
+
|
166
|
+
static VALUE ilu_CompareImage(VALUE obj, VALUE rb_cmp_img)
|
167
|
+
{
|
168
|
+
ILuint cmp_img = NUM2INT(rb_cmp_img);
|
169
|
+
|
170
|
+
ILboolean flag = iluCompareImage(rb_cmp_img);
|
171
|
+
|
172
|
+
return flag ? Qtrue : Qfalse;
|
173
|
+
}
|
174
|
+
/* end of functions added by banisterfiend */
|
175
|
+
|
176
|
+
void
|
177
|
+
InitializeILU() {
|
178
|
+
mILU = rb_define_module("ILU");
|
179
|
+
rb_define_module_function(mILU, "Init", ilu_Init, 0);
|
180
|
+
rb_define_module_function(mILU, "ErrorString", ilu_ErrorString, 1);
|
181
|
+
rb_define_module_function(mILU, "Alienify", ilu_Alienify, 0);
|
182
|
+
rb_define_module_function(mILU, "BlurAvg", ilu_BlurAvg, 1);
|
183
|
+
rb_define_module_function(mILU, "BlurGaussian", ilu_BlurGaussian, 1);
|
184
|
+
rb_define_module_function(mILU, "Contrast",ilu_Contrast , 1);
|
185
|
+
rb_define_module_function(mILU, "Equalize",ilu_Equalize , 0);
|
186
|
+
rb_define_module_function(mILU, "GammaCorrect",ilu_GammaCorrect , 1);
|
187
|
+
rb_define_module_function(mILU, "Negative", ilu_Negative , 0);
|
188
|
+
rb_define_module_function(mILU, "Noisify", ilu_Noisify , 1);
|
189
|
+
rb_define_module_function(mILU, "Pixelize", ilu_Pixelize , 1);
|
190
|
+
rb_define_module_function(mILU, "Sharpen", ilu_Sharpen, 2);
|
191
|
+
rb_define_module_function(mILU, "Scale", ilu_Scale , 3);
|
192
|
+
rb_define_module_function(mILU, "ImageParameter", ilu_ImageParameter , 2);
|
193
|
+
rb_define_module_function(mILU, "BuildMipmaps", ilu_BuildMipmaps, 0);
|
194
|
+
|
195
|
+
/* methods added by banisterfiend */
|
196
|
+
rb_define_module_function(mILU, "FlipImage", ilu_FlipImage, 0);
|
197
|
+
rb_define_module_function(mILU, "Rotate", ilu_Rotate, 1);
|
198
|
+
rb_define_module_function(mILU, "Crop", ilu_Crop, 6);
|
199
|
+
rb_define_module_function(mILU, "EnlargeCanvas", ilu_EnlargeCanvas, 3);
|
200
|
+
rb_define_module_function(mILU, "EdgeDetectP", ilu_EdgeDetectP, 0);
|
201
|
+
rb_define_module_function(mILU, "EdgeDetectS", ilu_EdgeDetectS, 0);
|
202
|
+
rb_define_module_function(mILU, "Emboss", ilu_Emboss, 0);
|
203
|
+
rb_define_module_function(mILU, "Mirror", ilu_Mirror, 0);
|
204
|
+
rb_define_module_function(mILU, "SwapColours", ilu_SwapColours, 0);
|
205
|
+
rb_define_module_function(mILU, "CompareImage", ilu_CompareImage, 1);
|
206
|
+
/* end of functions added by banisterfiend */
|
207
|
+
|
208
|
+
/* constants added by banisterfiend */
|
209
|
+
rb_define_const(mILU, "FILTER", INT2NUM(ILU_FILTER));
|
210
|
+
rb_define_const(mILU, "NEAREST", INT2NUM(ILU_NEAREST));
|
211
|
+
rb_define_const(mILU, "LINEAR", INT2NUM(ILU_LINEAR));
|
212
|
+
rb_define_const(mILU, "BILINEAR", INT2NUM(ILU_BILINEAR));
|
213
|
+
rb_define_const(mILU, "SCALE_BOX", INT2NUM(ILU_SCALE_BOX));
|
214
|
+
rb_define_const(mILU, "SCALE_TRIANGLE", INT2NUM(ILU_SCALE_TRIANGLE));
|
215
|
+
rb_define_const(mILU, "SCALE_BELL", INT2NUM(ILU_SCALE_BELL));
|
216
|
+
rb_define_const(mILU, "SCALE_BSPLINE", INT2NUM(ILU_SCALE_BSPLINE));
|
217
|
+
rb_define_const(mILU, "SCALE_LANCZOS3", INT2NUM(ILU_SCALE_LANCZOS3));
|
218
|
+
rb_define_const(mILU, "SCALE_MITCHELL", INT2NUM(ILU_SCALE_MITCHELL));
|
219
|
+
|
220
|
+
rb_define_const(mILU, "PLACEMENT", INT2NUM(ILU_PLACEMENT));
|
221
|
+
rb_define_const(mILU, "UPPER_LEFT", INT2NUM(ILU_UPPER_LEFT));
|
222
|
+
rb_define_const(mILU, "LOWER_LEFT", INT2NUM(ILU_LOWER_LEFT));
|
223
|
+
rb_define_const(mILU, "LOWER_RIGHT", INT2NUM(ILU_LOWER_RIGHT));
|
224
|
+
rb_define_const(mILU, "UPPER_RIGHT", INT2NUM(ILU_UPPER_RIGHT));
|
225
|
+
rb_define_const(mILU, "CENTER", INT2NUM(ILU_CENTER));
|
226
|
+
/* end of constants added by banisterfiend */
|
227
|
+
|
228
|
+
}
|
data/lib/1.8/devil.so
ADDED
Binary file
|
data/lib/1.9/devil.so
ADDED
Binary file
|
data/lib/devil.rb
ADDED
@@ -0,0 +1,547 @@
|
|
1
|
+
# (C) John Mair 2009, under the MIT licence
|
2
|
+
|
3
|
+
require 'rbconfig'
|
4
|
+
|
5
|
+
direc = File.dirname(__FILE__)
|
6
|
+
dlext = Config::CONFIG['DLEXT']
|
7
|
+
|
8
|
+
begin
|
9
|
+
if RUBY_VERSION && RUBY_VERSION =~ /1.9/
|
10
|
+
require "#{direc}/1.9/devil.#{dlext}"
|
11
|
+
else
|
12
|
+
require "#{direc}/1.8/devil.#{dlext}"
|
13
|
+
end
|
14
|
+
rescue LoadError => e
|
15
|
+
require "#{direc}/devil.#{dlext}"
|
16
|
+
end
|
17
|
+
require "#{direc}/devil/version"
|
18
|
+
|
19
|
+
# Provides a high level wrapper for the low-level DevIL Ruby bindings
|
20
|
+
module Devil
|
21
|
+
include IL
|
22
|
+
include ILU
|
23
|
+
|
24
|
+
class << self
|
25
|
+
|
26
|
+
# loads +file+ and returns a new image
|
27
|
+
# Optionally accepts a block and yields the newly created image to the block.
|
28
|
+
def load_image(file, options={}, &block)
|
29
|
+
name = prepare_image
|
30
|
+
attach_image_from_file(file)
|
31
|
+
|
32
|
+
out_profile = options[:out_profile]
|
33
|
+
in_profile = options[:in_profile]
|
34
|
+
|
35
|
+
# apply a color profile if one is provided
|
36
|
+
IL.ApplyProfile(in_profile, out_profile) if out_profile
|
37
|
+
|
38
|
+
check_and_run_hook(:load_image_hook)
|
39
|
+
error_check
|
40
|
+
wrap_and_yield(name, file, block)
|
41
|
+
end
|
42
|
+
|
43
|
+
alias_method :with_image, :load_image
|
44
|
+
alias_method :load, :load_image
|
45
|
+
|
46
|
+
# returns a blank image of +width+ and +height+.
|
47
|
+
# Optionally accepts the :color hash param that fills the new image with a color
|
48
|
+
# (see: Devil.set_options :clear_color)
|
49
|
+
# Optionally accepts a block and yields the newly created image to the block.
|
50
|
+
def create_image(width, height, options={}, &block)
|
51
|
+
name = prepare_image
|
52
|
+
out_profile = options[:out_profile]
|
53
|
+
in_profile = options[:in_profile]
|
54
|
+
|
55
|
+
clear_color = options[:color]
|
56
|
+
|
57
|
+
# created image is formatted RGBA8
|
58
|
+
IL.TexImage(width, height, 1, 4, IL::RGBA, IL::UNSIGNED_BYTE, nil)
|
59
|
+
|
60
|
+
# apply a color profile if one is provided
|
61
|
+
IL.ApplyProfile(in_profile, out_profile) if out_profile
|
62
|
+
|
63
|
+
IL.ClearColour(*clear_color) if clear_color
|
64
|
+
IL.ClearImage
|
65
|
+
IL.ClearColour(*Devil.get_options[:clear_color]) if clear_color
|
66
|
+
|
67
|
+
check_and_run_hook(:create_image_hook)
|
68
|
+
error_check
|
69
|
+
wrap_and_yield(name, nil, block)
|
70
|
+
end
|
71
|
+
|
72
|
+
alias_method :create_blank_image, :create_image
|
73
|
+
|
74
|
+
# load multiple images and yield them to the block
|
75
|
+
# e.g Devil.with_group("hello.png", "friend.png") { |img1, img2| ... }
|
76
|
+
# all yielded images are cleaned up at end of block so you do not need to
|
77
|
+
# explictly call img1.free
|
78
|
+
def with_group(*files, &block)
|
79
|
+
images = files.map do |file|
|
80
|
+
name = prepare_image
|
81
|
+
attach_image_from_file(file)
|
82
|
+
check_and_run_hook(:load_image_hook)
|
83
|
+
error_check
|
84
|
+
|
85
|
+
Image.new(name, file)
|
86
|
+
end
|
87
|
+
|
88
|
+
if block
|
89
|
+
begin
|
90
|
+
block.call(*images)
|
91
|
+
ensure
|
92
|
+
images.each { |img| img.free if img.name }
|
93
|
+
end
|
94
|
+
else
|
95
|
+
raise RuntimeError, "a block must be provided."
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
alias_method :with_images, :with_group
|
100
|
+
|
101
|
+
# convert an image +blob+ with +width+ and +height+
|
102
|
+
# to a bona fide image
|
103
|
+
def from_blob(blob, width, height)
|
104
|
+
|
105
|
+
# try to convert automatically from array to packed string
|
106
|
+
# if passed an array
|
107
|
+
blob = blob.pack("C*") if blob.instance_of?(Array)
|
108
|
+
|
109
|
+
Image.new(IL.FromBlob(blob, width, height), nil)
|
110
|
+
end
|
111
|
+
|
112
|
+
# configure Devil.
|
113
|
+
# accepts hash parameters: :scale_filter, :placement, :clear_color,
|
114
|
+
# :window_size, :edge_filter.
|
115
|
+
#
|
116
|
+
# :scale_filter accepts a valid scaling algorithm: (default is LANCZOS3).
|
117
|
+
# Devil::NEAREST, Devil::LINEAR, Devil::BILINEAR, Devil::SCALE_BOX,
|
118
|
+
# Devil::SCALE_TRIANGLE, Devil::SCALE_BELL, Devil::SCALE_BSPLINE,
|
119
|
+
# Devil::SCALE_LANCZOS3, Devil::SCALE_MITCHELL
|
120
|
+
#
|
121
|
+
# :placement determines where in the canvas the image will be placed after
|
122
|
+
# the canvas has been enlarged using the 'enlarge_canvas' method.
|
123
|
+
# Valid parameters are: Devil::CENTER, Devil::LOWER_LEFT, Devil::UPPER_RIGHT, etc
|
124
|
+
#
|
125
|
+
# :clear_color sets the current clearing colour to be used by future
|
126
|
+
# calls to clear. rotate and enlarge_canvas both use these values to
|
127
|
+
# clear blank space in images, too.
|
128
|
+
# e.g Devil.set_options(:clear_color => [255, 255, 0, 255])
|
129
|
+
# Above sets the clear color to yellow with full opacity.
|
130
|
+
#
|
131
|
+
# :window_size sets the display window size Gosu will use when displaying images
|
132
|
+
# that invoked the 'show' method. (default is 1024 x 768)
|
133
|
+
# e.g Devil.set_options(:window_size => [2000, 768])
|
134
|
+
# Example above sets a window size of 2000x768.
|
135
|
+
# Note: :window_size is only relevant when require 'devil/gosu' is used.
|
136
|
+
#
|
137
|
+
# :edge_filter sets the edge detection algorithm to use when invoking
|
138
|
+
# the 'edge_detect' method. (defaults to :prewitt)
|
139
|
+
# Allowed values are :prewitt and :sobel
|
140
|
+
#
|
141
|
+
# hooks:
|
142
|
+
# :prepare_image_hook, :create_image_hook, :load_image_hook
|
143
|
+
# e.g Devil.set_options :load_image_hook => proc { IL::ConvertImage(IL::RGBA, IL::UNSIGNED_BYTE) }
|
144
|
+
def set_options(options={})
|
145
|
+
@options.merge!(options)
|
146
|
+
|
147
|
+
# update the config. options
|
148
|
+
ILU.ImageParameter(ILU::FILTER, @options[:scale_filter])
|
149
|
+
ILU.ImageParameter(ILU::PLACEMENT, @options[:placement])
|
150
|
+
IL.SetInteger(IL::JPG_QUALITY, @options[:jpg_quality])
|
151
|
+
IL.ClearColour(*@options[:clear_color])
|
152
|
+
end
|
153
|
+
|
154
|
+
# return the current Devil configuration.
|
155
|
+
def get_options
|
156
|
+
@options
|
157
|
+
end
|
158
|
+
|
159
|
+
# initializes Devil and sets defaults.
|
160
|
+
# This method should never need to be called directly.
|
161
|
+
def init
|
162
|
+
# initialize DevIL
|
163
|
+
IL.Init
|
164
|
+
ILU.Init
|
165
|
+
|
166
|
+
set_defaults
|
167
|
+
end
|
168
|
+
|
169
|
+
# restore Devil's default configuration.
|
170
|
+
def set_defaults
|
171
|
+
@options = {
|
172
|
+
:scale_filter => ILU::SCALE_LANCZOS3,
|
173
|
+
:edge_filter => :prewitt,
|
174
|
+
:window_size => [1024, 768],
|
175
|
+
:clear_color => [255, 248, 230, 0],
|
176
|
+
:placement => ILU::CENTER,
|
177
|
+
:prepare_image_hook => nil,
|
178
|
+
:load_image_hook => nil,
|
179
|
+
:create_image_hook => nil,
|
180
|
+
:jpg_quality => 99
|
181
|
+
}
|
182
|
+
|
183
|
+
# configurable options
|
184
|
+
ILU.ImageParameter(ILU::FILTER, @options[:scale_filter])
|
185
|
+
ILU.ImageParameter(ILU::PLACEMENT, @options[:placement])
|
186
|
+
IL.SetInteger(IL::JPG_QUALITY, @options[:jpg_quality])
|
187
|
+
IL.ClearColour(*@options[:clear_color])
|
188
|
+
|
189
|
+
# fixed options
|
190
|
+
IL.Enable(IL::FILE_OVERWRITE)
|
191
|
+
IL.Enable(IL::ORIGIN_SET)
|
192
|
+
IL.OriginFunc(IL::ORIGIN_LOWER_LEFT)
|
193
|
+
end
|
194
|
+
|
195
|
+
alias_method :restore_defaults, :set_defaults
|
196
|
+
|
197
|
+
private
|
198
|
+
|
199
|
+
def prepare_image
|
200
|
+
name = IL.GenImages(1).first
|
201
|
+
IL.BindImage(name)
|
202
|
+
|
203
|
+
check_and_run_hook(:prepare_image_hook)
|
204
|
+
|
205
|
+
name
|
206
|
+
end
|
207
|
+
|
208
|
+
def attach_image_from_file(file)
|
209
|
+
IL.LoadImage(file)
|
210
|
+
|
211
|
+
# ensure all images are formatted RGBA8
|
212
|
+
IL.ConvertImage(IL::RGBA, IL::UNSIGNED_BYTE)
|
213
|
+
end
|
214
|
+
|
215
|
+
def wrap_and_yield(name, file, block)
|
216
|
+
img = Image.new(name, file)
|
217
|
+
if block
|
218
|
+
begin
|
219
|
+
block.call(img)
|
220
|
+
ensure
|
221
|
+
img.free if img.name
|
222
|
+
end
|
223
|
+
else
|
224
|
+
img
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
def check_and_run_hook(hook_name)
|
229
|
+
Devil.get_options[hook_name].call if Devil.get_options[hook_name]
|
230
|
+
end
|
231
|
+
|
232
|
+
def error_check
|
233
|
+
if (error_code = IL.GetError) != IL::NO_ERROR
|
234
|
+
raise RuntimeError, "An error occured. #{ILU.ErrorString(error_code)}"
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
## end of Devil module
|
240
|
+
|
241
|
+
# wraps a DevIL image
|
242
|
+
class Devil::Image
|
243
|
+
attr_reader :name, :file
|
244
|
+
|
245
|
+
def initialize(name, file)
|
246
|
+
@name = name
|
247
|
+
@file = file
|
248
|
+
end
|
249
|
+
|
250
|
+
# Frees the memory associated with the image.
|
251
|
+
# Must be called explictly if load_image or create_image is invoked without a block.
|
252
|
+
def free
|
253
|
+
raise "Error: calling 'free' on already freed image! #{self}" if !@name
|
254
|
+
IL.DeleteImages([@name])
|
255
|
+
error_check
|
256
|
+
@name = nil
|
257
|
+
end
|
258
|
+
|
259
|
+
alias_method :close, :free
|
260
|
+
alias_method :delete, :free
|
261
|
+
|
262
|
+
# returns the width of the image.
|
263
|
+
def width
|
264
|
+
action { IL.GetInteger(IL::IMAGE_WIDTH) }
|
265
|
+
end
|
266
|
+
|
267
|
+
alias_method :columns, :width
|
268
|
+
|
269
|
+
# returns the height of the image.
|
270
|
+
def height
|
271
|
+
action { IL.GetInteger(IL::IMAGE_HEIGHT) }
|
272
|
+
end
|
273
|
+
|
274
|
+
alias_method :rows, :height
|
275
|
+
|
276
|
+
# saves the image to +file+. If no +file+ is provided default to the opened file.
|
277
|
+
# Optional :quality hash parameter (only applies to JPEG images).
|
278
|
+
# Valid values are in the 0-99 range, with 99 being the best quality.
|
279
|
+
def save(file = @file, options = {})
|
280
|
+
quality = options[:quality]
|
281
|
+
|
282
|
+
raise "This image does not have an associated file. Please provide an explicit file name when saving." if !file
|
283
|
+
|
284
|
+
action do
|
285
|
+
IL.SetInteger(IL::JPG_QUALITY, quality) if quality
|
286
|
+
IL.SaveImage(file)
|
287
|
+
IL.SetInteger(IL::JPG_QUALITY, Devil.get_options[:jpg_quality]) if quality
|
288
|
+
end
|
289
|
+
self
|
290
|
+
end
|
291
|
+
|
292
|
+
# resize the image to +width+ and +height+. Aspect ratios of the image do not have to be the same.
|
293
|
+
# Optional :filter hash parameter that maps to a valid scale filter
|
294
|
+
# (see: Devil.set_options :scale_filter)
|
295
|
+
def resize(width, height, options = {})
|
296
|
+
filter = options[:filter]
|
297
|
+
|
298
|
+
action do
|
299
|
+
ILU.ImageParameter(ILU::FILTER, filter) if filter
|
300
|
+
ILU.Scale(width, height, 1)
|
301
|
+
ILU.ImageParameter(ILU::FILTER, Devil.get_options[:scale_filter]) if filter
|
302
|
+
end
|
303
|
+
|
304
|
+
self
|
305
|
+
end
|
306
|
+
|
307
|
+
# resize the image to +width+ and +height+. Aspect ratios of the image do not have to be the same.
|
308
|
+
# Applies a gaussian filter before rescaling to reduce aliasing.
|
309
|
+
# Optional :gauss parameter - number of times to apply gaussian filter before resizing (default is 2)
|
310
|
+
# Optional :filter hash parameter that maps to a valid scale filter
|
311
|
+
# (see: Devil.set_options :scale_filter)
|
312
|
+
def resize2(width, height, options = {})
|
313
|
+
gauss = options[:gauss] ||= 2
|
314
|
+
blur(gauss) if (width < self.width && height < self.height)
|
315
|
+
resize(width, height, options)
|
316
|
+
self
|
317
|
+
end
|
318
|
+
|
319
|
+
# Creates a proportional thumbnail of the image scaled so its longest
|
320
|
+
# edge is resized to +size+.
|
321
|
+
# Optional :filter hash parameter that maps to a valid scale filter
|
322
|
+
# (see: Devil.set_options :scale_filter)
|
323
|
+
def thumbnail(size, options = {})
|
324
|
+
|
325
|
+
# this thumbnail code from image_science.rb
|
326
|
+
w, h = width, height
|
327
|
+
scale = size.to_f / (w > h ? w : h)
|
328
|
+
resize((w * scale).to_i, (h * scale).to_i, options)
|
329
|
+
self
|
330
|
+
end
|
331
|
+
|
332
|
+
# Creates a proportional thumbnail of the image scaled so its longest
|
333
|
+
# edge is resized to +size+.
|
334
|
+
# Applies a gaussian filter before rescaling to reduce aliasing.
|
335
|
+
# Optional :gauss parameter - number of times to apply gaussian filter before resizing (default is 2)
|
336
|
+
# Optional :filter hash parameter that maps to a valid scale filter
|
337
|
+
# (see: Devil.set_options :scale_filter)
|
338
|
+
def thumbnail2(size, options = {})
|
339
|
+
gauss = options[:gauss] ||= 2
|
340
|
+
blur(gauss)
|
341
|
+
thumbnail(size, options)
|
342
|
+
self
|
343
|
+
end
|
344
|
+
|
345
|
+
# return a deep copy of the current image.
|
346
|
+
def dup
|
347
|
+
new_image_name = action { IL.CloneCurImage }
|
348
|
+
Devil::Image.new(new_image_name, nil)
|
349
|
+
end
|
350
|
+
|
351
|
+
alias_method :clone, :dup
|
352
|
+
|
353
|
+
# crop the current image.
|
354
|
+
# +xoff+ number of pixels to skip in x direction.
|
355
|
+
# +yoff+ number of pixels to skip in y direction.
|
356
|
+
# +width+ number of pixels to preserve in x direction.
|
357
|
+
# +height+ number of pixels to preserve in y direction.
|
358
|
+
def crop(xoff, yoff, width, height)
|
359
|
+
action { ILU.Crop(xoff, yoff, 1, width, height, 1) }
|
360
|
+
self
|
361
|
+
end
|
362
|
+
|
363
|
+
# enlarge the canvas of current image to +width+ and +height+.
|
364
|
+
def enlarge_canvas(width, height)
|
365
|
+
if width < self.width || height < self.height
|
366
|
+
raise "width and height parameters must be larger than current image width and height"
|
367
|
+
end
|
368
|
+
|
369
|
+
action { ILU.EnlargeCanvas(width, height, 1) }
|
370
|
+
self
|
371
|
+
end
|
372
|
+
|
373
|
+
# splice the +source+ image into current image at position +x+ and +y+.
|
374
|
+
# Takes an optional +:crop+ hash parameter that has the following format: +:crop => [sx, sy, width, height]+
|
375
|
+
# +sx+, +sy+, +width, +height+ crop the source image to be spliced.
|
376
|
+
# +sx+ is how many pixels to skip in x direction of source image.
|
377
|
+
# +sy+ is how many pixels to skip in y direction of source image.
|
378
|
+
# +width+ number of pixels to preserve in x direction of source image.
|
379
|
+
# +height+ number of pixels to preserve in y direction of source image.
|
380
|
+
# if no +:crop+ parameter is provided then the whole image is spliced in.
|
381
|
+
def blit(source, x, y, options = {})
|
382
|
+
options = {
|
383
|
+
:crop => [0, 0, source.width, source.height]
|
384
|
+
}.merge!(options)
|
385
|
+
|
386
|
+
action do
|
387
|
+
IL.Blit(source.name, x, y, 0, options[:crop][0], options[:crop][1], 0,
|
388
|
+
options[:crop][2], options[:crop][3], 1)
|
389
|
+
end
|
390
|
+
|
391
|
+
self
|
392
|
+
end
|
393
|
+
|
394
|
+
alias_method :composite, :blit
|
395
|
+
|
396
|
+
# reflect image about its y axis.
|
397
|
+
def mirror
|
398
|
+
action { ILU.Mirror }
|
399
|
+
self
|
400
|
+
end
|
401
|
+
|
402
|
+
# use prewitt or sobel filters to detect the edges in the current image.
|
403
|
+
# Optional :filter hash parameter selects filter to use (:prewitt or :sobel).
|
404
|
+
# (see: Devil.set_options :edge_filter)
|
405
|
+
def edge_detect(options={})
|
406
|
+
options = {
|
407
|
+
:filter => Devil.get_options[:edge_filter]
|
408
|
+
}.merge!(options)
|
409
|
+
|
410
|
+
case options[:filter]
|
411
|
+
when :prewitt
|
412
|
+
action { ILU.EdgeDetectP }
|
413
|
+
when :sobel
|
414
|
+
action { ILU.EdgeDetectS }
|
415
|
+
else
|
416
|
+
raise "No such edge filter #{options[:filter]}. Use :prewitt or :sobel"
|
417
|
+
end
|
418
|
+
self
|
419
|
+
end
|
420
|
+
|
421
|
+
# embosses an image, causing it to have a "relief" feel to it using a convolution filter.
|
422
|
+
def emboss
|
423
|
+
action { ILU.Emboss }
|
424
|
+
self
|
425
|
+
end
|
426
|
+
|
427
|
+
# applies a strange color distortion effect to the image giving a preternatural feel
|
428
|
+
def alienify
|
429
|
+
action { ILU.Alienify }
|
430
|
+
self
|
431
|
+
end
|
432
|
+
|
433
|
+
# performs a gaussian blur on the image. The blur is performed +iter+ times.
|
434
|
+
def blur(iter)
|
435
|
+
action { ILU.BlurGaussian(iter) }
|
436
|
+
self
|
437
|
+
end
|
438
|
+
|
439
|
+
# 'pixelize' the image using a pixel size of +pixel_size+.
|
440
|
+
def pixelize(pixel_size)
|
441
|
+
action { ILU.Pixelize(pixel_size) }
|
442
|
+
self
|
443
|
+
end
|
444
|
+
|
445
|
+
# add random noise to the image. +factor+ is the tolerance to use.
|
446
|
+
# accepeted values range from 0.0 - 1.0.
|
447
|
+
def noisify(factor)
|
448
|
+
action { ILU.Noisify(factor) }
|
449
|
+
self
|
450
|
+
end
|
451
|
+
|
452
|
+
# The sharpening +factor+ must be in the range of 0.0 - 2.5. A value of 1.0 for the sharpening.
|
453
|
+
# factor will have no effect on the image. Values in the range 1.0 - 2.5 will sharpen the
|
454
|
+
# image, with 2.5 having the most pronounced sharpening effect. Values from 0.0 to 1.0 do
|
455
|
+
# a type of reverse sharpening, blurring the image. Values outside of the 0.0 - 2.5 range
|
456
|
+
# produce undefined results.
|
457
|
+
#
|
458
|
+
# The number of +iter+ (iterations) to perform will usually be 1, but to achieve more sharpening,
|
459
|
+
# increase the number of iterations.
|
460
|
+
def sharpen(factor, iter)
|
461
|
+
action { ILU.Sharpen(factor, iter) }
|
462
|
+
self
|
463
|
+
end
|
464
|
+
|
465
|
+
# applies gamma correction to an image using an exponential curve.
|
466
|
+
# +factor+ is gamma correction factor to use.
|
467
|
+
# A value of 1.0 leaves the image unmodified.
|
468
|
+
# Values in the range 0.0 - 1.0 darken the image
|
469
|
+
# Values above 1.0 brighten the image.
|
470
|
+
def gamma_correct(factor)
|
471
|
+
action { ILU.GammaCorrect(factor) }
|
472
|
+
self
|
473
|
+
end
|
474
|
+
|
475
|
+
# invert the color of every pixel in the image.
|
476
|
+
def negate
|
477
|
+
action { ILU.Negative }
|
478
|
+
self
|
479
|
+
end
|
480
|
+
|
481
|
+
alias_method :negative, :negate
|
482
|
+
|
483
|
+
# +factor+ describes desired contrast to use
|
484
|
+
# A value of 1.0 has no effect on the image.
|
485
|
+
# Values between 1.0 and 1.7 increase the amount of contrast (values above 1.7 have no effect)
|
486
|
+
# Valid range of +factor+ is 0.0 - 1.7.
|
487
|
+
def contrast(factor)
|
488
|
+
action { ILU.Contrast(factor) }
|
489
|
+
self
|
490
|
+
end
|
491
|
+
|
492
|
+
# darkens the bright colours and lightens the dark
|
493
|
+
# colours, reducing the contrast in an image or 'equalizing' it.
|
494
|
+
def equalize
|
495
|
+
action { ILU.Equalize }
|
496
|
+
self
|
497
|
+
end
|
498
|
+
|
499
|
+
# returns the image data in the form of a ruby string.
|
500
|
+
# The image data is formatted to RGBA / UNSIGNED BYTE.
|
501
|
+
def to_blob
|
502
|
+
action { IL.ToBlob }
|
503
|
+
end
|
504
|
+
|
505
|
+
# flip the image about its x axis.
|
506
|
+
def flip
|
507
|
+
action { ILU.FlipImage }
|
508
|
+
self
|
509
|
+
end
|
510
|
+
|
511
|
+
# rotate an image about its central point by +angle+ degrees (counter clockwise).
|
512
|
+
def rotate(angle)
|
513
|
+
action { ILU.Rotate(angle) }
|
514
|
+
self
|
515
|
+
end
|
516
|
+
|
517
|
+
# simply clears the image to the 'clear color' (specified using Devil.set_options(:clear_color => [r, g, b, a])
|
518
|
+
def clear
|
519
|
+
action { IL.ClearImage }
|
520
|
+
self
|
521
|
+
end
|
522
|
+
|
523
|
+
private
|
524
|
+
|
525
|
+
def set_binding
|
526
|
+
raise "Error: trying to use image that has already been freed! #{self}" if !@name
|
527
|
+
IL.BindImage(@name)
|
528
|
+
end
|
529
|
+
|
530
|
+
def error_check
|
531
|
+
if (error_code = IL.GetError) != IL::NO_ERROR
|
532
|
+
raise RuntimeError, "An error occured. #{ILU.ErrorString(error_code)}"
|
533
|
+
end
|
534
|
+
end
|
535
|
+
|
536
|
+
def action
|
537
|
+
set_binding
|
538
|
+
result = yield
|
539
|
+
error_check
|
540
|
+
|
541
|
+
result
|
542
|
+
end
|
543
|
+
end
|
544
|
+
## end of Devil::Image
|
545
|
+
|
546
|
+
# initialize Devil and set default config
|
547
|
+
Devil.init
|