11

I'm using wicked_pdf with rails 3.2.11 and ruby 1.9.3 to generate a PDF from HTML and deploying to Heroku.

My pdf.css.scss.erb:

<% app_fullhost = Constants["app_fullhost"] %>

@font-face {
  font-family:'DosisMedium'; font-style:normal; font-weight:500;
  src: url(<%=app_fullhost%>/app/font/dosis/Dosis-Medium.ttf) format('woff');
}

*, body {
  font-family: "DosisLight", 'Times New Roman', 'Arial', sans-serif;
} 

where app_fullhost is the exact host, in development or production.

My pdf layout includes among other things :

%html{:lang => I18n.locale}
  %head
    %meta{:charset => "utf-8"}
    %title= content_for?(:title) ? yield(:title) : Settings.app_name
    = wicked_pdf_stylesheet_link_tag "pdf"

In production.rb I have

config.assets.precompile +=%w(pdf.css)

This works without problems in development, but on Heroku the pdf file doesn't load the desired font. I have also tried different solutions like adding these in production.rb:

config.assets.paths << "#{Rails.root}/app/assets/fonts"
config.assets.precompile += %w(*.svg *.eot *.woff *.ttf) 
config.assets.precompile += %w(.svg .eot .woff .ttf) 

and I tried also to change ( in pdf.css.scss.erb ) :

@font-face {
  font-family:'Dosis'; font-style:normal; font-weight:500;
  src: url('Dosis-Medium.ttf') format('woff');
}

or

@font-face {
  font-family:'Dosis'; font-style:normal; font-weight:500;
  src: url(<%= asset_path('Dosis-Medium.ttf')%>) format('woff');
}

The fonts are in assets/fonts and also in public/app/font/dosis and url on Heroku respond correctly with:

..//myapp/app/font/dosis/Dosis-Medium.ttf" and 
..//myapp/assets/Dosis-Medium.ttf 

How can I get the font to load on Heroku?

James Chevalier
  • 10,604
  • 5
  • 48
  • 74
Sten Ka Razin
  • 883
  • 1
  • 10
  • 23

3 Answers3

9

wkhtmltopdf, the program underlying wicked_pdf, is notoriously funky when it comes to loading fonts through CSS. On some systems it works with absolute paths, sometimes it requires relative paths. Even if you get the paths correctly, it may get thrown off by inaccurate CSS deceleration, etc. There are dozens of questions regarding this just on SO alone.

The best, most flexible and most portable soltion that I've found is to Base64-encode the font you're trying to use, and include it directly into the CSS file:

@font-face {
    font-family: 'OpenSans';
    src: url(data:font/truetype;charset=utf-8;base64,AAEAAAATAQA...
}
marzapower
  • 5,531
  • 7
  • 38
  • 76
Arman H
  • 5,488
  • 10
  • 51
  • 76
  • 1
    This definitely works, my only addition to this would be to use [Font Squirell Generator](http://www.fontsquirrel.com/tools/webfont-generator) to get the Base64 data. – Bjorn Forsberg Oct 07 '13 at 12:36
  • The original website resource I had linked has gone offline. You can use Font Squirrel or [**this tool**](http://www.opinionatedgeek.com/dotnet/tools/base64encode/) if you're using non-Font Squirrel fonts. – Arman H Oct 07 '13 at 18:49
  • Have you run into any caveats with multiple Base64-encoded `@font-face` entries in one file? – James Chevalier Jan 20 '14 at 21:36
  • @JamesChevalier: no caveats, you can use multiple fonts embedded into a single stylesheet with no issues. – Arman H Jan 20 '14 at 22:18
  • Does it makes a difference which font I need to convert to Base64 - eot, wott, ttf .. ? I keep seeing similar answer to this problem but no one clarifies that and for some reason this solution does not work for me. Thanks. – VelLes Nov 07 '14 at 07:07
  • I've used it with TTF files with no problems. Have you tried converting TTFs? – Arman H Nov 07 '14 at 11:12
  • This example explicitly shows using a TTF (the `data:font/truetype` bit). To use a WOTT, all you'd probably need to do is change the `src` to use the correct declaration: `src: url(data:application/x-font-woff;charset=utf-8;base64,d09GRgABAAwwBMA...`, and the same with EOT. – Arman H Nov 07 '14 at 11:19
  • I would just point in here a handy way to convert to base64 via rails is here https://github.com/mileszs/wicked_pdf/issues/250 – VelLes Nov 07 '14 at 22:06
3

I ran into this issue and followed the advice outlined by Arman H - I converted the font to base 64 and referenced it directly in the CSS/SCSS file. The rest of the steps I followed are very similar to those outlined in the original question.

I put together a full description (with a github link to the source code) here: http://apleroy.com/posts/custom-pdf-fonts-with-wicked_pdf-and-heroku

First I referenced the font within the font directory.

<%# /fonts/custom_fonts.css.scss.erb %>
@font-face {
    font-family: "SourceSansPro-Light";
    src: url('<%= asset_path("SourceSansPro-Light.otf") %>');
}

Then, to base 64 encode a font, I used this site (already addressed in a comment above): http://www.opinionatedgeek.com/dotnet/tools/base64encode/. The base-64 encoded output is a random string that is several hundred lines of alpha-numeric characters. I copied this output into the new pdf.css.scss file:

<%# /stylesheets/pdf.css.scss %>
@font-face {
  font-family: 'Source Sans Pro Light';
  src: url(data:font/truetype;charset=utf-8;base64,T1RUTw-----THIS IS HUNDREDS OF LINES LONG -------sGAnBSvO7nBqXQ==)
}

Within the actual html page (which is converted to PDF) I made reference using the wicked_pdf stylesheet tag - as addressed in the original question:

<%# views/pdf_pages/show.html.erb %>
<meta charset='utf-8' />
<%= wicked_pdf_stylesheet_link_tag "pdf" %>

Finally, I precompiled the pdf stylesheet so as to include it in the asset pipeline for deployment on Heroku:

#application.rb
config.assets.precompile += ['pdf.css']
apleroy
  • 587
  • 1
  • 6
  • 13
  • Welcome to Stackoverflow. Could you put the main part of your answer into the text instead of a link? It will be much easier to find in the future – slfan Jun 18 '15 at 19:03
  • 1
    I just added in the relevant information. Thanks for your help calling that out. – apleroy Jun 18 '15 at 19:26
1

Let me see if I have this right:

Server 1: building a PDF, needs fonts, and pulls them from a URL This works locally in dev, but not on heroku.

Is there anything in the logs? (do you see the http request for the font?)

You said it doesn't load the right font. Does it blow up, or just render as if it never loaded the font (eg a 404 on the font fetch).

Does this work if you don't pull the font file from heroku? (like use aws or some other font from another URL just as a test)

Are you pulling from the same server process that is currently running? Do you have more than one dyno or more than one unicorn process that can handle the current process (building the pdf), and the incoming request (serving the font file)

I've seen people run just a single dyno, but try to run two http events, and run into problems. If you only have one dyno (you didn't mention otherwise), add another one and see what happens, or add another unicorn process.

J_McCaffrey
  • 1,455
  • 12
  • 15