mathematical 0.4.2 → 0.5.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.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +20 -9
  3. data/Rakefile +5 -24
  4. data/ext/mathematical/extconf.rb +8 -3
  5. data/ext/mathematical/lasem/src/lsmdomparser.c +7 -7
  6. data/ext/mathematical/lasem/src/lsmdomparser.h +2 -2
  7. data/ext/mathematical/lasem/src/lsmitex.c +8 -5
  8. data/ext/mathematical/lasem/src/lsmitex.h +1 -1
  9. data/ext/mathematical/lasem/src/lsmmathmldocument.c +2 -2
  10. data/ext/mathematical/lasem/src/lsmmathmldocument.h +1 -1
  11. data/ext/mathematical/lasem/tests/lsmtest.c +2 -2
  12. data/ext/mathematical/mathematical.c +119 -10
  13. data/ext/mathematical/mtex2MML/ext/extconf.rb +4 -0
  14. data/ext/mathematical/mtex2MML/src/lex.yy.c +6791 -0
  15. data/ext/mathematical/mtex2MML/src/mtex2MML.h +59 -0
  16. data/ext/mathematical/mtex2MML/src/parse_extras.c +306 -0
  17. data/ext/mathematical/mtex2MML/src/parse_extras.h +78 -0
  18. data/ext/mathematical/mtex2MML/src/stack.c +80 -0
  19. data/ext/mathematical/mtex2MML/src/stack.h +101 -0
  20. data/ext/mathematical/mtex2MML/src/string_extras.c +211 -0
  21. data/ext/mathematical/mtex2MML/src/string_extras.h +46 -0
  22. data/ext/mathematical/mtex2MML/src/y.tab.c +7090 -0
  23. data/ext/mathematical/mtex2MML/src/y.tab.h +393 -0
  24. data/lib/mathematical.rb +1 -0
  25. data/lib/mathematical/corrections.rb +34 -0
  26. data/lib/mathematical/render.rb +21 -12
  27. data/lib/mathematical/version.rb +1 -1
  28. data/mathematical.gemspec +2 -2
  29. data/test/mathematical/corrections_test.rb +56 -0
  30. data/test/mathematical/fixtures/png/pmatrix.png +0 -0
  31. data/test/mathematical/fixtures_test.rb +11 -1
  32. data/test/mathematical/maliciousness_test.rb +10 -2
  33. data/test/mathematical/mathml_test.rb +22 -0
  34. data/test/mathematical/png_test.rb +26 -0
  35. data/test/test_helper.rb +13 -0
  36. metadata +150 -134
  37. data/ext/mathematical/itexToMML/itex2MML.h +0 -63
  38. data/ext/mathematical/itexToMML/lex.yy.c +0 -6548
  39. data/ext/mathematical/itexToMML/y.tab.c +0 -6179
  40. data/ext/mathematical/itexToMML/y.tab.h +0 -389
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7f786243252000f0ce7053c49e288c8024edc860
4
- data.tar.gz: 8958c2259c707f27a9cddb5655b8ac1e9dd6d76c
3
+ metadata.gz: 03f0731bd32ba0f8f1f6f8a3c83ce1ee89ece70d
4
+ data.tar.gz: e0ca46a7d69b7943645b8bb4bd64c2f6e780b8fa
5
5
  SHA512:
6
- metadata.gz: 623fa07b26e1693d761561ac91305a50d5e87da002a472e2a7a5b42342eb2ce6c8a69dcc43b0986f0195e8f9038dcd62add881e43407b44d72f7b637f1649a49
7
- data.tar.gz: 716e5e0ca88f633957d322dae909b1d5efc23ef2aedb7278d936ad0af6f09f54a646fef3fcf0cc01235c0d69eba938e5902b8a274683f63621fef615e9d49675
6
+ metadata.gz: 33098207ab043b4b6452b0b35eb332bf731abfedc2fb29ddb14f446e5dab94edc2fefaf51b8f4bc75b3877c69e3fb72c06dbfe3dda4350a3e561ae7516e18ffc
7
+ data.tar.gz: 2341104e60ea0d51019912c607bf8d81ddd48e46b41aaa2d789e11026eb28d5bde6af0c500754ff9d329431bb11f0d80e4f6a122128b5a8e1e95c42468ae52b4
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Mathematical
2
2
 
3
- Quickly convert math equations into beautiful SVGs.
3
+ Quickly convert math equations into beautiful SVGs (or PNGs/MathML).
4
4
 
5
5
  [![Build Status](https://travis-ci.org/gjtorikian/mathematical.svg?branch=master)](https://travis-ci.org/gjtorikian/mathematical)
6
6
 
@@ -25,16 +25,25 @@ Or install it yourself as:
25
25
  The simplest way to do this is
26
26
 
27
27
  ``` ruby
28
+ require 'mathematical'
29
+
28
30
  Mathematical::Render.new.render(string_with_math)
29
31
  ```
30
32
 
31
33
  `string_with_math` should just be a string of itex inline (`$..$`) or display (`$$..$$`) style math.
32
34
 
33
- The output will be a hash, with the following data:
35
+ The output will be a hash, with keys that depend on the format you want:
34
36
 
35
- * `width`: the width of the resulting SVG file
36
- * `height`: the height of the resulting SVG file
37
- * `svg`: the actual string of SVG
37
+ * If you asked for an SVG, you'll get:
38
+ * `width`: the width of the resulting image
39
+ * `height`: the height of the resulting image
40
+ * `svg`: the actual string of SVG
41
+ * If you asked for a PNG, you'll get:
42
+ * `width`: the width of the resulting image
43
+ * `height`: the height of the resulting image
44
+ * `png`: the PNG data
45
+ * If you asked for MathML, you'll get:
46
+ * `mathml`: the MathML data
38
47
 
39
48
  ### Options
40
49
 
@@ -43,6 +52,8 @@ The output will be a hash, with the following data:
43
52
  * `:ppi` - A double determining the pixels per inch of the resulting SVG (default: `72.0`).
44
53
  * `:zoom` - A double determining the zoom level of the resulting SVG (default: `1.0`).
45
54
  * `:base64` - A boolean determining whether Mathematical's output should be a base64-encoded SVG string (default: `false`).
55
+ * `:maxsize` - A numeral indicating the `MAXSIZE` the output string can be. (default: `unsigned long`).
56
+ * `:format` - A string indicating whether you want an "svg", "png", or "mathml" output. (default: `svg`).
46
57
 
47
58
  Pass these in as an options hash:
48
59
 
@@ -56,6 +67,8 @@ renderer.render('$a \ne b$')
56
67
 
57
68
  Literally everything on the [itex2MML homepage for version 1.5.1](http://golem.ph.utexas.edu/~distler/blog/itex2MMLcommands.html) is supported, because it acts as the interpretation engine for Mathematical.
58
69
 
70
+ **Note**: This library makes few assumptions about the strings that you pass in. It assumes that `$..$` is inline math, `$$..$$` is display math, and that slashes like `\\` are escaped (`\\\\`).
71
+
59
72
  ## Dependencies
60
73
 
61
74
  Before using this gem, you must install the following libraries:
@@ -98,11 +111,9 @@ curl -LO http://mirrors.ctan.org/fonts/cm/ps-type1/bakoma/ttf/cmex10.ttf \
98
111
  To install these dependencies on a *nix machine, fetch the packages through your package manager. For example:
99
112
 
100
113
  ```
101
- sudo apt-get -qq -y install libxml2-dev libcairo2-dev libpango1.0-dev ttf-lyx
114
+ sudo apt-get -qq -y install libglib2.0-dev libxml2-dev libcairo2-dev libpango1.0-dev ttf-lyx libgdk-pixbuf2.0-dev
102
115
  ```
103
116
 
104
- `glib` and `gdk-pixbuf` should be on your machine.
105
-
106
117
  ### Windows install
107
118
 
108
119
  On a Windows machine, I have no idea. Pull requests welcome!
@@ -121,7 +132,7 @@ Rendering... 9.470000 0.750000 10.220000 ( 13.9
121
132
 
122
133
  After cloning the repo:
123
134
 
124
- ```
135
+ ```
125
136
  script/bootstrap
126
137
  bundle exec rake compile
127
138
  ```
data/Rakefile CHANGED
@@ -28,34 +28,14 @@ Rake::Task[:test].prerequisites << :compile
28
28
 
29
29
  task :default => [:test]
30
30
 
31
- desc "Generate and publish to gh-pages"
32
- task :publish do
31
+ desc "Copy samples to gh-pages"
32
+ task :copy_samples do
33
33
  Dir.mktmpdir do |tmp|
34
- system "cp test/mathematical/fixtures/after/* #{tmp}"
35
- titles_to_content = {}
36
- Dir.glob("#{tmp}/compliance_*.html") do |item|
37
- titles_to_content[File.basename(item)] = File.read(item)
38
- end
34
+ system "cp -r samples #{tmp}"
39
35
 
40
36
  system "git checkout gh-pages"
41
37
 
42
- li_listing = titles_to_content.keys.map { |title| "<li><a href='#{title}'>#{File.basename(title, File.extname(title))}</a></li>" }
43
- index = File.read("index.html")
44
- File.open("index.html", 'w') { |file| file.write(index.sub(/<!-- LIST_GOES_HERE -->/, li_listing.join("\n"))) }
45
-
46
- layout = File.read("layout_shell.text")
47
- titles_to_content.each do |title, content|
48
- new_layout = layout.sub(/<!-- TITLE_GOES_HERE -->/, title)
49
- new_layout = new_layout.sub(/<!-- CONTENT_GOES_HERE -->/, content)
50
- File.open("#{title}", 'w') { |file| file.write(new_layout) }
51
- end
52
-
53
- message = "Site updated at #{Time.now.utc}"
54
- system "git add ."
55
- system "git commit -am #{message.shellescape}"
56
- system "git push origin gh-pages --force"
57
- system "git checkout master"
58
- system "echo yolo"
38
+ system "cp -r #{tmp}/samples ."
59
39
  end
60
40
  end
61
41
 
@@ -65,4 +45,5 @@ task :destroy_copies do
65
45
  next if f =~ /extconf.rb/ || f =~ /mathematical.c/
66
46
  File.delete(f)
67
47
  end
48
+ Dir.glob("#{ext_dir}/{lib,src,test,ext}").select { |d| FileUtils.rm_rf d }
68
49
  end
@@ -3,7 +3,7 @@ require 'rbconfig'
3
3
  host_os = RbConfig::CONFIG['host_os']
4
4
 
5
5
  LASEM_DIR = File.join(File.dirname(__FILE__), "lasem", "src")
6
- ITEX_DIR = File.join(File.dirname(__FILE__), "itexToMML")
6
+ MTEX_DIR = File.join(File.dirname(__FILE__), "mtex2MML", "src")
7
7
 
8
8
  if host_os =~ /darwin|mac os/
9
9
  ENV['PKG_CONFIG_PATH'] = "/opt/X11/lib/pkgconfig:#{ENV['PKG_CONFIG_PATH']}"
@@ -20,11 +20,16 @@ find_header("libxml/xpathInternals.h", "/usr/include/libxml2", "/usr/local/inclu
20
20
  FileUtils.cp_r(Dir.glob("#{LASEM_DIR}/*"), File.dirname(__FILE__))
21
21
  File.delete(File.join(File.dirname(__FILE__), "lasemrender.c"))
22
22
 
23
- FileUtils.cp_r(Dir.glob("#{ITEX_DIR}/*"), File.dirname(__FILE__))
23
+ # build mtex2MML Bison files
24
+ Dir.chdir(MTEX_DIR) do
25
+ system "make"
26
+ end
27
+
28
+ FileUtils.cp_r(Dir.glob("#{MTEX_DIR}/*.{c,h,cc}"), File.dirname(__FILE__))
24
29
 
25
30
  have_library("pangocairo-1.0")
26
31
 
27
32
  $LDFLAGS += " #{`pkg-config --static --libs glib-2.0 gdk-pixbuf-2.0 cairo pango`.chomp}"
28
- $CFLAGS += " #{`pkg-config --cflags glib-2.0 gdk-pixbuf-2.0 cairo pango`.chomp} -I#{LASEM_DIR} -I#{ITEX_DIR}"
33
+ $CFLAGS += " #{`pkg-config --cflags glib-2.0 gdk-pixbuf-2.0 cairo pango`.chomp} -DFLIP_OFFSET_VAL -I#{LASEM_DIR} -I#{MTEX_DIR}"
29
34
 
30
35
  create_makefile("mathematical/mathematical")
@@ -259,7 +259,7 @@ typedef enum {
259
259
 
260
260
  static LsmDomDocument *
261
261
  _parse_memory (LsmDomDocument *document, LsmDomNode *node,
262
- const void *buffer, gsize size, GError **error)
262
+ const void *buffer, gssize size, GError **error)
263
263
  {
264
264
  static LsmDomSaxParserState state;
265
265
 
@@ -269,7 +269,7 @@ _parse_memory (LsmDomDocument *document, LsmDomNode *node,
269
269
  else
270
270
  state.current_node = LSM_DOM_NODE (document);
271
271
 
272
- if (size < 1)
272
+ if (size < 0)
273
273
  size = strlen (buffer);
274
274
 
275
275
  if (xmlSAXUserParseMemory (&sax_handler, &state, buffer, size) < 0) {
@@ -293,18 +293,18 @@ _parse_memory (LsmDomDocument *document, LsmDomNode *node,
293
293
  * @document: a #LsmDomDocument
294
294
  * @node: a #LsmDomNode
295
295
  * @buffer: a memory buffer holding xml data
296
- * @size: size of the xml data, in bytes, 0 if unknown
296
+ * @size: size of the xml data, in bytes, -1 if NULL terminated
297
297
  * @error: an error placeholder
298
298
  *
299
299
  * Append a chunk of xml tree to an existing document. The resulting nodes will be appended to
300
300
  * @node, or to @document if @node == NULL.
301
301
  *
302
- * Size set to 0 indicates an unknow xml data size.
302
+ * Size set to -1 indicates the buffer is NULL terminated.
303
303
  */
304
304
 
305
305
  void
306
306
  lsm_dom_document_append_from_memory (LsmDomDocument *document, LsmDomNode *node,
307
- const void *buffer, gsize size, GError **error)
307
+ const void *buffer, gssize size, GError **error)
308
308
  {
309
309
  g_return_if_fail (LSM_IS_DOM_DOCUMENT (document));
310
310
  g_return_if_fail (LSM_IS_DOM_NODE (node) || node == NULL);
@@ -316,14 +316,14 @@ lsm_dom_document_append_from_memory (LsmDomDocument *document, LsmDomNode *node,
316
316
  /**
317
317
  * lsm_dom_document_new_from_memory:
318
318
  * @buffer: xml data
319
- * @size: size of the data, in bytes, 0 if unknown
319
+ * @size: size of the data, in bytes, -1 if NULL terminated
320
320
  * @error: an error placeholder
321
321
  *
322
322
  * Create a new document from a memory data buffer.
323
323
  */
324
324
 
325
325
  LsmDomDocument *
326
- lsm_dom_document_new_from_memory (const void *buffer, gsize size, GError **error)
326
+ lsm_dom_document_new_from_memory (const void *buffer, gssize size, GError **error)
327
327
  {
328
328
  g_return_val_if_fail (buffer != NULL, NULL);
329
329
 
@@ -30,8 +30,8 @@
30
30
  G_BEGIN_DECLS
31
31
 
32
32
  void lsm_dom_document_append_from_memory (LsmDomDocument *document, LsmDomNode *node,
33
- const void *buffer, gsize size, GError **error);
34
- LsmDomDocument * lsm_dom_document_new_from_memory (const void *buffer, gsize size, GError **error);
33
+ const void *buffer, gssize size, GError **error);
34
+ LsmDomDocument * lsm_dom_document_new_from_memory (const void *buffer, gssize size, GError **error);
35
35
  LsmDomDocument * lsm_dom_document_new_from_path (const char *path, GError **error);
36
36
  LsmDomDocument * lsm_dom_document_new_from_url (const char *url, GError **error);
37
37
 
@@ -28,7 +28,7 @@
28
28
  /**
29
29
  * lsm_itex_to_mathml:
30
30
  * @itex: (allow-none): an itex string
31
- * @size: itex string length, 0 if unknown
31
+ * @size: itex string length, -1 if NULL terminated
32
32
  *
33
33
  * Converts an itex string to a Mathml representation.
34
34
  *
@@ -36,17 +36,20 @@
36
36
  */
37
37
 
38
38
  char *
39
- lsm_itex_to_mathml (const char *itex, gsize size)
39
+ lsm_itex_to_mathml (const char *itex, gssize size)
40
40
  {
41
+ gsize usize;
41
42
  char *mathml;
42
43
 
43
44
  if (itex == NULL)
44
45
  return NULL;
45
46
 
46
- if (size < 1)
47
- size = strlen (itex);
47
+ if (size < 0)
48
+ usize = strlen (itex);
49
+ else
50
+ usize = size;
48
51
 
49
- mathml = itex2MML_parse (itex, size);
52
+ mathml = itex2MML_parse (itex, usize);
50
53
  if (mathml == NULL)
51
54
  return NULL;
52
55
 
@@ -28,7 +28,7 @@
28
28
 
29
29
  G_BEGIN_DECLS
30
30
 
31
- char * lsm_itex_to_mathml (const char *itex, gsize size);
31
+ char * lsm_itex_to_mathml (const char *itex, gssize size);
32
32
  void lsm_itex_free_mathml_buffer (char *mathml);
33
33
 
34
34
  G_END_DECLS
@@ -213,7 +213,7 @@ typedef enum {
213
213
  } LsmMathmlDocumentError;
214
214
 
215
215
  LsmMathmlDocument *
216
- lsm_mathml_document_new_from_itex (const char *itex, gsize size, GError **error)
216
+ lsm_mathml_document_new_from_itex (const char *itex, gssize size, GError **error)
217
217
  {
218
218
  LsmDomDocument *document;
219
219
  char *mathml;
@@ -250,7 +250,7 @@ static LsmMathmlDocument *
250
250
  lsm_mathml_document_new_from_itex_file (GFile *file, GError **error)
251
251
  {
252
252
  LsmMathmlDocument *document;
253
- gsize size = 0;
253
+ gssize size = 0;
254
254
  char *contents = NULL;
255
255
 
256
256
  if (!g_file_load_contents (file, NULL, &contents, &size, NULL, error))
@@ -51,7 +51,7 @@ GType lsm_mathml_document_get_type (void);
51
51
  LsmDomDocument * lsm_mathml_document_new (void);
52
52
  LsmMathmlMathElement * lsm_mathml_document_get_root_element (const LsmMathmlDocument *document);
53
53
 
54
- LsmMathmlDocument * lsm_mathml_document_new_from_itex (const char *itex, gsize size, GError **error);
54
+ LsmMathmlDocument * lsm_mathml_document_new_from_itex (const char *itex, gssize size, GError **error);
55
55
  LsmMathmlDocument * lsm_mathml_document_new_from_itex_path (const char *url, GError **error);
56
56
  LsmMathmlDocument * lsm_mathml_document_new_from_itex_url (const char *url, GError **error);
57
57
 
@@ -254,7 +254,7 @@ lasem_test_render (char const *filename, gboolean compare, gboolean dry_run, Sta
254
254
  cairo_t *cairo;
255
255
  cairo_surface_t *surface;
256
256
  char *buffer = NULL;
257
- gsize size;
257
+ gssize size;
258
258
  char *png_filename;
259
259
  char *reference_png_filename;
260
260
  char *test_name;
@@ -300,7 +300,7 @@ lasem_test_render (char const *filename, gboolean compare, gboolean dry_run, Sta
300
300
  xml = buffer;
301
301
  else {
302
302
  xml = itex2MML_parse (buffer, size);
303
- size = 0;
303
+ size = -1;
304
304
  }
305
305
 
306
306
  timer = g_timer_new ();
@@ -33,7 +33,7 @@
33
33
  #include <cairo-pdf.h>
34
34
  #include <cairo-svg.h>
35
35
  #include <cairo-ps.h>
36
- #include "itex2MML.h"
36
+ #include "mtex2MML.h"
37
37
 
38
38
  #define CSTR2SYM(str) ID2SYM(rb_intern(str))
39
39
 
@@ -49,6 +49,64 @@ static VALUE rb_eDocumentCreationError;
49
49
  // Raised when the SVG document could not be read
50
50
  static VALUE rb_eDocumentReadError;
51
51
 
52
+ typedef enum {
53
+ FORMAT_SVG,
54
+ FORMAT_PNG,
55
+ FORMAT_MATHML
56
+ } FileFormat;
57
+
58
+ /**
59
+ * lsm_mtex_to_mathml:
60
+ * @mtex: (allow-none): an mtex string
61
+ * @size: mtex string length, -1 if NULL terminated
62
+ *
63
+ * Converts an mtex string to a Mathml representation.
64
+ *
65
+ * Return value: a newly allocated string, NULL on parse error. The returned data must be freed using @lsm_mtex_free_mathml_buffer.
66
+ */
67
+
68
+ char *
69
+ lsm_mtex_to_mathml (const char *mtex, gssize size)
70
+ {
71
+ gsize usize;
72
+ char *mathml;
73
+
74
+ if (mtex == NULL)
75
+ return NULL;
76
+
77
+ if (size < 0)
78
+ usize = strlen (mtex);
79
+ else
80
+ usize = size;
81
+
82
+ mathml = mtex2MML_parse (mtex, usize);
83
+ if (mathml == NULL)
84
+ return NULL;
85
+
86
+ if (mathml[0] == '\0') {
87
+ mtex2MML_free_string (mathml);
88
+ return NULL;
89
+ }
90
+
91
+ return mathml;
92
+ }
93
+
94
+ /**
95
+ * lsm_mtex_free_mathml_buffer:
96
+ * @mathml: (allow-none): a mathml buffer
97
+ *
98
+ * Free the buffer returned by @lsm_mtex_to_mathml.
99
+ */
100
+
101
+ void
102
+ lsm_mtex_free_mathml_buffer (char *mathml)
103
+ {
104
+ if (mathml == NULL)
105
+ return;
106
+
107
+ mtex2MML_free_string (mathml);
108
+ }
109
+
52
110
  cairo_status_t cairoSvgSurfaceCallback (void *closure, const unsigned char *data, unsigned int length) {
53
111
  VALUE self = (VALUE) closure;
54
112
  if (rb_iv_get(self, "@svg") == Qnil) {
@@ -60,21 +118,37 @@ cairo_status_t cairoSvgSurfaceCallback (void *closure, const unsigned char *data
60
118
  return CAIRO_STATUS_SUCCESS;
61
119
  }
62
120
 
121
+ cairo_status_t cairoPngSurfaceCallback (void *closure, const unsigned char *data, unsigned int length) {
122
+ VALUE self = (VALUE) closure;
123
+ if (rb_iv_get(self, "@png") == Qnil) {
124
+ rb_iv_set(self, "@png", rb_str_new2(""));
125
+ }
126
+
127
+ rb_str_cat(rb_iv_get(self, "@png"), data, length);
128
+
129
+ return CAIRO_STATUS_SUCCESS;
130
+ }
131
+
63
132
  static VALUE MATHEMATICAL_init(VALUE self, VALUE rb_Options) {
64
133
  Check_Type (rb_Options, T_HASH);
65
- VALUE rb_ppi, rb_zoom, rb_maxsize;
134
+ VALUE rb_ppi, rb_zoom, rb_maxsize, rb_format;
66
135
 
67
136
  rb_ppi = rb_hash_aref(rb_Options, CSTR2SYM("ppi"));
68
137
  rb_zoom = rb_hash_aref(rb_Options, CSTR2SYM("zoom"));
69
138
  rb_maxsize = rb_hash_aref(rb_Options, CSTR2SYM("maxsize"));
139
+ rb_format = rb_hash_aref(rb_Options, CSTR2SYM("format"));
70
140
 
71
141
  Check_Type(rb_ppi, T_FLOAT);
72
142
  Check_Type(rb_zoom, T_FLOAT);
73
143
  Check_Type(rb_maxsize, T_FIXNUM);
144
+ Check_Type(rb_format, T_STRING);
74
145
 
75
146
  rb_iv_set(self, "@ppi", rb_ppi);
76
147
  rb_iv_set(self, "@zoom", rb_zoom);
77
148
  rb_iv_set(self, "@maxsize", rb_maxsize);
149
+ rb_iv_set(self, "@format", rb_format);
150
+
151
+ rb_iv_set(self, "@png", Qnil);
78
152
  rb_iv_set(self, "@svg", Qnil);
79
153
 
80
154
  return self;
@@ -99,20 +173,30 @@ static VALUE MATHEMATICAL_process(VALUE self, VALUE rb_LatexCode) {
99
173
  g_type_init ();
100
174
  #endif
101
175
 
176
+ VALUE result_hash = rb_hash_new();
177
+ const char* rb_format = RSTRING_PTR(rb_iv_get(self, "@format"));
178
+
102
179
  // convert the TeX math to MathML
103
- char * mathml = lsm_itex_to_mathml(latex_code, latex_size);
104
- if (mathml == NULL) rb_raise(rb_eParseError, "Failed to parse itex");
180
+ char * mathml = mtex2MML_parse(latex_code, latex_size);
181
+ if (mathml == NULL) rb_raise(rb_eParseError, "Failed to parse mtex");
182
+
183
+ if (strncmp(rb_format, "mathml", 6) == 0) {
184
+ rb_hash_aset (result_hash, rb_tainted_str_new2 ("mathml"), rb_str_new2(mathml));
185
+ mtex2MML_free_string(mathml);
186
+ return result_hash;
187
+ }
105
188
 
106
189
  int mathml_size = strlen(mathml);
107
190
 
108
191
  LsmDomDocument *document;
109
192
  document = lsm_dom_document_new_from_memory(mathml, mathml_size, NULL);
110
193
 
111
- lsm_itex_free_mathml_buffer (mathml);
194
+ mtex2MML_free_string(mathml);
112
195
 
113
196
  if (document == NULL) rb_raise(rb_eDocumentCreationError, "Failed to create document");
114
197
 
115
198
  LsmDomView *view;
199
+ FileFormat format;
116
200
 
117
201
  double ppi = NUM2DBL(rb_iv_get(self, "@ppi"));
118
202
  double zoom = NUM2DBL(rb_iv_get(self, "@zoom"));
@@ -132,26 +216,51 @@ static VALUE MATHEMATICAL_process(VALUE self, VALUE rb_LatexCode) {
132
216
  cairo_t *cairo;
133
217
  cairo_surface_t *surface;
134
218
 
135
- surface = cairo_svg_surface_create_for_stream (cairoSvgSurfaceCallback, self, width_pt, height_pt);
219
+ if (strncmp(rb_format, "svg", 3) == 0) {
220
+ format = FORMAT_SVG;
221
+ surface = cairo_svg_surface_create_for_stream (cairoSvgSurfaceCallback, self, width_pt, height_pt);
222
+ }
223
+ else if (strncmp(rb_format, "png", 3) == 0) {
224
+ format = FORMAT_PNG;
225
+ surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
226
+ }
227
+
136
228
  cairo = cairo_create (surface);
137
229
  cairo_surface_destroy (surface);
138
230
  cairo_scale (cairo, zoom, zoom);
139
231
  lsm_dom_view_render (view, cairo, 0, 0);
140
232
 
233
+ switch (format) {
234
+ case FORMAT_PNG:
235
+ cairo_surface_write_to_png_stream (cairo_get_target (cairo), cairoPngSurfaceCallback, self);
236
+ break;
237
+ default:
238
+ break;
239
+ }
240
+
141
241
  cairo_destroy (cairo);
142
242
  g_object_unref (view);
143
243
  g_object_unref (document);
144
244
 
145
- if (rb_iv_get(self, "@svg") == Qnil) rb_raise(rb_eDocumentReadError, "Failed to read SVG contents");
146
-
147
- VALUE result_hash = rb_hash_new();
245
+ switch (format) {
246
+ case FORMAT_SVG:
247
+ if (rb_iv_get(self, "@svg") == Qnil) rb_raise(rb_eDocumentReadError, "Failed to read SVG contents");
248
+ rb_hash_aset (result_hash, rb_tainted_str_new2 ("svg"), rb_iv_get(self, "@svg"));
249
+ break;
250
+ case FORMAT_PNG:
251
+ if (rb_iv_get(self, "@png") == Qnil) rb_raise(rb_eDocumentReadError, "Failed to read PNG contents");
252
+ rb_hash_aset (result_hash, rb_tainted_str_new2 ("png"), rb_iv_get(self, "@png"));
253
+ break;
254
+ default:
255
+ break;
256
+ }
148
257
 
149
258
  rb_hash_aset (result_hash, rb_tainted_str_new2 ("width"), INT2FIX(width_pt));
150
259
  rb_hash_aset (result_hash, rb_tainted_str_new2 ("height"), INT2FIX(height_pt));
151
- rb_hash_aset (result_hash, rb_tainted_str_new2 ("svg"), rb_iv_get(self, "@svg"));
152
260
 
153
261
  // we need to clear out this key when attempting multiple calls. See http://git.io/i1hblQ
154
262
  rb_iv_set(self, "@svg", Qnil);
263
+ rb_iv_set(self, "@png", Qnil);
155
264
 
156
265
  return result_hash;
157
266
  }