image-file 0.1.0

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/.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
+ }