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

Padding and Background #417

Open
seghier opened this issue Jun 11, 2023 · 9 comments
Open

Padding and Background #417

seghier opened this issue Jun 11, 2023 · 9 comments
Assignees

Comments

@seghier
Copy link

seghier commented Jun 11, 2023

Hi
The padding area remain transparent , is there a solution for that?
image

@ForNeVeR
Copy link
Owner

What's the input formula? What do you mean by the "padding area"?

@seghier
Copy link
Author

seghier commented Jun 11, 2023

I mean this (space), you called it (x,y)

var pngBytes = latexformula.RenderToPng(40.0, space, space, "Arial");

The background color applied to the bounds of the png and the rest of image remain transparent.

Any formula does not matter: \matrix{1 & 2 & 3 \\ 4 & 5 & 6}

@ForNeVeR
Copy link
Owner

And you set the background by calling Box.SetBackground, right?

@seghier
Copy link
Author

seghier commented Jun 11, 2023

I use this way:

using System.IO;
using WpfMath.Parsers;
using WpfMath;
using System.Windows.Media;
using XamlMath.Exceptions;

private void ConvertLatex(string formula, string fileName, System.Drawing.Color textClr, System.Drawing.Color backClr, double scale, double space)
try
    {
      var parser = WpfTeXFormulaParser.Instance;
      var latexformula = parser.Parse(formula);

      var mediaTextClr = System.Windows.Media.Color.FromRgb(textClr.R, textClr.G, textClr.B);
      var textsolidbrush = new System.Windows.Media.SolidColorBrush(mediaTextClr);
      var textBrush = WpfMath.Rendering.WpfBrush.FromBrush(textsolidbrush);
      latexformula.SetForeground(textBrush);

      var mediaBackClr = System.Windows.Media.Color.FromArgb(backClr.A, backClr.R, backClr.G, backClr.B);
      var backsolidbrush = new System.Windows.Media.SolidColorBrush(mediaBackClr);
      var backBrush = WpfMath.Rendering.WpfBrush.FromBrush(backsolidbrush);
      latexformula.SetBackground(backBrush);

      var pngBytes = latexformula.RenderToPng(scale, space, space, "Arial");
      File.WriteAllBytes(fileName, pngBytes);
    catch (TexException e)
    {
      Error = "Error when parsing formula: " + e.Message;
    }

@ForNeVeR
Copy link
Owner

ForNeVeR commented Jun 12, 2023

First things first, for further investigation, here's a full snipped I was able to somewhat reproduce the issue with:

    private void DoTest()
    {
        var parser = WpfTeXFormulaParser.Instance;
        var latexformula = parser.Parse(@"\matrix{1 & 2 & 3 \\ 4 & 5 & 6}");

        var mediaTextClr = System.Windows.Media.Color.FromRgb(0, 0, 0);
        var textsolidbrush = new System.Windows.Media.SolidColorBrush(mediaTextClr);
        var textBrush = WpfMath.Rendering.WpfBrush.FromBrush(textsolidbrush);
        latexformula.SetForeground(textBrush);

        var mediaBackClr = System.Windows.Media.Color.FromArgb(0xff, 0xff, 0, 0);
        var backsolidbrush = new System.Windows.Media.SolidColorBrush(mediaBackClr);
        var backBrush = WpfMath.Rendering.WpfBrush.FromBrush(backsolidbrush);
        latexformula.SetBackground(backBrush);

        var pngBytes = latexformula.RenderToPng(100, 10, 10, "Arial");
        File.WriteAllBytes(@"T:\Temp\foo.png", pngBytes);
    }

For whatever reason, this adds a padding of about 10 transparent pixels around the whole image.

(while I'd expect that to only move it from the top left corner by 10 px, and not add padding around everything)

Notably, even after replacing latexformula.RenderToPng(100, 10, 10, "Arial") with latexformula.RenderToPng(100, 0, 0, "Arial"), I didn't get a clean image, see this:
image

There's apparently one transparent pixel to the right and one semi-transparent to the bottom.

The core reason is that the image consists of various primitives, and SetBackground only changes the color of the root primitive, and not of the whole image.

Ideally, the bounding box of the root primitive would be the same as the whole image (well, without this weird padding), but in reality apparently it is not.

So, my first advice is to remove the padding from your call to RenderToPng, that should make it significantly better.

I have an idea how to make it even better, but it would be much easier if we provided a method requested in #289.

My idea is to just create a canvas filled with the background color, and then add the result generated by WPF-Math to it. This is doable, but I've tried to write some code using a (horrible) WriteableBitmap WPF API, and I am sorry but I failed. It's already 23:00 in my time zone, I am very tired, and so you'll have to do it yourself for now if that's required :(

I am leaving the issue open because we'll need to think on how to improve the API to provide better background handling. And also, yeah, implement the API for #289.

@seghier
Copy link
Author

seghier commented Jun 12, 2023

Thank you very much fo you work and effort
I tried to create images using this way to save: jpg, bmp which add white background automatically

using(Image image = Image.FromStream(new MemoryStream(pngBytes)))
        {
          image.Save(fileName, imageFormats[fileType]);
        }

image

And the new update works well now

latex.mp4

@ygra
Copy link
Contributor

ygra commented Jun 13, 2023

My idea is to just create a canvas filled with the background color, and then add the result generated by WPF-Math to it. This is doable, but I've tried to write some code using a (horrible) WriteableBitmap WPF API, and I am sorry but I failed.

Having semi-recently rewritten the image export code (using WriteableBitmap) at work to work properly, I could take a look if you want. I would expect things based on a Drawing to be significantly less problematic in practice than a few thousand FrameworkElements.

@seghier
Copy link
Author

seghier commented Jun 13, 2023

Hi
I use this way to fill the trasnparent area and it work fine

Bitmap CreateImage(string strLatex, double scale, double space, System.Drawing.Color tcolor, System.Drawing.Color bcolor)
  {
    Bitmap bmp;


    var parser = WpfTeXFormulaParser.Instance;
    var latexformula = parser.Parse(strLatex);

    var mediaTextClr = System.Windows.Media.Color.FromRgb(tcolor.R, tcolor.G, tcolor.B);
    var textsolidbrush = new System.Windows.Media.SolidColorBrush(mediaTextClr);
    var textBrush = WpfMath.Rendering.WpfBrush.FromBrush(textsolidbrush);
    latexformula.SetForeground(textBrush);

    var mediaBackClr = System.Windows.Media.Color.FromArgb(bcolor.A, bcolor.R, bcolor.G, bcolor.B);
    var backsolidbrush = new System.Windows.Media.SolidColorBrush(mediaBackClr);
    var backBrush = WpfMath.Rendering.WpfBrush.FromBrush(backsolidbrush);
    latexformula.SetBackground(backBrush);

    var pngBytes = latexformula.RenderToPng(scale, space, space, "Arial");

    using (var ms = new MemoryStream(pngBytes))
    {
      bmp = new Bitmap(ms);
    }

    Bitmap img = new Bitmap(bmp.Width, bmp.Height);

    img.SetResolution(bmp.HorizontalResolution, bmp.VerticalResolution);
    using (var g = Graphics.FromImage(img))
    {
      g.Clear(bcolor);
      g.DrawImageUnscaled(bmp, 0, 0);
    }

    return img;
  }
t.mp4

@ForNeVeR
Copy link
Owner

Yep, folks, that's what I meant. I am still unsure on how to better integrate this with the rest of XAML-Math API. Maybe an additional parameter of RenderToPng? But we'd still have a (somewhat) defunct SetBackground exposed.

Also, while it's totally fine for your end-user app, I'd like to avoid, if possible, using System.Drawing in WPF-related code. Not sure of the current state of things on that matter, but some time ago System.Drawing (together with WinForms) was a separate thing from WPF on the SDK level, and you'd get in some small problems if you reference that from a WPF project without also defining <UseWinForms>true</UseWinForms>.

It may be already fixed, or maybe I am misremembering, but still: conceptually, it would be better to stay in pure WPF (in a WPF-related part of the library, of course; again, not talking about an end-user app where the user is free to do whatever they choose).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants