15
$\begingroup$

I am trying to use a special font with musical symbols in a .cdf that I send to some friends. The font is called "Tempera" and is freely distributed here:

http://christian.texier.pagespro-orange.fr/mididesi/free/index.htm#tempera

In the .cdf I use substitutions like this:

sub = "A" -> "\*StyleBox[\(\!\(\*StyleBox[\"A\",\n\
   FontFamily->\"Mathematica6\"]\)\!\(\*StyleBox[\"U\",\n\
   FontFamily->\"Tempera\",\nFontSize->18,\nFontWeight->\"Plain\"]\)\)]";

which are used in this manner:

 "A" //. sub

What this does is to change the regular "A" character into a curly A (from the Mathematica6 font) and a symbol that is a half-sharp (the "U" from the Tempera font). This works fine in Mathematica, and also in the .cdf on my computer. However, when I send it to my friend, he sees the "U" and not the half-flat. This is probably what you will see too, unless you download the Tempera font. I believe this means that Mathematica does not embed the font in the .cdf, and I'm wondering if there is any way to force the embedding to occur. While I could have my friend download the font, if I ever want to place the .cdf on the web, this would not be practical.

$\endgroup$

3 Answers 3

11
$\begingroup$

Mathematica will only let you use fonts installed on the system. I have two suggestions here:

  1. At the top of your CDF file, display a link depending on the operating system, pointing to the correct file for downloading the font

    link = If[$OperatingSystem == "Linux" || $OperatingSystem == "Windows", 
        Hyperlink["Download font for " <> $OperatingSystem , "http://christian.texier.pagespro-orange.fr/mididesi/free/media/tempera.zip"],
                Hyperlink["Download font for Mac", "http://christian.texier.pagespro-orange.fr/mididesi/free/media/electronica.sit"]
    ];
    link
    
  2. Alternatively, you can create PDFs for the single characters you use. Out of them, you can create a textual representation which can be saved within your CDF file:

    pdfA = Import["tempera_a.pdf"][[1]];
    symbolA = Compress[pdfA]
    

    with the outputs from Compress[] you can maybe create a list for the alphabet you use. When you want to use the font afterwards, you can do

    "A"/.{"A" -> Uncompress[symbolA]}
    

Edit: For the latter approach, I just noticed that Mathematica does have severe problems with embedded fonts - they are not showing up in the correct font. I guess using a raster format like PNG instead of PDF would work, but it's not as nice as scalable fonts from a PDF. If you use PNG however, the files will stay small enough to be included, even at a relatively high resolution. I checked this with a PNG file with resolution 1000px*1000px, where the file size was 60kib, compared to 300kb for the PDF file with the same character and embedded font.

$\endgroup$
3
$\begingroup$

I guess the answer to my question is really quite simple: "no, it is not possible to embed fonts in a .cdf". Thanks to Ulrik for the ideas for work-arounds, and what I ended up doing is closely related to his second suggestion: to create a rasterized graphic element for each symbol that is needed. For instance, for the half-sharp of the original question, this is:

halfSharp = Rasterize["\*StyleBox[\"U\",\nFontFamily->\"Tempera\",
       \nFontSize->18,\nFontWeight->\"Plain\"]"];

Now, whenever the half-sharp symbol is needed, it can be displayed using the variable name halfSharp. This can also be made into a handy function:

rasterizeLetters[let_, font_] := ImagePad[Rasterize[Style[let, 
     FontFamily -> font, FontSize -> 100]], 10, White]

so the same image-symbol can now be created

halfSharp = rasterizeLetters["U","Tempera"]
$\endgroup$
3
$\begingroup$

Here is a variation on part 2 of Ulrik's answer, which works on my system (Mac) with the Tempera font. One can bypass file generation with ExportString and ImportString; the results can be stored in the CDF notebook. The result of each Import is Graphics, not a formatted String. Consequently all the font information is lost (e.g. kerning, baseline position) as well as other font advantages (e.g. smoothing). One the other hand, the graphics (at least in this case) are scalable.

Creating the images

There are two primary functions, temperaSign for a single music sign and graphicsForm for a combination of a letter and sign as in the OP's question; the auxiliary function combine creates a text-based combination of a letter and sign like the OP's example.

temperaSign[sign_] := 
  First @ ImportString[ExportString[Style[sign, FontFamily -> "Tempera"], "PDF"], "PDF"];

combine[letter_, sign_] := 
 StringForm["````", Style[letter, FontFamily -> "Mathematica6"], 
  Style[sign, FontFamily -> "Tempera", FontSize -> 18, FontWeight -> "Plain"]]; 
temperaForm[letter_, sign_] := 
 First @ ImportString[ExportString[combine[letter, sign], "PDF"], "PDF"]

Here's what the imported Graphics look like:

temperaSign["U"] // InputForm
  (* Graphics[{Thickness[0.6361323155216285], 
      Style[{FilledCurve[{{{0, 2, 0}, {0, 1, 0}, {0, 1, 0}, {0, 1, 0}, {0, 1, 0},
          {0, 1, 0}, {0, 1, 0}, {0, 1, 0}, {0, 1, 0}, {0, 1, 0}, {0, 1, 0}, {0, 1, 0}}}, 
         {{{0.01200488090515137, 6.366542406082154}, {0.01200488090515137, 5.374395179748535},
          ... 10 points omitted ...
          {0.01200488090515137, 6.366542406082154}}}]}, 
       Thickness[0.6361323155216285]]}, 
     ImageSize -> {2., 12.}, PlotRange -> {{0., 1.572}, {0., 12.}}, AspectRatio -> Automatic] *)

To get good size and positioning, one has to play with ImageSize and BaselinePosition. Close inspection shows the size is slightly off.

Row[{combine["A", "U"], 
  Show[temperaSign["U"], ImageSize -> {Automatic, 24}, BaselinePosition -> Scaled[0.41]]}]

Text, graphics sharp

Here is a somewhat high-resolution rendering comparing the text, graphics, and rasterized versions. (At screen resolution, the rasterized version is only slightly fuzzy.)

{combine["A", "U"], 
 Show[graphicsForm["A", "U"], ImageSize -> {Automatic, 24}, 
  BaselinePosition -> Scaled[0.37]],
 Rasterize@combine["A", "U"]}

Text, graphics, raster

Creating the database

One can compute all of the signs to be used and store them in a notebook. For instance:

m[#] -> temperaSign[#] & /@ CharacterRange["A", "Z"]

Then type sub = and copy the output:

Substitution rules

Here I used m as a wrapper; you might wish to use a more expressive symbol such as musicSign (but beware reusing temperaSign). Or you may wish to use letter-strings ("A" ->...).

One could process music text with something like:

baselineAdjust[m["U"]] = Scaled[0.37];
baselineAdjust[m["A"]] = Scaled[0.16];
  (* add more baseline defs as desired *)
baselineAdjust[_] := Center;
temperaAdjust[expr_Graphics, opts___] := Show[expr, opts];
temperaAdjust[expr_] /; Head[expr] =!= m := 
  expr /. sign_m :> temperaAdjust[sign, ImageSize -> {Automatic, 24}, 
                                        BaselinePosition -> baselineAdjust[sign]];

note = {"A", m["U"]};
temperaAdjust @ Row[note, BaseStyle -> {FontFamily -> "Mathematica6"}] /. sub

A half sharp

note = {"B", m["A"]};
temperaAdjust @ Row[note, BaseStyle -> {FontFamily -> "Mathematica6"}] /. sub

B flat

$\endgroup$

Your Answer

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

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