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.
- 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");
|