axon 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.rdoc +6 -0
- data/README.rdoc +23 -49
- data/Rakefile +33 -7
- data/TODO.rdoc +6 -1
- data/ext/axon/jpeg.c +32 -66
- data/ext/axon/png.c +46 -71
- data/ext/java/axon/AxonService.java +15 -0
- data/ext/java/axon/Interpolation.java +127 -0
- data/ext/java/axon/JPEG.java +119 -0
- data/ext/java/axon/JPEGReader.java +185 -0
- data/ext/java/axon/PNG.java +47 -0
- data/ext/java/axon/PNGReader.java +164 -0
- data/ext/java/axon/RubyImage.java +216 -0
- data/lib/axon.rb +93 -7
- data/lib/axon/alpha_stripper.rb +69 -0
- data/lib/axon/axon.jar +0 -0
- data/lib/axon/cropper.rb +6 -10
- data/lib/axon/fit.rb +53 -35
- data/lib/axon/generators.rb +1 -10
- data/lib/axon/scalers.rb +2 -16
- data/test/helper.rb +7 -9
- data/test/reader_tests.rb +0 -8
- data/test/test_alpha_stripper.rb +33 -0
- data/test/test_fit.rb +38 -0
- data/test/test_jpeg_reader.rb +49 -26
- data/test/test_jpeg_writer.rb +8 -0
- data/test/writer_tests.rb +51 -40
- metadata +96 -87
data/CHANGELOG.rdoc
CHANGED
data/README.rdoc
CHANGED
@@ -4,12 +4,8 @@ http://github.com/ender672/axon
|
|
4
4
|
|
5
5
|
== DESCRIPTION:
|
6
6
|
|
7
|
-
|
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
|
-
#
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
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
|
-
|
66
|
-
|
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)
|
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 '
|
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
|
42
|
+
t.libs << 'test'
|
28
43
|
t.test_files = FileList['test/test*.rb']
|
29
44
|
t.verbose = true
|
30
45
|
end
|
31
46
|
|
32
|
-
|
33
|
-
|
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
|
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.
|
data/ext/axon/jpeg.c
CHANGED
@@ -19,7 +19,7 @@
|
|
19
19
|
#define EXIF_MARKER (JPEG_APP0 + 1)
|
20
20
|
|
21
21
|
#define WRITE_BUFSIZE 1024
|
22
|
-
#define READ_SIZE
|
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
|
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
|
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
|
-
|
267
|
-
|
268
|
-
cinfo->in_color_space =
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
rb_raise(
|
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 =
|
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->
|
445
|
-
rb_raise(rb_eRuntimeError, "Can't modify a
|
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->
|
930
|
-
reader->
|
931
|
-
jpeg_start_decompress(
|
890
|
+
if (!reader->decompress_started) {
|
891
|
+
reader->decompress_started = 1;
|
892
|
+
jpeg_start_decompress(cinfo);
|
932
893
|
}
|
933
894
|
|
934
|
-
|
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
|
/*
|
data/ext/axon/png.c
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
#include <ruby.h>
|
2
2
|
#include <png.h>
|
3
3
|
|
4
|
-
static ID id_write, id_GRAYSCALE,
|
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
|
-
|
20
|
+
components_to_color_type(int components)
|
21
21
|
{
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
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
|
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
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
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,
|
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
|
-
|
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
|
-
|
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),
|
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
|
280
|
-
|
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
|
-
|
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
|
-
|
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");
|