|
Introduction
If you own applications such as Blogs, Forums or Wiki and strive to delight your customers with every new release, you probably don't need justification for this feature. In this article, I'll show you how you can allow your users to type in math equations and have them rendered in nice textbook format with absolutely minimal coding effort on your part.
The basic idea is to let the user type in something like this: <img src=".?$ x^2 = 25 $">
The above request first goes to your default.aspx file, where a line of code detects if it's a request for an image and transfers it to a handler. The handler uses MimeTeX to generate the GIF file for the equation and returns to the browser. Fortunately, you don't have to care about any of these, as it's all wrapped and ready for drag and drop.
If you are responsible for any of these types of applications, you owe it to your users to give them this ability:
- Blogs
- Forums
- Wiki
- Email apps
- Instant messengers
- HTML editors
- Word processing
Essentially, any application that ultimately renders user content in graphical form can add this feature. It doesn't have to be HTML content. For instance, a note-keeping software can detect the TeX content during editing surrounded by $ markers and replace them with a nice graphical form. It can use the exact same library given in this article for this purpose.
Tip:
How to show equations without any coding or even having your own server?
If you don't want to deploy and maintain code in this article, you can use my server for free. You can also use it on ANY blogs, Wikis or websites which do not support TeX and math equations.
To use my server, append http: by the equation you want. Here's an example:
<img src="http://www.shitalshah.com?$ x^2 = 25 $">
Give it a try! |
Background
MimeTeX is the guts of this code. MimeTeX is written by John Forkosh to mainly run under UNIX and as a CGI EXE under Windows. Obviously, while this works, it has many disadvantages like you have to have an ability to run a CGI EXE on IIS, which is a difficult feature for shared IIS hosting. Even if you have a dedicated server, the CGI EXE solution won't scale if you want to support thousands of users. Also, users would be required to add mimetex.exe into the image tag's source, which is less intuitive for users of applications like Blogs or Forums.
For this reason, I decided to convert the MimeTeX code into a Win32 DLL. This is a pretty simple task of taking C files, creating a VC++ Win32 DLL project, adding a DLL export and making other minor changes. But the bigger problem comes later: the DLL runs in-process and hence we should make sure that the C code is free from memory leaks. Unfortunately, this wasn't the case, but fortunately the debug functions like _CrtDumpMemoryLeaks and the VC++ IDE made it a little easier to find them. So, after a weekend's effort, this uncharted UNIX code was free from all known memory leaks. Over the next couple of weeks, John Forkosh and I were exchanging long emails discussing the 10 lines of changes I had made, analyzing them, perfecting them and thoroughly testing the code. It was great fun. The result was the MimeTeX Win32 DLL, which you can now call from your .NET code using DLLImport.
My next step was to create the ASP.NET IHttpHandler that would wrap this call, add caching on top of it and allow other customizations and admin functionality.
Using the Code
You can use this code in three ways:
- Integrate with your own web apps
Download the code, add the files in the folder named OnlyRequiredFiles (For VB.NET, look under the VB.NET Version folder) into your ASP.NET project and drop the MimeTex.DLL in the bin folder. Edit your default.aspx page and put this line somewhere in Page_Load or Page_Init (if you are using custom page templates):
Astrila.Eq2Img.ShowEq.HandleEquationQueries();
Recompile! Make sure the CachedEqImages folder exists and the ASP.NET user has write permissions for it. That's all there is! You may now create an HTML file in the virtual root folder with an example image tag the same as the one shown at the start of this article for testing.
- Use as a separate web app
Copy the Eq2Img folder in your wwwroot. Create a virtual folder, make sure the CachedEqImages folder exists and the ASP.NET user has write permissions for it, and that default.aspx is configured as the default page. You should now be up and running! Remember, your users would need to reference this virtual folder in the image tags like this: <img src="Eq2Img?$ x^2 = 25 $">
- Use in desktop apps
This is pretty easy. You just need to DLLImport MimeTex.DLL and call the CreateGifForEq function from your Windows Forms app like this:
[System.Runtime.InteropServices.DllImport("MimeTex.dll")]
internal static extern int CreateGifFromEq(string expr,
string fileName);
You can look into a sample Windows Forms app in the Eq2ImgWinForms folder, which looks like this:
The next question might be what is the format of the equations? How do you write Greek symbols, integrals, limits and so on? The format is known as TeX (or LaTeX) and you might be familiar with it if you have ever authored a scientific document in your school years. If not, it's a pretty simple format to learn. For instance, to display the pi symbol you just write \pi and to display the integration sign you write \int and so on. You can find good documentation here and here, but if you choose to be lazy, just use the free WYSWYG equation editor called TeXAide which will build the TeX string for you. Note that TeX ignores white spaces.
Points of Interest
You might have noticed that MimeTeX goes beyond just supporting the equations conforming to TeX format. For instance, you can also create sophisticated figures using LaTeX commands such as the following:
This is really cool because this feature allows your users to author scientific content just with MimeTeX. More examples are at John's website.
I've also thrown in some admin functionality to let you delete cache files (these are very small, typically 1 KB JPG files). You can access this using Eq2ImgAdmin.aspx. This page also lets you dynamically unload the MimeTeX DLL. Remember that this is a pure Win32 DLL, so it gets locked by the ASP.NET process once it gets loaded, unlike managed .NET DLLs. That means you can't update the DLL without restarting the IIS, an unfortunate scenario for shared hosting or even otherwise. To solve this problem, the admin page allows you to dynamically unload this unmanaged DLL from the process on demand. For the technically curious, I simply used GetModuleHandle and FreeLibrary Windows API calls. The admin functionality by default is not enabled. Follow the messages it shows to enable it. Also note that you can exclude this page completely without losing the core functionality.
The code supports a bunch of customization settings that you can put in web.config. By default none are required, but if you prefer, for example, you can choose to run MimeTeX out of the process instead of in-proc or you can run it as CGI or from an external URL. You can set the maximum length of equation strings and maximum cache size and cache folder and so on. I haven't got enough time to document them, but they are easy to figure out from the class Eq2ImgSettings and they all take the form:
<appSettings>
<add key="Eq2Img_ClientCacheAgeInSeconds" value="200" />
</appSettings>
Finally, here's the security disclosure you all have been waiting for: you are running unmanaged code from ASP.NET when you call into the MimeTeX DLL. That means ASP.NET should have sufficient permission for this (by default it does). However, the bigger concern is the possible nasty C bugs such as memory leaks and invalid pointers that might make your website unstable. In my testing, it does work satisfactorily; the in-proc mode is very scalable and MimeTeX itself has been in use on many websites since 2002. However, if you ever notice a problem, you do have an exit strategy of setting an option in your web.config file so that MimeTeX will run out of process or even completely disable it and serve only the cached files. As MimeTeX is an open source project, anyone has the liberty to fix the bugs as soon as they are found.
Need Help?
I'm passionate about enabling the web to allow users to author scientific content. If you have any problems using this code in your application, you can contact me for free assistance.
History
- 23rd August, 2005 - Newly created.
- 24th August, 2005 - Fixed a concurrency bug, created VB.NET version of the code.
- 30th January, 2008 - Article content updated
| You must Sign In to use this message board. |
|
| | Msgs 1 to 25 of 48 (Total in Forum: 48) (Refresh) | FirstPrevNext |
|
|
 |
|
|
 |
|
|
 |
|
|
Great work! Out of curiosity, is your mimetex.dll compiled with the anti-aliasing option? The resulting text looks like it could be quite a bit smoother. And if I try doing white text on a black background, the result is really bad looking. These are small gripes for an otherwise excellent effort.
I've been looking for a way to write a Compact Framework application that uses LaTeX, and this allows me to do that. I would have preferred having that functionality built into the app, but sending a webrequest to a website to fetch the image works well enough.
Any chance of you releasing the source code for the mimetex.dll?
Thanks again!!
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
When I try to compile the MimeTeX solution I get the following error: "MimeTeX error LNK2001: unresolved external symbol _gifSize"
Sounds like I'm missing a file if the linker can't resolve a symbol.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
 |
|
|
The DLL declaration MimTeX.dll in Visual Basic 6, parameter passing is causing problems. I get "run-time error 49: Bad DLL calling convention"
Declare Function CreateGifFromEq Lib "MimeTex.dll" (ByVal expr As String, ByVal FileName As String)
Thanks, -- Igor
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Dear Igorpett,
Since MimTeX.dll uses C-calling convention, we cannot call its function directly. Try the following code. I hope you can solve the matter. Best regards, Nguyen Quoc San quocsan@gmail.com (From Vietnam)
' (I got this module somewhere in the Internet and I forget the author. Sorry!) ' ~~~ Start of Code
' Module : RunDLL.Bas ' For calling C-type DLL ' Option Explicit Public Enum DECLSPEC eStdCall = 0 eCDecl End Enum Private Declare Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" (ByVal lpLibFileName As String) As Long Private Declare Function GetProcAddress Lib "kernel32" _ (ByVal hModule As Long, ByVal lpProcName As String) As Long Private Declare Function CallWindowProc Lib "User32" Alias "CallWindowProcA" ( _ ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal Msg As Long, _ ByVal wParam As Long, ByVal lParam As Long) As Long Private Declare Function FreeLibrary Lib "kernel32" (ByVal hLibModule As Long) As Long Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _ (lpDest As Any, lpSource As Any, ByVal cBytes As Long) Private m_opIndex As Long Private m_OpCode() As Byte 'Assembly OPCODE Public Function RunDll32(ByVal LibFileName As String, ByVal ProcName As String, _ ByVal CallingType As DECLSPEC, ParamArray Params()) As Long Dim hProc As Long, hModule As Long ReDim m_OpCode(400 + 6 * UBound(Params)) ' m_OpCode hModule = LoadLibrary(ByVal LibFileName) ' API If hModule = 0 Then MsgBox "Unable to load library'" & LibFileName & "'" Exit Function End If hProc = GetProcAddress(hModule, ByVal ProcName) If hProc = 0 Then: FreeLibrary hModule: Exit Function: RunDll32 = CallWindowProc(GetCodeStart(hProc, CallingType, Params), 0, 1, 2, 3) ' Assembly Code FreeLibrary hModule End Function Private Function GetCodeStart _ (ByVal lngProc As Long, ByVal CallingType As DECLSPEC, ByVal arrParams As Variant) As Long Dim i As Long, lCodeStart As Long lCodeStart = (VarPtr(m_OpCode(0)) Or &HF) + 1 m_opIndex = lCodeStart - VarPtr(m_OpCode(0)) For i = 0 To m_opIndex - 1 m_OpCode(i) = &HCC ' INT 3 Next i PrepareStack For i = UBound(arrParams) To 0 Step -1 AddByteToCode &H68 'PUSH AddLongToCode CLng(arrParams(i)) Next i AddByteToCode &HE8 ' CALL = HE8 AddLongToCode lngProc - VarPtr(m_OpCode(m_opIndex)) - 4 If CallingType = eCDecl Then Call ClearStack(arrParams) AddByteToCode &HC3 ' RET AddByteToCode &HCC GetCodeStart = lCodeStart End Function Private Sub ClearStack(ByVal Params As Variant) Dim i As Long For i = 0 To UBound(Params) AddByteToCode &H59 ' pop ecx - remove params from stack Next End Sub Private Sub PrepareStack() AddByteToCode &H58 ' pop eax - pop return address AddByteToCode &H59 ' pop ecx - kill hwnd AddByteToCode &H59 ' pop ecx - kill wmsg AddByteToCode &H59 ' pop ecx - kill wParam AddByteToCode &H59 ' pop ecx - kill lParam AddByteToCode &H50 ' push eax - put return address back End Sub Private Sub AddLongToCode(lData As Long) ' Long m_OpCode CopyMemory m_OpCode(m_opIndex), lData, 4 m_opIndex = m_opIndex + 4 End Sub Private Sub AddByteToCode(bData As Byte) ' Byte m_OpCode m_OpCode(m_opIndex) = bData m_opIndex = m_opIndex + 1 End Sub '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ' Module" EQ.bas Option Explicit Private Declare Function GetTempFileName Lib "kernel32" Alias "GetTempFileNameA" (ByVal lpszPath As String, ByVal lpPrefixString As String, ByVal wUnique As Long, ByVal lpTempFileName As String) As Long Private Declare Function GetTempPath Lib "kernel32" Alias "GetTempPathA" (ByVal nBufferLength As Long, ByVal lpBuffer As String) As Long Private Const MAX_PATH = 260
Function GetTempFile() As String Dim temp_path As String Dim temp_file As String Dim Length As Long ' Get the temporary file path. temp_path = Space(MAX_PATH) Length = GetTempPath(MAX_PATH, temp_path) temp_path = Left(temp_path, Length) ' Get the file name. temp_file = Space(MAX_PATH) GetTempFileName temp_path, "tmp", 0, temp_file GetTempFile = Left(temp_file, InStr(temp_file, vbNullChar) - 1) End Function
' ?Eq2img("ax^3+bx^3+cx=0", "d:\xx.gif") Function Eq2Img(ByVal sEQ As String, ByVal sPath As String) As Boolean Call RunDll32("MimeTeX.dll", "CreateGifFromEq", eCDecl, StrPtr(StrConv(sEQ, vbFromUnicode)), StrPtr(StrConv(sPath, vbFromUnicode))) Eq2Img = Len(Dir(sPath)) > 0 End Function
Sub Eq2GIF() If Windows.count < 1 Then Exit Sub Dim sPath As String, sEQ As String sEQ = Trim(Selection.Text) Selection.Text = " " sPath = GetTempFile If Len(sPath) = 0 Then Exit Sub If Not Eq2Img(sEQ, sPath) Then Exit Sub ' ActiveDocument.Shapes.AddPicture(Anchor:=Selection.Range, FileName:= _ sPath, LinkToFile:=False, SaveWithDocument:=True).WrapFormat.Type = _ wdWrapTopBottom Dim iSh As InlineShape Set iSh = ActiveDocument.InlineShapes.AddPicture(Filename:=sPath, Range:=Selection.Range) Set iSh = Nothing Application.StatusBar = "Converted from """ & sEQ & """. Undo if you need." Call Kill(sPath) End Sub ' ~~~ End of Code
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
With the help of your source code, I can write Math Equations in my web now. Thanks a lot! Thank you very much!
|
| Sign In·View Thread·PermaLink | 1.00/5 (1 vote) |
|
|
|
 |
|
|
If you want to build it for yourself, you'll need the project from
http://www.shitalshah.com/dev/eq2img_all.zip
but with gifsave.c from http://www.forkosh.com/mimetex.zip
|
| Sign In·View Thread·PermaLink | 5.00/5 (1 vote) |
|
|
|
 |
|
|
Hello,
do you have an solution to create the image in a winform app directly to a stream or an Image without saving a temp File?
Thank Thomas
P.S. I asked this question a time before, but now I need the functinallity urgend.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
I'm trying to opne the project with Visual Studio 2005 and I can't (the conversor fails). Can you help me, please?
|
| Sign In·View Thread·PermaLink | 1.00/5 (2 votes) |
|
|
|
 |
|
|
Thanks for your code but in my application I draw onto metafiles to ensure that my output is scalable.
Do you know of anyway that I can do something similar to your project here but create perhaps EMFs instead of GIFs?
Otherwise is there anyway to change your code so that the created GIF is sized to a specific size?
Thanks!
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hi There, I'm trying to get mimeTex working on my wintel box. mimeTex.exe works fine from the command line but not any other way I have tried.
I am using two approaches: a) web server (badblue) and b) calling CreateGifFromEq in MS Access. Neither works...
Badblue -- this is a simple web server, it works! Using a simple HTML file I get the following results:
<img src="mimetex.exe?x=\frac{-b\pm\sqrt{b^2-4ac}}{2a}"> --> no image <img src="http://www.forkosh.com/mimetex.cgi?c=\sqrt{a^2+b^2}" alt="" border=0 align=middle> --> works fine
In IE, this URL --> http://127.0.0.1/mimetex.exe?y=x^2 produces the following in the browser, rather than the rendered formula: Cache-Control: max-age=7200 Content-type: image/gif GIF87a(óÿÿÿßßßÚÚÚÕÕÕÊÊÊÅÅÅ¿¿¿ººº555000%%% !ù,(iÈI«½78°ÿž3 hž%žì·¶0%¬hñ”0‹ƒLš`v(9”rù*ŠÂJ4qŽªœÄ!PH†Wªk:¾äÜ"¡ÂÈ$s™$(RPM¡½9=By}-V6…,5‚‰;
MS Access -- The DLL declaration is OK, and the entry point is recognised, but the parameter passing is causing problems. I get "run-time error 49: Bad DLL calling convention"
I looked at mimetex.c, and noticed the following: #if defined(_USRDLL) extern _declspec(dllexport)int _cdecl CreateGifFromEq ( char *expression, char *gifFileName ); #endif
Looking further up in the code indicates that _USRDLL is defined on windows systems, so the _cdecl calling convention needs to be used. But, according to some very old (c. 1996) MSDN documentation:
"It is not possible to directly call a C function in a DLL if that function uses the _cdecl calling convention. This is because Visual Basic uses the _stdcall calling convention for calling functions. This is a problem because if _cdecl is used, the calling function is responsible for cleaning up the stack. However, if _stdcall is used, the called function is responsible for cleaning up the stack."
Please help if at all possible.
Thanks,
-- Hossein
P.S. I have limited development capability although I understand coding and S/W dev in general pretty well.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
I don't know anything about Windows development, so I can't address your dll remarks. But I've seen users with mimetex problems similar to yours. Note that "Cache-Control...GIF87a..." is indeed mimetex output, emitted only when the gif image is ready. So it looks to me like mimetex successfully ran to completion. What seems to be wrong is that your server is interpreting the emitted bytes as an ascii string rather than as a gif image. Depending on your server and its configuration, you sometimes (at least on Unix systems) have to edit your .htaccess file and add a line like AddType application/x-httpd-cgi .exe Judging from your output, I'd hazard a guess that you're having an analogous Windows problem. John Forkosh
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
The guys at CodeProject.com seems to be taking way loooooong time to upload the code updates I sent them (surprisingly emailing is currently the ONLY way to do that!). Meanwhile you can download the latest updated code from my website. This URL will always have the latest distribution.
http://www.shitalshah.com/dev/eq2img_all.zip
Regards, Shital. http://www.ShitalShah.com
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
I am wanting to display my mathmatical formula in a windows application I have developed. I am thinking that LaTex is the solution. I read the article but had no luck getting to work, plus it seems to be for the users use and not programmers. Any Help or Suggestions?
|
| Sign In·View Thread·PermaLink | 1.00/5 (1 vote) |
|
|
|
 |
|
|
The article is indeed targetted for programmers. Tell me more about how you want to show equations in the application you have developed. TeX definitely is a great solution for such task. You can also write to me offlist at sytelus@yahoo.com.
Regards, Shital. http://www.ShitalShah.com
|
| Sign In·View Thread·PermaLink | 2.00/5 (1 vote) |
|
|
|
 |
|
|
Hi,
is there a way to build a winform example as yours without writing the gif to a temp file?
Thanks
Thomas
|
| Sign In·View Thread·PermaLink | 1.00/5 (1 vote) |
|
|
|
 |
|
|
Yes, it is possible to do it but the functionality is currently not exposed through API. JohnF has added this enhancement in the MimeTeX code but its not .Net compatible. It would require just a little bit of more work to add this in API in MimeTeX DLL and ultimately it will return the image in GIF format as an byte array without creating any temp files. I can code it up if you really need it!
Regards, Shital. http://www.ShitalShah.com
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hello, I would have really needed it if I could more easily ajust the fonts. See my second question. So it doesn't fit in our look and feel so I do not need it the moment. Thank you very much for your help.
Thomas
|
| Sign In·View Thread·PermaLink | 2.00/5 (1 vote) |
|
|
|
 |
|
|
 |
|
|
General News Question Answer Joke Rant Admin
|