4

The tex file with the following code is to be converted into html.

\documentclass{article}
    \usepackage{amsmath,amssymb}
    \begin{document}
    \(\implies\) and \(\iff\) \\
    \(a \implies b\) \(a \iff b\)
    \end{document}

The command

htlatex texfile "xhtml,svg"

is used to convert tex file into html. The symbols \implies and \iff get converted into svg images. The produced svg images are different for these symbols as seen in the attached image. How can this be solved?

enter image description here

michal.h21
  • 50,697
user61681
  • 1,749
  • There is any examples at this link: https://tex.stackexchange.com/questions/43772/latex-xhtml-with-tex4ht-bad-quality-images-of-equations – Sebastiano Nov 10 '17 at 12:15
  • It should be sufficient to add option --exact to the call of dvisvgm in your tex4ht.env. – Martin Nov 10 '17 at 21:13

1 Answers1

5

Edit:

As Martin mentioned in the comments, some glyphs may exceed it's bounding box, which may result in a cropping of theirs parts. It is possible to tell dvisvgm to trace the actual glyph shape using --exact option. I will update tex4ht to use it. In the meantime, you may use a following .mk4 build file:

Make:image("svg$", "dvisvgm -n -p ${page} --exact -c 1.4,1.4 -s ${source} > ${output}")

The result:

enter image description here

Original answer:

It seems that dvisvgm sets wrong dimensions for some images, as it happens for standalone arrows in your example. It seems that height of the first two images is too small, so the image is cropped.

The height of the first image is 3.26027pt, vs 9.6859pt of the third one. It is clear that the height difference isn't as big.

I guess that the best solution would be to fix dvisvgm, but in the meantime, it is possible to use make4ht filters to guess the correct height value. The characters are saved in the SVG file as <path> elements:

<path d='M7.23288 -3.25778C7.65131 -2.89913 8.1594 -2.6401 8.48817 -2.49066C8.12951 -2.33126 7.64134 -2.07223 7.23288 -1.72354H0.9066C0.737235 -1.72354 0.547945 -1.72354 0.547945 -1.52428S0.727273 -1.32503 0.896638 -1.32503H6.78456C6.30635 -0.86675 5.78829 0.00996264 5.78829 0.139477C5.78829 0.249066 5.91781 0.249066 5.97758 0.249066C6.05729 0.249066 6.12702 0.249066 6.16687 0.169365C6.37609 -0.209215 6.65504 -0.737235 7.30262 -1.31507C7.99004 -1.92279 8.65753 -2.19178 9.17559 -2.34122C9.34496 -2.401 9.35492 -2.41096 9.37484 -2.43088C9.39477 -2.44085 9.39477 -2.47073 9.39477 -2.49066S9.39477 -2.53051 9.38481 -2.55044L9.35492 -2.57036C9.33499 -2.58032 9.32503 -2.59029 9.13574 -2.65006C7.79078 -3.04857 6.79452 -3.95517 6.23661 -5.02117C6.12702 -5.22042 6.11706 -5.23039 5.97758 -5.23039C5.91781 -5.23039 5.78829 -5.23039 5.78829 -5.1208C5.78829 -4.99128 6.29639 -4.12453 6.78456 -3.65629H0.896638C0.727273 -3.65629 0.547945 -3.65629 0.547945 -3.45704S0.737235 -3.25778 0.9066 -3.25778H7.23288Z' id='g0-41'/>

Every second number in the path is y coordinate. My naive approach is to process all y coordinates in the svg file, find the maximal value and set the height of the image to this value, if it is bigger than the original value. This approach isn't really robust, because curve sections may be rendered above the maximal coordinate, but I don't know how to solve this issue and I don't want to write proper SVG path parser. So we will hope that this doesn't matter much.

Save the following file as mybuild.mk4:

local filter = require "make4ht-filter"

local max = function(a,b)
  return a > b and a or b
end

local function get_height(svg)
  local height = svg:match("height='([0-9%.]+)pt'")
  return tonumber(height)
end

local function get_max_height(path,max_number)
  local coordinates = {}
  for number in path:gmatch("(%-?[0-9%.]+)") do
    table.insert(coordinates, tonumber(number))
  end
  for i = 2, #coordinates, 2 do
    max_number = max(max_number, coordinates[i])
  end
  return max_number
end

local function update_height(svg, height)
  return svg:gsub("height='.-pt'", "height='"..height .."pt'")
end

-- we need to fix the svg height
local process_svg = filter {function(svg)
  local max_height = 0
  local height = get_height(svg)
  for path in svg:gmatch("path d='([^']+)'") do
    -- find highest height in all paths in the svg file
    max_height = get_max_height(path, max_height)
  end
  -- update the height only if the max_height is larger than height set in the SVG file
  print(max_height, height)
  if max_height > height then
    svg = update_height(svg, max_height)
  end
  return svg
end}

Make:match("svg$", process_svg)

Compile the file using command

make4ht -u -e mybuild.mk4 texfile svg

This is the rendered result:

enter image description here

michal.h21
  • 50,697
  • The reason for the incorrect heights is that by default dvisvgm uses the character dimensions from TFM files to compute the bounding box. Since some glyphs may exceed their TFM box, the SVG graphics can be clipped in some cases. To avoid this, call dvisvgm with option --exact. – Martin Nov 10 '17 at 20:42
  • @Martin thanks, I missed that option, it works perfectly! – michal.h21 Nov 10 '17 at 23:01
  • @martin what do you think about bounding box issue with TikZ diagrams from this answer: https://tex.stackexchange.com/a/386775/2891 ? – michal.h21 Nov 11 '17 at 09:32
  • Would you please create tag for dvisvgm? It would be nice to post question with tag dvisvgm for issues related to dvisvgm... – user61681 Nov 11 '17 at 14:31
  • @michal.h21 as far as I can tell, the dvisvgm driver of TikZ doesn't add the required bbox specials together with the raw SVG fragments in order to update the bounding box accordingly. It might help to use the dvips driver instead, as dvisvgm also understands PostScript specials. I haven't tested that, though. – Martin Nov 11 '17 at 15:32
  • @Martin thanks, dvips seems to work in some instances, but for example the test file in the answer linked above produces error PostScript error: undefined in pgfo. – michal.h21 Nov 11 '17 at 16:12
  • The question https://tex.stackexchange.com/questions/194126/did-one-manage-to-get-the-new-dvisvgm-driver-from-pgf-3-0-to-work may be useful – user61681 Nov 11 '17 at 16:37
  • @michal.h21Yes, I can confirm the issue. The definition of PS operator pgfo is missing in the .idvfile. When using pgfsys-dvips.def directly together with LaTeX everything works. So, htlatex somehow omits the PGF PostScript header that's supposed to go into the DVI files. – Martin Nov 11 '17 at 17:35
  • @Martin I see. It seems to work when I explicitly add the definitions from \pgfsys@atbegindocument to \pgfsys@beginpicture, so it is saved in the .idv file. Thanks a lot! – michal.h21 Nov 11 '17 at 18:40
  • @Martin I've updated https://tex.stackexchange.com/a/386775/2891 with pfgsys-tex4ht.def which seems to work correctly with dvisvgm – michal.h21 Nov 11 '17 at 18:58
  • @michal.h21Great. I'm glad to hear the information helped to fix the issue. – Martin Nov 11 '17 at 19:18