19
$\begingroup$

Bug introduced in 8 or earlier and persisting through 11.2.0


I'm using Linux-x86-64 as operating system. Can someone explain this behaviour and maybe give a hint how to resolve it? Here are two lines of exact the same number of letters of a monospaced font:

Style["ZZZZZZZZZZ\n__________", 20, FontFamily -> "Courier"]

As output I get (here with 30 Z and 30 _)

monospaced

But what I expect from a monospaced font like Courier is to have the same size for every letter (and why is the line dashed anyway?). @Oleksandr was so kind to give me mental support and tried the things on his Windows machine. There the output seems ok:

monospaced win

More detailed question

What I really want is an image of arbitrary resolution of every letter. I thought when I use a combination of Style and Rasterize I can get equally sized images of them in exact the same form as they appear in text.

But there is (at least here) a clear difference between an assembled image from rasterized letters and a rasterized version of the string

ImageAssemble[
 Rasterize[Style[#, 30, FontFamily -> "Courier"], "Image"] & /@ 
  CharacterRange["A", "Z"]]

Rasterize[
 Style[StringJoin[CharacterRange["A", "Z"]], 30, 
  FontFamily -> "Courier"], "Image"]

Mathematica graphics Mathematica graphics

What I noticed is that the height of the letters is always the same, only the width varies. Looking at how many letters have which width gives here

Sort@Tally@First@
   Transpose[
    ImageDimensions[
       Rasterize[Style[#, 30, FontFamily -> "Courier"], "Image"]] & /@
      CharacterRange["A", "z"]]
(*
  Out[138]= {{18, 25}, {19, 16}, {20, 8}, {21, 8}, {24, 1}}
*)

This is a mess. Any ideas about this issue would be very welcome.

$\endgroup$
6
  • $\begingroup$ I see the same issue, but to a much lesser degree (also on Linux-x86-64). The first example is almost not noticeable to the eye and for the last I get: {{18, 53}, {19, 3}, {20, 1}, {21, 1}} which is somewhat better. I have no glue where this comes from, though. $\endgroup$
    – user21
    Sep 19, 2012 at 4:52
  • 1
    $\begingroup$ Well I don't have glue, but no clue either ;-) $\endgroup$
    – user21
    Sep 19, 2012 at 5:39
  • $\begingroup$ @ruebenko maybe glue is really necessary here to put the letters together. $\endgroup$
    – halirutan
    Sep 19, 2012 at 16:32
  • $\begingroup$ @halirutan I get a similar output to yours, however changing the second line Style["ZZZZZZZZZZ\nAAAAAAAAAA", 20, FontFamily -> "Courier"] or Style["ZZZZZZZZZZ\n0123456789", 20, FontFamily -> "Courier"] seem to be good. Does it make sense ? $\endgroup$ Sep 19, 2012 at 18:55
  • $\begingroup$ @b.gatessucks Yes, this makes sense in this scenario. Usually, in Courier all letters should have the same width. In Linux, some letters are wider than others. While the difference between "Z" and "_" is very large, the width of "A" and "Z" seem to be equal. Therefore, your examples look ok. $\endgroup$
    – halirutan
    Sep 19, 2012 at 21:44

3 Answers 3

16
$\begingroup$

While this is not an answer, I did not want to add it as a comment. The issue is not specific to Linux, happens under Windows as well (Win7 in particular). Also, it is not specific to font: any monospaced font seems to produce overhangs to the default frame of $n$ characters. While rasterized characters have different image dimensions, as pointed out by halirutan, this is not direclty related to the problem, as most of the operator characters comply with the expected dimensions (though they will cause a lot of problems) while those characters that have larger-than-unit dimensions (like A, W, M) might fit in nicely without an overhang. So I think that the different image dimensions and the kerning problem of e.g. "_" are different issues.

1. Rasterized characters

For the image assembly, I would suggest using a uniform image dimension applied via ImageCrop:

(* get standard character dimensions - find a suitable char, like "I" *)
unitDim = ImageDimensions@
  Rasterize[Style["I", 30, Bold, FontFamily -> "Courier"], "Image"]
{18, 34}
"non cropped individual images"
ImageAssemble[
 Rasterize[Style[#, 30, Bold, FontFamily -> "Courier"], "Image"] & /@ 
  CharacterRange["A", "Z"]]

"cropped individual images"
ImageAssemble[
 ImageCrop[
    Rasterize[Style[#, 30, Bold, FontFamily -> "Courier"], "Image"], 
    unitDim] & /@ CharacterRange["A", "Z"]]

"rasterize as a whole"
Rasterize[
 Style[StringJoin[CharacterRange["A", "Z"]], 30, Bold, 
  FontFamily -> "Courier"], "Image"]

Mathematica graphics

While cropping individual images is a possible workaround, sadly I have no idea why rasterized characters end up being larger than the monospaced frame. The following test indicates, that this effect depends on FontSize and Magnification but not on ImageResolution:

chars = CharacterRange["A", "Z"]; charPos = Thread[chars -> Range@Length@chars];
resRange = {10, 100, 1000}; sizeRange = {10, 15, 20, 30, 50, 100}; magRange = {.5, 1, 2, 10};

data = Table[
   style = {FontSize -> size, Magnification -> mag, FontWeight -> Bold, FontFamily -> "Courier"};
   img = Rasterize[Style[#, Sequence @@ style], "Image", ImageResolution -> res] & /@ chars;
   imgPos = Thread[img -> Range@Length@chars]; unitDim = ImageDimensions@img[["I" /. charPos]]; imgDim = ImageDimensions /@ img;
   Cases[img, x_?((d = ImageDimensions@#) =!= unitDim &) :> chars[[x /. imgPos]]],
   {res, resRange}, {size, sizeRange}, {mag, magRange}];

Column[MapThread[Labeled[TableForm[#1, TableHeadings -> {sizeRange, magRange}, TableDepth -> 2], "ImageResolution \[Rule] " <> ToString@#2, Top] &, {data, resRange}], Spacings -> 2]

Mathematica graphics

Figure lists those rasterized characters that do not match the ImageDimension of the standard monospaced dimension (taken from "I"). Horizontal dimension: Magnification; Vertical dimension: FontSize. I would consider this a bug.


2. Monospaced characters are not monospaced

Further investigating the first issue of monospaced characters not being monospaced when printed:

n = 30;
font = "Courier"; (* alternatively: "Lucida Console" *)
text = StringJoin[
   RandomChoice[{"=", "*", ":"}, n], "\n",
   RandomChoice[{"M"}, n], "\n",
   RandomChoice[{"@"}, n], "\n",
   RandomChoice[{":"}, n], "\n",
   RandomChoice[{"M", "A"}, n], "\n",
   RandomChoice[{"_"}, n], "\n",
   RandomChoice[{"@", "M"}, n], "\n",
   RandomChoice[{":", "M"}, n], "\n",
   RandomChoice[{":", "A"}, n], "\n",
   RandomChoice[{":", "J"}, n]
   ];

Grid[{{
   Style[StringJoin["Normal, 100% magnification, font size 10\n", 
     text], FontFamily -> font, FontSize -> 10],
   Style[StringJoin["Bold, 100% magnification, font size 10\n", text],
     FontFamily -> font, FontSize -> 10, Bold]
  }, {
   Style[StringJoin["Normal, 120% magnification, font size 10\n", 
     text], FontFamily -> font, FontSize -> 10, Magnification -> 1.2],
   Style[StringJoin["Normal, 120% magnification, font size 12\n", 
     text], FontFamily -> font, FontSize -> 12, Magnification -> 1.2]
   }}, Alignment -> {Left, Top}, Frame -> All]

Mathematica graphics

Note the followings:

  • Non-bold monospaced font with 100% magnification and 10 points height produces nicely fit lines - any divergence causes overhangs.
  • Operators with certain letters (while independently are ok) together form an overhang. This seems to be true for all the operators I've tested.
  • "_" is a renegate character as it does not even fit by itself into the frame, not even when not Bold.
  • Overhang depends on magnification, font family and font size.

Again, I have no idea what causes these problems, but is definitely operator-character-related. Here, the problem is that no setup that is found on one machine is guaranteed to work on another, as a lot of these parameters depend on the OS.

$\endgroup$
3
  • $\begingroup$ Although we could not resolve the problem properly, you did a great job digging further into this. I'll accept this answer. It's a pity, I was the only one who upvoted your work. $\endgroup$
    – halirutan
    Nov 19, 2012 at 1:05
  • $\begingroup$ @halirutan Thanks for the accept, let's hope this will be cured in v9! $\endgroup$ Nov 19, 2012 at 8:31
  • $\begingroup$ Just to update for v9: no, it is not cured yet, symptoms are the same for both issues. $\endgroup$ Oct 14, 2013 at 10:03
1
$\begingroup$

I use the following code to get the correct output:

Rasterize[
 Cell[TextData[
   StyleBox["1234567890\n!@#$%^&*()", FontFamily -> "Sarasa Mono SC"]], 
  "Text"]]

enter image description here

$\endgroup$
1
$\begingroup$

I've found that "monospace" fonts seem to be monospaced only at certain, usually fractional font sizes.

To find the right FontSize, I start with some integer multiple of ⅔ above or below 12 that's close to the desired size (i.e., 12+2k/3 — I have no idea why this is the magic formula). Then I make small adjustments up or down from there to find a value that gives the best results.

It's still not perfect, but it often produces something that's acceptable. And by avoiding Rasterize, the text remains selectable.

Here's a little widget to help you find a good FontSize:

With[
  {
    fontFamily="Courier Std",
    text="radiating = astonishment STAPES hitchhiker / melon 198 cakewalk FLAME 
      edibility COMBED _ > 284 deflationary 869835 easel PARADIGMATIC baobab 
      CONVIVIALITY conjugated 269 gaming $ CONSONANTAL nefariously DAUNTINGLY 
      FLEXIBLY > IOTA radiometer RUFF ADAGIO antenna 796 PUKKA 659 898 bookmaker 
      bowman PENDULUM licensee PARSIMONY warp MANTRA ` ^ determinate POETICALLY
      ? 270 crosshatched hobbit ~ TOLERANT 528 EXPERT 236 excavation refueling "
  },
  Manipulate[
    TextCell[
      Style[text,base+delta,FontFamily->fontFamily,LineSpacing->{0.85,0}]
  ],
  
    Row[
      {
        Control@{{base,12},4,24,2/3},
        Control@{{delta,0},-0.25,0.25},
        Dynamic[N[base+delta,4]]
      },
      "  "
    ]
  ]
]

sample

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.