image-file 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.autotest ADDED
@@ -0,0 +1,16 @@
1
+ require 'autotest/restart'
2
+
3
+ Autotest.add_hook :initialize do |at|
4
+ at.unit_diff = 'cat'
5
+ end
6
+
7
+ Autotest.add_hook :ran_command do |at|
8
+ log_file = File.expand_path('../tmp/autotest.log', __FILE__)
9
+ File.open(log_file, 'wb') {|f|
10
+ content = at.results.join
11
+ content.gsub!(/\x1B\[(\d+)m/, '')
12
+ f.write(content)
13
+ }
14
+ end
15
+
16
+ # vim: filetype=ruby
data/.document ADDED
@@ -0,0 +1,3 @@
1
+ README.markdown
2
+ License.txt
3
+ History.markdown
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ *~
2
+ Gemfile.lock
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --format documentation
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gem 'rake'
4
+ gem 'rake-compiler'
5
+ gem 'pkg-config'
6
+
7
+ group :test do
8
+ gem 'rspec', '2.3.0'
9
+ gem 'cairo'
10
+ end
data/History.markdown ADDED
@@ -0,0 +1,13 @@
1
+ image-file release history
2
+ ==========================
3
+
4
+ 0.1.0 / 2010-12-16
5
+ ------------------
6
+
7
+ * The first release
8
+ * Features
9
+ * support reading JPEG files of RGB color space.
10
+ * support creating Cairo::Surface from ImageFile::Image.
11
+
12
+ * Known Bugs
13
+ * reading JPEG files of CMYK color space is broken.
data/License.txt ADDED
@@ -0,0 +1,23 @@
1
+ (The MIT License)
2
+
3
+ Copyright (c) 2010 Kenta Murata
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 NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+
data/README.markdown ADDED
@@ -0,0 +1,4 @@
1
+ ImageFile
2
+ =========
3
+
4
+ A library for handling image files on Ruby.
data/Rakefile ADDED
@@ -0,0 +1,14 @@
1
+ require 'bundler'
2
+ Bundler.setup
3
+ Bundler::GemHelper.install_tasks
4
+
5
+ require 'rake/extensiontask'
6
+ Rake::ExtensionTask.new('image_file')
7
+
8
+ require 'rspec/core/rake_task'
9
+
10
+ desc "Run all examples"
11
+ RSpec::Core::RakeTask.new(:spec)
12
+
13
+ task :default => [:spec]
14
+ task :spec => [:compile]
@@ -0,0 +1 @@
1
+ Autotest.add_discovery { "rspec2" }
data/examples/pdf.rb ADDED
@@ -0,0 +1,15 @@
1
+ require 'image_file'
2
+ require 'cairo'
3
+
4
+ image = ImageFile::JpegReader.open(ARGV[0]).read_image
5
+
6
+ image_surface = image.create_cairo_surface
7
+
8
+ pdf = Cairo::PDFSurface.new(ARGV[1], image.width, image.height)
9
+ context = Cairo::Context.new(pdf)
10
+
11
+ context.set_source image_surface
12
+ context.paint
13
+ context.show_page
14
+
15
+ pdf.finish
@@ -0,0 +1,7 @@
1
+ image_file_common_deps = internal.h $(hdrdir)/ruby.h
2
+
3
+ image_file.o: image_file.c $(image_file_common_deps)
4
+
5
+ image.o: image.c $(image_file_common_deps)
6
+
7
+ jpeg_reader.o: jpeg_reader.c $(image_file_common_deps)
@@ -0,0 +1,25 @@
1
+ require 'mkmf'
2
+ require 'rubygems'
3
+ require 'pkg-config'
4
+
5
+ ver = RUBY_VERSION.split(/\./).join.to_i
6
+ $defs << "-DRUBY_VERSION=#{ver}"
7
+
8
+ $CFLAGS << ' -Wall -Wextra -Wshadow'
9
+
10
+ dir_config('jpeg')
11
+ have_header('jpeglib.h')
12
+ have_library('jpeg')
13
+
14
+ if PKGConfig.have_package('cairo', 1, 2, 0)
15
+ unless have_header('rb_cairo.h')
16
+ if cairo = Gem.searcher.find('cairo')
17
+ extconf_rb = File.expand_path(cairo.extensions[0], cairo.full_gem_path)
18
+ rb_cairo_h = File.expand_path('../rb_cairo.h', extconf_rb)
19
+ $CFLAGS << " -I#{File.dirname(rb_cairo_h)}"
20
+ have_header('rb_cairo.h')
21
+ end
22
+ end
23
+ end
24
+
25
+ create_makefile('image_file')
@@ -0,0 +1,411 @@
1
+ #include "internal.h"
2
+
3
+ #ifdef HAVE_RB_CAIRO_H
4
+ # include <rb_cairo.h>
5
+ #endif
6
+
7
+ VALUE cImageFileImage = Qnil;
8
+
9
+ static ID id_ARGB32;
10
+ static ID id_RGB24;
11
+ static ID id_RGB16_565;
12
+
13
+ struct image_data {
14
+ VALUE buffer;
15
+ rb_image_file_image_pixel_format_t pixel_format;
16
+ long width;
17
+ long height;
18
+ long stride;
19
+ };
20
+
21
+ static void
22
+ image_mark(void* ptr)
23
+ {
24
+ struct image_data* image = (struct image_data*)ptr;
25
+ rb_gc_mark(image->buffer);
26
+ }
27
+
28
+ static void
29
+ image_free(void* ptr)
30
+ {
31
+ struct image_data* image = (struct image_data*)ptr;
32
+ image->buffer = Qnil;
33
+ xfree(image);
34
+ }
35
+
36
+ static size_t
37
+ image_memsize(void const* ptr)
38
+ {
39
+ return ptr ? sizeof(struct image_data) : 0;
40
+ }
41
+
42
+ static rb_data_type_t const image_data_type = {
43
+ "image_file::image",
44
+ #if RUBY_VERSION >= 193
45
+ {
46
+ #endif
47
+ image_mark,
48
+ image_free,
49
+ image_memsize,
50
+ #if RUBY_VERSION >= 193
51
+ },
52
+ #endif
53
+ };
54
+
55
+ static VALUE
56
+ image_alloc(VALUE const klass)
57
+ {
58
+ struct image_data* image;
59
+ VALUE obj = TypedData_Make_Struct(klass, struct image_data, &image_data_type, image);
60
+ image->buffer = Qnil;
61
+ image->pixel_format = RB_IMAGE_FILE_IMAGE_PIXEL_FORMAT_INVALID;
62
+ image->width = 0;
63
+ image->height = 0;
64
+ image->stride = 0;
65
+ return obj;
66
+ }
67
+
68
+ static inline struct image_data*
69
+ get_image_data(VALUE const obj)
70
+ {
71
+ struct image_data* image;
72
+ TypedData_Get_Struct(obj, struct image_data, &image_data_type, image);
73
+ return image;
74
+ }
75
+
76
+ #ifdef HAVE_RB_CAIRO_H
77
+ static cairo_format_t
78
+ pixel_format_to_cairo_format(rb_image_file_image_pixel_format_t const pf)
79
+ {
80
+ switch (pf) {
81
+ case RB_IMAGE_FILE_IMAGE_PIXEL_FORMAT_INVALID:
82
+ break;
83
+
84
+ case RB_IMAGE_FILE_IMAGE_PIXEL_FORMAT_ARGB32:
85
+ return CAIRO_FORMAT_ARGB32;
86
+
87
+ case RB_IMAGE_FILE_IMAGE_PIXEL_FORMAT_RGB24:
88
+ return CAIRO_FORMAT_RGB24;
89
+
90
+ case RB_IMAGE_FILE_IMAGE_PIXEL_FORMAT_RGB16_565:
91
+ return CAIRO_FORMAT_RGB16_565;
92
+
93
+ default:
94
+ break;
95
+ }
96
+ rb_bug("unknown pixel format (%d)", pf);
97
+ return -1;
98
+ }
99
+ #endif /* HAVE_RB_CAIRO_H */
100
+
101
+ static inline int
102
+ pixel_format_size(rb_image_file_image_pixel_format_t const pf)
103
+ {
104
+ switch (pf) {
105
+ case RB_IMAGE_FILE_IMAGE_PIXEL_FORMAT_INVALID:
106
+ return -1;
107
+
108
+ case RB_IMAGE_FILE_IMAGE_PIXEL_FORMAT_ARGB32:
109
+ case RB_IMAGE_FILE_IMAGE_PIXEL_FORMAT_RGB24:
110
+ return 4;
111
+
112
+ case RB_IMAGE_FILE_IMAGE_PIXEL_FORMAT_RGB16_565:
113
+ return 2;
114
+
115
+ default:
116
+ break;
117
+ }
118
+ assert(0); /* MUST NOT REACH HERE */
119
+ return -1;
120
+ }
121
+
122
+ static long
123
+ minimum_buffer_size(rb_image_file_image_pixel_format_t const pf, long const st, long const ht)
124
+ {
125
+ long len = st * ht;
126
+
127
+ assert(st > 0);
128
+ assert(ht > 0);
129
+
130
+ switch (pf) {
131
+ case RB_IMAGE_FILE_IMAGE_PIXEL_FORMAT_INVALID:
132
+ return -1;
133
+
134
+ case RB_IMAGE_FILE_IMAGE_PIXEL_FORMAT_ARGB32:
135
+ return len * 4;
136
+
137
+ case RB_IMAGE_FILE_IMAGE_PIXEL_FORMAT_RGB24:
138
+ return len * 4;
139
+
140
+ case RB_IMAGE_FILE_IMAGE_PIXEL_FORMAT_RGB16_565:
141
+ return len * 2;
142
+
143
+ default:
144
+ break;
145
+ }
146
+ assert(0); /* MUST NOT REACH HERE */
147
+ return -1;
148
+ }
149
+
150
+ VALUE
151
+ rb_image_file_image_pixel_format_to_symbol(rb_image_file_image_pixel_format_t const pf)
152
+ {
153
+ switch (pf) {
154
+ case RB_IMAGE_FILE_IMAGE_PIXEL_FORMAT_INVALID:
155
+ return Qnil;
156
+
157
+ case RB_IMAGE_FILE_IMAGE_PIXEL_FORMAT_ARGB32:
158
+ return ID2SYM(id_ARGB32);
159
+
160
+ case RB_IMAGE_FILE_IMAGE_PIXEL_FORMAT_RGB24:
161
+ return ID2SYM(id_RGB24);
162
+
163
+ case RB_IMAGE_FILE_IMAGE_PIXEL_FORMAT_RGB16_565:
164
+ return ID2SYM(id_RGB16_565);
165
+
166
+ default:
167
+ break;
168
+ }
169
+ assert(0); /* MUST NOT REACH HERE */
170
+ return Qnil;
171
+ }
172
+
173
+ static inline rb_image_file_image_pixel_format_t
174
+ id_to_pixel_format(ID const id)
175
+ {
176
+ if (id == id_ARGB32)
177
+ return RB_IMAGE_FILE_IMAGE_PIXEL_FORMAT_ARGB32;
178
+
179
+ if (id == id_RGB24)
180
+ return RB_IMAGE_FILE_IMAGE_PIXEL_FORMAT_RGB24;
181
+
182
+ if (id == id_RGB16_565)
183
+ return RB_IMAGE_FILE_IMAGE_PIXEL_FORMAT_RGB16_565;
184
+
185
+ return RB_IMAGE_FILE_IMAGE_PIXEL_FORMAT_INVALID;
186
+ }
187
+
188
+ rb_image_file_image_pixel_format_t
189
+ rb_image_file_image_symbol_to_pixel_format(VALUE symbol)
190
+ {
191
+ Check_Type(symbol, T_SYMBOL);
192
+ return id_to_pixel_format(SYM2ID(symbol));
193
+ }
194
+
195
+ static rb_image_file_image_pixel_format_t
196
+ check_pixel_format(VALUE const pixel_format)
197
+ {
198
+ rb_image_file_image_pixel_format_t pf;
199
+
200
+ Check_Type(pixel_format, T_SYMBOL);
201
+ pf = id_to_pixel_format(SYM2ID(pixel_format));
202
+ if (RB_IMAGE_FILE_IMAGE_PIXEL_FORMAT_INVALID == pf)
203
+ rb_raise(rb_eArgError, "unknown pixel format");
204
+
205
+ return pf;
206
+ }
207
+
208
+ static void
209
+ process_arguments_of_image_initialize(int const argc, VALUE* const argv,
210
+ VALUE* buffer_ptr,
211
+ rb_image_file_image_pixel_format_t* pixel_format_ptr,
212
+ long* width_ptr,
213
+ long* height_ptr,
214
+ long* stride_ptr
215
+ )
216
+ {
217
+ VALUE params;
218
+ VALUE buffer = Qnil;
219
+ VALUE pixel_format = Qnil;
220
+ VALUE width = Qnil;
221
+ VALUE height = Qnil;
222
+ VALUE stride = Qnil;
223
+
224
+ rb_image_file_image_pixel_format_t pf;
225
+ long wd, ht, st;
226
+ long min_len;
227
+
228
+ ID id_pixel_format, id_data, id_width, id_height, id_row_stride;
229
+ CONST_ID(id_data, "data");
230
+ CONST_ID(id_pixel_format, "pixel_format");
231
+ CONST_ID(id_width, "width");
232
+ CONST_ID(id_height, "height");
233
+ CONST_ID(id_row_stride, "row_stride");
234
+
235
+ rb_scan_args(argc, argv, "01", &params);
236
+ if (TYPE(params) == T_HASH) {
237
+ buffer = rb_hash_lookup(params, ID2SYM(id_data));
238
+ pixel_format = rb_hash_lookup(params, ID2SYM(id_pixel_format));
239
+ width = rb_hash_lookup(params, ID2SYM(id_width));
240
+ height = rb_hash_lookup(params, ID2SYM(id_height));
241
+ stride = rb_hash_lookup(params, ID2SYM(id_row_stride));
242
+ }
243
+
244
+ if (!NIL_P(buffer)) {
245
+ Check_Type(buffer, T_STRING);
246
+ buffer = rb_str_dup(buffer);
247
+ }
248
+
249
+ if (NIL_P(pixel_format))
250
+ rb_raise(rb_eArgError, "missing image pixel format");
251
+ if (TYPE(pixel_format) == T_STRING)
252
+ pixel_format = rb_str_intern(pixel_format);
253
+ pf = check_pixel_format(pixel_format);
254
+
255
+ if (NIL_P(width))
256
+ rb_raise(rb_eArgError, "missing image width");
257
+ wd = NUM2LONG(width);
258
+ if (wd <= 0)
259
+ rb_raise(rb_eArgError, "zero or negative image width");
260
+
261
+ if (NIL_P(height))
262
+ rb_raise(rb_eArgError, "missing image height");
263
+ ht = NUM2LONG(height);
264
+ if (ht <= 0)
265
+ rb_raise(rb_eArgError, "zero or negative image height");
266
+
267
+ if (NIL_P(stride)) {
268
+ #ifdef HAVE_RB_CAIRO_H
269
+ st = cairo_format_stride_for_width(pixel_format_to_cairo_format(pf), (int)wd) / pixel_format_size(pf);
270
+ stride = INT2NUM(st);
271
+ #else
272
+ stride = width;
273
+ #endif
274
+ }
275
+ st = NUM2LONG(stride);
276
+ if (st <= 0)
277
+ rb_raise(rb_eArgError, "zero or negative image row-stride");
278
+ else if (st < wd) {
279
+ rb_warning("the given row-stride is less than the given image width.");
280
+ st = wd;
281
+ }
282
+
283
+ min_len = minimum_buffer_size(pf, st, ht);
284
+ if (NIL_P(buffer)) {
285
+ buffer = rb_str_new(NULL, min_len);
286
+ }
287
+ else if (RSTRING_LEN(buffer) < min_len) {
288
+ void rb_str_modify_expand(VALUE, long);
289
+ rb_warning("the size of the given data is too short for the given size of image");
290
+ rb_str_modify_expand(buffer, min_len - RSTRING_LEN(buffer));
291
+ }
292
+
293
+ *buffer_ptr = buffer;
294
+ *pixel_format_ptr = pf;
295
+ *width_ptr = wd;
296
+ *height_ptr = ht;
297
+ *stride_ptr = st;
298
+ }
299
+
300
+ static VALUE
301
+ image_initialize(int argc, VALUE* argv, VALUE obj)
302
+ {
303
+ struct image_data* image;
304
+ VALUE buffer;
305
+ rb_image_file_image_pixel_format_t pf;
306
+ long wd, ht, st;
307
+
308
+ process_arguments_of_image_initialize(argc, argv, &buffer, &pf, &wd, &ht, &st);
309
+ assert(!NIL_P(buffer));
310
+ assert(pf != RB_IMAGE_FILE_IMAGE_PIXEL_FORMAT_INVALID);
311
+ assert(wd > 0);
312
+ assert(ht > 0);
313
+ assert(st >= wd);
314
+
315
+ image = get_image_data(obj);
316
+ image->buffer = buffer;
317
+ image->pixel_format = pf;
318
+ image->width = wd;
319
+ image->height = ht;
320
+ image->stride = st;
321
+
322
+ return obj;
323
+ }
324
+
325
+ VALUE
326
+ rb_image_file_image_get_buffer(VALUE obj)
327
+ {
328
+ struct image_data* image = get_image_data(obj);
329
+ return image->buffer;
330
+ }
331
+
332
+ static VALUE
333
+ image_get_pixel_format(VALUE obj)
334
+ {
335
+ struct image_data* image = get_image_data(obj);
336
+ return rb_image_file_image_pixel_format_to_symbol(image->pixel_format);
337
+ }
338
+
339
+ static VALUE
340
+ image_get_width(VALUE obj)
341
+ {
342
+ struct image_data* image = get_image_data(obj);
343
+ return LONG2NUM(image->width);
344
+ }
345
+
346
+ static VALUE
347
+ image_get_height(VALUE obj)
348
+ {
349
+ struct image_data* image = get_image_data(obj);
350
+ return LONG2NUM(image->height);
351
+ }
352
+
353
+ static VALUE
354
+ image_get_row_stride(VALUE obj)
355
+ {
356
+ struct image_data* image = get_image_data(obj);
357
+ return LONG2NUM(image->stride);
358
+ }
359
+
360
+
361
+ #ifdef HAVE_RB_CAIRO_H
362
+ static cairo_user_data_key_t const cairo_data_key = {};
363
+
364
+ static void
365
+ image_surface_did_destroyed(void* data)
366
+ {
367
+ xfree(data);
368
+ }
369
+
370
+ static VALUE
371
+ image_create_cairo_surface(VALUE obj)
372
+ {
373
+ cairo_surface_t* cairo_surface;
374
+ cairo_format_t cairo_format;
375
+ unsigned char* data;
376
+ VALUE surface;
377
+ struct image_data* image = get_image_data(obj);
378
+
379
+ data = xmalloc(sizeof(unsigned char)*RSTRING_LEN(image->buffer));
380
+ MEMCPY(data, RSTRING_PTR(image->buffer), unsigned char, RSTRING_LEN(image->buffer));
381
+
382
+ cairo_format = pixel_format_to_cairo_format(image->pixel_format);
383
+ cairo_surface = cairo_image_surface_create_for_data(
384
+ data, cairo_format, (int)image->width, (int)image->height,
385
+ (int)image->stride*pixel_format_size(image->pixel_format));
386
+ cairo_surface_set_user_data(cairo_surface, &cairo_data_key, data, image_surface_did_destroyed);
387
+ surface = CRSURFACE2RVAL_WITH_DESTROY(cairo_surface);
388
+ return surface;
389
+ }
390
+ #endif
391
+
392
+ void
393
+ rb_image_file_Init_image_file_image(void)
394
+ {
395
+ cImageFileImage = rb_define_class_under(mImageFile, "Image", rb_cObject);
396
+ rb_define_alloc_func(cImageFileImage, image_alloc);
397
+ rb_define_method(cImageFileImage, "initialize", image_initialize, -1);
398
+
399
+ rb_define_method(cImageFileImage, "pixel_format", image_get_pixel_format, 0);
400
+ rb_define_method(cImageFileImage, "width", image_get_width, 0);
401
+ rb_define_method(cImageFileImage, "height", image_get_height, 0);
402
+ rb_define_method(cImageFileImage, "row_stride", image_get_row_stride, 0);
403
+
404
+ #ifdef HAVE_RB_CAIRO_H
405
+ rb_define_method(cImageFileImage, "create_cairo_surface", image_create_cairo_surface, 0);
406
+ #endif
407
+
408
+ CONST_ID(id_ARGB32, "ARGB32");
409
+ CONST_ID(id_RGB24, "RGB24");
410
+ CONST_ID(id_RGB16_565, "RGB16_565");
411
+ }