ruby-vips 0.1.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.
data/ext/ruby_vips.h ADDED
@@ -0,0 +1,26 @@
1
+ #ifndef RUBY_VIPS_H
2
+ #define RUBY_VIPS_H
3
+
4
+ #include "ruby.h"
5
+ #include "vips/vips.h"
6
+
7
+ extern VALUE mVIPS, eVIPSError;
8
+
9
+ void vips_lib_error();
10
+
11
+ /* Backports from ruby 1.9.2 for ruby 1.8.7
12
+ */
13
+
14
+ #ifndef DBL2NUM
15
+ #define DBL2NUM(dbl) rb_float_new(dbl)
16
+ #endif
17
+
18
+ #ifndef RARRAY_LENINT
19
+ #define RARRAY_LENINT(ary) RARRAY_LEN(ary)
20
+ #endif
21
+
22
+ #ifndef rb_str_new_cstr
23
+ #define rb_str_new_cstr(str) rb_str_new(str, (long)strlen(str))
24
+ #endif
25
+
26
+ #endif
data/ext/writer.c ADDED
@@ -0,0 +1,346 @@
1
+ #include "ruby_vips.h"
2
+ #include "image.h"
3
+ #include "header.h"
4
+
5
+ /* :nodoc: */
6
+
7
+ static VALUE
8
+ writer_initialize(int argc, VALUE *argv, VALUE obj)
9
+ {
10
+ VALUE image, opts;
11
+ rb_scan_args(argc, argv, "11", &image, &opts);
12
+ GetImg(image, data, im);
13
+ GetImg(obj, data_new, im_new);
14
+
15
+ img_add_dep(data_new, image);
16
+ if (im_copy(im, im_new))
17
+ vips_lib_error();
18
+
19
+ return obj;
20
+ }
21
+
22
+ /*
23
+ * call-seq:
24
+ * writer.image -> image
25
+ *
26
+ * Returns the image associated with *self*.
27
+ */
28
+
29
+ static VALUE
30
+ writer_image(VALUE obj)
31
+ {
32
+ GetImg(obj, data, im);
33
+
34
+ if(data->deps)
35
+ return data->deps[0];
36
+
37
+ return Qnil;
38
+ }
39
+
40
+ static VALUE
41
+ writer_meta_set(VALUE obj, const char* name, VALUE str)
42
+ {
43
+ GetImg(obj, data, im);
44
+
45
+ size_t len = RSTRING_LEN(str);
46
+ void *buf = malloc(len);
47
+ memcpy(buf, RSTRING_PTR(str), len);
48
+
49
+ if (im_meta_set_blob(im, name, (im_callback_fn)xfree, buf, len)) {
50
+ xfree(buf);
51
+ vips_lib_error();
52
+ }
53
+
54
+ return str;
55
+ }
56
+
57
+ static VALUE
58
+ writer_meta_remove(VALUE obj, const char* name)
59
+ {
60
+ GetImg(obj, data, im);
61
+ #if IM_MAJOR_VERSION > 7 || IM_MINOR_VERSION >= 22
62
+ if (im_meta_remove(im, name))
63
+ return Qfalse;
64
+ #else
65
+ rb_raise(eVIPSError, "This method is not implemented in your version of VIPS");
66
+ #endif
67
+ return Qtrue;
68
+ }
69
+
70
+ /*
71
+ * call-seq:
72
+ * writer.exif = exif_data
73
+ *
74
+ * Sets the exif header of the writer to <i>exif_data</i>. This will be
75
+ * written only if the file format supports embedded exif data.
76
+ *
77
+ */
78
+
79
+ static VALUE
80
+ writer_exif_set(VALUE obj, VALUE str)
81
+ {
82
+ return writer_meta_set(obj, IM_META_EXIF_NAME, str);
83
+ }
84
+
85
+ /*
86
+ * call-seq:
87
+ * writer.remove_exif -> true or false
88
+ *
89
+ * Removes exif data associated with *self*.
90
+ */
91
+
92
+ static VALUE
93
+ writer_remove_exif(VALUE obj)
94
+ {
95
+ return writer_meta_remove(obj, IM_META_EXIF_NAME);
96
+ }
97
+
98
+ /*
99
+ * call-seq:
100
+ * writer.icc = icc_data
101
+ *
102
+ * Sets the icc header of the writer to <i>icc_data</i>. This will be written
103
+ * only if the file format supports embedded icc data.
104
+ *
105
+ */
106
+
107
+ static VALUE
108
+ writer_icc_set(VALUE obj, VALUE str)
109
+ {
110
+ return writer_meta_set(obj, IM_META_ICC_NAME, str);
111
+ }
112
+
113
+ /*
114
+ * call-seq:
115
+ * writer.remove_icc -> true or false
116
+ *
117
+ * Removes icc data associated with *self*.
118
+ */
119
+
120
+ static VALUE
121
+ writer_remove_icc(VALUE obj)
122
+ {
123
+ return writer_meta_remove(obj, IM_META_ICC_NAME);
124
+ }
125
+
126
+ /* :nodoc: */
127
+
128
+ static VALUE
129
+ writer_write_internal(VALUE obj, VALUE path)
130
+ {
131
+ VipsImage *out;
132
+ GetImg(obj, data, im);
133
+
134
+ if (!(out = im_open(StringValuePtr(path), "w")) || im_copy(im, out))
135
+ vips_lib_error();
136
+
137
+ im_close(out);
138
+
139
+ return obj;
140
+ }
141
+
142
+ /* :nodoc: */
143
+
144
+ static VALUE
145
+ jpeg_buf_internal(VALUE obj, VALUE quality)
146
+ {
147
+ VipsImage *im_out;
148
+ char *buf = NULL;
149
+ int length;
150
+ VALUE str;
151
+
152
+ GetImg(obj, data, im);
153
+
154
+ if (!(im_out = im_open("writer_jpeg_buf", "p")))
155
+ vips_lib_error();
156
+
157
+ if (im_vips2bufjpeg(im, im_out, NUM2INT(quality), &buf, &length)) {
158
+ im_close(im_out);
159
+ vips_lib_error();
160
+ }
161
+
162
+ str = rb_tainted_str_new(buf, length);
163
+ im_close(im_out);
164
+
165
+ return str;
166
+ }
167
+
168
+ /* :nodoc: */
169
+
170
+ static VALUE
171
+ jpeg_write_internal(VALUE obj, VALUE path)
172
+ {
173
+ GetImg(obj, data, im);
174
+
175
+ if (im_vips2jpeg(im, RSTRING_PTR(path)))
176
+ vips_lib_error();
177
+
178
+ return obj;
179
+ }
180
+
181
+ /* :nodoc: */
182
+
183
+ static VALUE
184
+ tiff_write_internal(VALUE obj, VALUE path)
185
+ {
186
+ GetImg(obj, data, im);
187
+
188
+ if (im_vips2tiff(im, RSTRING_PTR(path)))
189
+ vips_lib_error();
190
+
191
+ return obj;
192
+ }
193
+
194
+ /* :nodoc: */
195
+
196
+ static VALUE
197
+ ppm_write_internal(VALUE obj, VALUE path)
198
+ {
199
+ GetImg(obj, data, im);
200
+
201
+ if (im_vips2ppm(im, RSTRING_PTR(path)))
202
+ vips_lib_error();
203
+
204
+ return obj;
205
+ }
206
+
207
+ /* :nodoc: */
208
+
209
+ static VALUE
210
+ png_buf_internal(VALUE obj, VALUE compression, VALUE interlace)
211
+ {
212
+ #if IM_MAJOR_VERSION > 7 || IM_MINOR_VERSION >= 23
213
+ VipsImage *im_out;
214
+ char *buf;
215
+ size_t length;
216
+ GetImg(obj, data, im);
217
+
218
+ if (!(im_out = im_open("writer_png_buf", "p")))
219
+ vips_lib_error();
220
+
221
+ if (im_vips2bufpng(im, im_out, NUM2INT(compression), NUM2INT(interlace),
222
+ &buf, &length)) {
223
+ im_close(im_out);
224
+ vips_lib_error();
225
+ }
226
+
227
+ im_close(im_out);
228
+
229
+ return rb_tainted_str_new(buf, length);
230
+ #else
231
+ rb_raise(eVIPSError, "This method is not implemented in your version of VIPS");
232
+ #endif
233
+ }
234
+
235
+ /* :nodoc: */
236
+
237
+ static VALUE
238
+ png_write_internal(VALUE obj, VALUE path)
239
+ {
240
+ GetImg(obj, data, im);
241
+
242
+ if (im_vips2png(im, RSTRING_PTR(path)))
243
+ vips_lib_error();
244
+
245
+ return obj;
246
+ }
247
+
248
+ /* :nodoc: */
249
+
250
+ static VALUE
251
+ csv_write_internal(VALUE obj, VALUE path)
252
+ {
253
+ GetImg(obj, data, im);
254
+
255
+ if (im_vips2csv(im, RSTRING_PTR(path)))
256
+ vips_lib_error();
257
+
258
+ return obj;
259
+ }
260
+
261
+ /* :nodoc: */
262
+
263
+ static VALUE
264
+ vips_write_internal(VALUE obj, VALUE path)
265
+ {
266
+ VipsImage *im_new;
267
+ GetImg(obj, data, im);
268
+
269
+ if (!(im_new = (VipsImage *)im_openout(RSTRING_PTR(path))))
270
+ vips_lib_error();
271
+
272
+ if (im_copy(im, im_new))
273
+ vips_lib_error();
274
+
275
+ im_close(im_new);
276
+
277
+ return obj;
278
+ }
279
+
280
+ /*
281
+ * Base class for image format readers.
282
+ */
283
+
284
+ void
285
+ init_Writer()
286
+ {
287
+ VALUE writer = rb_define_class_under(mVIPS, "Writer", rb_cObject);
288
+
289
+ rb_include_module(writer, mVIPSHeader);
290
+ rb_define_alloc_func(writer, img_init_partial_anyclass);
291
+ rb_define_method(writer, "initialize", writer_initialize, -1);
292
+ rb_define_method(writer, "image", writer_image, 0);
293
+ rb_define_method(writer, "exif=", writer_exif_set, 1);
294
+ rb_define_method(writer, "remove_exif", writer_remove_exif, 0);
295
+ rb_define_method(writer, "icc=", writer_icc_set, 1);
296
+ rb_define_method(writer, "remove_icc", writer_remove_icc, 0);
297
+ rb_define_private_method(writer, "write_internal", writer_write_internal, 1);
298
+
299
+ /*
300
+ * Write JPEG images.
301
+ */
302
+
303
+ VALUE jpeg_writer = rb_define_class_under(mVIPS, "JPEGWriter", writer);
304
+ rb_define_private_method(jpeg_writer, "buf_internal", jpeg_buf_internal, 1);
305
+ rb_define_private_method(jpeg_writer, "write_internal", jpeg_write_internal, 1);
306
+
307
+ /*
308
+ * Write TIFF images.
309
+ */
310
+
311
+ VALUE tiff_writer = rb_define_class_under(mVIPS, "TIFFWriter", writer);
312
+ rb_define_private_method(tiff_writer, "write_internal", tiff_write_internal, 1);
313
+
314
+ /*
315
+ * Write PPM images.
316
+ */
317
+
318
+ VALUE ppm_writer = rb_define_class_under(mVIPS, "PPMWriter", writer);
319
+ rb_define_private_method(ppm_writer, "write_internal", ppm_write_internal, 1);
320
+
321
+ /*
322
+ * Write PNG images.
323
+ */
324
+
325
+ VALUE png_writer = rb_define_class_under(mVIPS, "PNGWriter", writer);
326
+ rb_define_private_method(png_writer, "write_internal", png_write_internal, 1);
327
+ rb_define_private_method(png_writer, "buf_internal", png_buf_internal, 2);
328
+
329
+ /*
330
+ * Write CSV images.
331
+ */
332
+
333
+ VALUE csv_writer = rb_define_class_under(mVIPS, "CSVWriter", writer);
334
+ rb_define_private_method(csv_writer, "write_internal", csv_write_internal, 1);
335
+
336
+ /*
337
+ * Write native VIPS images.
338
+ */
339
+
340
+ VALUE vips_writer = rb_define_class_under(mVIPS, "VIPSWriter", writer);
341
+ rb_define_private_method(vips_writer, "write_internal", vips_write_internal, 1);
342
+
343
+ #if 0
344
+ VALUE mVIPS = rb_define_module("VIPS");
345
+ #endif
346
+ }
data/lib/vips.rb ADDED
@@ -0,0 +1,7 @@
1
+ # Vips will print warnings to stdout unless this is set
2
+ ENV['IM_WARNING'] = "0"
3
+
4
+ require 'vips_ext'
5
+ require 'vips/version'
6
+ require 'vips/reader'
7
+ require 'vips/writer'
@@ -0,0 +1,183 @@
1
+ module VIPS
2
+ class Reader
3
+ attr_reader :path
4
+
5
+ def initialize(path, options={})
6
+ @path = path
7
+ read_header path unless options[:skip_header]
8
+ end
9
+
10
+ def self.read(path, options={})
11
+ options[:skip_header] = true
12
+ reader = new path, options
13
+ reader.read
14
+ end
15
+
16
+ def read
17
+ read_internal @path
18
+ end
19
+ end
20
+
21
+ class CSVReader < Reader
22
+ attr_reader :line_skip, :line_limit
23
+ attr_accessor :whitespace, :separator
24
+
25
+ # Creates a CSV reader.
26
+ def initialize(path, options={})
27
+ @line_skip = 0
28
+ @whitespace = ' "'
29
+ @separator = ";,\t"
30
+ @line_limit = 0
31
+
32
+ self.line_skip = options[:line_skip] if options.has_key?(:line_skip)
33
+ self.whitespace = options[:whitespace] if options.has_key?(:whitespace)
34
+ self.separator = options[:separator] if options.has_key?(:separator)
35
+ self.line_limit = options[:line_limit] if options.has_key?(:line_limit)
36
+
37
+ super path, options
38
+ end
39
+
40
+ # Read the CSV file and return a VIPS Image object.
41
+ def read
42
+ str = "#{@path}:ski:#{@line_skip},whi:#{@whitespace}"
43
+ str << ",lin:#{@line_limit == 0 ? -1 : @line_limit}"
44
+
45
+ # VIPS magic open path limitation/bug -- we cannot specify the comma char
46
+ str << ",sep:#{@separator}" unless @separator[/,/]
47
+ read_internal str
48
+ end
49
+
50
+ # Set the number of lines to skip at the beginning of the file.
51
+ def line_skip=(line_skip_v)
52
+ if line_skip_v < 0
53
+ raise ArgumentError, "Line skip must be 0 or more."
54
+ end
55
+
56
+ @line_skip = line_skip_v
57
+ end
58
+
59
+ # Set a limit of how many lines to read in.
60
+ def line_limit=(line_limit_v)
61
+ if line_limit_v < 0
62
+ raise ArgumentError, "Line limit must be 0 (read all) or more."
63
+ end
64
+
65
+ @line_limit = line_limit_v
66
+ end
67
+ end
68
+
69
+ class JPEGReader < Reader
70
+ attr_reader :shrink_factor
71
+ attr_accessor :fail_on_warn
72
+
73
+ SHRINK_FACTOR = [1, 2, 4, 8]
74
+
75
+ # Creates a jpeg image file reader.
76
+ def initialize(path, options={})
77
+ @shrink_factor = 1
78
+ @fail_on_warn = false
79
+
80
+ self.shrink_factor = options[:shrink_factor] if options.has_key?(:shrink_factor)
81
+ self.fail_on_warn = options[:fail_on_warn] if options.has_key?(:fail_on_warn)
82
+
83
+ super path, options
84
+ end
85
+
86
+ # Read the jpeg file from disk and return a VIPS Image object.
87
+ def read
88
+ str = "#{@path}:#{shrink_factor}"
89
+ str << ",fail" if @fail_on_warn
90
+
91
+ read_internal str
92
+ end
93
+
94
+ # Shrink the jpeg while reading from disk. This means that the entire image
95
+ # never has to be loaded in memory. Shrink factor can be 1 (no shrink), 2,
96
+ # 4, or 8.
97
+ def shrink_factor=(shrink_factor_v)
98
+ unless SHRINK_FACTOR.include?(shrink_factor_v)
99
+ raise ArgumentError, "Shrink factor must be one of: #{SHRINK_FACTOR.join ', '}."
100
+ end
101
+
102
+ @shrink_factor = shrink_factor_v
103
+ end
104
+ end
105
+
106
+ class TIFFReader < Reader
107
+ attr_reader :page_number
108
+
109
+ # Create a tiff image file reader.
110
+ def initialize(path, options={})
111
+ self.page_number = options[:page_number] if options.has_key?(:page_number)
112
+ super path, options
113
+ end
114
+
115
+ # Read the tiff file from disk and return a VIPS Image object.
116
+ def read
117
+ str = @path
118
+ str << ":#{@page_number}" if @page_number
119
+
120
+ read_internal str
121
+ end
122
+
123
+ # Select which page in a multiple-page tiff to read. When set to nil, all
124
+ # pages are read as a single image.
125
+ def page_number=(page_number_v)
126
+ unless page_number_v.nil? || page_number_v > 0
127
+ raise ArgumentError, "Page number has to be nil or larger than zero."
128
+ end
129
+
130
+ @page_number = page_number_v
131
+ end
132
+ end
133
+
134
+ class Image
135
+
136
+ # Load a ppm file straight to a VIPS Image.
137
+ def self.ppm(*args)
138
+ PPMReader.read *args
139
+ end
140
+
141
+ # Load an exr file straight to a VIPS Image.
142
+ def self.exr(*args)
143
+ EXRReader.read *args
144
+ end
145
+
146
+ # Load a csv file straight to a VIPS Image.
147
+ def self.csv(*args)
148
+ CSVReader.read *args
149
+ end
150
+
151
+ # Load a jpeg file straight to a VIPS Image.
152
+ def self.jpeg(*args)
153
+ JPEGReader.read *args
154
+ end
155
+
156
+ # Load a file straight to a VIPS Image using the magick library.
157
+ def self.magick(*args)
158
+ MagickReader.read *args
159
+ end
160
+
161
+ # Load a png file straight to a VIPS Image.
162
+ def self.png(*args)
163
+ PNGReader.read *args
164
+ end
165
+
166
+ # Load a tiff file straight to a VIPS Image.
167
+ def self.tiff(*args)
168
+ TIFFReader.read *args
169
+ end
170
+
171
+ # Load a native vips file straight to a VIPS Image.
172
+ def self.vips(*args)
173
+ VIPSReader.read *args
174
+ end
175
+
176
+ # Load any file straight to a VIPS Image. VIPS will determine the format
177
+ # based on the file extension. If the extension is not recognized, VIPS
178
+ # will look at the file signature.
179
+ def self.new(*args)
180
+ Reader.read *args
181
+ end
182
+ end
183
+ end