devil 0.1.9.5-i386-mingw32

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+ }
Binary file
Binary file
@@ -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