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.
@@ -0,0 +1,15 @@
1
+ package axon;
2
+
3
+ import org.jruby.Ruby;
4
+ import org.jruby.runtime.load.BasicLibraryService;
5
+
6
+ public class AxonService implements BasicLibraryService {
7
+ public boolean basicLoad(Ruby runtime) {
8
+ PNG.initPNG(runtime);
9
+ PNGReader.initPNGReader(runtime);
10
+ JPEG.initJPEG(runtime);
11
+ JPEGReader.initJPEGReader(runtime);
12
+ Interpolation.initInterpolation(runtime);
13
+ return true;
14
+ }
15
+ }
@@ -0,0 +1,127 @@
1
+ package axon;
2
+
3
+ import org.jruby.Ruby;
4
+ import org.jruby.RubyFixnum;
5
+ import org.jruby.RubyNumeric;
6
+ import org.jruby.RubyModule;
7
+ import org.jruby.RubyString;
8
+ import org.jruby.anno.JRubyMethod;
9
+ import org.jruby.runtime.ThreadContext;
10
+ import org.jruby.runtime.builtin.IRubyObject;
11
+ import org.jruby.util.ByteList;
12
+
13
+ public class Interpolation {
14
+ @JRubyMethod(required = 5, meta = true)
15
+ public static IRubyObject bilinear(ThreadContext context, IRubyObject self,
16
+ IRubyObject[] args) {
17
+ ByteList scanline1, scanline2;
18
+ double ty;
19
+ int width, src_width, src_line_size, components;
20
+ byte[] scanline_out;
21
+
22
+ width = RubyFixnum.num2int(args[2]);
23
+ components = RubyFixnum.num2int(args[4]);
24
+ ty = RubyNumeric.num2dbl(args[3]);
25
+
26
+ scanline1 = args[0].convertToString().getByteList();
27
+ scanline2 = args[1].convertToString().getByteList();
28
+
29
+ src_line_size = scanline1.getRealSize();
30
+
31
+ src_width = src_line_size / components - 1;
32
+
33
+ scanline_out = calc_bilinear(width, src_width, components, ty,
34
+ scanline1.getUnsafeBytes(), scanline2.getUnsafeBytes());
35
+
36
+ return(new RubyString(context.getRuntime(), context.getRuntime().getString(), scanline_out));
37
+ }
38
+
39
+ private static byte[] calc_bilinear(int width, int src_width,
40
+ int components, double ty, byte[] scanline1, byte[] scanline2) {
41
+ byte[] dest_sl;
42
+ double width_ratio_inv, sample_x, tx, _tx, p00, p10, p01, p11;
43
+ int c0, c1, dest_pos, sample_x_i;
44
+ short c00, c10, c01, c11;
45
+
46
+ dest_sl = new byte[width * components];
47
+ width_ratio_inv = (double)src_width / width;
48
+
49
+ dest_pos = 0;
50
+ for (int i = 0; i < width; i++) {
51
+ sample_x = i * width_ratio_inv;
52
+ sample_x_i = (int)sample_x;
53
+
54
+ tx = sample_x - sample_x_i;
55
+ _tx = 1 - tx;
56
+
57
+ p11 = tx * ty;
58
+ p01 = _tx * ty;
59
+ p10 = tx - p11;
60
+ p00 = _tx - p01;
61
+
62
+ c0 = sample_x_i * components;
63
+ c1 = c0 + components;
64
+
65
+ for (int j = 0; j < components; j++) {
66
+ c00 = (short)(0x000000FF & (int)scanline1[c0 + j]);
67
+ c10 = (short)(0x000000FF & (int)scanline1[c1 + j]);
68
+ c01 = (short)(0x000000FF & (int)scanline2[c0 + j]);
69
+ c11 = (short)(0x000000FF & (int)scanline2[c1 + j]);
70
+
71
+ dest_sl[dest_pos] = (byte)(((short)(p00 * c00 + p10 * c10 + p01 * c01 + p11 * c11)) & 0xFF);
72
+ dest_pos += 1;
73
+ }
74
+ }
75
+
76
+ return dest_sl;
77
+
78
+ }
79
+
80
+ @JRubyMethod(meta = true)
81
+ public static IRubyObject nearest(ThreadContext context, IRubyObject self,
82
+ IRubyObject rb_scanline,
83
+ IRubyObject rb_width,
84
+ IRubyObject rb_components) {
85
+ ByteList scanline_in;
86
+ byte[] scanline_out;
87
+ int width, src_width, src_line_size, components;
88
+
89
+ width = RubyFixnum.num2int(rb_width);
90
+ components = RubyFixnum.num2int(rb_components);
91
+
92
+ scanline_in = rb_scanline.convertToString().getByteList();
93
+ src_line_size = scanline_in.getRealSize();
94
+
95
+ src_width = src_line_size / components;
96
+ scanline_out = calc_nearest(width, src_width, components, scanline_in.getUnsafeBytes());
97
+
98
+ return(new RubyString(context.getRuntime(), context.getRuntime().getString(), scanline_out));
99
+ }
100
+
101
+ private static byte[] calc_nearest(int width, int src_width,
102
+ int components, byte[] scanline) {
103
+ double inv_scale_x;
104
+ byte[] dest_sl;
105
+ int src_pos, dest_pos, i, j;
106
+
107
+ inv_scale_x = (double)src_width / width;
108
+ dest_sl = new byte[width * components];
109
+
110
+ dest_pos = 0;
111
+ for (i = 0; i < width; i++) {
112
+ src_pos = (int)(i * inv_scale_x) * components;
113
+ for (j = 0; j < components; j++) {
114
+ dest_sl[dest_pos] = scanline[src_pos + j];
115
+ dest_pos += 1;
116
+ }
117
+ }
118
+
119
+ return dest_sl;
120
+ }
121
+
122
+ static void initInterpolation(Ruby runtime) {
123
+ RubyModule axon = runtime.defineModule("Axon");
124
+ RubyModule interpolation = axon.defineModuleUnder("Interpolation");
125
+ interpolation.defineAnnotatedMethods(Interpolation.class);
126
+ }
127
+ }
@@ -0,0 +1,119 @@
1
+ package axon;
2
+
3
+ import java.io.IOException;
4
+ import java.util.Iterator;
5
+
6
+ import javax.imageio.ImageIO;
7
+ import javax.imageio.IIOImage;
8
+ import javax.imageio.IIOException;
9
+ import javax.imageio.ImageTypeSpecifier;
10
+ import javax.imageio.ImageWriteParam;
11
+ import javax.imageio.ImageWriter;
12
+ import javax.imageio.stream.ImageOutputStream;
13
+
14
+ import java.awt.image.ColorModel;
15
+ import java.awt.image.SampleModel;
16
+
17
+ import org.jruby.Ruby;
18
+ import org.jruby.RubyFixnum;
19
+ import org.jruby.RubyHash;
20
+ import org.jruby.RubyString;
21
+ import org.jruby.RubyModule;
22
+ import org.jruby.RubySymbol;
23
+ import org.jruby.anno.JRubyMethod;
24
+ import org.jruby.runtime.ThreadContext;
25
+ import org.jruby.runtime.builtin.IRubyObject;
26
+ import org.jruby.util.IOOutputStream;
27
+
28
+ public class JPEG {
29
+
30
+ /*
31
+ * OpenJDK (IcedTea6 1.9.10), has an implementation of JPEGImageReader that
32
+ * loads the entire image into memory via read() before compressing it. Not
33
+ * sure why it does this -- the PNGImageReader is much nicer and only
34
+ * buffers one scanline at a time.
35
+ *
36
+ * Be warned -- large images can take up lots of memory here.
37
+ */
38
+
39
+ @JRubyMethod(meta = true, required = 2, optional = 1)
40
+ public static IRubyObject write(ThreadContext context, IRubyObject self,
41
+ IRubyObject[] args) throws IOException {
42
+ IRubyObject img_in, ruby_io, rb_quality, rb_icc_profile;
43
+ RubyHash options;
44
+ Iterator writers;
45
+ ImageWriter writer;
46
+ IOOutputStream jruby_io;
47
+ ImageOutputStream ios;
48
+ RubyImage img;
49
+ ImageWriteParam iwp;
50
+ ImageTypeSpecifier dest_type;
51
+ ColorModel cm;
52
+ SampleModel sm;
53
+ int quality;
54
+ byte[] icc_profile;
55
+
56
+ writers = ImageIO.getImageWritersByFormatName("jpeg");
57
+ writer = (ImageWriter)writers.next();
58
+ img_in = args[0];
59
+ ruby_io = args[1];
60
+ rb_quality = null;
61
+ rb_icc_profile = null;
62
+
63
+ if (args.length > 2) {
64
+ options = (RubyHash)args[2];
65
+ rb_quality = options.fastARef(RubySymbol.newSymbol(context.getRuntime(),
66
+ "quality"));
67
+ rb_icc_profile = options.fastARef(RubySymbol.newSymbol(context.getRuntime(),
68
+ "icc_profile"));
69
+ }
70
+
71
+ jruby_io = new IOOutputStream(ruby_io, false, false);
72
+ ios = ImageIO.createImageOutputStream(jruby_io);
73
+ writer.setOutput(ios);
74
+ img = new RubyImage(img_in);
75
+ iwp = writer.getDefaultWriteParam();
76
+
77
+ if (rb_quality != null && !rb_quality.isNil()) {
78
+ quality = RubyFixnum.num2int(rb_quality);
79
+ if (quality < 1)
80
+ quality = 1;
81
+ else if (quality > 100)
82
+ quality = 100;
83
+ iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
84
+ iwp.setCompressionQuality(quality / 100.0f);
85
+ }
86
+
87
+ /* ImageWriteParam -> ImageTypeSpecifier -> ColorModel -> ColorSpace ->
88
+ * ICC_Profile
89
+ */
90
+ if (rb_icc_profile != null && !rb_icc_profile.isNil()) {
91
+ icc_profile = ((RubyString)rb_icc_profile).getBytes();
92
+ cm = img.getICCColorModel(icc_profile);
93
+ sm = cm.createCompatibleSampleModel(img.getWidth(), img.getHeight());
94
+
95
+ iwp.setDestinationType(new ImageTypeSpecifier(cm, sm));
96
+ // System.out.println(cs);
97
+ // iwp.setDestinationType()
98
+ }
99
+
100
+ try {
101
+ writer.write(null, new IIOImage(img, null, null), iwp);
102
+ }
103
+ catch(NegativeArraySizeException nas) {
104
+ throw context.getRuntime().newRuntimeError("An exception occurred while writing.");
105
+ }
106
+ catch(IIOException iioe) {
107
+ throw context.getRuntime().newRuntimeError("An exception occurred while writing.");
108
+ }
109
+ ios.flush();
110
+
111
+ return context.getRuntime().newFixnum(ios.getStreamPosition());
112
+ }
113
+
114
+ static void initJPEG(Ruby runtime) {
115
+ RubyModule axon = runtime.defineModule("Axon");
116
+ RubyModule jpeg = axon.defineModuleUnder("JPEG");
117
+ jpeg.defineAnnotatedMethods(JPEG.class);
118
+ }
119
+ }
@@ -0,0 +1,185 @@
1
+ package axon;
2
+
3
+ import java.awt.Rectangle;
4
+ import java.awt.color.ICC_ColorSpace;
5
+ import java.awt.image.BufferedImage;
6
+ import java.awt.image.DataBufferByte;
7
+ import java.awt.image.WritableRaster;
8
+ import java.io.IOException;
9
+ import java.io.OutputStream;
10
+ import java.io.OutputStreamWriter;
11
+ import java.io.StringWriter;
12
+ import java.util.Iterator;
13
+
14
+ import javax.imageio.ImageIO;
15
+ import javax.imageio.ImageReadParam;
16
+ import javax.imageio.ImageReader;
17
+ import javax.imageio.ImageTypeSpecifier;
18
+ import javax.imageio.metadata.IIOMetadataNode;
19
+ import javax.imageio.metadata.IIOMetadata;
20
+ import javax.imageio.stream.ImageInputStream;
21
+
22
+ import javax.xml.transform.TransformerFactory;
23
+ import javax.xml.transform.Transformer;
24
+ import javax.xml.transform.TransformerConfigurationException;
25
+ import javax.xml.transform.dom.DOMSource;
26
+ import javax.xml.transform.stream.StreamResult;
27
+ import javax.xml.transform.OutputKeys;
28
+ import javax.xml.transform.TransformerException;
29
+
30
+ import org.w3c.dom.Node;
31
+ import org.w3c.dom.Document;
32
+
33
+ import org.jruby.Ruby;
34
+ import org.jruby.RubyClass;
35
+ import org.jruby.RubyString;
36
+ import org.jruby.RubyModule;
37
+ import org.jruby.RubyObject;
38
+ import org.jruby.anno.JRubyMethod;
39
+ import org.jruby.runtime.ObjectAllocator;
40
+ import org.jruby.runtime.ThreadContext;
41
+ import org.jruby.runtime.builtin.IRubyObject;
42
+ import org.jruby.util.IOInputStream;
43
+
44
+ public class JPEGReader extends RubyObject {
45
+ private ImageReader reader;
46
+ private IRubyObject rb_io_in;
47
+ private ImageTypeSpecifier its;
48
+ private int lineno_i;
49
+
50
+ private static ObjectAllocator ALLOCATOR = new ObjectAllocator() {
51
+ public IRubyObject allocate(Ruby runtime, RubyClass klass) {
52
+ return new JPEGReader(runtime, klass);
53
+ }
54
+ };
55
+
56
+ public JPEGReader(Ruby runtime, RubyClass klass) {
57
+ super(runtime, klass);
58
+ }
59
+
60
+ @JRubyMethod
61
+ public IRubyObject initialize(IRubyObject io) {
62
+ Iterator readers;
63
+ ImageInputStream iis;
64
+
65
+ rb_io_in = io;
66
+ lineno_i = 0;
67
+
68
+ readers = ImageIO.getImageReadersByFormatName("jpeg");
69
+ reader = (ImageReader)readers.next();
70
+
71
+ try {
72
+ iis = ImageIO.createImageInputStream(new IOInputStream(rb_io_in));
73
+ }
74
+ catch(IOException ioe) {
75
+ throw getRuntime().newIOErrorFromException(ioe);
76
+ }
77
+
78
+ reader.setInput(iis, true);
79
+
80
+ try {
81
+ its = reader.getImageTypes(0).next();
82
+ }
83
+ catch(IOException ioe) {
84
+ throw getRuntime().newRuntimeError("An IO Error occured while reading.");
85
+ }
86
+ catch(ArrayIndexOutOfBoundsException oob) {
87
+ throw getRuntime().newRuntimeError("An index out of bounds error occurred while reading.");
88
+ }
89
+
90
+ return this;
91
+ }
92
+
93
+ @JRubyMethod
94
+ public IRubyObject width(ThreadContext context) {
95
+ try {
96
+ return getRuntime().newFixnum(reader.getWidth(0));
97
+ }
98
+ catch(IOException ioe) {
99
+ throw getRuntime().newIOErrorFromException(ioe);
100
+ }
101
+ }
102
+
103
+ @JRubyMethod
104
+ public IRubyObject height(ThreadContext context) {
105
+ try {
106
+ return getRuntime().newFixnum(reader.getHeight(0));
107
+ }
108
+ catch(IOException ioe) {
109
+ throw getRuntime().newIOErrorFromException(ioe);
110
+ }
111
+ }
112
+
113
+ @JRubyMethod
114
+ public IRubyObject components(ThreadContext context) {
115
+ try {
116
+ return getRuntime().newFixnum(getBands());
117
+ }
118
+ catch(IOException ioe) {
119
+ throw getRuntime().newIOErrorFromException(ioe);
120
+ }
121
+ }
122
+
123
+ @JRubyMethod
124
+ public IRubyObject gets(ThreadContext context) throws IOException {
125
+ BufferedImage image;
126
+ ImageReadParam irp;
127
+ WritableRaster raster;
128
+ DataBufferByte buffer;
129
+ byte[] data;
130
+ int numbands;
131
+ byte tmp;
132
+
133
+ /* Return nil if we are already at the bottom of the image */
134
+ if (lineno_i >= reader.getHeight(0))
135
+ return(context.nil);
136
+
137
+ /* request one scanline */
138
+ irp = reader.getDefaultReadParam();
139
+ irp.setSourceRegion(new Rectangle(0, lineno_i, reader.getWidth(0), 1));
140
+
141
+ image = reader.read(0, irp);
142
+
143
+ /* get the raw bytes from the scanline */
144
+ raster = image.getRaster();
145
+
146
+ buffer = (DataBufferByte)raster.getDataBuffer();
147
+ data = buffer.getData();
148
+
149
+ /* JPEGReader forces us to reorder BGR to RGB. */
150
+ numbands = getBands();
151
+ if (numbands == 3) {
152
+ for (int i = 0; i < data.length / 3; i++) {
153
+ tmp = data[i * 3];
154
+ data[i * 3] = data[i * 3 + 2];
155
+ data[i * 3 + 2] = tmp;
156
+ }
157
+ }
158
+
159
+ lineno_i += 1;
160
+ return(new RubyString(getRuntime(), getRuntime().getString(), data));
161
+ }
162
+
163
+ @JRubyMethod
164
+ public IRubyObject lineno(ThreadContext context) {
165
+ return getRuntime().newFixnum(lineno_i);
166
+ }
167
+
168
+ @JRubyMethod
169
+ public IRubyObject icc_profile(ThreadContext context) {
170
+ byte[] data;
171
+ data = ((ICC_ColorSpace)its.getColorModel().getColorSpace()).getProfile().getData();
172
+ return(new RubyString(getRuntime(), getRuntime().getString(), data));
173
+ }
174
+
175
+ public static void initJPEGReader(Ruby runtime) {
176
+ RubyModule axon = runtime.defineModule("Axon");
177
+ RubyModule png = axon.defineModuleUnder("JPEG");
178
+ RubyClass jpegReader = png.defineClassUnder("Reader", runtime.getObject(), ALLOCATOR);
179
+ jpegReader.defineAnnotatedMethods(JPEGReader.class);
180
+ }
181
+
182
+ private int getBands() throws IOException {
183
+ return its.getNumComponents();
184
+ }
185
+ }
@@ -0,0 +1,47 @@
1
+ package axon;
2
+
3
+ import java.io.IOException;
4
+ import java.util.Iterator;
5
+
6
+ import javax.imageio.ImageIO;
7
+ import javax.imageio.ImageWriter;
8
+ import javax.imageio.stream.ImageOutputStream;
9
+
10
+ import org.jruby.Ruby;
11
+ import org.jruby.RubyModule;
12
+ import org.jruby.anno.JRubyMethod;
13
+ import org.jruby.runtime.ThreadContext;
14
+ import org.jruby.runtime.builtin.IRubyObject;
15
+ import org.jruby.util.IOOutputStream;
16
+
17
+ public class PNG {
18
+ @JRubyMethod(meta = true)
19
+ public static IRubyObject write(ThreadContext context, IRubyObject self,
20
+ IRubyObject img_in, IRubyObject ruby_io) throws IOException {
21
+ Iterator writers = ImageIO.getImageWritersByFormatName("png");
22
+ ImageWriter writer = (ImageWriter)writers.next();
23
+ IOOutputStream jruby_io = new IOOutputStream(ruby_io, false, false);
24
+ ImageOutputStream ios = ImageIO.createImageOutputStream(jruby_io);
25
+ writer.setOutput(ios);
26
+ RubyImage img = new RubyImage(img_in);
27
+ try {
28
+ writer.write(img);
29
+ }
30
+ catch(IllegalArgumentException iae) {
31
+ throw context.getRuntime().newRuntimeError("An Illegal Argument exception occurred while writing.");
32
+ }
33
+ catch(ArrayIndexOutOfBoundsException oob) {
34
+ throw context.getRuntime().newRuntimeError("An Out of Bounds exception occurred while writing.");
35
+ }
36
+ catch(NegativeArraySizeException nas) {
37
+ throw context.getRuntime().newRuntimeError("An exception occurred while writing.");
38
+ }
39
+ return context.getRuntime().newFixnum(ios.getStreamPosition());
40
+ }
41
+
42
+ static void initPNG(Ruby runtime) {
43
+ RubyModule axon = runtime.defineModule("Axon");
44
+ RubyModule png = axon.defineModuleUnder("PNG");
45
+ png.defineAnnotatedMethods(PNG.class);
46
+ }
47
+ }