devil 0.1.9.5-i386-mingw32

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