ffi-gmagick 0.0.1

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