JavaFx Could not load @font-face font because of com.sun.javafx.css.StyleManager loadStylesheetUnPrivileged
Asked Answered
A

6

11

I had already asked a similar question here but it seems It wasn't clear since I had a lot of code in the project and couldn't post it here So please don't mark as duplicate.

Because of that, I then decided to create a new project with just a Label in it to make the code small and clean and also to eliminate other potential suspects of the error I'm getting.

So here is my Java Source code

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {
        Group root = new Group();

        Label label = new Label("Sample Label");
        label.setId("sampleLabel");
        root.getChildren().add(label);

        Scene scene = new Scene(root, 300, 275);
        scene.getStylesheets().add(getClass().getResource("applicationStyles.css").toExternalForm());
        primaryStage.setTitle("Hello World");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

And this is my css file

/**/
@font-face {
    font-family:'Roboto';
    src:url("Roboto-Thin.ttf");
}
#sampleLabel{
    -fx-font-family: Roboto ;
}

This is the error I'm getting in Intellij Idea

Dec 02, 2015 9:16:34 AM com.sun.javafx.css.StyleManager loadStylesheetUnPrivileged
INFO: Could not load @font-face font [file:/C:/Users/UserName/Desktop/Java8%20projects/TeamViewer/out/production/TeamViewer/sample/Roboto-Thin.ttf]

All the project files are in one package and the font file is also present in the out>production>TeamViewer>sample>Roboto-Thin.ttf. I also upgraded from jdk-8u65 to jdk-8u66

Thanks, any help is greatly appreciated.

Alibi answered 2/12, 2015 at 6:25 Comment(6)
Are you using maven resource filtering? I've just faced the same issue and it turns out to be caused by maven filtering, as I forgot to exclude them from filtering.Mignonmignonette
@MajedAbdulaziz Thanks a lot for the reply, but I'm not using maven, I don't think this is the cause in my case.Alibi
Where in relation to your source file and the compiled class file is the Roboto-Thin.ttf located?Steeplejack
@Steeplejack They are all in the same folder out>production>TeamViewer>sample>Main.class and out>production>TeamViewer>sample>Roboto-Thin.ttfAlibi
If you move the project to a different location, which does not have a path containing a space (Java8%20projects) does that make a difference? What if you package the application in a jar file and run that one?Steeplejack
@Steeplejack Thanks a lot, removing the space from Java8%20projects to Java8projects tends to solve the problem.Alibi
C
4

I found the possible cause and a work-around: Under the hood the css-loader uses the function Font.loadFont to load the font-face in your CSS. Font.loadFont simply returns null if it fails, which give the "warning".

It seems that this function does not work with %20 it its path/url-string. So you need to resolve the path and then replace it with a space. That means you will have to load your fonts with code in stead of with CSS (for now).

In Clojure my work-around looks like this:

(require '[clojure.java.io :as cio])
(require '[clojure.string :as s])
(-> "fonts/SourceCodePro-Regular.ttf" 
  cio/resource 
  str 
  (s/replace "%20" " ") 
  (javafx.scene.text.Font/loadFont  10.))

;-)

Crossexamine answered 1/2, 2016 at 16:13 Comment(2)
I had solved it by just removing the space to get rid of the %20, but this also solves the problem. Thanks a lot +1Alibi
Is there a way to do it in CSS? The reason I am asking this is, if we load the font with code, then it'd be a tough task to setFont for each and every element.Dowell
J
1

I'm using the e(fx)clipse plugin for Eclipse, which does not recognize your CSS file as valid JavaFX CSS. I do not get the exception when I start the program however, it simply uses the default font.

With the following changes, the font is being loaded and displayed.

/**/
@font-face {
    font-family: Roboto; /* removed '' */
    src: url("Roboto-Thin.ttf");
}
#sampleLabel{
    -fx-font-family: Roboto ; /* added -fx- prefix */
}
Jemison answered 4/12, 2015 at 22:27 Comment(5)
Thanks for reply, but I'm still getting the same error, Also sorry I had forgotten the -fx- prefix but I have just added itAlibi
May be the problem is with Intellij IdeaAlibi
Have you tried compiling/running it with plain javac/java, without an IDE? Just tried it myself and even your original CSS works fine that way.Jemison
I guess that and even eclipse would work, But I need a solution for IntelliJ Idea ,Also It was initially working perfectly but it just suddenly stopped.Alibi
I had this problem today. Even if years later I can add my bit. If you are using Maven and IntelliJ Idea, I found helpful to manually reimport maven projects after importing the font files. It worked after that.Bin
C
1

So, almost 2 years later, and I came across my own response to the same problem I still have.

But now I have a cooler and more elegant solution, after studying the source code for com.sun.javafx.css.StyleManager : Simply parse the stylesheets myself and load the fonts.

See relevant source code here: lines 932-662

(Yes, this is all in Clojure, but I am sure you can figure it out.)

I start with this:

(defn add-stylesheet [^Scene scene path]
  (let [logger (Logging/getCSSLogger)
        level (.level logger)]
    (.setLevel logger PlatformLogger$Level/OFF)  ;; turn off logger
    (-> scene .getStylesheets (.add path))  ;; set stylesheet
    (.setLevel logger level) ;; turn logger back on
    (-> path stylesheet-parsed load-fonts))) ;; parse and load fonts

(Turning off logging doesn't work, for some reason).

The stylesheet is parsed with this:

(defn stylesheet-parsed [path]
  (.parse (CSSParser.) (cio/resource path)))

And finally the fonts are loaded with this:

(defn- load-fonts [^Stylesheet stylesheet]
  (doseq [^FontFace fontface (.getFontFaces stylesheet)]
    (doseq [^FontFace$FontFaceSrc ffsrc (.getSources fontface)]
      (let [src (-> ffsrc .getSrc (cs/replace "%20" " "))] ;; <- sanitizing path for Font/getFont
        (println "Loading font:" src)
        (let [f (Font/loadFont src 10.)]
          (println "Font loaded:" f))))))

This works just fine, and looks a lot like the original. An advantage is that here we don't check for type URL only, so we could theoretically extend it to handle @font-face more extensively.

Here is a more Clojure-y implementation of load-fonts which returns a list of all fonts loaded:

(defn- load-fontface-src [^FontFace$FontFaceSrc ffsrc]
  (-> ffsrc .getSrc (cs/replace "%20" " ") (Font/loadFont 10.)))

(defn- load-fontface [^FontFace ff]
  (map load-fontface-src (.getSources ff)))

(defn- load-fonts [^Stylesheet stylesheet]
  (vec (flatten (map load-fontface (.getFontFaces stylesheet)))))

And the imports needed:

(import
  '[com.sun.javafx.css.parser CSSParser]
  '[com.sun.javafx.css Stylesheet FontFace FontFace$FontFaceSrc]
  '[com.sun.javafx.util Logging]
  '[sun.util.logging PlatformLogger$Level])

TODO:
1. Turn of logging. (It is annoying, though only a problem in development.)
2. Test to see if any fonts were not loaded, and only then to the alternative parsing and loading. But probably the simply checking would require as much processing as actually loading the fonts an extra time.

FIX: added vec to the left of flatten, to ensure that lazy seqs are realized.

Crossexamine answered 31/12, 2017 at 12:37 Comment(0)
L
1

In my case this is produced by the '-' character in the font file name, replace this with a '_' and it works.

i identify that the font family must be the same file name but replacing all special characters ' ' (a blank space) and split the camel case words.

so:

before (no working):

@font-face {
    font-family: 'RifficFree Bold';
    src: url("../fonts/RifficFree-Bold.ttf");
}
.bingo-number, .label{
    -fx-font-family: 'RifficFree Bold';
}

after (working):

@font-face {
    font-family: 'Riffic Free Bold';
    src: url("../fonts/RifficFree_Bold.ttf");
}
.bingo-number, .label{
    -fx-font-family: 'Riffic Free Bold';
}
Leialeibman answered 3/12, 2020 at 14:30 Comment(0)
A
0

For those who - like me - still have this issue and do not want or know how to use Clojure, here is how to do it in Java only:
Bevore adding the stylesheet(s) to your scene, use Font.loadFont(getClass().getResourceAsStream([fontpath...]), [Some font-size, for example 12]);
The font will then be registered in JavaFX and you can use the -fx-font-family css-Property with the loaded font.

Ardoin answered 12/1, 2020 at 11:23 Comment(0)
S
0

I found a solution on Reddit that worked for me. Here's the link: Reddit post

When defining the font family in the CSS stylesheet, make sure to use the exact name mentioned on the first line of the font file.

For example, if the first line says "Pixeloid Sans", the font family should be specified as follows:

-fx-font-family: "Pixeloid Sans";

I also removed the @font-face declaration, as it was unnecessary.

Lastly, I should mention that all of my .tff files are located in a folder within /resources.

Sabba answered 17/5, 2023 at 22:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.