Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LaTeX without npm #448

Open
davibarreira opened this issue Dec 13, 2021 · 15 comments
Open

LaTeX without npm #448

davibarreira opened this issue Dec 13, 2021 · 15 comments
Labels
enhancement New feature or request

Comments

@davibarreira
Copy link

Hello Javis developers. This is actually a tip. I've been playing around with Luxor, and I've implemented LaTeX without the need to install LaTeX in the users computer. To do so, I've used the package MathTeXEngine.jl. This awesome package is the one used by Makie to write LaTeX. Here is my implementation for a package that I'm working on

"""
    latex_text_size(lstr::LaTeXString)
Returns the width and height of a latex string.
"""
function latex_text_size(lstr::LaTeXString)
    sentence = generate_tex_elements(lstr)
    els = filter(x -> x[1] isa TeXChar, sentence)
    chars = [x[1].char for x in els]
    fonts = [x[1].font for x in els]
    pos_x = [x[2][1] for x in els]
    pos_y = [x[2][2] for x in els]
    scales = [x[3] for x in els]
    extents = [get_extent(f, c) for (f, c) in zip(fonts, chars)]

    textw = []
    texth= []
    for i in 1:length(extents)
        textw = push!(textw,height_insensitive_boundingbox(extents[i], fonts[i]).widths[1]*scales[i]+pos_x[i])
        texth = push!(texth,height_insensitive_boundingbox(extents[i], fonts[i]).widths[2]*scales[i]-pos_y[i])
    end
    return (maximum(textw), maximum(texth))
end


"""
    Luxor.text(lstr::LaTeXString, valign=:baseline, halign=:left; kwargs...)
Draws LaTeX string using `MathTexEngine.jl`. Hence, uses ModernCMU as font family.
Note that `valign` is not perfect.
This function assumes that the axis are in the standard Luxor directions,
i.e. ↓→.
"""
function Luxor.text(lstr::LaTeXString, pt::Point; valign=:baseline, halign=:left, kwargs...)

    # Function from MathTexEngine
    sentence = generate_tex_elements(lstr)

    # Get current font size.
    textsize = get_fontsize()

    textw, texth = latex_text_size(lstr)
    
    if halign === :left
        translate_x = 0
    elseif halign === :right
        translate_x = -textw * textsize
    elseif halign === :center
        translate_x = -textw/2 * textsize
    end
    
    if valign === :baseline
        translate_y = 0
    elseif valign === :top
        translate_y = -textsize
    elseif valign === :bottom
        translate_y = texth * textsize
    elseif valign === :middle
        translate_y = textsize/2
    end

    # Writes text using ModernCMU font.
    for text in sentence
        if text[1] isa TeXChar
            @layer begin
                translate(translate_x,translate_y)
                fontface(text[1].font.family_name)
                fontsize(textsize*text[3])
                Luxor.text(string(text[1].char), pt + Point(text[2]...)*textsize*(1,-1))
            end
        elseif text[1] isa HLine
            @layer begin
                translate(translate_x,translate_y)
                pointstart = pt+Point(text[2]...)*textsize*(1,-1)
                pointend = pointstart + Point(text[1].width,0)*textsize
                setline(1*text[1].thickness*textsize)
                line(pointstart, pointend,:stroke)
            end
        end
    end
end
@davibarreira davibarreira added the enhancement New feature or request label Dec 13, 2021
@Wikunia
Copy link
Member

Wikunia commented Dec 13, 2021

Awesome. Thanks a lot! Hopefully this will fix also our #212 issue 😅 I'll have a look at integrating this into Javis

@davibarreira
Copy link
Author

No problem! I suggested adding the LaTeX support directly to Luxor, but since it requires adding MathTeXEngine as a dependency, it was reject. I do understand though. So hopefully those of use who need LaTeX can add this small chunk of code and move on.

BTW, this is not a perfect implementation. There is some small issues with aligning. Feel free to improve on this code, so I can steal it back 😁

@Wikunia
Copy link
Member

Wikunia commented Dec 13, 2021

Haha sounds good. Yeah we would have the ability to have an extra JavisLatex package otherwise but I think for us it makes sense to directly integrate it.

@TheCedarPrince
Copy link
Member

Out of curiosity, how does this work?
Does it use the artifact system to package it within the Julia ecosystem?
I've been looking into Tectonic so was curious if this was used under the hood or what was.
Regardless, thanks @davibarreira and great to cross paths again!
Hope all has been well!

@davibarreira
Copy link
Author

Hey @TheCedarPrince ! Yeah, I still owe you the answers for Chapter 2. Finished reading it, but haven't implemented. End of semester, things are chaotic again.
About MathTeXEngine. Not an expert at all, but from what I understood, the package uses the CMU font and maps the LaTeX commands to the respective unicode characters. In other words, it's just a smart way to turning latex into unicode.
Here is a more detailed account:
MathTeXEngine parses your LaTeXString from left to right. Each latex symbol is transformed in either a unicode, a vertical line or a horizontal line, and also returns the position of the object. Take the following example:

L"\frac{\mu}{x}"

Now, MathTexEngine will recognize that the "\frac{}{}" will generate a horizontal line in a position, say (0,5), meaning that it's at the start of the string and at the middle in terms of vertical alignment. Next, it will parse to you that "\mu" is actually the unicode for \mu, at position (0,6). Finally, "x" is just "x" at position (0,-6).

This is what it returns

horizontal_line at (0,5)
\mu unicode at (0, 6)
x at (0,-6)

Now you do you :) I mean, it's your job to draw this. This is where my functions come from. I use Luxor to draw this with SVG.
Hope it's clear.

@cormullion
Copy link
Contributor

LaTeX support directly to Luxor, but since it requires adding MathTeXEngine as a dependency, it was reject.

It's an open issue (JuliaGraphics/Luxor.jl#124) and not rejected. 😂

@TheCedarPrince
Copy link
Member

Hey @Wikunia , I extensively tested @davibarreira 's suggestion and I can confirm, using his solution is completely feasible.
I think the approach will actually be soon added into the issue @cormullion referenced, which, if so, only means that a user would have to install Lyx fonts onto their computer and not all of LaTeX nor fiddle with npm.
A much easier solution I'd imagine!

@Wikunia
Copy link
Member

Wikunia commented Dec 28, 2021

Great thanks for testing @TheCedarPrince will it be integrated into Luxor or another package or do we have to do it in Javis directly?

@davibarreira
Copy link
Author

It should be integrated into Luxor.jl with Requires.jl.

@davibarreira
Copy link
Author

It should be integrated into Luxor.jl with Requires.jl.

The idea is to extend Luxor.text to be used on LaTeXStrings. So things should work almost out of the box. The only requirements will probably be that the user will need to install CMU font, and MathTeXEngine.jl needs to be loaded, since the dependency will not be hard coded.
If you wish Javis users to be able to use it without loading MathTeXEngine, you could make it a dependency in you package and load it.

@TheCedarPrince
Copy link
Member

TheCedarPrince commented Jan 3, 2022

Hey @Wikunia, @cormullion, and @davibarreira !
After some tinkering thanks to Davi's awesome work on this, here is so far what I have found being able to be rendered using MathTeXEngine: https://github.com/Kolaru/MathTeXEngine.jl#supported-constructions

A more visual example that I made is here:

image

However, it would appear that MathTeXEngine cannot yet fully subsume all parts of LaTeX just yet.
One crucial aspect is the lack of rendering matrices as seen here: Kolaru/MathTeXEngine.jl#48
That unfortunately makes it so we cannot replace the LaTeX parsing system in Javis yet as we would be unable to support morphing.

However, as you were suggesting earlier, actually, @Wikunia , I would rather advocate to create a new package in the JuliaAnimators called like JavisTeX or JavisLaTeX to move some of this code from out of core Javis to other modules.
Just thinking it might make hacking on things easier (especially for new contributors) and more accessible to figure out LaTeX support in Javis.
What do you think?

@davibarreira
Copy link
Author

@TheCedarPrince , perhaps improving MathTeXEngine is a better route. It doesn't seem like supporting matrices would be hard.

@davibarreira
Copy link
Author

Oh, I just saw that you opened an issue. Nice!
I myself am thinking of contributing to MathTeXEngine. So I might try to implement the matrix notation.

@TheCedarPrince
Copy link
Member

TheCedarPrince commented Jan 3, 2022

I'll follow-up with you over at the issue here @davibarreira : Kolaru/MathTeXEngine.jl#48

But, I was thinking about having a Javis TeX package for at least a staging ground for experimentation and development of Javis specific TeX handling.
Plus with JSoC coming up, might be a good area for folks to contribute to potentially. :)

@asinghvi17
Copy link

asinghvi17 commented May 22, 2022

From #483 which I opened too soon, another alternative is to:
Use an approach similar to the old one from MakieTeX.jl (latexstring/latex document -> compiled latex as pdf -> SVG through dvisvgm). There is a lightweight TeX compiler one can use which is called tectonic, which also ships as a JLL.

The reason I have used this complicated pipeline as opposed to MathJax is because it allows the user to use arbitrary LaTeX packages (like amsmath, physics, tikz, lstlistings, et cetera. Arbitrary custom commands are also supported as a consequence, so one can paste sections of preamble from their paper and have identical LaTeX in their figures.

I have switched MakieTeX to use Poppler to render direct from PDF now, but you can see the old implementation in v0.0.4.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

5 participants