sdsykes-fastimage 0.1.0 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README +0 -27
- data/README.textile +22 -26
- data/VERSION.yml +3 -3
- data/lib/fastimage.rb +252 -0
- metadata +3 -4
- data/lib/fastimage_resize.rb +0 -137
- data/test/test.rb +0 -1
data/README
CHANGED
@@ -1,27 +0,0 @@
|
|
1
|
-
FastImage Resize is an extremely light solution for resizing images in ruby by using libgd
|
2
|
-
|
3
|
-
=== Examples
|
4
|
-
|
5
|
-
require 'fastimage_resize'
|
6
|
-
|
7
|
-
FastImage.resize("http://stephensykes.com/images/ss.com_x.gif", "my.gif", 100, 20)
|
8
|
-
=> 1
|
9
|
-
|
10
|
-
=== Requirements
|
11
|
-
|
12
|
-
RubyInline
|
13
|
-
|
14
|
-
sudo gem install RubyInline
|
15
|
-
|
16
|
-
FastImage
|
17
|
-
|
18
|
-
sudo gem install sdsykes-fastimage -s http://gems.github.com
|
19
|
-
|
20
|
-
Libgd
|
21
|
-
|
22
|
-
See http://www.libgd.org/
|
23
|
-
Libgd is commonly available on most unix platforms, including OSX.
|
24
|
-
|
25
|
-
=== References
|
26
|
-
|
27
|
-
* http://blog.new-bamboo.co.uk/2007/12/3/super-f-simple-resizing
|
data/README.textile
CHANGED
@@ -1,42 +1,38 @@
|
|
1
|
-
h1. FastImage
|
1
|
+
h1. FastImage
|
2
2
|
|
3
|
-
h4. FastImage
|
3
|
+
h4. FastImage finds the size or type of an image given its uri by fetching as little as needed
|
4
4
|
|
5
|
-
h2.
|
5
|
+
h2. The problem
|
6
6
|
|
7
|
-
|
8
|
-
<code>
|
9
|
-
require 'fastimage_resize'
|
7
|
+
Your app needs to find the size or type of an image. But the image is not locally stored - it's on another server, or in the cloud - at Amazon S3 for example.
|
10
8
|
|
11
|
-
|
12
|
-
=> 1
|
13
|
-
</pre>
|
14
|
-
</code>
|
9
|
+
You don't want to download the entire image, which could be many tens of kilobytes, or even megabytes just to get this information. For most image types, the size of the image is simply stored at the start of the file. For JPEG files it's a little bit more complex, but even so you do not need to fetch most of the image to find the size.
|
15
10
|
|
16
|
-
|
11
|
+
FastImage does this minimal fetch for image types GIF, JPEG, PNG and BMP.
|
17
12
|
|
18
|
-
|
13
|
+
You only need supply the uri, and FastImage will do the rest.
|
19
14
|
|
20
|
-
|
21
|
-
<code>
|
22
|
-
sudo gem install RubyInline
|
23
|
-
</pre>
|
24
|
-
</code>
|
25
|
-
|
26
|
-
* FastImage
|
15
|
+
h2. Examples
|
27
16
|
|
28
17
|
<pre>
|
29
18
|
<code>
|
30
|
-
|
31
|
-
|
19
|
+
require 'fastimage'
|
20
|
+
|
21
|
+
FastImage.size("http://stephensykes.com/images/ss.com_x.gif")
|
22
|
+
=> [266, 56] # width, height
|
23
|
+
FastImage.type("http://stephensykes.com/images/pngimage")
|
24
|
+
=> :png
|
32
25
|
</code>
|
26
|
+
</pre>
|
33
27
|
|
34
|
-
|
28
|
+
h2. Installation
|
35
29
|
|
36
|
-
|
30
|
+
h4. Gem
|
31
|
+
|
32
|
+
sudo gem install sdsykes-fastimage -s http://gems.github.com
|
37
33
|
|
38
|
-
|
34
|
+
h2. Documentation
|
39
35
|
|
40
|
-
|
36
|
+
"http://rdoc.info/projects/sdsykes/fastimage":http://rdoc.info/projects/sdsykes/fastimage
|
41
37
|
|
42
|
-
|
38
|
+
(c) 2009 Stephen Sykes (sdsykes)
|
data/VERSION.yml
CHANGED
@@ -1,4 +1,4 @@
|
|
1
1
|
---
|
2
|
-
:patch:
|
3
|
-
:major:
|
4
|
-
:minor:
|
2
|
+
:patch: 1
|
3
|
+
:major: 1
|
4
|
+
:minor: 0
|
data/lib/fastimage.rb
ADDED
@@ -0,0 +1,252 @@
|
|
1
|
+
# FastImage finds the size or type of an image given its uri.
|
2
|
+
# It is careful to only fetch and parse as much of the image as is needed to determine the result.
|
3
|
+
# It does this by using a feature of Net::HTTP that yields strings from the resource being fetched
|
4
|
+
# as soon as the packets arrive.
|
5
|
+
#
|
6
|
+
# No external libraries such as ImageMagick are used here, this is a very lightweight solution to
|
7
|
+
# finding image information.
|
8
|
+
#
|
9
|
+
# FastImage knows about GIF, JPEG, BMP and PNG files.
|
10
|
+
#
|
11
|
+
# === Examples
|
12
|
+
# require 'fastimage'
|
13
|
+
#
|
14
|
+
# FastImage.size("http://stephensykes.com/images/ss.com_x.gif")
|
15
|
+
# => [266, 56]
|
16
|
+
# FastImage.type("http://stephensykes.com/images/pngimage")
|
17
|
+
# => :png
|
18
|
+
#
|
19
|
+
# === References
|
20
|
+
# * http://snippets.dzone.com/posts/show/805
|
21
|
+
# * http://www.anttikupila.com/flash/getting-jpg-dimensions-with-as3-without-loading-the-entire-file/
|
22
|
+
# * http://pennysmalls.com/2008/08/19/find-jpeg-dimensions-fast-in-ruby/
|
23
|
+
#
|
24
|
+
require 'net/https'
|
25
|
+
|
26
|
+
class FastImage
|
27
|
+
attr_reader :size, :type
|
28
|
+
|
29
|
+
class FastImageException < StandardError # :nodoc:
|
30
|
+
end
|
31
|
+
class MoreCharsNeeded < FastImageException # :nodoc:
|
32
|
+
end
|
33
|
+
class UnknownImageType < FastImageException # :nodoc:
|
34
|
+
end
|
35
|
+
class ImageFetchFailure < FastImageException # :nodoc:
|
36
|
+
end
|
37
|
+
class SizeNotFound < FastImageException # :nodoc:
|
38
|
+
end
|
39
|
+
|
40
|
+
DefaultTimeout = 2
|
41
|
+
|
42
|
+
# Returns an array containing the width and height of the image.
|
43
|
+
# It will return nil if the image could not be fetched, or if the image type was not recognised.
|
44
|
+
#
|
45
|
+
# By default there is a timeout of 2 seconds for opening and reading from the remote server.
|
46
|
+
# This can be changed by passing a :timeout => number_of_seconds in the options.
|
47
|
+
#
|
48
|
+
# If you wish FastImage to raise if it cannot size the image for any reason, then pass
|
49
|
+
# :raise_on_failure => true in the options.
|
50
|
+
#
|
51
|
+
# FastImage knows about GIF, JPEG, BMP and PNG files.
|
52
|
+
#
|
53
|
+
# === Example
|
54
|
+
#
|
55
|
+
# require 'fastimage'
|
56
|
+
#
|
57
|
+
# FastImage.size("http://stephensykes.com/images/ss.com_x.gif")
|
58
|
+
# => [266, 56]
|
59
|
+
# FastImage.type("http://stephensykes.com/images/pngimage")
|
60
|
+
# => [16, 16]
|
61
|
+
# FastImage.size("http://farm4.static.flickr.com/3023/3047236863_9dce98b836.jpg")
|
62
|
+
# => [500, 375]
|
63
|
+
# FastImage.size("http://www-ece.rice.edu/~wakin/images/lena512.bmp")
|
64
|
+
# => [512, 512]
|
65
|
+
# FastImage.size("http://pennysmalls.com/does_not_exist")
|
66
|
+
# => nil
|
67
|
+
# FastImage.size("http://pennysmalls.com/does_not_exist", :raise_on_failure=>true)
|
68
|
+
# => raises FastImage::ImageFetchFailure
|
69
|
+
# FastImage.size("http://stephensykes.com/favicon.ico", :raise_on_failure=>true)
|
70
|
+
# => raises FastImage::UnknownImageType
|
71
|
+
# FastImage.size("http://stephensykes.com/favicon.ico", :raise_on_failure=>true, :timeout=>0.01)
|
72
|
+
# => raises FastImage::ImageFetchFailure
|
73
|
+
# FastImage.size("http://stephensykes.com/images/faulty.jpg", :raise_on_failure=>true)
|
74
|
+
# => raises FastImage::SizeNotFound
|
75
|
+
#
|
76
|
+
# === Supported options
|
77
|
+
# [:timeout]
|
78
|
+
# Overrides the default timeout of 2 seconds. Applies both to reading from and opening the http connection.
|
79
|
+
# [:raise_on_failure]
|
80
|
+
# If set to true causes an exception to be raised if the image size cannot be found for any reason.
|
81
|
+
#
|
82
|
+
def self.size(uri, options={})
|
83
|
+
new(uri, options).size
|
84
|
+
end
|
85
|
+
|
86
|
+
# Returns an symbol indicating the image type fetched from a uri.
|
87
|
+
# It will return nil if the image could not be fetched, or if the image type was not recognised.
|
88
|
+
#
|
89
|
+
# By default there is a timeout of 2 seconds for opening and reading from the remote server.
|
90
|
+
# This can be changed by passing a :timeout => number_of_seconds in the options.
|
91
|
+
#
|
92
|
+
# If you wish FastImage to raise if it cannot find the type of the image for any reason, then pass
|
93
|
+
# :raise_on_failure => true in the options.
|
94
|
+
#
|
95
|
+
# === Example
|
96
|
+
#
|
97
|
+
# require 'fastimage'
|
98
|
+
#
|
99
|
+
# FastImage.type("http://stephensykes.com/images/ss.com_x.gif")
|
100
|
+
# => :gif
|
101
|
+
# FastImage.type("http://stephensykes.com/images/pngimage")
|
102
|
+
# => :png
|
103
|
+
# FastImage.type("http://farm4.static.flickr.com/3023/3047236863_9dce98b836.jpg")
|
104
|
+
# => :jpg
|
105
|
+
# FastImage.type("http://www-ece.rice.edu/~wakin/images/lena512.bmp")
|
106
|
+
# => :bmp
|
107
|
+
# FastImage.type("http://pennysmalls.com/does_not_exist")
|
108
|
+
# => nil
|
109
|
+
#
|
110
|
+
# === Supported options
|
111
|
+
# [:timeout]
|
112
|
+
# Overrides the default timeout of 2 seconds. Applies both to reading from and opening the http connection.
|
113
|
+
# [:raise_on_failure]
|
114
|
+
# If set to true causes an exception to be raised if the image type cannot be found for any reason.
|
115
|
+
#
|
116
|
+
def self.type(uri, options={})
|
117
|
+
new(uri, options.merge(:type_only=>true)).type
|
118
|
+
end
|
119
|
+
|
120
|
+
def initialize(uri, options={})
|
121
|
+
@type_only = options[:type_only]
|
122
|
+
setup_http(uri, options)
|
123
|
+
@http.request_get(@http_get_path) do |res|
|
124
|
+
raise ImageFetchFailure unless res.is_a?(Net::HTTPSuccess)
|
125
|
+
fetch_size_from_response(res)
|
126
|
+
end
|
127
|
+
raise SizeNotFound if options[:raise_on_failure] && !@size
|
128
|
+
rescue Timeout::Error, SocketError, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Errno::ECONNRESET, ImageFetchFailure
|
129
|
+
raise ImageFetchFailure if options[:raise_on_failure]
|
130
|
+
rescue UnknownImageType
|
131
|
+
raise UnknownImageType if options[:raise_on_failure]
|
132
|
+
end
|
133
|
+
|
134
|
+
private
|
135
|
+
|
136
|
+
def setup_http(uri, options)
|
137
|
+
u = URI.parse(uri)
|
138
|
+
@http = Net::HTTP.new(u.host, u.port)
|
139
|
+
@http.use_ssl = (u.scheme == "https")
|
140
|
+
@http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
141
|
+
@http.open_timeout = options[:timeout] || DefaultTimeout
|
142
|
+
@http.read_timeout = options[:timeout] || DefaultTimeout
|
143
|
+
@http_get_path = u.request_uri
|
144
|
+
end
|
145
|
+
|
146
|
+
def fetch_type_from_response(res)
|
147
|
+
fetch_from_response(res, :type){parse_type}
|
148
|
+
end
|
149
|
+
|
150
|
+
def fetch_size_from_response(res)
|
151
|
+
fetch_from_response(res, :size){parse_size}
|
152
|
+
end
|
153
|
+
|
154
|
+
def fetch_from_response(res, item)
|
155
|
+
@unused_str = ""
|
156
|
+
res.read_body do |str|
|
157
|
+
@str = @unused_str + str
|
158
|
+
@strpos = 0
|
159
|
+
begin
|
160
|
+
result = yield
|
161
|
+
if result
|
162
|
+
instance_variable_set("@#{item}", result)
|
163
|
+
break
|
164
|
+
end
|
165
|
+
rescue MoreCharsNeeded
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def parse_size
|
171
|
+
@type = parse_type unless @type
|
172
|
+
send("parse_size_for_#{@type}")
|
173
|
+
end
|
174
|
+
|
175
|
+
def get_chars(n)
|
176
|
+
if @strpos + n - 1 >= @str.size
|
177
|
+
@unused_str = @str[@strpos..-1]
|
178
|
+
raise MoreCharsNeeded
|
179
|
+
else
|
180
|
+
result = @str[@strpos..(@strpos + n - 1)]
|
181
|
+
@strpos += n
|
182
|
+
result
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
def get_byte
|
187
|
+
get_chars(1).unpack("C")[0]
|
188
|
+
end
|
189
|
+
|
190
|
+
def read_int(str)
|
191
|
+
size_bytes = str.unpack("CC")
|
192
|
+
(size_bytes[0] << 8) + size_bytes[1]
|
193
|
+
end
|
194
|
+
|
195
|
+
def parse_type
|
196
|
+
case get_chars(2)
|
197
|
+
when "BM"
|
198
|
+
:bmp
|
199
|
+
when "GI"
|
200
|
+
:gif
|
201
|
+
when 0xff.chr + 0xd8.chr
|
202
|
+
:jpg
|
203
|
+
when 0x89.chr + "P"
|
204
|
+
:png
|
205
|
+
else
|
206
|
+
raise UnknownImageType
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
def parse_size_for_gif
|
211
|
+
get_chars(9)[4..8].unpack('SS')
|
212
|
+
end
|
213
|
+
|
214
|
+
def parse_size_for_png
|
215
|
+
get_chars(23)[14..22].unpack('NN')
|
216
|
+
end
|
217
|
+
|
218
|
+
def parse_size_for_jpg
|
219
|
+
loop do
|
220
|
+
@state = case @state
|
221
|
+
when nil
|
222
|
+
get_chars(2)
|
223
|
+
:started
|
224
|
+
when :started
|
225
|
+
get_byte == 0xFF ? :sof : :started
|
226
|
+
when :sof
|
227
|
+
c = get_byte
|
228
|
+
if (0xe0..0xef).include?(c)
|
229
|
+
:skipframe
|
230
|
+
elsif [0xC0..0xC3, 0xC5..0xC7, 0xC9..0xCB, 0xCD..0xCF].detect {|r| r.include? c}
|
231
|
+
:readsize
|
232
|
+
else
|
233
|
+
:skipframe
|
234
|
+
end
|
235
|
+
when :skipframe
|
236
|
+
@skip_chars = read_int(get_chars(2)) - 2
|
237
|
+
:do_skip
|
238
|
+
when :do_skip
|
239
|
+
get_chars(@skip_chars)
|
240
|
+
:started
|
241
|
+
when :readsize
|
242
|
+
s = get_chars(7)
|
243
|
+
return [read_int(s[5..6]), read_int(s[3..4])]
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
def parse_size_for_bmp
|
249
|
+
d = get_chars(27)[12..26]
|
250
|
+
d[0] == 40 ? d[4..-1].unpack('LL') : d[4..8].unpack('SS')
|
251
|
+
end
|
252
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sdsykes-fastimage
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1
|
4
|
+
version: 1.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stephen Sykes
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-06-11 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -27,8 +27,7 @@ files:
|
|
27
27
|
- README
|
28
28
|
- README.textile
|
29
29
|
- VERSION.yml
|
30
|
-
- lib/
|
31
|
-
- test/test.rb
|
30
|
+
- lib/fastimage.rb
|
32
31
|
has_rdoc: true
|
33
32
|
homepage: http://github.com/sdsykes/fastimage
|
34
33
|
post_install_message:
|
data/lib/fastimage_resize.rb
DELETED
@@ -1,137 +0,0 @@
|
|
1
|
-
# FastImage Resize is an extremely light solution for resizing images in ruby by using libgd
|
2
|
-
#
|
3
|
-
# === Examples
|
4
|
-
#
|
5
|
-
# require 'fastimage_resize'
|
6
|
-
#
|
7
|
-
# FastImage.resize("http://stephensykes.com/images/ss.com_x.gif", "my.gif", 100, 20)
|
8
|
-
# => 1
|
9
|
-
#
|
10
|
-
# === Requirements
|
11
|
-
#
|
12
|
-
# RubyInline
|
13
|
-
#
|
14
|
-
# sudo gem install RubyInline
|
15
|
-
#
|
16
|
-
# FastImage
|
17
|
-
#
|
18
|
-
# sudo gem install sdsykes-fastimage -s http://gems.github.com
|
19
|
-
#
|
20
|
-
# Libgd
|
21
|
-
#
|
22
|
-
# See http://www.libgd.org/
|
23
|
-
# Libgd is commonly available on most unix platforms, including OSX.
|
24
|
-
#
|
25
|
-
# === References
|
26
|
-
#
|
27
|
-
# * http://blog.new-bamboo.co.uk/2007/12/3/super-f-simple-resizing
|
28
|
-
|
29
|
-
require 'inline'
|
30
|
-
require 'open-uri'
|
31
|
-
require 'tempfile'
|
32
|
-
require 'fastimage'
|
33
|
-
|
34
|
-
class FastImage
|
35
|
-
SUPPORTED_FORMATS = [:jpg, :png, :gif]
|
36
|
-
|
37
|
-
class FormatNotSupported < FastImageException # :nodoc:
|
38
|
-
end
|
39
|
-
|
40
|
-
def self.resize(uri_in, file_out, w, h, options={})
|
41
|
-
jpeg_quality = options[:jpeg_quality] || -1
|
42
|
-
|
43
|
-
u = URI.parse(uri_in)
|
44
|
-
if u.scheme == "http" || u.scheme == "https" || u.scheme == "ftp"
|
45
|
-
f = Tempfile.new(name)
|
46
|
-
f.write(open(u).read)
|
47
|
-
f.close
|
48
|
-
resize_local(f.path, file_out, w, h, jpeg_quality)
|
49
|
-
File.unlink(f.path)
|
50
|
-
else
|
51
|
-
resize_local(uri_in, file_out, w, h, jpeg_quality)
|
52
|
-
end
|
53
|
-
rescue OpenURI::HTTPError, SocketError
|
54
|
-
raise ImageFetchFailure
|
55
|
-
end
|
56
|
-
|
57
|
-
def self.resize_local(file_in, file_out, w, h, jpeg_quality)
|
58
|
-
fi = new(file_in, :raise_on_failure=>true, :type_only=>true)
|
59
|
-
type_index = SUPPORTED_FORMATS.index(fi.type)
|
60
|
-
raise FormatNotSupported unless type_index
|
61
|
-
fi.resize_image(file_in, file_out, w, h, type_index, jpeg_quality)
|
62
|
-
end
|
63
|
-
|
64
|
-
def resize_image(filename_in, filename_out, w, h, image_type, jpeg_quality); end
|
65
|
-
|
66
|
-
inline do |builder|
|
67
|
-
builder.include '"gd.h"'
|
68
|
-
builder.add_link_flags "-lgd"
|
69
|
-
|
70
|
-
builder.c <<-"END"
|
71
|
-
void resize_image(char *filename_in, char *filename_out, int w, int h, int image_type, int jpeg_quality) {
|
72
|
-
gdImagePtr im_in, im_out;
|
73
|
-
FILE *in, *out;
|
74
|
-
int trans, trans_r, trans_g, trans_b;
|
75
|
-
int x, y, f = 0;
|
76
|
-
|
77
|
-
in = fopen(filename_in, "rb");
|
78
|
-
if (!in) return;
|
79
|
-
|
80
|
-
im_out = gdImageCreateTrueColor(w, h); /* must be truecolor */
|
81
|
-
switch(image_type) {
|
82
|
-
case 0: im_in = gdImageCreateFromJpeg(in);
|
83
|
-
break;
|
84
|
-
case 1: im_in = gdImageCreateFromPng(in);
|
85
|
-
gdImageAlphaBlending(im_out, 0); /* handle transparency correctly */
|
86
|
-
gdImageSaveAlpha(im_out, 1);
|
87
|
-
break;
|
88
|
-
case 2: im_in = gdImageCreateFromGif(in);
|
89
|
-
trans = gdImageGetTransparent(im_in);
|
90
|
-
/* find a transparent pixel, then turn off transparency
|
91
|
-
so that it copies correctly */
|
92
|
-
if (trans >= 0) {
|
93
|
-
for (x=0; x<gdImageSX(im_in); x++) {
|
94
|
-
for (y=0; y<gdImageSY(im_in); y++) {
|
95
|
-
if (gdImageGetPixel(im_in, x, y) == trans) {
|
96
|
-
f = 1;
|
97
|
-
break;
|
98
|
-
}
|
99
|
-
}
|
100
|
-
if (f) break;
|
101
|
-
}
|
102
|
-
gdImageColorTransparent(im_in, -1);
|
103
|
-
if (!f) trans = -1; /* no transparent pixel found */
|
104
|
-
}
|
105
|
-
break;
|
106
|
-
}
|
107
|
-
|
108
|
-
fclose(in);
|
109
|
-
|
110
|
-
/* Now copy the original */
|
111
|
-
gdImageCopyResampled(im_out, im_in, 0, 0, 0, 0,
|
112
|
-
gdImageSX(im_out), gdImageSY(im_out),
|
113
|
-
gdImageSX(im_in), gdImageSY(im_in));
|
114
|
-
|
115
|
-
out = fopen(filename_out, "wb");
|
116
|
-
if (out) {
|
117
|
-
switch(image_type) {
|
118
|
-
case 0: gdImageJpeg(im_out, out, jpeg_quality);
|
119
|
-
break;
|
120
|
-
case 1: gdImagePng(im_out, out);
|
121
|
-
break;
|
122
|
-
case 2: gdImageTrueColorToPalette(im_out, 0, 256);
|
123
|
-
if (trans >= 0) {
|
124
|
-
trans = gdImageGetPixel(im_out, x, y); /* get the color index of our transparent pixel */
|
125
|
-
gdImageColorTransparent(im_out, trans); /* may not always work as hoped */
|
126
|
-
}
|
127
|
-
gdImageGif(im_out, out);
|
128
|
-
break;
|
129
|
-
}
|
130
|
-
fclose(out);
|
131
|
-
}
|
132
|
-
gdImageDestroy(im_in);
|
133
|
-
gdImageDestroy(im_out);
|
134
|
-
}
|
135
|
-
END
|
136
|
-
end
|
137
|
-
end
|
data/test/test.rb
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
# todo
|