ruby-vips 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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