quick_magick 0.4.0 → 0.5.0
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.
Potentially problematic release.
This version of quick_magick might be problematic. Click here for more details.
- data/Manifest +2 -2
- data/README +99 -42
- data/Rakefile +1 -1
- data/lib/quick_magick/image.rb +40 -31
- data/lib/quick_magick.rb +119 -6
- data/quick_magick.gemspec +4 -4
- data/test/9.gif +0 -0
- data/test/image_list_test.rb +53 -23
- data/test/image_test.rb +59 -16
- data/test/test_magick.rb +169 -0
- metadata +5 -4
- data/test/imagemagick-logo.png +0 -0
- data/test/logo-small.jpg +0 -0
data/Manifest
CHANGED
data/README
CHANGED
@@ -1,72 +1,125 @@
|
|
1
|
-
|
1
|
+
= Quick Magick
|
2
2
|
|
3
|
+
== What is QuickMagick
|
3
4
|
QuickMagick is a gem for easily accessing ImageMagick command line tools from Ruby programs.
|
4
5
|
|
5
|
-
==
|
6
|
+
== When to use QuickMagick
|
7
|
+
QuickMagick is a library that allows you to create and manipulate images.
|
8
|
+
When you are faced with a problem that requires high quality manipulation of images you can use QuickMagick.
|
9
|
+
These are some situation when QuickMagick will be useful for you:
|
10
|
+
* Suppose you built an image gallery site that allows users to upload images. You can use QuickMagick to check uploaded images dimensions and make thumbnails for them.
|
11
|
+
* Generate captchas to check whether the user is a robot or a human.
|
12
|
+
* Generate graphical reports and charts to the user based on some calculations.
|
13
|
+
* Convert uploaded images to a format usable by your application. For example, you can transform .pdf files to .jpg so that you can display them at your web site.
|
14
|
+
|
15
|
+
== Features
|
16
|
+
* Open an existing image from disk and determine basic info like width, height.
|
17
|
+
* Open an image from blob. For example, an image read from an upload form.
|
18
|
+
* Do basic and advanced operations on images like resize, rotate, shear, motion blur and other.
|
19
|
+
* Create an image from scratch and draw basic elements on it like line, circle and text. This allows making captchas for example.
|
20
|
+
* Combine images using ImageList to make a multipage or animated images.
|
21
|
+
* API is very simple and powerful.
|
22
|
+
* Minimizes disk access by calling command line tools only when required.
|
23
|
+
|
24
|
+
== How to install
|
25
|
+
First, you should install ImageMagick (http://www.imagemagick.org/) on your machine.
|
26
|
+
Command lines of ImageMagick must be in your system path.
|
27
|
+
You can check this by running the command:
|
28
|
+
identify --version
|
29
|
+
Now to install QuickMagick just type at your command line:
|
30
|
+
gem install quick_magick
|
31
|
+
... and it's done.
|
32
|
+
You don't have to install any libraries or compile code from source.
|
6
33
|
|
34
|
+
== What is different?
|
7
35
|
But what's different from other gems like RMagick and mini-magick?
|
8
|
-
RMagick is a very good gem and QuickMagick is not a replacement of it.
|
9
|
-
RMagick mainpulates images in memory.
|
10
|
-
This is sometimes preferable but not in all cases.
|
11
|
-
It uses a huge amonut of memory when manipulating images of large sizes.
|
12
|
-
QuickMagick allows you to access all the powerful commands of ImageMagick that are accessible from command line.
|
13
|
-
When you need more advanced options like reading pixel values, you should go to RMagick.
|
14
|
-
Another good point in QuickMagick is that it's very easy to install.
|
15
|
-
It doesn't require any Magick libraries or compile something from source to be installed.
|
16
|
-
A running copy of ImageMagick is enough.
|
17
|
-
|
18
|
-
The idea of this gem came from MiniMagick.
|
19
|
-
I used MiniMagick for a little time but I found that some advanced options are missing.
|
20
|
-
For example, you cannot manipulate multipage images.
|
21
|
-
Also, it uses "mogrify" and creates temporary files to simulate the "convert" command which makes it slower as it accesses the disk multiple times.
|
22
|
-
Another small stuff is that it relies on method_missing to set command line arguments which is slow and not preferable.
|
23
|
-
|
24
|
-
In QuickMagick I tried to solve the above problems while keeping the API as easy as possible.
|
25
36
|
|
26
|
-
|
37
|
+
The story begins when I was working on a project at BadrIT (http://www.badrit.com) using Ruby on Rails.
|
38
|
+
In this projects users were uploading images in many formats like pdf, tiff and png.
|
39
|
+
We were using Flex as a front end to display and annotate these images.
|
40
|
+
Flex has a limitation in that it can open images up to 8192x8192.
|
41
|
+
Unfortunately, users were uploading images much larger than this.
|
42
|
+
Another issue is that Flex can only open .jpg, .png and .gif files.
|
43
|
+
The solution was to convert all images uploaded to one of these formats and resizing them down to at most 8192x8192.
|
44
|
+
|
45
|
+
First, I used ImageMagick as a command line tool and was calling it using system calls.
|
46
|
+
This accomplished the work perfectly buy my source code was a rubbish.
|
47
|
+
It has many lines of code to handle creating temporary files and accessing multipage tiff and pdf files.
|
48
|
+
I found RMagick at that time and decided to use it.
|
49
|
+
It caused the code to be much simple without affecting performance notably.
|
50
|
+
It worked with me well while I was using my application with test images.
|
51
|
+
Once I decided to test it with real images it failed.
|
52
|
+
For example, when I transform a tiff image from 14400x9600 to 8192x8192 while transforming it to gif, my machine runs out of memory (2GB RAM).
|
53
|
+
When I tried to make the same operation from command line using (convert) it was working much better.
|
54
|
+
It did not finish in a second but at least it worked correctly.
|
55
|
+
The solution was to return back to command line.
|
56
|
+
|
57
|
+
I searched for alternatives and found MiniMagick.
|
58
|
+
MiniMagick is a gem that allows you to perform basic operations using ImageMagick through command line tools.
|
59
|
+
I tried to use it but it was not good enough.
|
60
|
+
First, it writes temporary images and files as it is working which makes it slow for nothing.
|
61
|
+
Second, it doesn't handle multipage images.
|
62
|
+
I tried it with a .pdf file and I found that it handled the first page only.
|
63
|
+
Third, it doesn't give an API to draw images from scratch.
|
64
|
+
Actually, I didn't need this feature, but I may need it in the future.
|
65
|
+
|
66
|
+
At this point I decided to make my own gem and QuickMagick was born.
|
67
|
+
I addressed the problems of MiniMagick while using the same main idea.
|
68
|
+
First, QuickMagick doesn't write any temporary images to disk.
|
69
|
+
It doesn't issue any command line commands till the very end when you are saving the image.
|
70
|
+
Second, I made an API similar to RMagick which allows for accessing multipage images.
|
71
|
+
Third, I added API commands to create images from scratch and drawing simple primitives on images.
|
72
|
+
I tested my gem, compared it to MiniMagick and RMagick and it pleased me.
|
27
73
|
|
74
|
+
== Comparison
|
28
75
|
I've made some test benches to compare the speed of QuickMagick, MiniMagick and RMagick.
|
76
|
+
All denoted numbers are in seconds.
|
29
77
|
Here are the results:
|
30
78
|
|
31
|
-
Test 1: resize a normal image
|
79
|
+
===Test 1: resize a normal image
|
32
80
|
user system total real
|
33
|
-
mini 0.
|
34
|
-
quick 0.010000 0.
|
35
|
-
rmagick 1.
|
81
|
+
mini 0.030000 0.040000 3.640000 ( 3.585617)
|
82
|
+
quick 0.010000 0.030000 3.330000 ( 3.295369)
|
83
|
+
rmagick 1.680000 1.660000 3.340000 ( 3.150202)
|
36
84
|
|
37
|
-
It's clear that QuickMagick is faster
|
38
|
-
|
39
|
-
Actually, this is not always the case.
|
40
|
-
Sometimes It's faster than QuickMagick.
|
41
|
-
On average, we can say that they both take the same time.
|
85
|
+
It's clear that QuickMagick is faster than MiniMagick.
|
86
|
+
RMagick was the fastest as it accesses the requested operations directly without the need to load an executable file or parse a command line.
|
42
87
|
|
43
|
-
Test 2: resize a large image
|
88
|
+
===Test 2: resize a large image
|
44
89
|
user system total real
|
45
|
-
mini 0.000000 0.
|
46
|
-
quick 0.
|
90
|
+
mini 0.000000 0.040000 57.150000 (130.609229)
|
91
|
+
quick 0.010000 0.010000 56.510000 ( 58.426361)
|
47
92
|
|
48
93
|
Again QuickMagick is faster than MiniMagick.
|
49
94
|
However, RMagick has failed to pass this test.
|
50
95
|
It kept working and eating memory, cpu and harddisk till I had to unplug my computer to stop it.
|
51
96
|
So, I removed it from this test bench.
|
52
97
|
|
53
|
-
Test 3: generate random captchas
|
98
|
+
===Test 3: generate random captchas
|
54
99
|
user system total real
|
55
|
-
quick 0.
|
56
|
-
rmagick
|
100
|
+
quick 0.000000 0.000000 0.290000 ( 3.623418)
|
101
|
+
rmagick 0.150000 0.120000 0.270000 ( 3.171975)
|
57
102
|
|
58
|
-
In this last test, RMagick was
|
103
|
+
In this last test, RMagick was about 12% faster than QuickMagick.
|
59
104
|
This is normal because it works in memory and doesn't have to parse a command line string to know what to draw.
|
60
105
|
I couldn't test MiniMagick for this because it doesn't support an API for drawing functions.
|
61
106
|
|
62
|
-
==
|
107
|
+
== Conclusion
|
108
|
+
QuickMagick is very easy to install, very easy to use and allows you to access most features of ImageMagick.
|
109
|
+
RMagick is a bit faster and has an advantage of allowing you to access single pixels but it's a bit hard to install.
|
110
|
+
Also RMagick sometimes fail when it tries to handle large images.
|
111
|
+
MiniMagick is proved to be a bit slower than QuickMagick with no advantage.
|
112
|
+
So, it's better to use QuickMagick when your application is not image-centric.
|
113
|
+
This means, you're not going to build an image manipulation tool or something like this.
|
114
|
+
For normal operations like resize, rotate, generating captchas ... etc, QuickMagick will be a good friend of you.
|
63
115
|
|
116
|
+
== Examples
|
64
117
|
Determine image information
|
65
118
|
i = QuickMagick::Image.read('test.jpg').first
|
66
119
|
i.width # Retrieves width in pixels
|
67
120
|
i.height # Retrieves height in pixels
|
68
121
|
|
69
|
-
Resize
|
122
|
+
Resize an image
|
70
123
|
i = QuickMagick::Image.read('test.jpg').first
|
71
124
|
i.resize "300x300!"
|
72
125
|
i.save "resized_image.jpg"
|
@@ -80,7 +133,7 @@ Resize and image
|
|
80
133
|
|
81
134
|
Access multipage image
|
82
135
|
i = QuickMagick::Image.read("multipage.pdf") {|image| image.density = 300}
|
83
|
-
i.size
|
136
|
+
i.size # number of pages
|
84
137
|
i.each_with_index do |page, i|
|
85
138
|
i.save "page_#{i}.jpg"
|
86
139
|
end
|
@@ -99,14 +152,15 @@ You can also display an image to Xserver
|
|
99
152
|
i = QuickMagick::Image.read('test.jpg')
|
100
153
|
i.display
|
101
154
|
|
102
|
-
QuickMagick supports also
|
155
|
+
QuickMagick supports also ImageList s
|
156
|
+
# Batch generate a list of jpg files to gif while resizing them
|
103
157
|
il = QuickMagick::ImageList.new('test.jpg', 'test2.jpg')
|
104
158
|
il << QuickMagick::Image.read('test3.jpg')
|
105
159
|
il.format = 'gif'
|
106
160
|
il.resize "300x300>"
|
107
161
|
il.save!
|
108
162
|
|
109
|
-
You can also create images from scratch
|
163
|
+
(new) You can also create images from scratch
|
110
164
|
# Create a 300x300 gradient image from yellow to red
|
111
165
|
i1 = QuickMagick::Image::gradient(300, 300, QuickMagick::RadialGradient, :yellow, :red)
|
112
166
|
i1.save 'gradient.png'
|
@@ -121,5 +175,8 @@ You can also create images from scratch
|
|
121
175
|
i.draw_text(30, 30, "Hello world!", :rotate=>45)
|
122
176
|
i.save 'hello.jpg'
|
123
177
|
|
124
|
-
|
178
|
+
For more information on drawing API visit:
|
179
|
+
http://www.imagemagick.org/Usage/draw/
|
180
|
+
|
181
|
+
Check all command line options of ImageMagick at:
|
125
182
|
http://www.imagemagick.org/script/convert.php
|
data/Rakefile
CHANGED
@@ -2,7 +2,7 @@ require 'rubygems'
|
|
2
2
|
require 'rake'
|
3
3
|
require 'echoe'
|
4
4
|
|
5
|
-
Echoe.new('quick_magick', '0.
|
5
|
+
Echoe.new('quick_magick', '0.5.0') do |p|
|
6
6
|
p.description = "QuickMagick allows you to access ImageMagick command line functions using Ruby interface."
|
7
7
|
p.url = "http://quickmagick.rubyforge.org/"
|
8
8
|
p.author = "Ahmed ElDawy"
|
data/lib/quick_magick/image.rb
CHANGED
@@ -42,7 +42,7 @@ module QuickMagick
|
|
42
42
|
template_name << color1.to_s if color1
|
43
43
|
template_name << '-' << color2.to_s if color2
|
44
44
|
i = self.new(template_name, nil, true)
|
45
|
-
i.size = QuickMagick::
|
45
|
+
i.size = QuickMagick::geometry(width, height)
|
46
46
|
i
|
47
47
|
end
|
48
48
|
|
@@ -51,7 +51,7 @@ module QuickMagick
|
|
51
51
|
template_name = QuickMagick::SolidColor+":"
|
52
52
|
template_name << color.to_s if color
|
53
53
|
i = self.new(template_name, nil, true)
|
54
|
-
i.size = QuickMagick::
|
54
|
+
i.size = QuickMagick::geometry(width, height)
|
55
55
|
i
|
56
56
|
end
|
57
57
|
|
@@ -60,7 +60,7 @@ module QuickMagick
|
|
60
60
|
raise QuickMagick::QuickMagickError, "Invalid pattern '#{pattern.to_s}'" unless QuickMagick::Patterns.include?(pattern.to_s)
|
61
61
|
template_name = "pattern:#{pattern.to_s}"
|
62
62
|
i = self.new(template_name, nil, true)
|
63
|
-
i.size = QuickMagick::
|
63
|
+
i.size = QuickMagick::geometry(width, height)
|
64
64
|
i
|
65
65
|
end
|
66
66
|
|
@@ -69,26 +69,12 @@ module QuickMagick
|
|
69
69
|
`identify #{filename} 2>&1`
|
70
70
|
end
|
71
71
|
|
72
|
-
# Encodes a geometry string with the given options
|
73
|
-
def retrieve_geometry(width, height=nil, x=nil, y=nil, flag=nil)
|
74
|
-
geometry_string = ""
|
75
|
-
geometry_string << width.to_s if width
|
76
|
-
geometry_string << 'x' << height.to_s if height
|
77
|
-
geometry_string << '+' << x.to_s if x
|
78
|
-
geometry_string << '+' << y.to_s if y
|
79
|
-
geometry_string << flag if flag
|
80
|
-
geometry_string
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
# append the given option, value pair to the args for the current image
|
85
|
-
def append_to_operators(arg, value="")
|
86
|
-
@operators << %Q<-#{arg} "#{value}" >
|
87
72
|
end
|
88
73
|
|
89
74
|
# append the given option, value pair to the settings of the current image
|
90
75
|
def append_to_settings(arg, value="")
|
91
|
-
@
|
76
|
+
@arguments << %Q<-#{arg} "#{value}" >
|
77
|
+
self
|
92
78
|
end
|
93
79
|
|
94
80
|
# Image settings supported by ImageMagick
|
@@ -104,10 +90,28 @@ module QuickMagick
|
|
104
90
|
density page sampling-factor size tile-offset
|
105
91
|
}
|
106
92
|
|
93
|
+
# append the given option, value pair to the args for the current image
|
94
|
+
def append_to_operators(arg, value="")
|
95
|
+
if @last_is_draw
|
96
|
+
@arguments.insert(@arguments.rindex('"'), " #{value}")
|
97
|
+
else
|
98
|
+
@arguments << %Q<-#{arg} "#{value}" >
|
99
|
+
end
|
100
|
+
@last_is_draw = arg == 'draw'
|
101
|
+
self
|
102
|
+
end
|
103
|
+
|
104
|
+
# Reverts this image to its last saved state.
|
105
|
+
# Note that you cannot revert an image created from scratch.
|
106
|
+
def revert!
|
107
|
+
raise QuickMagick::QuickMagickError, "Cannot revert a pseudo image" if @pseudo_image
|
108
|
+
@arguments = ""
|
109
|
+
end
|
110
|
+
|
107
111
|
# Image operators supported by ImageMagick
|
108
112
|
IMAGE_OPERATORS_METHODS = %w{
|
109
113
|
alpha auto-orient bench black-threshold bordercolor charcoal clip clip-mask clip-path colorize
|
110
|
-
contrast convolve cycle decipher deskew despeckle distort
|
114
|
+
contrast convolve cycle decipher deskew despeckle distort edge encipher emboss enhance equalize
|
111
115
|
evaluate flip flop function gamma identify implode layers level level-colors median modulate monochrome
|
112
116
|
negate noise normalize opaque ordered-dither NxN paint polaroid posterize print profile quantize
|
113
117
|
radial-blur Raise random-threshold recolor render rotate segment sepia-tone set shade solarize
|
@@ -123,11 +127,6 @@ module QuickMagick
|
|
123
127
|
crop
|
124
128
|
}
|
125
129
|
|
126
|
-
# fills a rectangle with a solid color
|
127
|
-
def floodfill(width, height=nil, x=nil, y=nil, flag=nil, color=nil)
|
128
|
-
append_to_operators "floodfill", QuickMagick::Image.retrieve_geometry(width, height, x, y, flag), color
|
129
|
-
end
|
130
|
-
|
131
130
|
# methods that are called with (=)
|
132
131
|
WITH_EQUAL_METHODS =
|
133
132
|
%w{alpha antialias background bias black-point-compensation blue-primary border bordercolor caption
|
@@ -151,7 +150,7 @@ module QuickMagick
|
|
151
150
|
end
|
152
151
|
elsif WITH_GEOMETRY_METHODS.include?(method)
|
153
152
|
define_method((method).to_sym) do |*args|
|
154
|
-
append_to_settings(method, QuickMagick::
|
153
|
+
append_to_settings(method, QuickMagick::geometry(*args) )
|
155
154
|
end
|
156
155
|
else
|
157
156
|
define_method(method.to_sym) do |*args|
|
@@ -167,7 +166,7 @@ module QuickMagick
|
|
167
166
|
end
|
168
167
|
elsif WITH_GEOMETRY_METHODS.include?(method)
|
169
168
|
define_method((method).to_sym) do |*args|
|
170
|
-
append_to_operators(method, QuickMagick::
|
169
|
+
append_to_operators(method, QuickMagick::geometry(*args) )
|
171
170
|
end
|
172
171
|
else
|
173
172
|
define_method(method.to_sym) do |*args|
|
@@ -175,6 +174,11 @@ module QuickMagick
|
|
175
174
|
end
|
176
175
|
end
|
177
176
|
end
|
177
|
+
|
178
|
+
# Fills a rectangle with a solid color
|
179
|
+
def floodfill(width, height=nil, x=nil, y=nil, flag=nil, color=nil)
|
180
|
+
append_to_operators "floodfill", QuickMagick::geometry(width, height, x, y, flag), color
|
181
|
+
end
|
178
182
|
|
179
183
|
# define attribute readers (getters)
|
180
184
|
attr_reader :image_filename
|
@@ -188,13 +192,12 @@ module QuickMagick
|
|
188
192
|
@image_infoline = info_line.split
|
189
193
|
@image_infoline[0..1] = @image_infoline[0..1].join(' ') while @image_infoline.size > 1 && !@image_infoline[0].start_with?(image_filename)
|
190
194
|
end
|
191
|
-
@
|
192
|
-
@settings = ""
|
195
|
+
@arguments = ""
|
193
196
|
end
|
194
197
|
|
195
198
|
# The command line so far that will be used to convert or save the image
|
196
199
|
def command_line
|
197
|
-
%Q
|
200
|
+
%Q< "(" #{@arguments} "#{image_filename}" ")" >
|
198
201
|
end
|
199
202
|
|
200
203
|
# An information line about the image obtained using 'identify' command line
|
@@ -214,6 +217,8 @@ module QuickMagick
|
|
214
217
|
# * skewX degrees
|
215
218
|
# * skewY degrees
|
216
219
|
# * gravity NorthWest, North, NorthEast, West, Center, East, SouthWest, South, or SouthEast
|
220
|
+
# * stroke color
|
221
|
+
# * fill color
|
217
222
|
# The rotate primitive rotates subsequent shape primitives and text primitives about the origin of the main image.
|
218
223
|
# If you set the region before the draw command, the origin for transformations is the upper left corner of the region.
|
219
224
|
# The translate primitive translates subsequent shape and text primitives.
|
@@ -290,6 +295,7 @@ module QuickMagick
|
|
290
295
|
# The polyline primitive requires three or more points to define their perimeters.
|
291
296
|
# A polyline is simply a polygon in which the final point is not stroked to the start point.
|
292
297
|
# When unfilled, this is a polygonal line. If the -stroke setting is none (the default), then a polyline is identical to a polygon.
|
298
|
+
# points - A single array with each pair forming a coordinate in the form (x, y). e.g. [0,0,100,100,100,0] will draw a polyline between points (0,0)-(100,100)-(100,0)
|
293
299
|
def draw_polyline(points, options={})
|
294
300
|
append_to_operators("draw", "#{options_to_str(options)} polyline #{points_to_str(points)}")
|
295
301
|
end
|
@@ -297,6 +303,7 @@ module QuickMagick
|
|
297
303
|
# The polygon primitive requires three or more points to define their perimeters.
|
298
304
|
# A polyline is simply a polygon in which the final point is not stroked to the start point.
|
299
305
|
# When unfilled, this is a polygonal line. If the -stroke setting is none (the default), then a polyline is identical to a polygon.
|
306
|
+
# points - A single array with each pair forming a coordinate in the form (x, y). e.g. [0,0,100,100,100,0] will draw a polygon between points (0,0)-(100,100)-(100,0)
|
300
307
|
def draw_polygon(points, options={})
|
301
308
|
append_to_operators("draw", "#{options_to_str(options)} polygon #{points_to_str(points)}")
|
302
309
|
end
|
@@ -362,6 +369,8 @@ module QuickMagick
|
|
362
369
|
raise QuickMagick::QuickMagickError, "Cannot mogrify a pseudo image" if @pseudo_image
|
363
370
|
result = `mogrify #{command_line}`
|
364
371
|
if $?.success?
|
372
|
+
# remove all operations to avoid duplicate operations
|
373
|
+
revert!
|
365
374
|
return result
|
366
375
|
else
|
367
376
|
error_message = <<-ERRORMSG
|
@@ -419,4 +428,4 @@ module QuickMagick
|
|
419
428
|
`display #{command_line}`
|
420
429
|
end
|
421
430
|
end
|
422
|
-
end
|
431
|
+
end
|
data/lib/quick_magick.rb
CHANGED
@@ -13,12 +13,32 @@ rescue Errno::ENOENT
|
|
13
13
|
end
|
14
14
|
|
15
15
|
module QuickMagick
|
16
|
-
#
|
16
|
+
# Normally the attributes are treated as pixels.
|
17
|
+
# Use this flag when the width and height attributes represent percentages.
|
18
|
+
# For example, 125x75 means 125% of the height and 75% of the width.
|
19
|
+
# The x and y attributes are not affected by this flag.
|
17
20
|
PercentGeometry = "%"
|
21
|
+
|
22
|
+
# Use this flag when you want to force the new image to have exactly the size specified by the the width and height attributes.
|
18
23
|
AspectGeometry = "!"
|
24
|
+
|
25
|
+
# Use this flag when you want to change the size of the image only if both its width and height
|
26
|
+
# are smaller the values specified by those attributes. The image size is changed proportionally.
|
19
27
|
LessGeometry = "<"
|
28
|
+
|
29
|
+
# Use this flag when you want to change the size of the image if either its width and height
|
30
|
+
# exceed the values specified by those attributes. The image size is changed proportionally.
|
20
31
|
GreaterGeometry = ">"
|
32
|
+
|
33
|
+
# This flag is useful only with a single width attribute.
|
34
|
+
# When present, it means the width attribute represents the total area of the image in pixels.
|
21
35
|
AreaGeometry = "@"
|
36
|
+
|
37
|
+
# Use ^ to set a minimum image size limit.
|
38
|
+
# The geometry 640x480^, for example, means the image width will not be less than 640 and
|
39
|
+
# the image height will not be less than 480 pixels after the resize.
|
40
|
+
# One of those dimensions will match the requested size,
|
41
|
+
# but the image will likely overflow the space requested to preserve its aspect ratio.
|
22
42
|
MinimumGeometry = "^"
|
23
43
|
|
24
44
|
# Command for solid color
|
@@ -35,11 +55,96 @@ module QuickMagick
|
|
35
55
|
hs_vertical left30 left45 leftshingle octagons right30 right45 rightshingle smallfishscales
|
36
56
|
vertical verticalbricks verticalleftshingle verticalrightshingle verticalsaw}
|
37
57
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
58
|
+
|
59
|
+
class <<self
|
60
|
+
# Generate a random string of specified length.
|
61
|
+
# Used to generate random names for temp files
|
62
|
+
def random_string(length=10)
|
63
|
+
@@CHARS ||= ("a".."z").to_a + ("1".."9").to_a
|
64
|
+
Array.new(length, '').collect{@@CHARS[rand(@@CHARS.size)]}.join
|
65
|
+
end
|
66
|
+
|
67
|
+
# Encodes a geometry string with the given options
|
68
|
+
def geometry(width, height=nil, x=nil, y=nil, flag=nil)
|
69
|
+
geometry_string = ""
|
70
|
+
geometry_string << width.to_s if width
|
71
|
+
geometry_string << 'x' << height.to_s if height
|
72
|
+
geometry_string << '+' << x.to_s if x
|
73
|
+
geometry_string << '+' << y.to_s if y
|
74
|
+
geometry_string << flag if flag
|
75
|
+
geometry_string
|
76
|
+
end
|
77
|
+
|
78
|
+
# Returns a formatted string for the color with the given components
|
79
|
+
# each component could take one of the following values
|
80
|
+
# * an integer from 0 to 255
|
81
|
+
# * a float from 0.0 to 1.0
|
82
|
+
# * a string showing percentage from "0%" to "100%"
|
83
|
+
def rgba_color(red, green, blue, alpha=255)
|
84
|
+
"#%02x%02x%02x%02x" % [red, green, blue, alpha].collect do |component|
|
85
|
+
case component
|
86
|
+
when Integer then component
|
87
|
+
when Float then Integer(component*255)
|
88
|
+
when String then Integer(component.sub('%', '')) * 255 / 100
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
alias rgb_color rgba_color
|
94
|
+
|
95
|
+
# Returns a formatted string for a gray color with the given level and alpha.
|
96
|
+
# level and alpha could take one of the following values
|
97
|
+
# * an integer from 0 to 255
|
98
|
+
# * a float from 0.0 to 1.0
|
99
|
+
# * a string showing percentage from "0%" to "100%"
|
100
|
+
def graya_color(level, alpha=255)
|
101
|
+
rgba_color(level, level, level, alpha)
|
102
|
+
end
|
103
|
+
|
104
|
+
alias gray_color graya_color
|
105
|
+
|
106
|
+
# HSL colors are encoding as a triple (hue, saturation, lightness).
|
107
|
+
# Hue is represented as an angle of the color circle (i.e. the rainbow represented in a circle).
|
108
|
+
# This angle is so typically measured in degrees that the unit is implicit in CSS;
|
109
|
+
# syntactically, only a number is given. By definition red=0=360,
|
110
|
+
# and the other colors are spread around the circle, so green=120, blue=240, etc.
|
111
|
+
# As an angle, it implicitly wraps around such that -120=240 and 480=120, for instance.
|
112
|
+
# (Students of trigonometry would say that "coterminal angles are equivalent" here;
|
113
|
+
# an angle (theta) can be standardized by computing the equivalent angle, (theta) mod 360.)
|
114
|
+
#
|
115
|
+
# Saturation and lightness are represented as percentages.
|
116
|
+
# 100% is full saturation, and 0% is a shade of grey.
|
117
|
+
# 0% lightness is black, 100% lightness is white, and 50% lightness is 'normal'.
|
118
|
+
#
|
119
|
+
# Hue can take one of the following values:
|
120
|
+
# * an integer from 0...360 representing angle in degrees
|
121
|
+
# * a float value from 0...2*PI represeting angle in radians
|
122
|
+
#
|
123
|
+
# saturation, lightness and alpha can take one of the following values:
|
124
|
+
# * an integer from 0 to 255
|
125
|
+
# * a float from 0.0 to 1.0
|
126
|
+
# * a string showing percentage from "0%" to "100%"
|
127
|
+
def hsla_color(hue, saturation, lightness, alpha=1.0)
|
128
|
+
components = [case hue
|
129
|
+
when Integer then hue
|
130
|
+
when Float then Integer(hue * 360 / 2 / Math::PI)
|
131
|
+
end]
|
132
|
+
components += [saturation, lightness].collect do |component|
|
133
|
+
case component
|
134
|
+
when Integer then (component * 100.0 / 255).round
|
135
|
+
when Float then Integer(component*100)
|
136
|
+
when String then Integer(component.sub('%', ''))
|
137
|
+
end
|
138
|
+
end
|
139
|
+
components << case alpha
|
140
|
+
when Integer then alpha * 100.0 / 255
|
141
|
+
when Float then alpha
|
142
|
+
when String then Float(alpha.sub('%', '')) / 100.0
|
143
|
+
end
|
144
|
+
"hsla(%d,%d%%,%d%%,%g)" % components
|
145
|
+
end
|
146
|
+
|
147
|
+
alias hsl_color hsla_color
|
43
148
|
end
|
44
149
|
end
|
45
150
|
|
@@ -52,5 +157,13 @@ unless "".respond_to? :start_with?
|
|
52
157
|
end
|
53
158
|
end
|
54
159
|
|
160
|
+
unless "".respond_to? :end_with?
|
161
|
+
class String
|
162
|
+
def end_with?(x)
|
163
|
+
self.index(x) == self.length - 1
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
55
168
|
require 'quick_magick/image'
|
56
169
|
require 'quick_magick/image_list'
|
data/quick_magick.gemspec
CHANGED
@@ -2,15 +2,15 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{quick_magick}
|
5
|
-
s.version = "0.
|
5
|
+
s.version = "0.5.0"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Ahmed ElDawy"]
|
9
|
-
s.date = %q{2009-08-
|
9
|
+
s.date = %q{2009-08-12}
|
10
10
|
s.description = %q{QuickMagick allows you to access ImageMagick command line functions using Ruby interface.}
|
11
11
|
s.email = %q{ahmed.eldawy@badrit.com}
|
12
12
|
s.extra_rdoc_files = ["README", "lib/quick_magick/image.rb", "lib/quick_magick/image_list.rb", "lib/quick_magick.rb"]
|
13
|
-
s.files = ["README", "Rakefile", "lib/quick_magick/image.rb", "lib/quick_magick/image_list.rb", "lib/quick_magick.rb", "Manifest", "quick_magick.gemspec", "test/image_test.rb", "test/
|
13
|
+
s.files = ["README", "Rakefile", "lib/quick_magick/image.rb", "lib/quick_magick/image_list.rb", "lib/quick_magick.rb", "Manifest", "quick_magick.gemspec", "test/image_test.rb", "test/badfile.xxx", "test/multipage.tif", "test/image_list_test.rb", "test/test_magick.rb", "test/9.gif"]
|
14
14
|
s.has_rdoc = true
|
15
15
|
s.homepage = %q{http://quickmagick.rubyforge.org/}
|
16
16
|
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Quick_magick", "--main", "README"]
|
@@ -18,7 +18,7 @@ Gem::Specification.new do |s|
|
|
18
18
|
s.rubyforge_project = %q{quickmagick}
|
19
19
|
s.rubygems_version = %q{1.3.1}
|
20
20
|
s.summary = %q{QuickMagick allows you to access ImageMagick command line functions using Ruby interface.}
|
21
|
-
s.test_files = ["test/image_test.rb", "test/image_list_test.rb"]
|
21
|
+
s.test_files = ["test/image_test.rb", "test/image_list_test.rb", "test/test_magick.rb"]
|
22
22
|
|
23
23
|
if s.respond_to? :specification_version then
|
24
24
|
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
data/test/9.gif
ADDED
Binary file
|
data/test/image_list_test.rb
CHANGED
@@ -5,16 +5,25 @@ require 'ftools'
|
|
5
5
|
$base_dir = File.dirname(File.expand_path(__FILE__))
|
6
6
|
|
7
7
|
class ImageTest < Test::Unit::TestCase
|
8
|
+
def setup
|
9
|
+
@logo_filename = File.join($base_dir, "imagemagick-logo.png")
|
10
|
+
`convert magick:logo #{@logo_filename}`
|
11
|
+
@small_logo_filename = File.join($base_dir, "logo-small.jpg")
|
12
|
+
`convert magick:logo -resize 100x100! #{@small_logo_filename}`
|
13
|
+
end
|
14
|
+
|
15
|
+
def teardown
|
16
|
+
File.delete(@logo_filename) if File.exists?(@logo_filename)
|
17
|
+
File.delete(@small_logo_filename) if File.exists?(@small_logo_filename)
|
18
|
+
end
|
19
|
+
|
8
20
|
def test_open_file
|
9
|
-
|
10
|
-
i = QuickMagick::ImageList.new(image_filename)
|
21
|
+
i = QuickMagick::ImageList.new(@logo_filename)
|
11
22
|
assert_equal 1, i.length
|
12
23
|
end
|
13
24
|
|
14
25
|
def test_save_multipage
|
15
|
-
|
16
|
-
image_filename2 = File.join($base_dir, "logo-small.jpg")
|
17
|
-
i = QuickMagick::ImageList.new(image_filename, image_filename2)
|
26
|
+
i = QuickMagick::ImageList.new(@logo_filename, @small_logo_filename)
|
18
27
|
assert_equal 2, i.length
|
19
28
|
out_filename = File.join($base_dir, "out.tif")
|
20
29
|
i.save out_filename
|
@@ -27,9 +36,7 @@ class ImageTest < Test::Unit::TestCase
|
|
27
36
|
end
|
28
37
|
|
29
38
|
def test_bulk_resize
|
30
|
-
|
31
|
-
image_filename2 = File.join($base_dir, "logo-small.jpg")
|
32
|
-
i = QuickMagick::ImageList.new(image_filename1, image_filename2)
|
39
|
+
i = QuickMagick::ImageList.new(@logo_filename, @small_logo_filename)
|
33
40
|
i.resize "50x50!"
|
34
41
|
out_filename = File.join($base_dir, "out.tif")
|
35
42
|
i.save out_filename
|
@@ -43,11 +50,9 @@ class ImageTest < Test::Unit::TestCase
|
|
43
50
|
end
|
44
51
|
|
45
52
|
def test_append_image
|
46
|
-
image_filename1 = File.join($base_dir, "imagemagick-logo.png")
|
47
|
-
image_filename2 = File.join($base_dir, "logo-small.jpg")
|
48
53
|
i = QuickMagick::ImageList.new
|
49
|
-
i << QuickMagick::Image.read(
|
50
|
-
i << QuickMagick::Image.read(
|
54
|
+
i << QuickMagick::Image.read(@logo_filename)
|
55
|
+
i << QuickMagick::Image.read(@small_logo_filename)
|
51
56
|
i.resize "50x50!"
|
52
57
|
out_filename = File.join($base_dir, "out.tif")
|
53
58
|
i.save out_filename
|
@@ -60,24 +65,49 @@ class ImageTest < Test::Unit::TestCase
|
|
60
65
|
File.delete(out_filename) if out_filename && File.exists?(out_filename)
|
61
66
|
end
|
62
67
|
|
68
|
+
def test_different_operators
|
69
|
+
i = QuickMagick::ImageList.new
|
70
|
+
i << QuickMagick::Image.read(@logo_filename)
|
71
|
+
i << QuickMagick::Image.read(@small_logo_filename)
|
72
|
+
i[0].resize "50x50!"
|
73
|
+
i[1].resize "75x75!"
|
74
|
+
out_filename = File.join($base_dir, "out.tif")
|
75
|
+
i.save out_filename
|
76
|
+
|
77
|
+
i = QuickMagick::Image.read(out_filename)
|
78
|
+
assert_equal 2, i.length
|
79
|
+
assert_equal 50, i[0].width
|
80
|
+
assert_equal 75, i[1].width
|
81
|
+
ensure
|
82
|
+
File.delete(out_filename) if out_filename && File.exists?(out_filename)
|
83
|
+
end
|
84
|
+
|
85
|
+
def test_resize_one_image_in_a_list
|
86
|
+
i = QuickMagick::ImageList.new
|
87
|
+
i << QuickMagick::Image.read(@logo_filename)
|
88
|
+
i << QuickMagick::Image.read(@small_logo_filename)
|
89
|
+
i[0].resize "50x50!"
|
90
|
+
out_filename = File.join($base_dir, "out.tif")
|
91
|
+
i.save out_filename
|
92
|
+
|
93
|
+
i = QuickMagick::Image.read(out_filename)
|
94
|
+
assert_equal 2, i.length
|
95
|
+
assert_equal 50, i[0].width
|
96
|
+
assert_equal 100, i[1].width
|
97
|
+
ensure
|
98
|
+
File.delete(out_filename) if out_filename && File.exists?(out_filename)
|
99
|
+
end
|
100
|
+
|
63
101
|
def test_bulk_convert
|
64
|
-
|
65
|
-
image_filename2 = File.join($base_dir, "logo-small.jpg")
|
66
|
-
new_image_filename1 = File.join($base_dir, "temp1.png")
|
67
|
-
new_image_filename2 = File.join($base_dir, "temp2.jpg")
|
68
|
-
File.copy(image_filename1, new_image_filename1)
|
69
|
-
File.copy(image_filename2, new_image_filename2)
|
70
|
-
i = QuickMagick::ImageList.new(new_image_filename1, new_image_filename2)
|
102
|
+
i = QuickMagick::ImageList.new(@logo_filename, @small_logo_filename)
|
71
103
|
i.format = 'gif'
|
72
104
|
i.save!
|
73
105
|
|
74
|
-
out_filename1 =
|
75
|
-
out_filename2 =
|
106
|
+
out_filename1 = @logo_filename.sub('.png', '.gif')
|
107
|
+
out_filename2 = @small_logo_filename.sub('.jpg', '.gif')
|
76
108
|
assert File.exists?(out_filename1)
|
77
109
|
assert File.exists?(out_filename2)
|
78
110
|
ensure
|
79
|
-
File.delete(new_image_filename1) if new_image_filename1 && File.exists?(new_image_filename1)
|
80
|
-
File.delete(new_image_filename2) if new_image_filename2 && File.exists?(new_image_filename2)
|
81
111
|
File.delete(out_filename1) if out_filename1 && File.exists?(out_filename1)
|
82
112
|
File.delete(out_filename2) if out_filename2 && File.exists?(out_filename2)
|
83
113
|
end
|
data/test/image_test.rb
CHANGED
@@ -4,16 +4,27 @@ require 'quick_magick'
|
|
4
4
|
$base_dir = File.dirname(File.expand_path(__FILE__))
|
5
5
|
|
6
6
|
class ImageTest < Test::Unit::TestCase
|
7
|
+
|
8
|
+
def setup
|
9
|
+
@logo_filename = File.join($base_dir, "imagemagick-logo.png")
|
10
|
+
`convert magick:logo #{@logo_filename}`
|
11
|
+
@small_logo_filename = File.join($base_dir, "logo-small.jpg")
|
12
|
+
`convert magick:logo -resize 100x100! #{@small_logo_filename}`
|
13
|
+
end
|
14
|
+
|
15
|
+
def teardown
|
16
|
+
File.delete(@logo_filename) if File.exists?(@logo_filename)
|
17
|
+
File.delete(@small_logo_filename) if File.exists?(@small_logo_filename)
|
18
|
+
end
|
19
|
+
|
7
20
|
def test_open_existing_image
|
8
|
-
|
9
|
-
i = QuickMagick::Image.read(image_filename)
|
21
|
+
i = QuickMagick::Image.read(@logo_filename)
|
10
22
|
assert_equal 1, i.size
|
11
23
|
end
|
12
24
|
|
13
25
|
def test_create_from_blob
|
14
|
-
image_filename = File.join($base_dir, "imagemagick-logo.png")
|
15
26
|
blob = nil
|
16
|
-
File.open(
|
27
|
+
File.open(@logo_filename, "rb") do |f|
|
17
28
|
blob = f.read
|
18
29
|
end
|
19
30
|
i = QuickMagick::Image.from_blob(blob)
|
@@ -21,10 +32,9 @@ class ImageTest < Test::Unit::TestCase
|
|
21
32
|
end
|
22
33
|
|
23
34
|
def test_image_info
|
24
|
-
|
25
|
-
|
26
|
-
assert_equal
|
27
|
-
assert_equal 479, i.height
|
35
|
+
i = QuickMagick::Image.read(@logo_filename).first
|
36
|
+
assert_equal 640, i.width
|
37
|
+
assert_equal 480, i.height
|
28
38
|
end
|
29
39
|
|
30
40
|
def test_open_non_existing_file
|
@@ -50,8 +60,7 @@ class ImageTest < Test::Unit::TestCase
|
|
50
60
|
end
|
51
61
|
|
52
62
|
def test_resize_image
|
53
|
-
|
54
|
-
i = QuickMagick::Image.read(image_filename).first
|
63
|
+
i = QuickMagick::Image.read(@logo_filename).first
|
55
64
|
i.resize("300x300!")
|
56
65
|
out_filename = File.join($base_dir, "imagemagick-resized.png")
|
57
66
|
File.delete out_filename if File.exists?(out_filename)
|
@@ -66,8 +75,7 @@ class ImageTest < Test::Unit::TestCase
|
|
66
75
|
end
|
67
76
|
|
68
77
|
def test_crop_image
|
69
|
-
|
70
|
-
i = QuickMagick::Image.read(image_filename).first
|
78
|
+
i = QuickMagick::Image.read(@logo_filename).first
|
71
79
|
i.crop("300x200+0+0")
|
72
80
|
out_filename = File.join($base_dir, "imagemagick-cropped.png")
|
73
81
|
File.delete out_filename if File.exists?(out_filename)
|
@@ -82,8 +90,7 @@ class ImageTest < Test::Unit::TestCase
|
|
82
90
|
end
|
83
91
|
|
84
92
|
def test_resize_with_geometry_options
|
85
|
-
|
86
|
-
i = QuickMagick::Image.read(image_filename).first
|
93
|
+
i = QuickMagick::Image.read(@logo_filename).first
|
87
94
|
i.resize(300, 300, nil, nil, QuickMagick::AspectGeometry)
|
88
95
|
out_filename = File.join($base_dir, "imagemagick-resized.png")
|
89
96
|
File.delete out_filename if File.exists?(out_filename)
|
@@ -98,8 +105,7 @@ class ImageTest < Test::Unit::TestCase
|
|
98
105
|
end
|
99
106
|
|
100
107
|
def test_resize_with_append_to_operators
|
101
|
-
|
102
|
-
i = QuickMagick::Image.read(image_filename).first
|
108
|
+
i = QuickMagick::Image.read(@logo_filename).first
|
103
109
|
i.append_to_operators 'resize', '300x300!'
|
104
110
|
out_filename = File.join($base_dir, "imagemagick-resized.png")
|
105
111
|
File.delete out_filename if File.exists?(out_filename)
|
@@ -142,4 +148,41 @@ class ImageTest < Test::Unit::TestCase
|
|
142
148
|
# clean up
|
143
149
|
File.delete(out_filename) if out_filename && File.exists?(out_filename)
|
144
150
|
end
|
151
|
+
|
152
|
+
def test_line_and_circle
|
153
|
+
i = QuickMagick::Image.solid(100, 100, :white)
|
154
|
+
i.draw_line(0,0,20,20)
|
155
|
+
i.draw_circle(30,30,20,20)
|
156
|
+
out_filename = File.join($base_dir, "draw_test.gif")
|
157
|
+
i.save out_filename
|
158
|
+
ensure
|
159
|
+
# clean up
|
160
|
+
File.delete(out_filename) if out_filename && File.exists?(out_filename)
|
161
|
+
end
|
162
|
+
|
163
|
+
def test_colors
|
164
|
+
assert_equal "#00ff00ff", QuickMagick::rgb_color(0, 255, 0)
|
165
|
+
assert_equal "#00007fff", QuickMagick::rgb_color(0, 0, 0.5)
|
166
|
+
assert_equal "#3f0000ff", QuickMagick::rgb_color("25%" ,0 , 0)
|
167
|
+
|
168
|
+
assert_equal "#ff00007f", QuickMagick::rgba_color(1.0, 0, 0, 0.5)
|
169
|
+
|
170
|
+
assert_equal "#7f7f7f7f", QuickMagick::graya_color(0.5, 0.5)
|
171
|
+
|
172
|
+
assert_equal "hsla(30,50%,50%,1)", QuickMagick::hsl_color(30, 127, 127)
|
173
|
+
assert_equal "hsla(180,50%,50%,0.5)", QuickMagick::hsla_color(Math::PI, 0.5, "50%", 0.5)
|
174
|
+
end
|
175
|
+
|
176
|
+
def test_revert
|
177
|
+
i = QuickMagick::Image.read(@logo_filename).first
|
178
|
+
i.resize("300x300!")
|
179
|
+
i.revert!
|
180
|
+
out_filename = File.join($base_dir, "imagemagick-resized.png")
|
181
|
+
File.delete out_filename if File.exists?(out_filename)
|
182
|
+
i.save(out_filename)
|
183
|
+
assert File.exists?(out_filename)
|
184
|
+
i2 = QuickMagick::Image.read(out_filename).first
|
185
|
+
assert_equal 640, i2.width
|
186
|
+
assert_equal 480, i2.height
|
187
|
+
end
|
145
188
|
end
|
data/test/test_magick.rb
ADDED
@@ -0,0 +1,169 @@
|
|
1
|
+
if __FILE__ == $0
|
2
|
+
require 'rubygems'
|
3
|
+
require 'mini_magick'
|
4
|
+
require 'quick_magick'
|
5
|
+
require 'RMagick'
|
6
|
+
require 'benchmark'
|
7
|
+
require 'ftools'
|
8
|
+
|
9
|
+
begin
|
10
|
+
include Benchmark
|
11
|
+
|
12
|
+
$base_dir = File.dirname(File.expand_path(__FILE__))
|
13
|
+
|
14
|
+
# Generate a test file
|
15
|
+
in_file = File.join($base_dir, 'logo.png')
|
16
|
+
out_file = File.join($base_dir, 'testout.gif')
|
17
|
+
|
18
|
+
`convert magick:logo #{in_file}`
|
19
|
+
|
20
|
+
test_quick = lambda {
|
21
|
+
image_filename =
|
22
|
+
20.times {
|
23
|
+
i = QuickMagick::Image.read(in_file).first
|
24
|
+
i.resize "100x100!"
|
25
|
+
i.save out_file
|
26
|
+
}
|
27
|
+
}
|
28
|
+
|
29
|
+
test_mini = lambda {
|
30
|
+
20.times {
|
31
|
+
i = MiniMagick::Image.from_file(in_file)
|
32
|
+
i.combine_options do |c|
|
33
|
+
c.resize "100x100!"
|
34
|
+
c.format "gif"
|
35
|
+
end
|
36
|
+
i.write out_file
|
37
|
+
}
|
38
|
+
}
|
39
|
+
|
40
|
+
test_r = lambda {
|
41
|
+
20.times {
|
42
|
+
i = Magick::Image.read(in_file).first
|
43
|
+
i = i.change_geometry!('100x100!') { |cols, rows, img|
|
44
|
+
img.resize!(cols, rows)
|
45
|
+
}
|
46
|
+
i.write out_file
|
47
|
+
}
|
48
|
+
}
|
49
|
+
|
50
|
+
puts "Test 1: resize a normal image"
|
51
|
+
bm(12) { |x|
|
52
|
+
x.report("mini", &test_mini)
|
53
|
+
x.report("quick", &test_quick)
|
54
|
+
x.report("rmagick", &test_r)
|
55
|
+
}
|
56
|
+
|
57
|
+
##################################################
|
58
|
+
|
59
|
+
in_file = File.join($base_dir, '9.gif')
|
60
|
+
out_file = File.join($base_dir, 'testout.gif')
|
61
|
+
|
62
|
+
test_quick = lambda {
|
63
|
+
i = QuickMagick::Image.read(in_file).first
|
64
|
+
i.resize "8190x8190>"
|
65
|
+
i.save out_file
|
66
|
+
}
|
67
|
+
|
68
|
+
test_mini = lambda {
|
69
|
+
i = MiniMagick::Image.from_file(in_file)
|
70
|
+
i.combine_options do |c|
|
71
|
+
c.resize "8190x8190>"
|
72
|
+
c.format "gif"
|
73
|
+
end
|
74
|
+
i.write out_file
|
75
|
+
}
|
76
|
+
|
77
|
+
test_r = lambda {
|
78
|
+
i = Magick::Image.read(in_file).first
|
79
|
+
i = i.change_geometry!('8190x8190>') { |cols, rows, img|
|
80
|
+
img.resize!(cols, rows)
|
81
|
+
}
|
82
|
+
i.write out_file
|
83
|
+
}
|
84
|
+
|
85
|
+
puts "Test 2: resize a large image"
|
86
|
+
bm(12) { |x|
|
87
|
+
x.report("mini", &test_mini)
|
88
|
+
x.report("quick", &test_quick)
|
89
|
+
# Don't try RMagick! You'll regret that ... a lot :'(
|
90
|
+
# x.report("rmagick", &test_r)
|
91
|
+
}
|
92
|
+
|
93
|
+
##################################################
|
94
|
+
|
95
|
+
class String
|
96
|
+
CHARS = ("a".."z").to_a + ("1".."9").to_a
|
97
|
+
def self.random(length)
|
98
|
+
Array.new(length, '').collect{CHARS[rand(CHARS.size)]}.join
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def generate_captcha(length, width, height)
|
103
|
+
captcha = []
|
104
|
+
String.random(6).chars.each_with_index do |c, i|
|
105
|
+
letter = {}
|
106
|
+
letter[:char] = c
|
107
|
+
letter[:x] = width * i / length + (rand - 0.5) * width / length / 8
|
108
|
+
letter[:y] = height / 5 + (rand - 0.5) * height / 2
|
109
|
+
letter[:sx] = rand * 90 - 45
|
110
|
+
letter[:bx] = width * i / length + (rand - 0.5) * width / length / 2
|
111
|
+
letter[:by] = height / 2 + (rand - 0.5) * height
|
112
|
+
captcha << letter
|
113
|
+
end
|
114
|
+
captcha
|
115
|
+
end
|
116
|
+
|
117
|
+
out_file = File.join($base_dir, 'captcha.gif')
|
118
|
+
|
119
|
+
test_quick = lambda {
|
120
|
+
i = QuickMagick::Image.solid(290, 70, :white)
|
121
|
+
i.bordercolor = :black
|
122
|
+
i.border = 5
|
123
|
+
i.fill = :black
|
124
|
+
i.stroke = :black
|
125
|
+
i.strokewidth = 1
|
126
|
+
i.pointsize = 40
|
127
|
+
i.gravity = :northwest
|
128
|
+
captcha = generate_captcha(6, 290, 70)
|
129
|
+
captcha.each do |letter|
|
130
|
+
i.draw_text letter[:x], letter[:y], letter[:char], :skewx=>letter[:sx]
|
131
|
+
end
|
132
|
+
i.save out_file
|
133
|
+
}
|
134
|
+
|
135
|
+
test_mini = lambda {
|
136
|
+
}
|
137
|
+
|
138
|
+
test_r = lambda {
|
139
|
+
i = Magick::Image.new(290, 70)
|
140
|
+
gc = Magick::Draw.new
|
141
|
+
i.border! 5, 5, "black"
|
142
|
+
gc.stroke "black"
|
143
|
+
gc.stroke_width 1
|
144
|
+
gc.pointsize 40
|
145
|
+
gc.gravity = Magick::NorthWestGravity
|
146
|
+
captcha = generate_captcha(6, 290, 70)
|
147
|
+
captcha.each do |letter|
|
148
|
+
gc.skewx letter[:sx]
|
149
|
+
gc.text letter[:x], letter[:y], letter[:char]
|
150
|
+
end
|
151
|
+
gc.fill "none"
|
152
|
+
gc.draw i
|
153
|
+
i.write out_file
|
154
|
+
}
|
155
|
+
|
156
|
+
puts "Test 3: generate random captchas"
|
157
|
+
bm(12) { |x|
|
158
|
+
# x.report("mini", &test_mini)
|
159
|
+
x.report("quick", &test_quick)
|
160
|
+
x.report("rmagick", &test_r)
|
161
|
+
}
|
162
|
+
# Cleanup temp files
|
163
|
+
ensure
|
164
|
+
%w{captcha.gif testout.gif logo.png}.each do |filename|
|
165
|
+
fullname = File.join($base_dir, filename)
|
166
|
+
File.delete(fullname) if File.exists?(fullname)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: quick_magick
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ahmed ElDawy
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-08-
|
12
|
+
date: 2009-08-12 00:00:00 +03:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -33,11 +33,11 @@ files:
|
|
33
33
|
- Manifest
|
34
34
|
- quick_magick.gemspec
|
35
35
|
- test/image_test.rb
|
36
|
-
- test/logo-small.jpg
|
37
36
|
- test/badfile.xxx
|
38
37
|
- test/multipage.tif
|
39
38
|
- test/image_list_test.rb
|
40
|
-
- test/
|
39
|
+
- test/test_magick.rb
|
40
|
+
- test/9.gif
|
41
41
|
has_rdoc: true
|
42
42
|
homepage: http://quickmagick.rubyforge.org/
|
43
43
|
post_install_message:
|
@@ -72,3 +72,4 @@ summary: QuickMagick allows you to access ImageMagick command line functions usi
|
|
72
72
|
test_files:
|
73
73
|
- test/image_test.rb
|
74
74
|
- test/image_list_test.rb
|
75
|
+
- test/test_magick.rb
|
data/test/imagemagick-logo.png
DELETED
Binary file
|
data/test/logo-small.jpg
DELETED
Binary file
|