axon 0.1.1 → 0.2.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.
@@ -1,3 +1,9 @@
1
+ === 0.2.0 / 2012-??-??
2
+
3
+ * JRuby Support
4
+ * Add Axon.jpeg_file, Axon.png_file, Axon#jpeg_file, and Axon#png_file
5
+ * Removed #color_model since we can use #components.
6
+
1
7
  === 0.1.1 / 2012-01-06
2
8
 
3
9
  * Add a .gemtest file. Trying rubygems-test.
@@ -4,12 +4,8 @@ http://github.com/ender672/axon
4
4
 
5
5
  == DESCRIPTION:
6
6
 
7
- axon reads, manipulates, and writes images.
8
-
9
- axon depends only on libjpeg and libpng.
10
-
11
- axon never stores an entire image in memory. All images and operations are
12
- streamed. This keeps memory requirements and latency low.
7
+ Read, manipulate, and write images with an emphasis on speed and a low memory
8
+ profile.
13
9
 
14
10
  == FEATURES:
15
11
 
@@ -20,60 +16,38 @@ streamed. This keeps memory requirements and latency low.
20
16
 
21
17
  == SYNOPSIS:
22
18
 
23
- # Short, chained example. Reads a JPEG from io_in and writes scaled png to
24
- # io_out.
25
- Axon.jpeg(io_in).fit(100, 100).png(io_out)
26
-
27
- # Longer example, reads the JPEG header, looks at properties and header
28
- # values, sets decompression options, scales the image, sets compression
29
- # options, and writes a JPEG.
30
- reader = Axon::JPEG::Reader(io, [:APP2])
31
-
32
- puts reader.width #=> Integer
33
- puts reader.height #=> Integer
34
- puts reader[:APP2] #=> Array of Strings
35
- reader.scale_denom = 4 # Image will be scaled by 1/4 on read
36
-
37
- fitted = Axon::Fit.new(reader, 100, 100) # Fits image in a 100x100 box
38
- JPEG.write(fitted, io, :quality => 88)
39
-
40
- == BASIC API:
41
-
42
- All image objects are expected to respond to the following methods:
43
-
44
- * Image#height
45
- Output height of the image.
46
- * Image#width
47
- Output width of the image.
48
- * Image#color_model
49
- Can be :GRAYSCALE or :RGB
50
- * Image#components
51
- RGB image with alpha has 4 components.
52
- RGB image has 3 components.
53
- Grayscale image with alpha has 2 components.
54
- Grayscale image has 1 component.
55
- * Image#gets
56
- Returns the next line in the image as a binary ruby string.
57
- * Image#lineno
58
- The line number of the next line that will be returned, starting at 0.
59
-
60
- A Reader object has the same methods as an Image object, with added methods that
61
- are specific to the decoding of the image format.
19
+ # Read a JPEG and write it as a scaled PNG.
20
+ Axon.jpeg_file("image.jpg") do |image|
21
+ image.fit(100, 100)
22
+ image.png_file("image.png")
23
+ end
62
24
 
63
25
  == REQUIREMENTS:
64
26
 
65
- IJG JPEG Library Version 6b or later.
66
- pnglib version 1.2.x or later.
27
+ The JRuby extension uses the Java Image I/O API.
28
+
29
+ The MRI/Rubinius extension uses:
30
+
31
+ * IJG JPEG Library Version 6b or later.
32
+ * pnglib version 1.2.x or later.
33
+
34
+ Installing libjpeg headers (OSX):
35
+
36
+ $ brew install libjpeg # requires homebrew (http://mxcl.github.com/homebrew/)
37
+
38
+ Installing libjpeg and libpng headers (Debian/Ubuntu):
39
+
40
+ $ sudo apt-get install libjpeg-dev libpng-dev
67
41
 
68
42
  == INSTALL:
69
43
 
70
- gem install axon
44
+ $ gem install axon
71
45
 
72
46
  == LICENSE:
73
47
 
74
48
  (The MIT License)
75
49
 
76
- Copyright (c) 2011
50
+ Copyright (c) 2012
77
51
 
78
52
  * {Timothy Elliott}[http://holymonkey.com]
79
53
 
data/Rakefile CHANGED
@@ -1,21 +1,36 @@
1
1
  require 'rake/clean'
2
2
  require 'rake/testtask'
3
3
 
4
+ # Java compiling
5
+ def quote_file_list(l)
6
+ list = FileList.new(l)
7
+ (list.to_a.map { |f| "'#{f}'" }).join(' ')
8
+ end
9
+
10
+ file 'lib/axon/axon.jar' => FileList.new('ext/java/axon/*.java') do
11
+ cd 'ext/java' do
12
+ sh "javac -g -cp #{Config::CONFIG['prefix']}/lib/jruby.jar #{FileList['axon/*.java']}"
13
+ sh "jar cf axon/axon.jar #{quote_file_list('axon/*.class')}"
14
+ end
15
+
16
+ FileUtils.mv 'ext/java/axon/axon.jar', 'lib/axon/axon.jar'
17
+ end
18
+
19
+ # gcc compiling
4
20
  file 'ext/axon/Makefile' do
5
21
  cd 'ext/axon' do
6
22
  ruby "extconf.rb #{ENV['EXTOPTS']}"
7
23
  end
8
24
  end
9
25
 
10
- file 'ext/axon/axon.so' => FileList.new('ext/axon/Makefile', 'ext/axon/*{.c,.h}') do
26
+ file 'lib/axon/axon.so' => FileList.new('ext/axon/Makefile', 'ext/axon/*{.c,.h}') do
11
27
  cd 'ext/axon' do
12
28
  sh 'make'
13
29
  end
30
+
31
+ FileUtils.mv 'ext/axon/axon.so', 'lib/axon/axon.so'
14
32
  end
15
33
 
16
- CLEAN.add('ext/axon/*{.o,.so,.log}', 'ext/axon/Makefile')
17
- CLOBBER.add('*.gem')
18
-
19
34
  desc 'Clean up Rubinius .rbc files.'
20
35
  namespace :clean do
21
36
  task :rbc do
@@ -24,12 +39,23 @@ namespace :clean do
24
39
  end
25
40
 
26
41
  Rake::TestTask.new do |t|
27
- t.libs += ['test', 'ext']
42
+ t.libs << 'test'
28
43
  t.test_files = FileList['test/test*.rb']
29
44
  t.verbose = true
30
45
  end
31
46
 
32
- desc 'Compile axon'
33
- task :compile => 'ext/axon/axon.so'
47
+ CLEAN.add('ext/axon/*{.o,.so,.log}', 'ext/axon/Makefile')
48
+ CLEAN.add('ext/java/axon/*.class', 'ext/java/axon/axon.jar')
49
+ CLEAN.add('lib/axon/axon{.so,.jar}')
50
+ CLOBBER.add('*.gem')
51
+
52
+ desc 'Build the gem'
53
+ task :gem => "lib/axon/axon.jar" do
54
+ system "gem build axon.gemspec"
55
+ end
56
+
57
+ desc 'Compile the extension'
58
+ task :compile => "lib/axon/axon.#{RUBY_PLATFORM =~ /java/ ? 'jar' : 'so'}"
59
+
34
60
  task :test => :compile
35
61
  task :default => :test
data/TODO.rdoc CHANGED
@@ -1,5 +1,10 @@
1
1
  = TODO
2
- * get everything running on osx and windows
2
+ * get everything running on windows
3
+ * get all tests passing on jruby
4
+ * for jruby, consider adding kind of a back-door method, e.g.
5
+ gets_as_jruby_bufferedimage that allows internal calls to pass scanlines
6
+ along natively. Something similar might slightly speed up the C extension
7
+ as well by eliminating some memory copies.
3
8
  * have a setting where decode / encode warnings will result in exceptions
4
9
  * add #initialize_copy
5
10
  * Check frozen status on setters, etc.
@@ -19,7 +19,7 @@
19
19
  #define EXIF_MARKER (JPEG_APP0 + 1)
20
20
 
21
21
  #define WRITE_BUFSIZE 1024
22
- #define READ_SIZE 2048
22
+ #define READ_SIZE 1024
23
23
 
24
24
  static ID id_ISLOW, id_IFAST, id_FLOAT, id_DEFAULT, id_FASTEST;
25
25
  static ID id_GRAYSCALE, id_RGB, id_YCbCr, id_CMYK, id_YCCK, id_UNKNOWN;
@@ -45,7 +45,7 @@ struct readerdata {
45
45
  struct jpeg_source_mgr mgr;
46
46
 
47
47
  int header_read;
48
- int locked;
48
+ int decompress_started;
49
49
 
50
50
  VALUE source_io;
51
51
  VALUE buffer;
@@ -156,10 +156,6 @@ empty_output_buffer(j_compress_ptr cinfo)
156
156
  str = rb_str_new(dest->buffer, dest->alloc);
157
157
 
158
158
  write_len = rb_funcall(dest->io, id_write, 1, str);
159
- /* in 1.8.7, NUM2INT gives funny numbers for Symbols */
160
- if (SYMBOL_P(write_len))
161
- rb_raise(rb_eTypeError, "write returned a symbol.");
162
-
163
159
  write_len_i = (size_t)NUM2INT(write_len);
164
160
  dest->total += write_len_i;
165
161
  if (write_len_i != dest->alloc)
@@ -181,9 +177,6 @@ term_destination(j_compress_ptr cinfo)
181
177
  if (len > 0) {
182
178
  str = rb_str_new(dest->buffer, len);
183
179
  write_len = rb_funcall(dest->io, id_write, 1, str);
184
- /* in 1.8.7, NUM2INT gives funny numbers for Symbols */
185
- if (SYMBOL_P(write_len))
186
- rb_raise(rb_eTypeError, "write returned a symbol.");
187
180
  write_len_i = (size_t)NUM2INT(write_len);
188
181
  dest->total += write_len_i;
189
182
  if (write_len_i != len)
@@ -238,41 +231,32 @@ write_exif(j_compress_ptr cinfo, char *str, int len)
238
231
  static void
239
232
  write_configure(j_compress_ptr cinfo, VALUE image_in, VALUE quality)
240
233
  {
241
- VALUE color_model, width, components, rb_height;
234
+ VALUE width, components, rb_height;
242
235
  int height;
243
236
 
244
237
  width = rb_funcall(image_in, id_width, 0);
245
- /* in 1.8.7, NUM2INT gives funny numbers for Symbols */
246
- if (SYMBOL_P(width))
247
- rb_raise(rb_eTypeError, "source image has a symbol for width.");
248
238
  cinfo->image_width = NUM2INT(width);
249
239
 
250
240
  rb_height = rb_funcall(image_in, id_height, 0);
251
- /* in 1.8.7, NUM2INT gives funny numbers for Symbols */
252
- if (SYMBOL_P(rb_height))
253
- rb_raise(rb_eTypeError, "source image has a symbol for height.");
254
-
255
241
  height = NUM2INT(rb_height);
256
242
  if (height < 1)
257
243
  rb_raise(rb_eRuntimeError, "Source image gave an invalid height.");
258
244
  cinfo->image_height = height;
259
245
 
260
246
  components = rb_funcall(image_in, id_components, 0);
261
- /* in 1.8.7, NUM2INT gives funny numbers for Symbols */
262
- if (SYMBOL_P(components))
263
- rb_raise(rb_eTypeError, "source image has a symbol for components.");
264
247
  cinfo->input_components = NUM2INT(components);
265
-
266
- color_model = rb_funcall(image_in, id_color_model, 0);
267
- if (SYMBOL_P(color_model))
268
- cinfo->in_color_space = id_to_j_color_space(SYM2ID(color_model));
269
- else
270
- rb_raise(rb_eTypeError, "source image has a non symbol color space");
271
-
272
- /* in 1.8.7, NUM2INT gives funny numbers for Symbols */
273
- if (SYMBOL_P(quality))
274
- rb_raise(rb_eTypeError, "symbol for quality.");
275
-
248
+
249
+ switch (cinfo->input_components) {
250
+ case 1:
251
+ cinfo->in_color_space = JCS_GRAYSCALE;
252
+ break;
253
+ case 3:
254
+ cinfo->in_color_space = JCS_RGB;
255
+ break;
256
+ default:
257
+ rb_raise(rb_eRuntimeError, "source image has the wrong number of components");
258
+ break;
259
+ }
276
260
 
277
261
  jpeg_set_defaults(cinfo);
278
262
 
@@ -347,7 +331,7 @@ write_jpeg2(VALUE image_in, VALUE io_out, size_t bufsize, VALUE icc_profile,
347
331
  mgr.pub.init_destination = init_destination;
348
332
  mgr.pub.empty_output_buffer = empty_output_buffer;
349
333
  mgr.pub.term_destination = term_destination;
350
- mgr.alloc = 1024;
334
+ mgr.alloc = bufsize;
351
335
  mgr.io = io_out;
352
336
  cinfo.dest = (struct jpeg_destination_mgr *)&mgr;
353
337
 
@@ -394,10 +378,6 @@ write_jpeg(int argc, VALUE *argv, VALUE self)
394
378
 
395
379
  if (!NIL_P(options) && TYPE(options) == T_HASH) {
396
380
  rb_bufsize = rb_hash_aref(options, sym_bufsize);
397
- /* in 1.8.7, NUM2INT gives funny numbers for Symbols */
398
- if (SYMBOL_P(rb_bufsize))
399
- rb_raise(rb_eTypeError, "symbol for bufsize.");
400
-
401
381
  if (!NIL_P(rb_bufsize)) {
402
382
  bufsize = NUM2INT(rb_bufsize);
403
383
  if (bufsize < 1)
@@ -441,8 +421,8 @@ init_jerror(struct jpeg_error_mgr * err)
441
421
  static void
442
422
  raise_if_locked(struct readerdata *reader)
443
423
  {
444
- if (reader->locked)
445
- rb_raise(rb_eRuntimeError, "Can't modify a locked Reader");
424
+ if (reader->decompress_started)
425
+ rb_raise(rb_eRuntimeError, "Can't modify a Reader after decompress started.");
446
426
  }
447
427
 
448
428
  static void
@@ -624,7 +604,6 @@ initialize(int argc, VALUE *argv, VALUE self)
624
604
  struct readerdata *reader;
625
605
  j_decompress_ptr cinfo;
626
606
  VALUE io, markers;
627
- int i;
628
607
 
629
608
  Data_Get_Struct(self, struct readerdata, reader);
630
609
  raise_if_locked(reader);
@@ -883,28 +862,6 @@ set_dct_method(VALUE self, VALUE dct_method)
883
862
  }
884
863
  }
885
864
 
886
- static VALUE
887
- j_gets2(struct readerdata *reader)
888
- {
889
- struct jpeg_decompress_struct * cinfo;
890
- VALUE sl;
891
- int width, components, sl_width, ret;
892
- JSAMPROW ijg_buffer;
893
-
894
- cinfo = &reader->cinfo;
895
-
896
- width = cinfo->output_width;
897
- components = cinfo->output_components;
898
-
899
- sl_width = width * components;
900
-
901
- sl = rb_str_new(0, sl_width);
902
- ijg_buffer = (JSAMPROW)RSTRING_PTR(sl);
903
- ret = jpeg_read_scanlines(cinfo, &ijg_buffer, 1);
904
-
905
- return ret == 0 ? Qnil : sl;
906
- }
907
-
908
865
  /*
909
866
  * call-seq:
910
867
  * gets -> string or nil
@@ -918,20 +875,29 @@ j_gets2(struct readerdata *reader)
918
875
  static VALUE
919
876
  j_gets(VALUE self)
920
877
  {
921
- struct jpeg_decompress_struct * cinfo;
922
878
  struct readerdata *reader;
879
+ struct jpeg_decompress_struct *cinfo;
880
+ VALUE sl;
881
+ int sl_width, ret;
882
+ JSAMPROW ijg_buffer;
923
883
 
924
884
  Data_Get_Struct(self, struct readerdata, reader);
885
+ cinfo = &reader->cinfo;
925
886
 
926
887
  if (!reader->header_read)
927
888
  read_header(reader, Qnil);
928
889
 
929
- if (reader->locked == 0) {
930
- reader->locked = 1;
931
- jpeg_start_decompress(&reader->cinfo);
890
+ if (!reader->decompress_started) {
891
+ reader->decompress_started = 1;
892
+ jpeg_start_decompress(cinfo);
932
893
  }
933
894
 
934
- return j_gets2(reader);
895
+ sl_width = cinfo->output_width * cinfo->output_components;
896
+ sl = rb_str_new(0, sl_width);
897
+ ijg_buffer = (JSAMPROW)RSTRING_PTR(sl);
898
+
899
+ ret = jpeg_read_scanlines(cinfo, &ijg_buffer, 1);
900
+ return ret == 0 ? Qnil : sl;
935
901
  }
936
902
 
937
903
  /*
@@ -1,8 +1,8 @@
1
1
  #include <ruby.h>
2
2
  #include <png.h>
3
3
 
4
- static ID id_write, id_GRAYSCALE, id_RGB, id_gets, id_width, id_height,
5
- id_color_model, id_components, id_read;
4
+ static ID id_write, id_GRAYSCALE, id_GRAYSCALE_ALPHA, id_RGB, id_RGB_ALPHA,
5
+ id_gets, id_width, id_height, id_color_model, id_components, id_read;
6
6
 
7
7
  struct png_data {
8
8
  png_structp png_ptr;
@@ -17,24 +17,39 @@ struct io_write {
17
17
  };
18
18
 
19
19
  static int
20
- id_to_color_type(ID rb, int components)
20
+ components_to_color_type(int components)
21
21
  {
22
- if (rb == id_GRAYSCALE && components == 1) return PNG_COLOR_TYPE_GRAY;
23
- else if (rb == id_GRAYSCALE && components == 2) return PNG_COLOR_TYPE_GRAY_ALPHA;
24
- else if (rb == id_RGB && components == 3) return PNG_COLOR_TYPE_RGB;
25
- else if (rb == id_RGB && components == 4) return PNG_COLOR_TYPE_RGB_ALPHA;
22
+ switch (components) {
23
+ case 1: return PNG_COLOR_TYPE_GRAY;
24
+ case 2: return PNG_COLOR_TYPE_GRAY_ALPHA;
25
+ case 3: return PNG_COLOR_TYPE_RGB;
26
+ case 4: return PNG_COLOR_TYPE_RGB_ALPHA;
27
+ }
28
+
29
+ rb_raise(rb_eRuntimeError, "Unrecognized number of components.");
30
+ }
31
+
32
+ static ID
33
+ png_color_type_to_id(png_byte color_type)
34
+ {
35
+ switch (color_type) {
36
+ case PNG_COLOR_TYPE_GRAY: return id_GRAYSCALE;
37
+ case PNG_COLOR_TYPE_GRAY_ALPHA: return id_GRAYSCALE_ALPHA;
38
+ case PNG_COLOR_TYPE_RGB: return id_RGB;
39
+ case PNG_COLOR_TYPE_RGB_ALPHA: return id_RGB_ALPHA;
40
+ }
26
41
 
27
- rb_raise(rb_eRuntimeError, "Color Space not recognized.");
42
+ rb_raise(rb_eRuntimeError, "PNG Color Type not recognized.");
28
43
  }
29
44
 
30
45
  static int
31
46
  get_components(png_structp png_ptr, png_infop info_ptr)
32
47
  {
33
48
  switch (png_get_color_type(png_ptr, info_ptr)) {
34
- case PNG_COLOR_TYPE_GRAY: return 1;
35
- case PNG_COLOR_TYPE_GRAY_ALPHA: return 2;
36
- case PNG_COLOR_TYPE_RGB: return 3;
37
- case PNG_COLOR_TYPE_RGB_ALPHA: return 4;
49
+ case PNG_COLOR_TYPE_GRAY: return 1;
50
+ case PNG_COLOR_TYPE_GRAY_ALPHA: return 2;
51
+ case PNG_COLOR_TYPE_RGB: return 3;
52
+ case PNG_COLOR_TYPE_RGB_ALPHA: return 4;
38
53
  }
39
54
 
40
55
  return 0;
@@ -65,11 +80,6 @@ write_data(png_structp png_ptr, png_bytep data, png_size_t length)
65
80
  str = rb_str_new(data, length);
66
81
  iw = (struct io_write *)png_get_io_ptr(png_ptr);
67
82
  rb_write_len = rb_funcall(iw->io, id_write, 1, str);
68
-
69
- /* Ruby 1.8.7 makes up odd numbers when running NUM2INT on a symbol */
70
- if (TYPE(rb_write_len) == T_SYMBOL)
71
- rb_raise(rb_eTypeError, "Number Expected, but got Symbol.");
72
-
73
83
  write_len = NUM2INT(rb_write_len);
74
84
 
75
85
  if ((size_t)write_len != length)
@@ -106,29 +116,14 @@ write_scanline(VALUE scan_line, png_structp png_ptr, png_infop info_ptr)
106
116
  static void
107
117
  write_configure(VALUE image_in, png_structp png_ptr, png_infop info_ptr)
108
118
  {
109
- VALUE width, height, color_model, components;
119
+ VALUE width, height, components;
110
120
  int color_type;
111
121
 
112
122
  width = rb_funcall(image_in, id_width, 0);
113
- /* in 1.8.7, NUM2INT gives funny numbers for Symbols */
114
- if (SYMBOL_P(width))
115
- rb_raise(rb_eTypeError, "source image has a symbol for width.");
116
-
117
123
  height = rb_funcall(image_in, id_height, 0);
118
- /* in 1.8.7, NUM2INT gives funny numbers for Symbols */
119
- if (SYMBOL_P(height))
120
- rb_raise(rb_eTypeError, "source image has a symbol for height.");
121
124
 
122
125
  components = rb_funcall(image_in, id_components, 0);
123
- /* in 1.8.7, NUM2INT gives funny numbers for Symbols */
124
- if (SYMBOL_P(components))
125
- rb_raise(rb_eTypeError, "source image has a symbol for components.");
126
-
127
- color_model = rb_funcall(image_in, id_color_model, 0);
128
- if (SYMBOL_P(color_model))
129
- color_type = id_to_color_type(SYM2ID(color_model), NUM2INT(components));
130
- else
131
- rb_raise(rb_eTypeError, "source image has a non symbol color space");
126
+ color_type = components_to_color_type(NUM2INT(components));
132
127
 
133
128
  png_set_IHDR(png_ptr, info_ptr, NUM2INT(width), NUM2INT(height), 8,
134
129
  color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
@@ -221,7 +216,7 @@ raise_if_locked(struct png_data *reader)
221
216
  }
222
217
 
223
218
  static void
224
- free_png(struct png_data *reader)
219
+ free_reader(struct png_data *reader)
225
220
  {
226
221
  png_structp png_ptr;
227
222
  png_infop info_ptr;
@@ -233,12 +228,7 @@ free_png(struct png_data *reader)
233
228
  png_destroy_read_struct(&png_ptr, &info_ptr, (png_info **)NULL);
234
229
  else if (png_ptr)
235
230
  png_destroy_read_struct(&png_ptr, (png_info **)NULL, (png_info **)NULL);
236
- }
237
231
 
238
- static void
239
- free_reader(struct png_data *reader)
240
- {
241
- free_png(reader);
242
232
  free(reader);
243
233
  }
244
234
 
@@ -264,7 +254,7 @@ read_data_fn(png_structp png_ptr, png_bytep data, png_size_t length)
264
254
  rb_raise(rb_eRuntimeError, "Read Error. Read %d instead of %d bytes.",
265
255
  (int)read_len, (int)length);
266
256
 
267
- memcpy(data, RSTRING_PTR(str), read_len);
257
+ memcpy(data, RSTRING_PTR(str), length);
268
258
  }
269
259
 
270
260
  static void
@@ -276,12 +266,15 @@ mark(struct png_data *reader)
276
266
  rb_gc_mark(io);
277
267
  }
278
268
 
279
- static void
280
- allocate_png(struct png_data *reader)
269
+ static VALUE
270
+ allocate(VALUE klass)
281
271
  {
272
+ VALUE self;
273
+ struct png_data *reader;
282
274
  png_structp png_ptr;
283
275
  png_infop info_ptr;
284
-
276
+
277
+ self = Data_Make_Struct(klass, struct png_data, mark, free_reader, reader);
285
278
  png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL,
286
279
  (png_error_ptr)png_error_fn,
287
280
  (png_error_ptr)png_warning_fn);
@@ -297,16 +290,6 @@ allocate_png(struct png_data *reader)
297
290
 
298
291
  reader->png_ptr = png_ptr;
299
292
  reader->info_ptr = info_ptr;
300
- }
301
-
302
- static VALUE
303
- allocate(VALUE klass)
304
- {
305
- VALUE self;
306
- struct png_data *reader;
307
-
308
- self = Data_Make_Struct(klass, struct png_data, mark, free_reader, reader);
309
- allocate_png(reader);
310
293
 
311
294
  return self;
312
295
  }
@@ -337,6 +320,11 @@ initialize(VALUE self, VALUE io)
337
320
  png_set_read_fn(png_ptr, (void *)io, read_data_fn);
338
321
  reader->io = io;
339
322
  png_read_info(png_ptr, info_ptr);
323
+
324
+ if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_PALETTE) {
325
+ png_set_palette_to_rgb(png_ptr);
326
+ png_read_update_info(png_ptr, info_ptr);
327
+ }
340
328
 
341
329
  return self;
342
330
  }
@@ -368,19 +356,6 @@ components(VALUE self)
368
356
  return INT2FIX(c);
369
357
  }
370
358
 
371
- static ID
372
- png_color_type_to_id(png_byte color_type)
373
- {
374
- switch (color_type) {
375
- case PNG_COLOR_TYPE_GRAY: return id_GRAYSCALE;
376
- case PNG_COLOR_TYPE_GRAY_ALPHA: return id_GRAYSCALE;
377
- case PNG_COLOR_TYPE_RGB: return id_RGB;
378
- case PNG_COLOR_TYPE_RGB_ALPHA: return id_RGB;
379
- }
380
-
381
- rb_raise(rb_eRuntimeError, "PNG Color Type not recognized.");
382
- }
383
-
384
359
  /*
385
360
  * call-seq:
386
361
  * reader.color_model -> symbol
@@ -420,7 +395,7 @@ p_gets(VALUE self)
420
395
  struct png_data *reader;
421
396
  png_structp png_ptr;
422
397
  png_infop info_ptr;
423
- int width, components, sl_width;
398
+ png_uint_32 sl_width;
424
399
  size_t height;
425
400
  VALUE sl;
426
401
 
@@ -432,9 +407,7 @@ p_gets(VALUE self)
432
407
  if (reader->lineno >= height)
433
408
  return Qnil;
434
409
 
435
- width = png_get_image_width(png_ptr, info_ptr);
436
- components = get_components(png_ptr, info_ptr);
437
- sl_width = width * components;
410
+ sl_width = png_get_rowbytes(png_ptr, info_ptr);
438
411
 
439
412
  sl = rb_str_new(0, sl_width);
440
413
  png_read_row(png_ptr, (png_bytep)RSTRING_PTR(sl), (png_bytep)NULL);
@@ -532,6 +505,8 @@ Init_PNG()
532
505
 
533
506
  id_GRAYSCALE = rb_intern("GRAYSCALE");
534
507
  id_RGB = rb_intern("RGB");
508
+ id_GRAYSCALE = rb_intern("GRAYSCALE_ALPHA");
509
+ id_RGB = rb_intern("RGB_ALPHA");
535
510
  id_write = rb_intern("write");
536
511
  id_read = rb_intern("read");
537
512
  id_gets = rb_intern("gets");