morandi 0.12.1 → 0.99.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e6da7620befd8e8fdac1a547cafbbcb0dd9e12c7d8edb5c2be0e57112e4e26ec
4
- data.tar.gz: 2d883102edca613748f79c7aa54b6ebe7a95930b8372c2812fddde7b3762a1b9
3
+ metadata.gz: 72cf19456503d11e3729ece721a4f8cf542ec674d5c35497d53efc8d333ebbd4
4
+ data.tar.gz: 3d05af03a553609b7bb4901071b675273127a329b323fb45bd1d7c071fe8aed5
5
5
  SHA512:
6
- metadata.gz: 92dae873f4b4de40ad3e2b89d1dd4203ef48281b6390f6d59f425364aeb503b949fa6f10972fda1f1f77854dc21873cf52f1611cba38f52702d903252ec618c3
7
- data.tar.gz: 6eb80b2a9f8b1a0fb84788a275e69f1a66c408a96337e49b33dafcc3da7ed11e80df2d74de0c9dabb1568e5bc2760b0c6ecca03c81864e55080b729034ee31ec
6
+ metadata.gz: fa60e3b5ccefa7a76fa8e4f70d28f3ef1ad80e81a8f1d07c35a258e6748e9a4ce4e5923f82be682456a74c5ca8acc185030a783f925246bf04fad5776d20aed1
7
+ data.tar.gz: 9bfff0edf6d1d52d2be6f836138b60d35c22a788fc337c46c7837a9b719f91ca6347ff746bd79f757737d6f6abba5615dd9f480e79ed07a8e9d67085cf6e3ad2
data/CHANGELOG.md CHANGED
@@ -4,7 +4,44 @@ All notable changes to this project will be documented in this file.
4
4
  The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
5
5
  and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
6
6
 
7
- ## Last updated 10.12.2020
7
+ ## [0.99.4] 18.11.2024
8
+ ### Added
9
+ - Better test coverage for straighten operation
10
+ - Support for visual image comparison in specs
11
+ - Automated visual comparison of images in specs, also serving as a record of exact rendering behaviour
12
+ - Development scripts for performing benchmarks
13
+ - Basic test coverage for transparency support
14
+
15
+ ### Changed
16
+ - Extracted image operations to separate files within a dedicated module
17
+ - [BREAKING] Introduced raising Morandi's own errors instead of bubbling Pixbuf's
18
+
19
+ ### Fixed
20
+ - Updated required ruby version in gemspec to reflect dropping Ruby 2.3 support
21
+
22
+ ### Removed
23
+ - [BREAKING] `config` accessor in ImageProcessor removed in favour of `user_options` supplied in constructor
24
+
25
+ ## [0.99.03] 19.09.2024
26
+ ### Added
27
+ - Copied pixbufutils and redeye gems into main gem
28
+ - Added gdk_pixbuf_cairo C extension to convert between GdkPixbufs and ImageSurfaces
29
+ - Added Ruby 3 support
30
+ - Bumped version to 0.99.01 in preparation for a 1.0 release
31
+
32
+ ### Removed
33
+ - [BREAKING] support for Ruby 2.0 (and illusion of it being tested by CI)
34
+ - [BREAKING] support for Ruby 2.3
35
+ - gtk2 dependency
36
+
37
+ ## [0.13.0] 16.12.2020
38
+ ### Fixed
39
+ - Refactored test suite
40
+ - Fixed most rubocop offenses
41
+ ### Added
42
+ - CI pipeline
43
+ - rubocop
44
+ - Development image
8
45
 
9
46
  ## [0.12.1] 10.12.2020
10
47
  ### Fixed
@@ -13,7 +50,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
13
50
  ## [0.12.0] 10.12.2020
14
51
  ### Fixed
15
52
  - Compatability with gdk_pixbuf v3.4.0+ [TECH-14001]
16
- ### Aded
53
+ ### Added
17
54
  - .ruby-version file
18
55
 
19
56
 
data/README.md CHANGED
@@ -1,11 +1,10 @@
1
1
  # Morandi
2
2
 
3
- Library of simple image manipulations - replicating the behaviour of
4
- morandi-js.
3
+ Library of simple image manipulations - replicating the behaviour of morandi-js.
5
4
 
6
5
  ## Installation
7
6
 
8
- Install `liblcms2-utils` to provide the `jpgicc` command used by `Morandi::ProfiledPixbuf`
7
+ Install `liblcms2-utils` to provide the `jpgicc` command used by `Morandi::ProfiledPixbuf`. Also ensure that your host system has `imagemagick` installed, which is required by the `colorscore` gem.
9
8
 
10
9
  Add this line to your application's Gemfile:
11
10
 
@@ -22,25 +21,10 @@ Or install it yourself as:
22
21
  ## Usage
23
22
 
24
23
  ````
25
- Morandi.process(in_file, settings, out_file)
24
+ Morandi.process(source, options, target_path)
26
25
  ````
27
- - in_file is a string
28
- - settings is a hash
29
- - out_file is a string
30
-
31
- Settings Key | Values | Description
32
- -------------|--------|---------------
33
- brighten | Integer -20..20 | Change image brightness
34
- gamma | Float | Gamma correct image
35
- contrast | Integer -20..20 | Change image contrast
36
- sharpen | Integer -5..5 | Sharpen / Blur (negative value)
37
- redeye | Array[[Integer,Integer],...] | Apply redeye correction at point
38
- angle | Integer 0,90,180,270 | Rotate image
39
- crop | Array[Integer,Integer,Integer,Integer] | Crop image
40
- fx | String greyscale,sepia,bluetone | Apply colour filters
41
- border-style | String square,retro | Set border style
42
- background-style | String retro,black,white | Set border colour
43
- quality | String '1'..'100' | Set JPG compression value, defaults to 97%
26
+
27
+ For the detailed documentation of options see `lib/morandi.rb`
44
28
 
45
29
  ## Contributing
46
30
 
@@ -49,3 +33,7 @@ quality | String '1'..'100' | Set JPG compression value, defaults to 97%
49
33
  3. Commit your changes (`git commit -am 'Add some feature'`)
50
34
  4. Push to the branch (`git push origin my-new-feature`)
51
35
  5. Create new Pull Request
36
+
37
+ ### Development
38
+
39
+ Since this gem depends on the `liblcms2-utils` library, which can be awkward to install on some operating systems, we also provide a development docker image. A Makefile is also provided as a simple CLI. To build the image and run the container, type `make` from the project root. The container itself runs `guard` as its main process. Running the container via `make` will drop you into the guard prompt, which will run the test suite whenever any of the source code or tests are changed. The tests can be kicked-off manually via the `all` command at the guard prompt. Individual test can be run using the `focus: true` annotation on an example or describe block. If you need to access a bash shell in the container (for example, to run rubocop), use the command `make shell`.
@@ -0,0 +1,124 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rubocop:disable Style/GlobalVars
4
+ require 'mkmf'
5
+
6
+ require 'English'
7
+ require 'rubygems'
8
+ gem 'glib2'
9
+ require 'mkmf-gnome'
10
+
11
+ def macos?
12
+ !!(RUBY_PLATFORM =~ /darwin/)
13
+ end
14
+
15
+ def clang?
16
+ cc_version = `#{RbConfig.expand('$(CC) --version'.dup)}`
17
+ cc_version.match?(/clang/i)
18
+ end
19
+
20
+ # XCode 14 warns if `-Wl,-undefined dynamic_lookup` is specified, and as
21
+ # a result Ruby interpreters compiled under XCode 14 no longer specify
22
+ # this flag by default in DLDFLAGS. Let's specify the list of dynamic symbols
23
+ # here to avoid compilation failures.
24
+ if clang? && macos?
25
+ dynamic_symbols = %w[
26
+ _rb_cairo_surface_from_ruby_object
27
+ _rb_cairo_surface_to_ruby_object_with_destroy
28
+ _rbgobj_instance_from_ruby_object
29
+ _rbgobj_ruby_object_from_instance
30
+ ]
31
+ dynamic_symbols.each do |sym|
32
+ $DLDFLAGS << " -Wl,-U,#{sym.strip}"
33
+ end
34
+ end
35
+
36
+ %w[rbglib.h rbpango.h rcairo.h].each do |header|
37
+ Gem.find_files(header).each do |f|
38
+ $CFLAGS += " '-I#{File.dirname(f)}'"
39
+ end
40
+ end
41
+ # Look for headers in {gem_root}/ext/{package}
42
+ %w[glib2 cairo].each do |package|
43
+ require package
44
+ if Gem.loaded_specs[package]
45
+ $CFLAGS += " -I#{Gem.loaded_specs[package].full_gem_path}/ext/#{package}"
46
+ else
47
+ fn = $LOADED_FEATURES.find { |n| n.sub(/[.](so|rb)$/, '') == package }
48
+ if fn
49
+ dr = $LOAD_PATH.find { |d| File.exist?(File.join(d, fn)) }
50
+ pt = File.join(dr, fn) if dr && fn
51
+ else
52
+ pt = '??'
53
+ end
54
+ warn "require '#{package}' loaded '#{pt}' instead of the gem - trying to continue, but build may fail"
55
+ end
56
+ end
57
+ $CFLAGS += " -I#{RbConfig::CONFIG['rubyhdrdir']}/ruby" if RbConfig::CONFIG.key?('rubyhdrdir')
58
+
59
+ $CFLAGS += ' -I.'
60
+ have_func('rb_errinfo')
61
+ PKGConfig.have_package('gdk-pixbuf-2.0') or exit(-1)
62
+ # PKGConfig.have_package('gdk-2.0') or exit(-1)
63
+ PKGConfig.have_package('cairo') or exit(-1)
64
+
65
+ unless have_header('gdk-pixbuf/gdk-pixbuf.h')
66
+ paths = Gem.find_files('gdk-pixbuf/gdk-pixbuf.h')
67
+ paths.each do |path|
68
+ $CFLAGS += " '-I#{File.dirname(path)}'"
69
+ end
70
+ have_header('gdk-pixbuf/gdk-pixbuf.h') or exit(-1)
71
+ end
72
+
73
+ unless have_header('rbglib.h')
74
+ paths = Gem.find_files('rbglib.h')
75
+ paths.each do |path|
76
+ $CFLAGS += " '-I#{File.dirname(path)}'"
77
+ end
78
+ have_header('rbglib.h') or exit(-1)
79
+ end
80
+
81
+ unless have_header('rbgobject.h')
82
+ paths = Gem.find_files('rbgobject.h')
83
+ paths.each do |path|
84
+ $CFLAGS += " '-I#{File.dirname(path)}'"
85
+ end
86
+ have_header('rbgobject.h') or exit(-1)
87
+ end
88
+
89
+ $defs << '-DHAVE_OBJECT_ALLOCATE'
90
+
91
+ top = File.expand_path("#{File.dirname(__FILE__)}/..") # XXX
92
+ $CFLAGS << ' ' << ['glib/src'].map do |d|
93
+ "-I#{File.join(top, d)}"
94
+ end.join(' ')
95
+
96
+ begin
97
+ srcdir = File.expand_path(File.dirname($PROGRAM_NAME))
98
+
99
+ obj_ext = ".#{$OBJEXT}"
100
+ $libs = $libs.split(/ /).uniq.join(' ')
101
+ $source_files = Dir.glob(format('%s/*.c', srcdir)).map do |fname|
102
+ fname[0, srcdir.length + 1] = ''
103
+ fname
104
+ end
105
+ $objs = $source_files.collect do |item|
106
+ item.gsub(/.c$/, obj_ext)
107
+ end
108
+
109
+ #
110
+ # create Makefile
111
+ #
112
+ $defs << '-DRUBY_MORANDI_NATIVE_COMPILATION'
113
+ create_makefile('gdk_pixbuf_cairo', srcdir)
114
+ raise Interrupt unless FileTest.exist? 'Makefile'
115
+
116
+ File.open('Makefile', 'a') do |mfile|
117
+ $source_files.each do |e|
118
+ mfile.print("#{e.gsub(/.c$/, obj_ext)}: #{e}\n")
119
+ end
120
+ end
121
+ rescue Interrupt
122
+ print " [error] #{$ERROR_INFO}\n"
123
+ end
124
+ # rubocop:enable Style/GlobalVars
@@ -0,0 +1,260 @@
1
+ /* Includes */
2
+ #include <ruby.h>
3
+ #include <stdlib.h>
4
+ #include <stdio.h>
5
+ #include <string.h>
6
+
7
+ #if defined GCC
8
+ #define OPTIONAL_ATTR __attribute__((unused))
9
+ #else
10
+ #define OPTIONAL_ATTR
11
+ #endif
12
+
13
+ #include "gdk-pixbuf/gdk-pixbuf.h"
14
+ #include "rbglib.h"
15
+ #include "rbgobject.h"
16
+ #include "rb_cairo.h"
17
+
18
+ static VALUE mGdkPixbufCairo;
19
+ void Init_gdk_pixbuf_cairo(void);
20
+
21
+ /**
22
+ * pixbuf_cairo_create:
23
+ * @pixbuf: GdkPixbuf that you wish to wrap with cairo context
24
+ *
25
+ * This function will initialize new cairo context with contents of @pixbuf. You
26
+ * can then draw using returned context. When finished drawing, you must call
27
+ * pixbuf_cairo_destroy() or your pixbuf will not be updated with new contents!
28
+ *
29
+ * Return value: New cairo_t context. When you're done with it, call
30
+ * pixbuf_cairo_destroy() to update your pixbuf and free memory.
31
+ */
32
+ static cairo_surface_t *
33
+ pixbuf_to_surface(GdkPixbuf *pixbuf) {
34
+ gint width, /* Width of both pixbuf and surface */
35
+ height, /* Height of both pixbuf and surface */
36
+ p_stride, /* Pixbuf stride value */
37
+ p_n_channels, /* RGB -> 3, RGBA -> 4 */
38
+ s_stride, /* Surface stride value */
39
+ j;
40
+ guchar *p_pixels, /* Pixbuf's pixel data */
41
+ *s_pixels; /* Surface's pixel data */
42
+ cairo_surface_t *surface; /* Temporary image surface */
43
+
44
+ g_object_ref(G_OBJECT(pixbuf));
45
+
46
+ /* Inspect input pixbuf and create compatible cairo surface */
47
+ g_object_get(G_OBJECT(pixbuf), "width", &width,
48
+ "height", &height,
49
+ "rowstride", &p_stride,
50
+ "n-channels", &p_n_channels,
51
+ "pixels", &p_pixels,
52
+ NULL);
53
+ surface = cairo_image_surface_create(p_n_channels == 4 ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_RGB24, width, height);
54
+ s_stride = cairo_image_surface_get_stride(surface);
55
+ s_pixels = cairo_image_surface_get_data(surface);
56
+
57
+ /* Copy pixel data from pixbuf to surface */
58
+ for (j = height; j; j--) {
59
+ guchar *p = p_pixels;
60
+ guchar *q = s_pixels;
61
+
62
+ if (p_n_channels == 3) {
63
+ guchar *end = p + 3 * width;
64
+
65
+ while (p < end) {
66
+ #if G_BYTE_ORDER == G_LITTLE_ENDIAN
67
+ q[0] = p[2];
68
+ q[1] = p[1];
69
+ q[2] = p[0];
70
+ q[3] = 0xFF;
71
+ #else
72
+ q[0] = 0xFF;
73
+ q[1] = p[0];
74
+ q[2] = p[1];
75
+ q[3] = p[2];
76
+ #endif
77
+ p += 3;
78
+ q += 4;
79
+ }
80
+ } else {
81
+ guchar *end = p + 4 * width;
82
+ guint t1, t2, t3;
83
+
84
+ #define MULT(d, c, a, t) G_STMT_START { t = c * a + 0x80; d = ((t >> 8) + t) >> 8; } G_STMT_END
85
+
86
+ while (p < end) {
87
+ #if G_BYTE_ORDER == G_LITTLE_ENDIAN
88
+ MULT(q[0], p[2], p[3], t1);
89
+ MULT(q[1], p[1], p[3], t2);
90
+ MULT(q[2], p[0], p[3], t3);
91
+ q[3] = p[3];
92
+ #else
93
+ q[0] = p[3];
94
+ MULT(q[1], p[0], p[3], t1);
95
+ MULT(q[2], p[1], p[3], t2);
96
+ MULT(q[3], p[2], p[3], t3);
97
+ #endif
98
+
99
+ p += 4;
100
+ q += 4;
101
+ }
102
+
103
+ #undef MULT
104
+ }
105
+
106
+ p_pixels += p_stride;
107
+ s_pixels += s_stride;
108
+ }
109
+ g_object_unref(G_OBJECT(pixbuf));
110
+
111
+ cairo_surface_mark_dirty(surface);
112
+
113
+ return surface;
114
+ }
115
+
116
+ /**
117
+ * pixbuf_cairo_destroy:
118
+ * @cr: Cairo context that you wish to destroy
119
+ * @create_new_pixbuf: If TRUE, new pixbuf will be created and returned. If
120
+ * FALSE, input pixbuf will be updated in place.
121
+ *
122
+ * This function will destroy cairo context, created with pixbuf_cairo_create().
123
+ *
124
+ * Return value: New or updated GdkPixbuf. You own a new reference on return
125
+ * value, so you need to call g_object_unref() on returned pixbuf when you don't
126
+ * need it anymore.
127
+ */
128
+ static GdkPixbuf *
129
+ surface_to_pixbuf(cairo_surface_t *surface) {
130
+ gint width, /* Width of both pixbuf and surface */
131
+ height, /* Height of both pixbuf and surface */
132
+ p_stride, /* Pixbuf stride value */
133
+ p_n_channels, /* RGB -> 3, RGBA -> 4 */
134
+ s_stride, /* Surface stride value */
135
+ j;
136
+ guchar *p_pixels, /* Pixbuf's pixel data */
137
+ *s_pixels; /* Surface's pixel data */
138
+ GdkPixbuf *pixbuf; /* Pixbuf to be returned */
139
+ cairo_format_t format; /* cairo surface format */
140
+
141
+ format = cairo_image_surface_get_format(surface);
142
+
143
+ switch (format) {
144
+ case CAIRO_FORMAT_ARGB32:
145
+ p_n_channels = 4;
146
+ break;
147
+ case CAIRO_FORMAT_RGB24:
148
+ p_n_channels = 3;
149
+ break;
150
+ default:
151
+ return (GdkPixbuf *) 0;
152
+ break;
153
+ }
154
+
155
+ width = cairo_image_surface_get_width(surface);
156
+ height = cairo_image_surface_get_height(surface);
157
+ s_stride = cairo_image_surface_get_stride(surface);
158
+ s_pixels = cairo_image_surface_get_data(surface);
159
+
160
+ /* Create pixbuf to be returned */
161
+ pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, p_n_channels == 4, 8, width, height);
162
+
163
+ g_return_val_if_fail(pixbuf != NULL, NULL);
164
+
165
+ /* Inspect pixbuf and surface */
166
+ g_object_get(G_OBJECT(pixbuf),
167
+ "width", &width,
168
+ "height", &height,
169
+ "rowstride", &p_stride,
170
+ "n-channels", &p_n_channels,
171
+ "pixels", &p_pixels,
172
+ NULL);
173
+
174
+
175
+ /* Copy pixel data from surface to pixbuf */
176
+ for (j = height; j; j--) {
177
+ guchar *p = p_pixels;
178
+ guchar *q = s_pixels;
179
+
180
+ if (p_n_channels == 3) {
181
+ guchar *end = p + 3 * width;
182
+
183
+ while (p < end) {
184
+ #if G_BYTE_ORDER == G_LITTLE_ENDIAN
185
+ p[2] = q[0];
186
+ p[1] = q[1];
187
+ p[0] = q[2];
188
+ #else
189
+ p[0] = q[1];
190
+ p[1] = q[2];
191
+ p[2] = q[3];
192
+ #endif
193
+ p += 3;
194
+ q += 4;
195
+ }
196
+ } else {
197
+ guchar *end = p + 4 * width;
198
+ guint t1, t2, t3;
199
+
200
+ #define UNMULT(s_byte, p_byte, a, t) G_STMT_START { \
201
+ t = s_byte * 255 / a; \
202
+ p_byte = t; \
203
+ } G_STMT_END
204
+
205
+ while (p < end) {
206
+ #if G_BYTE_ORDER == G_LITTLE_ENDIAN
207
+ UNMULT(q[0], p[2], q[3], t1);
208
+ UNMULT(q[1], p[1], q[3], t2);
209
+ UNMULT(q[2], p[0], q[3], t3);
210
+ p[3] = q[3];
211
+ #else
212
+ p[3] = q[0];
213
+ UNMULT(q[1], p[0], q[3], t1);
214
+ UNMULT(q[2], p[1], q[3], t2);
215
+ UNMULT(q[3], p[2], q[3], t3);
216
+ #endif
217
+
218
+ p += 4;
219
+ q += 4;
220
+ }
221
+
222
+ #undef MULT
223
+ }
224
+
225
+ p_pixels += p_stride;
226
+ s_pixels += s_stride;
227
+ }
228
+
229
+ /* Return pixbuf */
230
+ return (pixbuf);
231
+ }
232
+
233
+ static
234
+ VALUE rb_pixbuf_to_surface(__attribute__((unused)) VALUE _self, VALUE pixbuf) {
235
+ cairo_surface_t *surface = pixbuf_to_surface(GDK_PIXBUF(RVAL2GOBJ(pixbuf)));
236
+ return CRSURFACE2RVAL_WITH_DESTROY(surface);
237
+ }
238
+
239
+ static
240
+ VALUE rb_surface_to_pixbuf(__attribute__((unused)) VALUE _self, VALUE surface) {
241
+ VALUE obj;
242
+ GdkPixbuf *pixbuf = surface_to_pixbuf(RVAL2CRSURFACE(surface));
243
+ if (pixbuf) {
244
+ obj = GOBJ2RVAL(pixbuf);
245
+ g_object_unref(pixbuf);
246
+ return obj;
247
+ }
248
+
249
+ rb_raise(rb_eRuntimeError, "Unable to convert Cairo::ImageSurface to Gdk::Pixbuf");
250
+
251
+ return Qnil;
252
+ }
253
+
254
+ /* Init */
255
+ void
256
+ Init_gdk_pixbuf_cairo(void) {
257
+ mGdkPixbufCairo = rb_define_module("GdkPixbufCairo");
258
+ rb_define_singleton_method(mGdkPixbufCairo, "pixbuf_to_surface", rb_pixbuf_to_surface, 1);
259
+ rb_define_singleton_method(mGdkPixbufCairo, "surface_to_pixbuf", rb_surface_to_pixbuf, 1);
260
+ }
@@ -0,0 +1,121 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rubocop:disable Style/GlobalVars
4
+ require 'mkmf'
5
+
6
+ require 'English'
7
+ require 'rubygems'
8
+ gem 'glib2'
9
+ require 'mkmf-gnome'
10
+
11
+ def macos?
12
+ !!(RUBY_PLATFORM =~ /darwin/)
13
+ end
14
+
15
+ def clang?
16
+ cc_version = `#{RbConfig.expand('$(CC) --version'.dup)}`
17
+ cc_version.match?(/clang/i)
18
+ end
19
+
20
+ # XCode 14 warns if `-Wl,-undefined dynamic_lookup` is specified, and as
21
+ # a result Ruby interpreters compiled under XCode 14 no longer specify
22
+ # this flag by default in DLDFLAGS. Let's specify the list of dynamic symbols
23
+ # here to avoid compilation failures.
24
+ if clang? && macos?
25
+ dynamic_symbols = %w[
26
+ _rbgobj_instance_from_ruby_object
27
+ _rbgobj_ruby_object_from_instance
28
+ ]
29
+ dynamic_symbols.each do |sym|
30
+ $DLDFLAGS << " -Wl,-U,#{sym.strip}"
31
+ end
32
+ end
33
+
34
+ %w[rbglib.h rbpango.h].each do |header|
35
+ Gem.find_files(header).each do |f|
36
+ $CFLAGS += " '-I#{File.dirname(f)}'"
37
+ end
38
+ end
39
+ # Look for headers in {gem_root}/ext/{package}
40
+ %w[glib2].each do |package|
41
+ require package
42
+ if Gem.loaded_specs[package]
43
+ $CFLAGS += " -I#{Gem.loaded_specs[package].full_gem_path}/ext/#{package}"
44
+ else
45
+ fn = $LOADED_FEATURES.find { |n| n.sub(/[.](so|rb)$/, '') == package }
46
+ if fn
47
+ dr = $LOAD_PATH.find { |d| File.exist?(File.join(d, fn)) }
48
+ pt = File.join(dr, fn) if dr && fn
49
+ else
50
+ pt = '??'
51
+ end
52
+ warn "require '#{package}' loaded '#{pt}' instead of the gem - trying to continue, but build may fail"
53
+ end
54
+ end
55
+ $CFLAGS += " -I#{RbConfig::CONFIG['rubyhdrdir']}/ruby" if RbConfig::CONFIG.key?('rubyhdrdir')
56
+
57
+ $CFLAGS += ' -I.'
58
+ have_func('rb_errinfo')
59
+ PKGConfig.have_package('gdk-pixbuf-2.0') or exit(-1)
60
+ # PKGConfig.have_package('gdk-2.0') or exit(-1)
61
+
62
+ unless have_header('gdk-pixbuf/gdk-pixbuf.h')
63
+ paths = Gem.find_files('gdk-pixbuf/gdk-pixbuf.h')
64
+ paths.each do |path|
65
+ $CFLAGS += " '-I#{File.dirname(path)}'"
66
+ end
67
+ have_header('gdk-pixbuf/gdk-pixbuf.h') or exit(-1)
68
+ end
69
+
70
+ unless have_header('rbglib.h')
71
+ paths = Gem.find_files('rbglib.h')
72
+ paths.each do |path|
73
+ $CFLAGS += " '-I#{File.dirname(path)}'"
74
+ end
75
+ have_header('rbglib.h') or exit(-1)
76
+ end
77
+
78
+ unless have_header('rbgobject.h')
79
+ paths = Gem.find_files('rbgobject.h')
80
+ paths.each do |path|
81
+ $CFLAGS += " '-I#{File.dirname(path)}'"
82
+ end
83
+ have_header('rbgobject.h') or exit(-1)
84
+ end
85
+
86
+ $defs << '-DHAVE_OBJECT_ALLOCATE'
87
+
88
+ top = File.expand_path("#{File.dirname(__FILE__)}/..") # XXX
89
+ $CFLAGS << ' ' << ['glib/src'].map do |d|
90
+ "-I#{File.join(top, d)}"
91
+ end.join(' ')
92
+
93
+ begin
94
+ srcdir = File.expand_path(File.dirname($PROGRAM_NAME))
95
+
96
+ obj_ext = ".#{$OBJEXT}"
97
+ $libs = $libs.split(/ /).uniq.join(' ')
98
+ $source_files = Dir.glob(format('%s/*.c', srcdir)).map do |fname|
99
+ fname[0, srcdir.length + 1] = ''
100
+ fname
101
+ end
102
+ $objs = $source_files.collect do |item|
103
+ item.gsub(/.c$/, obj_ext)
104
+ end
105
+
106
+ #
107
+ # create Makefile
108
+ #
109
+ $defs << '-DRUBY_MORANDI_NATIVE_COMPILATION'
110
+ create_makefile('morandi_native', srcdir)
111
+ raise Interrupt unless FileTest.exist? 'Makefile'
112
+
113
+ File.open('Makefile', 'a') do |mfile|
114
+ $source_files.each do |e|
115
+ mfile.print("#{e.gsub(/.c$/, obj_ext)}: #{e}\n")
116
+ end
117
+ end
118
+ rescue Interrupt
119
+ print " [error] #{$ERROR_INFO}\n"
120
+ end
121
+ # rubocop:enable Style/GlobalVars