ffi-gmagick 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c44392e5977b3e429dc8c977131f5223cf391554
4
+ data.tar.gz: 4e169e7a89e4ece9154c8a930cdf53ad50104870
5
+ SHA512:
6
+ metadata.gz: a28e768fd12e76ccc36f0d193b54f5010e660add60ba10a241a65e70f8d21327ee490681e93a924fbb8254c72b932054d5d931917c94ab89de8d5227351f55e8
7
+ data.tar.gz: 598a9f18be1265c25ec7a23ce90d6dfc5c30ec68ab59f5db41d82f8f3790939217c9619d4056aa48171d6d2368cb07dcc44779fe49278030ed0b2cf037d88187
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ .ruby-*
7
+ Gemfile.lock
8
+ InstalledFiles
9
+ _yardoc
10
+ coverage
11
+ doc/
12
+ lib/bundler/man
13
+ pkg
14
+ rdoc
15
+ spec/reports
16
+ test/tmp
17
+ test/version_tmp
18
+ tmp
data/.travis.yml ADDED
@@ -0,0 +1,8 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0.0
4
+ - 1.9.3
5
+ notifications:
6
+ email:
7
+ recipients:
8
+ - rnhurt@gmail.com
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in ffi-gmagick.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Richard Hurt
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,56 @@
1
+ # FFI::GMagick
2
+
3
+ FFI wrapper for the GraphicsMagick image processing library.
4
+
5
+ ## Introduction
6
+
7
+ This Gem provides an FFI wrapper for the GraphicsMagick image processing library. All of the
8
+ other *Magick Gems I found either only worked with ImageMagick or were simply wrappers around
9
+ the command line interfaces. These are great Gems but I needed to work with images in RAM
10
+ and not hit the hard drive at all. So, I created this Gem to allow me to work with images
11
+ completely in RAM without touching the file system at all.
12
+
13
+ [![Build Status](https://travis-ci.org/rnhurt/ffi-gmagick.png)](https://travis-ci.org/rnhurt/ffi-gmagick)
14
+
15
+ ## Installation
16
+
17
+ Add this line to your application's Gemfile:
18
+
19
+ gem 'ffi-gmagick'
20
+
21
+ And then execute:
22
+
23
+ $ bundle
24
+
25
+ Or install it yourself as:
26
+
27
+ $ gem install ffi-gmagick
28
+
29
+ You also must have a recent version of GraphicsMagick installed and the library in your
30
+ systems load path. Don't worry about the load path, most installers do that for you.
31
+
32
+ ## Usage
33
+
34
+ Basic usage is as following:
35
+
36
+ require 'ffi/gmagick'
37
+
38
+ WATERMARK = FFI::GMagick::Image.new
39
+ WATERMARK.from_blob(File.open("watermark.png").read)
40
+
41
+ image = FFI::GMagick::Image.new
42
+ image.from_blob(File.open("./my_picture.jpg").read)
43
+
44
+ new_thumbnail = image.thumbnail(100, 100, true)
45
+ new_thumbnail.compose(WATERMARK)
46
+
47
+ new_thumbnail.to_file("./my_thumb.jpg")
48
+
49
+
50
+ ## Contributing
51
+
52
+ 1. Fork it
53
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
54
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
55
+ 4. Push to the branch (`git push origin my-new-feature`)
56
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+
4
+ task :default => [:test]
5
+
6
+ desc 'Run tests'
7
+ Rake::TestTask.new do |t|
8
+ t.libs << 'test'
9
+ t.test_files = FileList['test/*_test.rb']
10
+ t.verbose = true
11
+ t.warning = true
12
+ end
@@ -0,0 +1,30 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'ffi/gmagick/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "ffi-gmagick"
8
+ spec.version = FFI::GMagick::VERSION
9
+ spec.authors = ["Richard Hurt"]
10
+ spec.email = ["rnhurt@gmail.com"]
11
+ spec.summary = "Use the C GraphicsMagick bindings to provide a Ruby interface"
12
+ spec.description = "This is not a simple 'Ruby'-like implementation. It is more of a
13
+ raw 'C' implementation. As such, it may be a bit more difficult to
14
+ work with than something like rmagick, but it should perform just as
15
+ well."
16
+ spec.homepage = "https://github.com/rnhurt/ffi-gmagick"
17
+ spec.license = "MIT"
18
+
19
+ spec.files = `git ls-files`.split($/)
20
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
21
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
22
+ spec.require_paths = ["lib"]
23
+
24
+ spec.requirements << 'libGraphicsMagick, v1.3.18'
25
+
26
+ spec.add_runtime_dependency 'ffi', '~> 1.9'
27
+
28
+ spec.add_development_dependency "bundler", "~> 1.3"
29
+ spec.add_development_dependency "rake"
30
+ end
@@ -0,0 +1,253 @@
1
+ module FFI
2
+ module GMagick
3
+ class Image
4
+ # This is a convenience class that takes care of most of the messy work
5
+ # of dealing with the raw FFI::GMagick interface.
6
+ #
7
+ # Basic usage is as following:
8
+ #
9
+ # require 'ffi/gmagick'
10
+ #
11
+ # WATERMARK = FFI::GMagick::Image.new
12
+ # WATERMARK.from_blob(File.open("watermark.png").read)
13
+ #
14
+ # image = FFI::GMagick::Image.new
15
+ # image.from_blob(File.open("./my_picture.jpg").read)
16
+ #
17
+ # new_thumbnail = image.thumbnail(100, 100, true)
18
+ # new_thumbnail.compose(WATERMARK)
19
+ #
20
+ # new_thumbnail.to_file("./my_thumb.jpg")
21
+ #
22
+ # This will open two images, a picture and a watermark, create a square
23
+ # thumbnail and apply the watermark in the center of the image.
24
+ attr_accessor :wand, :status
25
+
26
+ def initialize(old_wand=nil)
27
+ if old_wand
28
+ @wand = FFI::GMagick.CloneMagickWand( old_wand )
29
+ else
30
+ @wand ||= FFI::GMagick.NewMagickWand
31
+ end
32
+ @status = 1
33
+ end
34
+
35
+ # Read image data from a BLOB
36
+ def from_blob(blob)
37
+ @status = FFI::GMagick.MagickReadImageBlob( @wand, blob, blob.bytesize)
38
+
39
+ # Note: PDF images don't report proper bytesize
40
+ return blob.bytesize
41
+ end
42
+
43
+ # Write image data to a BLOB
44
+ def to_blob
45
+ output = nil
46
+ FFI::MemoryPointer.new(:ulong, 64) do |length|
47
+ blobout = FFI::GMagick.MagickWriteImageBlob( @wand, length )
48
+ output = blobout.read_string(length.read_long)
49
+ end
50
+ return output
51
+ end
52
+
53
+ # Read image data from a filename
54
+ def from_file(filename)
55
+ blob = File.open(filename).read
56
+ self.from_blob(blob)
57
+ end
58
+
59
+ # Write image data to a filename
60
+ def to_file(filename)
61
+ @status = FFI::GMagick.MagickWriteImage( @wand, filename )
62
+ end
63
+
64
+ # Return the width of the image in pixels
65
+ def width
66
+ FFI::GMagick.MagickGetImageWidth( @wand ).to_f
67
+ end
68
+ alias_method :cols, :width
69
+
70
+ # Return the height of the image in pixels
71
+ def height
72
+ FFI::GMagick.MagickGetImageHeight( @wand ).to_f
73
+ end
74
+ alias_method :rows, :height
75
+
76
+ # Return the size of the image in bytes
77
+ def size
78
+ FFI::GMagick.MagickGetImageSize( @wand )
79
+ end
80
+ alias_method :length, :size
81
+
82
+ # Return the image format
83
+ def format
84
+ FFI::GMagick.MagickGetImageFormat( @wand )
85
+ end
86
+
87
+ # Set the image format
88
+ def format=(format)
89
+ FFI::GMagick.MagickSetImageFormat( @wand, format )
90
+ end
91
+
92
+ # Negate the colors in the specified channel
93
+ def negate_channel(channel, gray=0)
94
+ @status = FFI::GMagick.MagickNegateImageChannel( @wand, channel, gray )
95
+ end
96
+
97
+ # Set the gamma value for the specified channel
98
+ def gamma_channel(channel, gamma=0)
99
+ @status = FFI::GMagick.MagickGammaImageChannel( @wand, channel, gamma )
100
+ end
101
+
102
+ # Return the value of the named attribute
103
+ def attribute(name)
104
+ FFI::GMagick.MagickGetImageAttribute( @wand, name )
105
+ end
106
+
107
+ # Return the image type
108
+ def type
109
+ FFI::GMagick.MagickGetImageType( @wand )
110
+ end
111
+
112
+ # Set the image type to one of the valid
113
+ # <a href="http://www.graphicsmagick.org/api/types.html#imagetype">image types</a>
114
+ def type=(type)
115
+ @status = FFI::GMagick.MagickSetImageType( @wand, type )
116
+ end
117
+
118
+ # Return the colorspace
119
+ def colorspace
120
+ FFI::GMagick.MagickGetImageColorspace( @wand )
121
+ end
122
+ alias_method :colormodel, :colorspace
123
+
124
+ # Set the image colorspace to one of the valid
125
+ # <a href="http://www.graphicsmagick.org/api/types.html#colorspacetype">colorspace types</a>.
126
+ def colorspace=(colorspace)
127
+ FFI::GMagick.MagickSetImageColorspace( @wand, colorspace )
128
+ end
129
+ alias_method :colormodel=, :colorspace=
130
+
131
+ # Return the information for a specific profile in the image
132
+ def profile(name="ICC")
133
+ output = nil
134
+ FFI::MemoryPointer.new(:ulong, 64) do |length|
135
+ blobout = FFI::GMagick.MagickGetImageProfile( @wand, name, length )
136
+ output = blobout.read_string(length.read_long)
137
+ end
138
+ return output
139
+ end
140
+
141
+ # Add a profile to this image
142
+ def add_profile(name, profile)
143
+ @status = FFI::GMagick.MagickProfileImage( @wand, name, profile, profile.size )
144
+ raise "invalid profile" unless 1 == status
145
+ end
146
+
147
+ # Return the interlace information as one of the valid
148
+ # <a href="http://www.graphicsmagick.org/api/types.html#interlacetype">interlace types</a>.
149
+ def interlace
150
+ FFI::GMagick.MagickGetImageInterlaceScheme( @wand )
151
+ end
152
+
153
+ # Set the interlace information to one of the valid
154
+ # <a href="http://www.graphicsmagick.org/api/types.html#interlacetype">interlace types</a>.
155
+ def interlace=(interlace)
156
+ @status = FFI::GMagick.MagickSetImageInterlaceScheme( @wand, interlace )
157
+ raise "invalid interlace type" unless 1 == status
158
+ end
159
+
160
+ # Strip the image of extra data (comments, profiles, etc.)
161
+ def strip
162
+ @status = FFI::GMagick.MagickStripImage( @wand )
163
+ end
164
+
165
+ def quality=(quality)
166
+ @status = FFI::GMagick.MagickSetCompressionQuality( @wand, quality )
167
+ end
168
+
169
+ # Resize the image to the desired dimensions using various
170
+ # <a href="http://www.graphicsmagick.org/api/types.html#filtertypes">filters</a>.
171
+ def resize(width, height, filter=:BoxFilter, blur=1.0)
172
+ @status = FFI::GMagick.MagickResizeImage( @wand, width, height, filter, blur )
173
+ end
174
+
175
+
176
+ # Crop the image to the desired dimensions. If you don't provide an
177
+ # X,Y offset the crop will be centered.
178
+ def crop(width, height, x=nil, y=nil)
179
+ if x.nil? || y.nil?
180
+ old_width = self.width
181
+ old_height = self.height
182
+
183
+ x = (old_width / 2) - (width / 2)
184
+ y = (old_height / 2) - (height / 2)
185
+ end
186
+
187
+ @status = FFI::GMagick.MagickCropImage( @wand, width, height, x, y )
188
+ end
189
+
190
+ # A convenience method. Resize the image to fit within the specified
191
+ # dimensions while retaining the aspect ratio of the original image.
192
+ # If necessary, crop the image in the larger dimension.
193
+ #
194
+ # Returns a new image object
195
+ def resize_to_fill(new_width, new_height=nil)
196
+ new_height ||= new_width
197
+ local_image = FFI::GMagick::Image.new(@wand)
198
+
199
+ if new_width != local_image.width || new_height != local_image.height
200
+ scale = [new_width/local_image.width.to_f, new_height/local_image.height.to_f].max
201
+ local_image.resize(scale*width+0.5, scale*height+0.5)
202
+ end
203
+
204
+ if new_width != local_image.width || new_height != local_image.height
205
+ local_image.crop(new_width, new_height)
206
+ end
207
+
208
+ return local_image
209
+ end
210
+
211
+ # A convenience method. Resize the image to fit within the
212
+ # specified dimensions while retaining the original aspect
213
+ # ratio. The image may be shorter or narrower than specified
214
+ # in the smaller dimension but will not be larger than the
215
+ # specified values.
216
+ #
217
+ # Returns a new image object
218
+ def resize_to_fit(width, height=nil)
219
+ height ||= width
220
+ geometry = "#{width}x#{height}>"
221
+ local_wand = FFI::GMagick.MagickTransformImage( @wand, "", geometry )
222
+ return FFI::GMagick::Image.new(local_wand)
223
+ end
224
+
225
+ # Composites an Image (such as a watermark) with this one using various
226
+ # <a href="http://www.graphicsmagick.org/api/types.html#compositeoperator">composite operators</a>.
227
+ #
228
+ # If you don't provide an X,Y offset then the operation with be centered on the base image.
229
+ def compose(image, operator=:OverCompositeOp, x=nil, y=nil)
230
+ if x.nil? || y.nil?
231
+ width = self.width
232
+ height = self.height
233
+ new_width = image.width
234
+ new_height = image.height
235
+
236
+ x = (width / 2) - (new_width / 2)
237
+ y = (height / 2) - (new_height / 2)
238
+ end
239
+ @status = FFI::GMagick.MagickCompositeImage(@wand, image.wand, operator, x, y)
240
+ end
241
+
242
+ # Is this a valid image
243
+ def valid?
244
+ @status == 1
245
+ end
246
+
247
+ # Return the copywrite notification for GraphicsMagick
248
+ def copywrite
249
+ FFI::GMagick.MagickGetCopyright
250
+ end
251
+ end
252
+ end
253
+ end
@@ -0,0 +1,16 @@
1
+ module FFI
2
+ module GMagick
3
+ class PixelPacket < FFI::Struct
4
+ layout :red, :uint,
5
+ :green, :uint,
6
+ :blue, :uint,
7
+ :opacity, :uint
8
+ end
9
+
10
+ class ImageInfo < FFI::Struct
11
+ layout :adjoin, :uint,
12
+ :antialias, :uint,
13
+ :background_color, PixelPacket.ptr
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,5 @@
1
+ module FFI
2
+ module GMagick
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
@@ -0,0 +1,138 @@
1
+ require "ffi"
2
+ require "ffi/gmagick/image"
3
+ require "ffi/gmagick/version"
4
+
5
+ module FFI
6
+ # FFI::GMagick is an FFI binding for the GraphicsMagick MagickWand image library.
7
+ # Basic usage is as following:
8
+ #
9
+ # require 'ffi/gmagick'
10
+ #
11
+ # wand = FFI::GMagick.NewMagickWand
12
+ # FFI::GMagick.MagickReadImage( wand, "./test.jpg")
13
+ #
14
+ # FFI::GMagick.MagickSetImageFormat( wand, "PNG" )
15
+ #
16
+ # FFI::GMagick.MagickResizeImage( wand, 500, 500, :UndefinedFilter, 0.0)
17
+ # FFI::GMagick.MagickWriteImage( wand, "./test-out.jpg" )
18
+ #
19
+ # For more information on commands and syntax see http://www.graphicsmagick.org/wand/magick_wand.html
20
+ #
21
+ module GMagick
22
+ extend FFI::Library
23
+ ffi_lib "GraphicsMagickWand"
24
+
25
+ enum :interlace_type, [:UndefinedInterlace, :NoInterlace, :LineInterlace, :PlaneInterlace, :PartitionInterlace]
26
+
27
+ enum :filter_type, [:UndefinedFilter, :PointFilter, :BoxFilter, :TriangleFilter,
28
+ :HermiteFilter, :HanningFilter, :HammingFilter, :BlackmanFilter,
29
+ :GaussianFilter, :QuadraticFilter, :CubicFilter, :CatromFilter,
30
+ :MitchellFilter, :LanczosFilter, :BesselFilter, :SincFilter]
31
+ enum :channel_type, [:UndefinedChannel, :RedChannel, :CyanChannel, :GreenChannel, :MagentaChannel,
32
+ :BlueChannel, :YellowChannel, :OpacityChannel, :BlackChannel, :MatteChannel,
33
+ :AllChannels, :GrayChannel]
34
+
35
+ enum :image_type, [:UndefinedType, :BilevelType, :GrayscaleType, :PaletteType, :PaletteMatteType,
36
+ :TrueColorType, :TrueColorMatteType, :ColorSeparationType]
37
+
38
+ enum :colorspace, [:UndefinedColorspace, :RGBColorspace, :GRAYColorspace,
39
+ :TransparentColorspace, :OHTAColorspace, :XYZColorspace, :YCCColorspace,
40
+ :YIQColorspace, :YPbPrColorspace, :YUVColorspace, :CMYKColorspace,
41
+ :sRGBColorspace, :HSLColorspace, :HWBColorspace, :LABColorspace,
42
+ :CineonLogRGBColorspace, :Rec601LumaColorspace, :Rec601YCbCrColorspace,
43
+ :Rec709LumaColorspace, :Rec709YCbCrColorspace]
44
+
45
+ enum :gravity_type, [:ForgetGravity, :NorthWestGravity, :NorthGravity, :NorthEastGravity,
46
+ :WestGravity, :CenterGravity, :EastGravity, :SouthWestGravity,
47
+ :SouthGravity, :SouthEastGravity]
48
+
49
+ enum :composite_operator, [:UndefinedCompositeOp, :OverCompositeOp, :InCompositeOp, :OutCompositeOp,
50
+ :AtopCompositeOp, :XorCompositeOp, :PlusCompositeOp, :MinusCompositeOp,
51
+ :AddCompositeOp, :SubtractCompositeOp, :DifferenceCompositeOp, :BumpmapCompositeOp,
52
+ :CopyCompositeOp, :CopyRedCompositeOp, :CopyGreenCompositeOp, :CopyBlueCompositeOp,
53
+ :CopyOpacityCompositeOp, :ClearCompositeOp, :DissolveCompositeOp, :DisplaceCompositeOp,
54
+ :ModulateCompositeOp, :ThresholdCompositeOp, :NoCompositeOp, :DarkenCompositeOp,
55
+ :LightenCompositeOp, :HueCompositeOp, :SaturateCompositeOp, :ColorizeCompositeOp,
56
+ :LuminizeCompositeOp, :ScreenCompositeOp, :OverlayCompositeOp, :CopyCyanCompositeOp,
57
+ :CopyMagentaCompositeOp, :CopyYellowCompositeOp, :CopyBlackCompositeOp, :DivideCompositeOp]
58
+
59
+ typedef :pointer, :wand
60
+ typedef :pointer, :composite_wand
61
+ typedef :pointer, :blob
62
+ typedef :pointer, :profile
63
+ typedef :string, :name
64
+ typedef :string, :filename
65
+ typedef :string, :format
66
+ typedef :string, :geometry
67
+ typedef :string, :crop
68
+ typedef :uint, :magick_pass_fail
69
+ typedef :uint, :dither
70
+ typedef :uint, :measure_error
71
+ typedef :uint, :gray
72
+ typedef :ulong, :columns
73
+ typedef :ulong, :rows
74
+ typedef :ulong, :depth
75
+ typedef :ulong, :quality
76
+ typedef :ulong, :width
77
+ typedef :ulong, :height
78
+ typedef :ulong, :number_colors
79
+ typedef :ulong, :tree_depth
80
+ typedef :long, :x
81
+ typedef :long, :y
82
+ typedef :double, :blur
83
+ typedef :double, :radius
84
+ typedef :double, :sigma
85
+ typedef :double, :gamma
86
+ typedef :double, :amount
87
+ typedef :double, :threshold
88
+ typedef :double, :x_resolution
89
+ typedef :double, :y_resolution
90
+ typedef :size_t, :length
91
+
92
+
93
+
94
+ attach_function :NewMagickWand, [], :wand
95
+ attach_function :CloneMagickWand, [ :wand ], :wand
96
+
97
+ attach_function :MagickReadImage, [ :wand, :filename ], :magick_pass_fail
98
+ attach_function :MagickReadImageBlob, [ :wand, :blob, :length ], :magick_pass_fail
99
+ attach_function :MagickWriteImage, [ :wand, :filename ], :magick_pass_fail
100
+ attach_function :MagickWriteImageBlob, [ :wand, :pointer ], :pointer
101
+
102
+ attach_function :MagickGetImageFormat, [ :wand ], :string
103
+ attach_function :MagickSetImageFormat, [ :wand, :format ], :uint
104
+ attach_function :MagickGetImageHeight, [ :wand ], :ulong
105
+ attach_function :MagickGetImageWidth, [ :wand ], :ulong
106
+ attach_function :MagickGetImageType, [ :wand ], :image_type
107
+ attach_function :MagickSetImageType, [ :wand, :image_type ], :magick_pass_fail
108
+ attach_function :MagickGetImageAttribute, [ :wand, :string ], :string
109
+ attach_function :MagickGetImageColorspace, [ :wand ], :colorspace
110
+ attach_function :MagickSetImageColorspace, [ :wand, :colorspace ], :magick_pass_fail
111
+ attach_function :MagickGetImageDepth, [ :wand ], :depth
112
+ attach_function :MagickSetImageDepth, [ :wand, :depth ], :magick_pass_fail
113
+ attach_function :MagickGetImageSize, [ :wand ], :ulong
114
+
115
+ attach_function :MagickSetCompressionQuality, [ :wand, :quality ], :magick_pass_fail
116
+ attach_function :MagickStripImage, [ :wand ], :magick_pass_fail
117
+ attach_function :MagickUnsharpMaskImage, [ :wand, :radius, :sigma, :amount, :threshold ], :magick_pass_fail
118
+ attach_function :MagickQuantizeImage, [ :wand, :number_colors, :colorspace, :tree_depth, :dither, :measure_error ], :magick_pass_fail
119
+ attach_function :MagickNegateImageChannel, [ :wand, :channel_type, :gray ], :magick_pass_fail
120
+ attach_function :MagickGammaImageChannel, [ :wand, :channel_type, :gamma ], :magick_pass_fail
121
+ attach_function :MagickProfileImage, [ :wand, :name, :profile, :length], :magick_pass_fail
122
+ attach_function :MagickGetImageProfile, [ :wand, :name, :profile ], :profile
123
+ attach_function :MagickSetImageProfile, [ :wand, :name, :profile, :ulong ], :magick_pass_fail
124
+ attach_function :MagickGetImageInterlaceScheme, [ :wand ], :interlace_type
125
+ attach_function :MagickSetImageInterlaceScheme, [ :wand, :interlace_type ], :magick_pass_fail
126
+
127
+ attach_function :MagickResizeImage, [ :wand, :columns, :rows, :filter_type, :blur ], :magick_pass_fail
128
+ attach_function :MagickResampleImage, [ :wand, :x_resolution, :y_resolution, :filter_type, :blur ], :magick_pass_fail
129
+ attach_function :MagickTransformImage, [ :wand, :crop, :geometry ], :wand
130
+ attach_function :MagickScaleImage, [ :wand, :columns, :rows ], :magick_pass_fail
131
+ attach_function :MagickCropImage, [ :wand, :width, :height, :x, :y ], :magick_pass_fail
132
+ attach_function :MagickCompositeImage, [ :wand, :composite_wand, :composite_operator, :x, :y ], :magick_pass_fail
133
+
134
+ attach_function :MagickGetConfigureInfo, [ :wand, :string ], :string
135
+ attach_function :MagickGetVersion, [ :pointer ], :string
136
+ attach_function :MagickGetCopyright, [], :string
137
+ end
138
+ end
@@ -0,0 +1,79 @@
1
+ require 'test_helper'
2
+
3
+ class ImageTest < MiniTest::Unit::TestCase
4
+ def setup
5
+ @image = FFI::GMagick::Image.new()
6
+ @image.from_blob(BLOB)
7
+ end
8
+
9
+ def test_size
10
+ assert_equal 2005, @image.size, "BLOBs are not equal"
11
+ end
12
+
13
+ def test_crop
14
+ @image.crop(10,10)
15
+ assert_equal 10, @image.width, "invalid width"
16
+ assert_equal 10, @image.height, "invalid height"
17
+ end
18
+
19
+ def test_crop_with_offset
20
+ @image.crop(10,10, 5, 15)
21
+ assert_equal 10, @image.width, "invalid width"
22
+ assert_equal 10, @image.height, "invalid height"
23
+ # TODO: How do you test offsets??
24
+ end
25
+
26
+ def test_resize
27
+ @image.resize(10,20)
28
+ assert_equal 10, @image.width, "invalid width"
29
+ assert_equal 20, @image.height, "invalid height"
30
+ end
31
+
32
+ def test_resize_to_fill
33
+ new_image = @image.resize_to_fill(100,200)
34
+ assert_equal 100, new_image.width, "invalid width"
35
+ assert_equal 200, new_image.height, "invalid height"
36
+ end
37
+
38
+ def test_resize_to_fill_by_width
39
+ new_image = @image.resize_to_fill(100)
40
+ assert_equal 100, new_image.width, "invalid width"
41
+ assert_equal 100, new_image.height, "invalid height"
42
+ end
43
+
44
+ def test_resize_to_fit
45
+ new_image = @image.resize_to_fit(100,200)
46
+ assert_equal 100, new_image.width, "invalid width"
47
+ assert_equal 63, new_image.height, "invalid height"
48
+ end
49
+
50
+ def test_resize_to_fit_by_width
51
+ new_image = @image.resize_to_fit(100)
52
+ assert_equal 100, new_image.width, "invalid width"
53
+ assert_equal 63, new_image.height, "invalid height"
54
+ end
55
+
56
+ def test_colorspace
57
+ assert_equal :RGBColorspace, @image.colorspace, "invalid color space"
58
+ assert_equal :RGBColorspace, @image.colormodel, "invalid color model"
59
+ end
60
+
61
+ def test_get_type
62
+ assert_equal :TrueColorMatteType, @image.type, "invalid type"
63
+ end
64
+
65
+ def test_set_type
66
+ skip # not yet working
67
+ @image.type = :TrueColorType
68
+ assert @image.valid?
69
+ assert_equal :TrueColorType, @image.type, "invalid type"
70
+ end
71
+
72
+ def test_strip
73
+ skip # not yet working
74
+ old_size = @image.size
75
+ @image.strip
76
+ assert @image.valid?
77
+ assert old_size > @image.size, "image is not smaller"
78
+ end
79
+ end
@@ -0,0 +1,5 @@
1
+ require 'minitest/autorun'
2
+ require 'ffi/gmagick'
3
+
4
+ # JPEG 150x94+0+0 DirectClass 8-bit 2.0K (2,005 bytes) TrueColorMatteType
5
+ BLOB = "\xFF\xD8\xFF\xE0\u0000\u0010JFIF\u0000\u0001\u0001\u0001\u0000H\u0000H\u0000\u0000\xFF\xFE\u0000\u0013This is a comment\xFF\xDB\u0000C\u0000\b\u0006\u0006\a\u0006\u0005\b\a\a\a\t\t\b\n\f\u0014\r\f\v\v\f\u0019\u0012\u0013\u000F\u0014\u001D\u001A\u001F\u001E\u001D\u001A\u001C\u001C $.' \",#\u001C\u001C(7),01444\u001F'9=82<.342\xFF\xDB\u0000C\u0001\t\t\t\f\v\f\u0018\r\r\u00182!\u001C!22222222222222222222222222222222222222222222222222\xFF\xC0\u0000\u0011\b\u0000^\u0000\x96\u0003\u0001\"\u0000\u0002\u0011\u0001\u0003\u0011\u0001\xFF\xC4\u0000\u001C\u0000\u0000\u0002\u0002\u0003\u0001\u0001\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0005\u0003\u0004\u0006\a\b\u0002\u0001\xFF\xC4\u0000B\u0010\u0000\u0001\u0002\u0003\u0002\b\v\u0004\a\t\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0001\u0003\u0002\u0004\u0005\u0006\u0011\u0012\u0016!14qr\xB1\a236AQt\x81\x93\x94\xC1\u0015TU\xB2#57Va\x92\xD1\u0013\u0017$BRs\x91\xA1\xE1\xFF\xC4\u0000\e\u0001\u0000\u0002\u0003\u0001\u0001\u0001\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0006\a\u0000\u0004\u0005\u0003\u0002\u0001\xFF\xC4\u00004\u0011\u0000\u0002\u0000\u0003\u0003\b\t\u0004\u0003\u0001\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0001\u0002\u0003\u0004\u00064q\u0005\u0011\u0013!13\xB1\xC1\u00142AQRar\x91\xD1\u0012\"5\x81\u0016\x92\xA1S\xFF\xDA\u0000\f\u0003\u0001\u0000\u0002\u0011\u0003\u0011\u0000?\u0000\xDB\xC0\u0000B\u001E\xA0\xE3\u0013\u0010\xC1\xC6&\u0001-\u0015\xF7\xF4\xB9\x96\xE4\xF5C\xABP\xBAs\x95\x87dcը]9\xCAòv\xB2ߐX>F=\xA0\xB9<W2\u0000\u0000\u0019\xC0 \x91s\xA8\u0002\xE7P\u0014/i\xA4U\xA8\xE8.wo\u0012&t\xD4;\xA8\xE8.wo\u0012&t\xD43\xACe\xC2/S\xE0\x86u\x8C\xB8E\xEA|\u0010t\t\xAA\x9AD;\u001E\xA3\x9E\x815SH\x87c\xD4\xD4\xCB\xF7'\x8A\r\xA9\xF7\x85 \u0000\u0001\r#\u0018\u007FHwiw\x91\x92?\xA4;\xB4\xBB\xC8ǽ6\xE6\f\u0017\u0004!*w\xD1\xE2\xF8\xB0\u0000\u0002\xC1\xC4\xEA\u0010\u0000\u0013\xC1\t\xEA\u000E11\f\u001Cb`\u0012\xD1_\u007FK\x99nOT:\xB5\v\xA79XvF=Z\x85Ӝ\xAC;'k-\xF9\u0005\x83\xE4c\xDA\v\x93\xC5s \u0000\u0001\x9C\u0002\t\u0017:\x80.u\u0001B\xF6\x9AEZ\x8E\x82\xE7v\xF1\"gMC\xBA\x8E\x82\xE7v\xF1\"gMC:\xC6\\\"\xF5>\bgX˄^\xA7\xC1\a@\x9A\xA9\xA4C\xB1\xEA9\xE8\u0013U4\x88v=ML\xBFrx\xA0ڟxR\u0000\u0000\u0010\xD21\x87\xF4\x87v\x97y\u0019#\xFAC\xBBK\xBC\x8C{\xD3n`\xC1pB\u0012\xA7}\u001E/\x8B\u0000\u0000,\u001CN\xA1\u0000\u0001<\u0010\x9E\xA0\xE3\u0013\u0010\xC1\xC6&\u0001-\u0015\xF7\xF4\xB9\x96\xE4\xF5C\xABP\xBAs\x95\x87dcը]9\xCAòv\xB2ߐX>F=\xA0\xB9<W2\u0000\u0000\u0019\xC0 \x91s\xA8\u0002\xE7P\u0014/i\xA4U\xA8\xE8.wo\u0012&t\xD4;\xA8\xE8.wo\u0012&t\xD43\xACe\xC2/S\xE0\x86u\x8C\xB8E\xEA|\u0010t\t\xAA\x9AD;\u001E\xA3\x9E\x815SH\x87c\xD4\xD4\xCB\xF7'\x8A\r\xA9\xF7\x85 \u0000\u0001\r#\u0018\u007FHwiw\x91\x92?\xA4;\xB4\xBB\xC8ǽ6\xE6\f\u0017\u0004!*w\xD1\xE2\xF8\xB0\u0000\u0002\xC1\xC4\xEA\u0010\u0014cU\x9F\xF8\xDD?DŽ1\xAA\xCF\xFCn\x9F\xE3\xC2):4\xFF\u0000\u0003\xF6\u007F\u0006\xFE\x92\u001E\xF1\xCC\u001Cbk\x8C~+af؇\r\xCA\xF5:\bs_\u0014\xC4(y\xC7\xCB%\xF7\x96\x95\xE6\xA0\xFD@[EK?\xA6\xEE\xDE\xC5\xD8\xFC\xFC\x8Brb_N\xD3!\xBDn\xBC];\xCBC\x913\v\xA1\xB7VY8\xF6\x86\x97\u000E\xB9\xA8?S\xE2\xDA\nEC\xE9\xA4\xEA2\x93\r\xA2\xE0\xACm\xBC\x91%\xFDY\u000E\xB6^\x9El\u0015\xE9\xC5\v\xD8\xFB\u001F\x97\x91\x97\x97%\xC56\x93閳\xBC\xEBf\xBE\u0019\xCBw\x85\xE5Oh\xCA{\xCB\u001E\"\a\xB4\xA4\xFD\xE5\x8F\u0011\u0006O\xD1\u0017p\u001D\xD0*\xBF\xE5\u0017\xF5\x8B࠹\xD4\u0004\xABk\xAC\xEA*\xDF[\xA7\xF9\x98\u000F\x98\xDFg~7O\xF3\u0010\ngO7?U\xFB?\x82ւg\x85\xFB?\x81\x85K@wRo\u0012]}עf.E[\xA5U\eYi\n\x84\xAC\xD3\xD1䅦]H\xA2[\xB2\xADȟ\x81\u0014R\u0013\xC9r\xC3$\xE2\xA5\xDFң\"ǭ\u001D\fPǫ\xEE{uv!\x8Be'˧\xA1\x8A\u0019\xB1(_\xD4\xF6\xB4\xBB\u0017{D\u0019\xD1r\t\xEA\xA9\xFCD9\u0013\x89\xEAd)#;\xEE\xAE~E1\x8BE4\xD5:u\xA6\xE7\u001Cn]ț\xC2H]\\\u0015T\xBDr\xE54\xF2\xEBQѸa\xEFA\x855u+\x99\x99L\x87\xFB/\x92\u0000({b\x97\xEF\xF2\xDE\"\a\xB6)~\xFF\u0000-\xE2 \u0011\xA2\x8F\xB8\xD3\xE9R<k\xDD|\x89\xDF\xD2\u001D\xDA]\xE4cx\xAC\xE5ne\u007Fn\xC5\"u\xD6\\\xFAH#\x85\x85T\x8A\u0015ʊ\x8B\xD5pb\xAD\xA0\xF8\u001C\xFF\u0000\x97\x88v\xD3T\xC8Ra\xFB\xD6\xC5ڻ\x97\x98\x90\xA8\x82':-]\xAF\x8B\u0014\u0000\xDF\u0015m\a\xC0\xE7\xFC\xBC@v\xE9R<k\xDD|\x9Ctqw\t\xB0\x93\xAD\u0003\t:Ј\u000FzF|\xCCU\xAB\xC1\u0013\xF28\u0010B\xB1ņ\x8Bre)Sl\x85\xA3\xAC5\e\xD4\xDA4\xEC\xD3PE\x81\u0014L\xB2\xB1\".{\x86\xE6\xF3\xE07\x9B\xD5N؟$ \xAD\xA2\xA2\x85\xC0\xEA\xF3\xEBԳv\u001A\u0014sZz3@\xFE\xEEm\xA6U\xC5z\xAF\x96\x88\xD96\u0016\xCA\xD7\xE9\xD6}\xD6')\u0013\x8C8\xAF\xC5\u0012B\xE3K\n\xDDt9N\x88ȉ\xF8\u001EW.eN\xF0V\x9E{\x91\u001E\x91,\xE6\xCD-TT\xD34\x90\xAC望\xA6O\xC8\xCB957&\xE3,6\x97\xC6\xE3\x90ܐ\xA7Z\xA8\x9A*\xC51Q/\x9E\x97\xFC\xE8m~\u0011~ϫ}\x99w\xA1\xCC+\xAC-\xC9/\xA6\xCAqǫ3ͫ\u0002\xDC\xFBM>SI@\xBF\xD3\u0015\x8EBm\\\x89R]\xCC\xEB\xFC\xA7\x9FgM\xFB\xBB\x9F\x94\xCA\xC0\xF9\xFCfG\x8D\xFF\u0000\x80\xCFN\x8B\xB8\xF3\xC1\xBC\xE4\xAD&\xDE\xC8\xCCT^\x82Y\xA6\xD1Ď7\x97\u0005!\xBD\xB8\x91/\xFF\u0000&\xF9\xC7{.\x991\x82\x9F\u007F\xF7\x90\xE6\u001A\x9F\xD6O.[\xB0\x8A\x99\xD7X12.\x8F6)K^f\xCF5Y6]dJlm\xADGTc͗\xBF%~\x9D㡦\xF8^\xABS\xAB6\x92M\xFAl\xEB3M\xC1&\x90E\u00131a\".\u001Ckw\xFB5Ңߔ\xFBz'\xFCS\x94\xC9\xEE5\x99\xA2Rd\x99t\xB3t\xB0\xC4߱\xE0u/d\xAD\fԻs\u0012\xF4i\xD7Yr\u0014\x8A\b\xE0iU\"Ę%:^\xC7\xF3>\x89\xD8\xDA\xDCp5\u0006\xB4Kefd,\xFD6Nn\xBFObe\x89V\x9Ay\xA7\u001ED\x8A\b\xE1\x85\u0011QS\xA1QQP\xBF\x8F\xD6C\xEF%3\xCC!\xCAփ\x9C\x95N\xD8\xF7\u03A2\xD2\u0010\xEB\xBC~\xB2\u001Fy)\x9Ea\u0000\xE4@!\f\xD4\u0000\u0006\xB9\x82\u0006\xF3\xE07\x9B\xD5N؟\"\u001A0\xDE|\u0006\xF3z\xA9\xDB\u0013\xE4C\u0016\xD0\\b\xC5q,\xD2oM\xAC\u0000\u0000\u0011\xAAb\xDC#}\x9FV\xFB2\xEFC\x97\xD79\xD4\u001C#}\x9FV\xFB2\xEFC\x97\xD78gfn\xF1\xE3\xC8ͭ\xEB \u0000\u0000\x90\xA6c\u0015O\xAC\x9E\xDA(\x97\xAA\x9FY=\xB4Q\u0016u\xB7\x99\x98\xBE,ۗ\xD4@\u0000\u0005C\xD8\u001D/c\xF9\x9FD\xECmn9\xA0\xE9{\u001F\xCC\xFA'ckq\bs\u0560\xE7%S\xB6=\xF3\xA8\xB4eh9\xC9T\xED\x8F|\xEA-!\u0000\u0000\bC\xFF\xD9"
metadata ADDED
@@ -0,0 +1,106 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ffi-gmagick
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Richard Hurt
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-11-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: ffi
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.9'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.9'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '1.3'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '1.3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: |-
56
+ This is not a simple 'Ruby'-like implementation. It is more of a
57
+ raw 'C' implementation. As such, it may be a bit more difficult to
58
+ work with than something like rmagick, but it should perform just as
59
+ well.
60
+ email:
61
+ - rnhurt@gmail.com
62
+ executables: []
63
+ extensions: []
64
+ extra_rdoc_files: []
65
+ files:
66
+ - .gitignore
67
+ - .travis.yml
68
+ - Gemfile
69
+ - LICENSE.txt
70
+ - README.md
71
+ - Rakefile
72
+ - ffi-gmagick.gemspec
73
+ - lib/ffi/gmagick.rb
74
+ - lib/ffi/gmagick/image.rb
75
+ - lib/ffi/gmagick/struct.rb
76
+ - lib/ffi/gmagick/version.rb
77
+ - test/image_test.rb
78
+ - test/test_helper.rb
79
+ homepage: https://github.com/rnhurt/ffi-gmagick
80
+ licenses:
81
+ - MIT
82
+ metadata: {}
83
+ post_install_message:
84
+ rdoc_options: []
85
+ require_paths:
86
+ - lib
87
+ required_ruby_version: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - '>='
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ required_rubygems_version: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ requirements:
98
+ - libGraphicsMagick, v1.3.18
99
+ rubyforge_project:
100
+ rubygems_version: 2.1.11
101
+ signing_key:
102
+ specification_version: 4
103
+ summary: Use the C GraphicsMagick bindings to provide a Ruby interface
104
+ test_files:
105
+ - test/image_test.rb
106
+ - test/test_helper.rb