devil 0.1.8.5 → 0.1.8.8

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,3 +1,20 @@
1
+ 2009-10-29 John Mair (Banisterfiend)
2
+ * version 0.1.8.8
3
+ * added Devil.with_group (for loading multiple images into the same block)
4
+ * all images passed into block are cleaned up at end of block
5
+ * images at end of block are only free'd if they have not already been freed by user
6
+ * ruby_il.c: added IMAGE_BITS_PER_PIXEL and IMAGE_BYTES_PER_PIXEL constants
7
+ * finalizers still not implemented
8
+
9
+ 2009-10-28 John Mair (Banisterfiend)
10
+ * removed finalizer and replaced with explicit call to image.free at end of block. If no block is used, user must call image.free at end of use
11
+ * above fixes memory leak.
12
+ * changed STR2CSTR() to StringValuePtr() in ruby_il.c
13
+
14
+ 2009-10-28 John Mair (Banisterfiend)
15
+ * added IL::ConvertImage(IL::RGBA, IL::UNSIGNED_BYTE) to Devil#load; ensures that all image data is in the same format (image files only support RGB/UB and RGBA/UB so make them all RGBA/UB)
16
+ * changed compile-time conditional for the IL_LBM constant. now checks if IL_LBM is defined before it tries IL_ILBM
17
+
1
18
  2009-10-25 John Mair (Banisterfiend)
2
19
  version 0.1.8.5
3
20
  * added hooks: prepare_image_hook, create_image_hook, load_image_hook
data/README CHANGED
@@ -1,4 +1,4 @@
1
- Ruby Devil version 0.1.8.5
1
+ Ruby Devil version 0.1.8.8
2
2
  ========================
3
3
 
4
4
  * Original author: Jaroslaw Tworek <dev.jrx@gmail.com>
data/Rakefile CHANGED
@@ -8,7 +8,7 @@ require 'rake/gempackagetask'
8
8
  require 'rake/testtask'
9
9
  require 'rake/rdoctask'
10
10
 
11
- DEVIL_VERSION = "0.1.8.5"
11
+ DEVIL_VERSION = "0.1.8.8"
12
12
 
13
13
  dlext = Config::CONFIG['DLEXT']
14
14
 
@@ -80,21 +80,21 @@ static VALUE il_DeleteImages(VALUE obj, VALUE images) {
80
80
  }
81
81
 
82
82
  static VALUE il_LoadImage(VALUE obj, VALUE rb_filename) {
83
- char* filename = STR2CSTR(rb_filename);
83
+ char* filename = StringValuePtr(rb_filename);
84
84
  ILboolean load = ilLoadImage(filename);
85
85
  return load ? Qtrue : Qfalse;
86
86
  }
87
87
 
88
88
  static VALUE il_Load(VALUE obj, VALUE rb_type, VALUE rb_filename) {
89
89
  ILenum type = NUM2INT(rb_type);
90
- char* filename = STR2CSTR(rb_filename);
90
+ char* filename = StringValuePtr(rb_filename);
91
91
 
92
92
  ILboolean load = ilLoad(type, filename);
93
93
  return load ? Qtrue : Qfalse;
94
94
  }
95
95
 
96
96
  static VALUE il_SaveImage(VALUE obj, VALUE rb_filename) {
97
- char* filename = STR2CSTR(rb_filename);
97
+ char* filename = StringValuePtr(rb_filename);
98
98
  ILboolean load = ilSaveImage(filename);
99
99
 
100
100
  return load ? Qtrue : Qfalse;
@@ -102,7 +102,7 @@ static VALUE il_SaveImage(VALUE obj, VALUE rb_filename) {
102
102
 
103
103
  static VALUE il_Save(VALUE obj, VALUE rb_type, VALUE rb_filename) {
104
104
  ILenum type = NUM2INT(rb_type);
105
- char* filename = STR2CSTR(rb_filename);
105
+ char* filename = StringValuePtr(rb_filename);
106
106
  ILboolean load = ilSave(type, filename);
107
107
 
108
108
  return load ? Qtrue : Qfalse;
@@ -117,6 +117,7 @@ static VALUE il_TexImage(VALUE obj, VALUE rb_width, VALUE rb_height,
117
117
  ILubyte bpp = NUM2INT(rb_bpp);
118
118
  ILenum format = NUM2INT(rb_format);
119
119
  ILenum type = NUM2INT(rb_type);
120
+ ILboolean flag;
120
121
 
121
122
  /* from ILvoid */
122
123
  void * data = NULL;
@@ -126,7 +127,7 @@ static VALUE il_TexImage(VALUE obj, VALUE rb_width, VALUE rb_height,
126
127
  else
127
128
  data = ImageData2Arr(rb_data);
128
129
 
129
- ILboolean flag = ilTexImage(width, height, depth,
130
+ flag = ilTexImage(width, height, depth,
130
131
  bpp, format, type, data);
131
132
  return flag ? Qtrue : Qfalse;
132
133
  }
@@ -435,7 +436,7 @@ InitializeIL() {
435
436
  rb_define_const(mIL, "JPG", INT2NUM(IL_JPG));
436
437
  rb_define_const(mIL, "JFIF", INT2NUM(IL_JFIF));
437
438
 
438
- #ifdef _WIN32
439
+ #ifndef IL_LBM
439
440
  rb_define_const(mIL, "LBM", INT2NUM(IL_ILBM));
440
441
  #else
441
442
  rb_define_const(mIL, "LBM", INT2NUM(IL_LBM));
@@ -517,6 +518,8 @@ InitializeIL() {
517
518
  rb_define_const(mIL, "IMAGE_WIDTH", INT2NUM(IL_IMAGE_WIDTH));
518
519
  rb_define_const(mIL, "IMAGE_HEIGHT", INT2NUM(IL_IMAGE_HEIGHT));
519
520
  rb_define_const(mIL, "IMAGE_FORMAT", INT2NUM(IL_IMAGE_FORMAT));
521
+ rb_define_const(mIL, "IMAGE_BITS_PER_PIXEL", INT2NUM(IL_IMAGE_BITS_PER_PIXEL));
522
+ rb_define_const(mIL, "IMAGE_BYTES_PER_PIXEL", INT2NUM(IL_IMAGE_BYTES_PER_PIXEL));
520
523
  rb_define_const(mIL, "FILE_OVERWRITE", INT2NUM(IL_FILE_OVERWRITE));
521
524
  rb_define_const(mIL, "ORIGIN_SET", INT2NUM(IL_ORIGIN_SET));
522
525
  rb_define_const(mIL, "CONV_PAL", INT2NUM(IL_CONV_PAL));
@@ -19,7 +19,7 @@ module Devil
19
19
  include IL
20
20
  include ILU
21
21
 
22
- VERSION = '0.1.8.5'
22
+ VERSION = '0.1.8.8'
23
23
 
24
24
  class << self
25
25
 
@@ -27,29 +27,31 @@ module Devil
27
27
  # Optionally accepts a block and yields the newly created image to the block.
28
28
  def load_image(file, options={}, &block)
29
29
  name = prepare_image
30
+ attach_image_from_file(file)
31
+
30
32
  out_profile = options[:out_profile]
31
33
  in_profile = options[:in_profile]
32
34
 
33
- IL.LoadImage(file)
34
-
35
35
  # apply a color profile if one is provided
36
36
  IL.ApplyProfile(in_profile, out_profile) if out_profile
37
37
 
38
- # run the proc (if it exists)
39
- load_image_proc = Devil.get_options[:load_image_hook]
40
- load_image_proc.call if load_image_proc
41
-
42
- if (error_code = IL.GetError) != IL::NO_ERROR
43
- raise RuntimeError, "an error occured while trying to "+
44
- "load the image #{file}. #{ILU.ErrorString(error_code)}"
45
- end
46
-
38
+ # run the load image hook (if it exists)
39
+ check_and_run_hook(:load_image_hook)
40
+
41
+ error_check
42
+
47
43
  img = Image.new(name, file)
48
44
  if block
49
- block.call(img)
45
+ begin
46
+ block.call(img)
47
+ ensure
48
+ # don't bother freeing it if it's already free
49
+ img.free if img.name
50
+ end
51
+ else
52
+ # ObjectSpace.define_finalizer(img, proc { IL.DeleteImages([img.name]) if img.name })
53
+ img
50
54
  end
51
-
52
- img
53
55
  end
54
56
 
55
57
  alias_method :with_image, :load_image
@@ -66,6 +68,7 @@ module Devil
66
68
 
67
69
  clear_color = options[:color]
68
70
 
71
+ # created image is formatted RGBA8
69
72
  IL.TexImage(width, height, 1, 4, IL::RGBA, IL::UNSIGNED_BYTE, nil)
70
73
 
71
74
  # apply a color profile if one is provided
@@ -75,26 +78,52 @@ module Devil
75
78
  IL.ClearImage
76
79
  IL.ClearColour(*Devil.get_options[:clear_color]) if clear_color
77
80
 
78
- # run the proc (if it exists)
79
- create_image_proc = Devil.get_options[:create_image_hook]
80
- create_image_proc.call if create_image_proc
81
+ # run the create image hook (if it exists)
82
+ check_and_run_hook(:create_image_hook)
83
+
84
+ error_check
85
+
86
+ img = Image.new(name, nil)
87
+ if block
88
+ begin
89
+ block.call(img)
90
+ ensure
91
+ img.free if img.name
92
+ end
93
+ else
94
+ # ObjectSpace.define_finalizer(img, proc { IL.DeleteImages([img.name]) if img.name })
95
+ img
96
+ end
97
+ end
81
98
 
82
- if (error_code = IL.GetError) != IL::NO_ERROR
83
- raise RuntimeError, "an error occured while trying to "+
84
- "create an image. #{ILU.ErrorString(error_code)}"
99
+ alias_method :create_blank_image, :create_image
100
+
101
+ # load multiple images and yield them to the block
102
+ # e.g Devil.with_group("hello.png", "friend.png") { |img1, img2| ... }
103
+ # all yielded images are cleaned up at end of block so you do not need to
104
+ # explictly call img1.free
105
+ def with_group(*files, &block)
106
+ images = files.map do |file|
107
+ name = prepare_image
108
+ attach_image_from_file(file)
109
+ check_and_run_hook(:load_image_hook)
110
+ error_check
111
+
112
+ Image.new(name, file)
85
113
  end
86
114
 
87
- img = Image.new(name, nil)
88
115
  if block
89
- block.call(img)
116
+ begin
117
+ block.call(*images)
118
+ ensure
119
+ images.each { |img| img.free if img.name }
120
+ end
121
+ else
122
+ raise RuntimeError, "a block must be provided."
90
123
  end
91
-
92
- img
93
124
  end
94
125
 
95
- alias_method :create_blank_image, :create_image
96
- alias_method :create_blank, :create_image
97
- alias_method :blank_image, :create_image
126
+ alias_method :with_images, :with_group
98
127
 
99
128
  # convert an image +blob+ with +width+ and +height+
100
129
  # to a bona fide image
@@ -130,6 +159,10 @@ module Devil
130
159
  # :edge_filter sets the edge detection algorithm to use when invoking
131
160
  # the 'edge_detect' method. (defaults to :prewitt)
132
161
  # Allowed values are :prewitt and :sobel
162
+ #
163
+ # hooks:
164
+ # :prepare_image_hook, :create_image_hook, :load_image_hook
165
+ # e.g Devil.set_options :load_image_hook => proc { IL::ConvertImage(IL::RGBA, IL::UNSIGNED_BYTE) }
133
166
  def set_options(options={})
134
167
  @options.merge!(options)
135
168
 
@@ -186,15 +219,31 @@ module Devil
186
219
  name = IL.GenImages(1).first
187
220
  IL.BindImage(name)
188
221
 
189
- # run the proc (if it exists)
190
- prepare_image_proc = Devil.get_options[:prepare_image_hook]
191
- prepare_image_proc.call if prepare_image_proc
222
+ # run the prepare image hook (if it exists)
223
+ check_and_run_hook(:prepare_image_hook)
192
224
 
193
225
  name
194
226
  end
227
+
228
+ def attach_image_from_file(file)
229
+ IL.LoadImage(file)
230
+
231
+ # ensure all images are formatted RGBA8
232
+ IL.ConvertImage(IL::RGBA, IL::UNSIGNED_BYTE)
233
+ end
234
+
235
+ def check_and_run_hook(hook_name)
236
+ Devil.get_options[hook_name].call if Devil.get_options[hook_name]
237
+ end
238
+
239
+ def error_check
240
+ if (error_code = IL.GetError) != IL::NO_ERROR
241
+ raise RuntimeError, "An error occured. #{ILU.ErrorString(error_code)}"
242
+ end
243
+ end
195
244
  end
196
245
  end
197
- # end of Devil module
246
+ ## end of Devil module
198
247
 
199
248
  # wraps a DevIL image
200
249
  class Devil::Image
@@ -203,9 +252,19 @@ class Devil::Image
203
252
  def initialize(name, file)
204
253
  @name = name
205
254
  @file = file
255
+ end
206
256
 
207
- ObjectSpace.define_finalizer( self, proc { IL.DeleteImages(1, [name]) } )
257
+ # Frees the memory associated with the image.
258
+ # Must be called explictly if load_image or create_image is invoked without a block.
259
+ def free
260
+ raise "Error: calling 'free' on already freed image! #{self}" if !@name
261
+ IL.DeleteImages([@name])
262
+ error_check
263
+ @name = nil
208
264
  end
265
+
266
+ alias_method :close, :free
267
+ alias_method :delete, :free
209
268
 
210
269
  # returns the width of the image.
211
270
  def width
@@ -438,6 +497,7 @@ class Devil::Image
438
497
  private
439
498
 
440
499
  def set_binding
500
+ raise "Error: trying to use image that has already been freed! #{self}" if !@name
441
501
  IL.BindImage(@name)
442
502
  end
443
503
 
@@ -455,5 +515,7 @@ class Devil::Image
455
515
  result
456
516
  end
457
517
  end
518
+ ## end of Devil::Image
458
519
 
520
+ # initialize Devil and set default config
459
521
  Devil.init
@@ -9,8 +9,10 @@ module TexPlay
9
9
  # save a Gosu::Image to +file+
10
10
  # This method is only available if require 'devil/gosu' is used
11
11
  def save(file)
12
- capture {
13
- to_devil.save(file)
12
+ capture {
13
+ img = to_devil
14
+ img.save(file)
15
+ img.free
14
16
  }
15
17
  self
16
18
  end
@@ -20,7 +22,7 @@ module TexPlay
20
22
  def to_devil
21
23
  devil_img = nil
22
24
  capture {
23
- devil_img = Devil.from_blob(self.to_blob, self.width, self.height)
25
+ devil_img = Devil.from_blob(self.to_blob, self.width, self.height).flip
24
26
  devil_img
25
27
  }
26
28
  devil_img
@@ -64,8 +66,15 @@ class Gosu::Image
64
66
  def new(window, file, *args, &block)
65
67
  if file.respond_to?(:to_blob) || file =~ /\.(bmp|png)$/
66
68
  original_new_redux(window, file, *args, &block)
67
- else
68
- original_new_redux(window, Devil.load(file).flip, *args, &block)
69
+ else
70
+ img = Devil.load(file).flip
71
+ begin
72
+ gosu_img = original_new_redux(window, img, *args, &block)
73
+ ensure
74
+ img.free
75
+ end
76
+
77
+ gosu_img
69
78
  end
70
79
  end
71
80
  end
@@ -113,8 +122,11 @@ class Devil::Image
113
122
  end
114
123
 
115
124
  # note we dup the image so the displayed image is a snapshot taken at the time #show is invoked
116
- @@window.show_list.push :image => Gosu::Image.new(@@window, self.dup.flip), :x => x, :y => y
117
125
 
126
+ img = self.dup.flip
127
+ @@window.show_list.push :image => Gosu::Image.new(@@window, img), :x => x, :y => y
128
+ img.free
129
+
118
130
  self
119
131
  end
120
132
  end
@@ -5,13 +5,17 @@ $LOAD_PATH.push("#{$direc}/../lib/")
5
5
  require 'rubygems'
6
6
  require 'devil/gosu'
7
7
 
8
- Devil.set_options :load_image_hook => proc { IL.ConvertImage(IL::RGBA, IL::UNSIGNED_BYTE) }
9
-
10
8
  Devil.create_image(500, 500, :color => [255, 255, 0, 255]) do |img|
11
9
  source1 = Devil.load("texture.png").thumbnail(100)
12
10
  img.blit source1, 100, 100
13
11
  img.blit source1, 400, 100
14
- img.blit source1.dup.rotate(45), 100, 300
12
+
13
+ source1_dup = source1.dup
14
+ img.blit source1_dup.rotate(45), 100, 300
15
+
15
16
  img.show
17
+
18
+ source1.free
19
+ source1_dup.free
16
20
  end
17
21
 
@@ -7,10 +7,9 @@ require 'devil/gosu'
7
7
 
8
8
  Devil.with_image("#{$direc}/texture.png") do |img|
9
9
  img2 = Devil.load("#{$direc}/red.png")
10
-
11
- img.show(200,200)
12
-
10
+
13
11
  img.blit img2, 100, 100, :crop => [0, 0, img2.width / 2, img2.height / 2]
12
+ img2.free
14
13
 
15
14
  img.show
16
15
  end
@@ -15,6 +15,9 @@ img.rotate(rand(360))
15
15
  img.show(200,200)
16
16
  img_dup.show(450, 200)
17
17
 
18
+ img.free
19
+ img_dup.free
20
+
18
21
 
19
22
 
20
23
 
@@ -10,7 +10,6 @@ class W < Gosu::Window
10
10
  super(1024, 768, false, 20)
11
11
 
12
12
  @img = Gosu::Image.new(self, "#{$direc}/texture.jpg")
13
- @img = @img.to_devil.save("cunt.png").to_gosu(self).to_devil.blur(5).to_gosu(self)
14
13
  end
15
14
 
16
15
  def draw
@@ -10,10 +10,12 @@ class W < Gosu::Window
10
10
  super(1024, 768, false, 20)
11
11
 
12
12
  @img = Gosu::Image.new(self, "#{$direc}/texture.jpg")
13
- @img = @img.to_devil.
14
- emboss.
13
+ dimg = @img.to_devil
14
+ @img = dimg.emboss.
15
15
  rotate(45).
16
16
  to_gosu(self)
17
+
18
+ dimg.free
17
19
  end
18
20
 
19
21
  def draw
@@ -24,4 +26,4 @@ end
24
26
 
25
27
  w = W.new
26
28
  w.show
27
-
29
+
@@ -0,0 +1,18 @@
1
+ $direc = File.dirname(__FILE__)
2
+
3
+ $LOAD_PATH.push("#{$direc}/../lib/")
4
+
5
+ require 'rubygems'
6
+ require 'devil/gosu'
7
+
8
+ Devil.with_group("#{$direc}/texture.png", "#{$direc}/red.png") do |img, img2|
9
+
10
+ img.blit img2, 100, 100, :crop => [0, 0, img2.width / 2, img2.height / 2]
11
+ img.show
12
+ end
13
+
14
+
15
+
16
+
17
+
18
+
@@ -6,8 +6,9 @@ require 'rubygems'
6
6
  require "devil"
7
7
 
8
8
  Devil.with_image("#{$direc}/texture.png") do |img|
9
- img.negative
10
- img.save("#{$direc}/texture_neg.png")
9
+ img.pixelize(10)
10
+ img.save("#{$direc}/texture_blocky.png")
11
+ img.free
11
12
  end
12
13
 
13
14
  img = Devil.load_image("#{$direc}/texture.png")
@@ -16,8 +17,10 @@ bink = Devil.load_image("#{$direc}/texture.png")
16
17
  img.gamma_correct(1.6)
17
18
  bink.resize(50, 50)
18
19
 
19
- img.save("#{$direc}/texture_gamma.png")
20
- bink.save("#{$direc}/texture_tiny.png")
20
+ img.save("#{$direc}/texture_gamma.png").free
21
+ bink.save("#{$direc}/texture_tiny.png").free
22
+
23
+
21
24
 
22
25
 
23
26
 
@@ -5,4 +5,4 @@ $LOAD_PATH.push("#{$direc}/../lib/")
5
5
  require 'rubygems'
6
6
  require 'devil/gosu'
7
7
 
8
- Devil.load("texture.png", :inprofile => "sRGB.icm", :out_profile => "color/AdobeRGB1998.icc").save("texture_out.png")
8
+ Devil.load("texture.png", :inprofile => "sRGB.icm", :out_profile => "AdobeRGB1998.icc").save("texture_out.png").free
@@ -22,7 +22,7 @@ class W < Gosu::Window
22
22
 
23
23
  def update
24
24
  if button_down?(Gosu::KbEscape)
25
- screenshot.rotate(45).save("screenshot.png")
25
+ screenshot.rotate(45).save("screenshot.png").free
26
26
  exit
27
27
  end
28
28
  end
@@ -6,7 +6,7 @@ require 'rubygems'
6
6
  require 'devil/gosu'
7
7
 
8
8
  Devil.load("texture.png") do |img|
9
- img.dup.thumbnail(150, :filter => Devil::NEAREST).show(100, 300)
10
- img.dup.thumbnail(150).show(100, 100)
9
+ img.dup.thumbnail(150, :filter => Devil::NEAREST).show(100, 300).free
10
+ img.dup.thumbnail(150).show(100, 100).free
11
11
  end
12
12
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: devil
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.8.5
4
+ version: 0.1.8.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jaroslaw Tworek, John Mair (banisterfiend)
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-10-25 00:00:00 -04:00
12
+ date: 2009-10-29 00:00:00 -04:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -42,6 +42,7 @@ files:
42
42
  - test/test_gosu_show.rb
43
43
  - test/test_profile.rb
44
44
  - test/test_screenshot.rb
45
+ - test/test_group.rb
45
46
  - test/test_gosu_roundtrip.rb
46
47
  - test/test_gosu_save.rb
47
48
  - test/test_thumbnail.rb