-
Notifications
You must be signed in to change notification settings - Fork 356
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Base64 encode fonts and images for PDF rendering #1363
Conversation
@miq-bot add_labels bug, pending core @dclarizio This is ready for a look. |
app/helpers/image_encode_helper.rb
Outdated
def encodable_image_tag(source, options = {}) | ||
image_tag(encodable_image_source(source), options) | ||
end | ||
alias eimage_tag encodable_image_tag |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do we need this alias (and the one below -- eimage_source
)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a future convenience. Any image that might ever make it into a PDF should use this helper.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not a fan of "future convenience" reasons. Would prefer we just name the method the way we want the API to look, and that should be the defined API.
app/helpers/image_encode_helper.rb
Outdated
|
||
if asset.content_type == 'image/svg+xml' | ||
encoding = 'charset=utf-8' | ||
data = CGI.escape(asset.source).gsub('+', '%20') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ERB::Util.url_encode
probably? I know it does the same but in other cases we prefered the Active*/Rails variants over CGI
@hayesr Looks like none of these pdf-related css files are ever precompiled, which means they get compiled on the appliance, the first time somebody tries to use the css. Is that so? Shouldn't you add them to some asset precompile array? |
app/helpers/quadicon_helper.rb
Outdated
@@ -477,7 +467,7 @@ def render_host_quadicon(item, options) | |||
output << flobj_img_simple('100/shield.png', "g72") unless item.get_policies.empty? | |||
else | |||
output << flobj_img_simple | |||
output << flobj_img_small(img_for_host_vendor(item), "e72") | |||
output << flobj_img_simple(img_for_host_vendor(item), "e72", 64) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why this change? Seems like you're just undoing a simplification, without ever calling it with another value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
flobj_img_simple
seemed redundant, we can probably get rid of using the size altogether now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a change I made early in the process. It makes the PR too noisy now, I'll just revert these.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, I have no real objection to removing it, especially if we can get rid of that size completely :) Just confused me here, thanks :)
@skateman We render PDFs using Prince, and by sending an HTML blob and a single stylesheet file. Currently the files don't go through the pipeline, they're just static css files. When everything was in one directory and in a predictable place that worked fine. Now we need to worry about fonts and images that might be in multiple gem directories. Encoding them means the paths don't matter. |
@himdel You're correct in that these would be compiled on first-use. Precompiling is definitely an option, I'm not sure how much time or resources it will save. Not all users need PDF functionality, and it adds like ~250k but that's not a huge deal. I'm neutral on the idea. |
@hayesr I'm pretty neutral about precompiling too... From those tree-related BZs with missing |
def base64_encoded_uri(source) | ||
asset = Rails.application.assets[source] | ||
|
||
if asset.content_type == 'image/svg+xml' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we actually need a special SVG branch here?
Guess what, base64 encoded images are smaller :) - for our SVGs, the size sum is 1215 kB URL-encoded and 1189 kB base64 encoded.
So, simpler code and smaller images...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prince prefers straight SVG sometimes..
Are you sure that's not a bug in the base64 branch of code? Unless prince's uri parser is signifcantly broken, this should not happen, so it feels like this may be exposing a bug there.
Are you sure there's not a working non-home-cooked way of converting files to data uris?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Guess what, base64 encoded images are smaller :) - for our SVGs, the size sum is 1215 kB URL-encoded and 1189 kB base64 encoded.
Sounds like we need to run all of our images through an optimizer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is more about base64 reliably taking 8/6ths of space, while URL-encoding a SVG tends to preserve most bytes, but for about a fifth, it makes them 3 times larger.
But really, my concern here is mostly about having a hand-rolled solution to encode URLs in 2 different ways. If we used something ..established, I don't care what the resulting format is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you sure there's not a working non-home-cooked way of converting files to data uris?
I googled for a while but did not find one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Even URI::Data supports just parsing them. Oh well.
app/helpers/image_encode_helper.rb
Outdated
data = Base64.encode64(asset.source) | ||
end | ||
|
||
"data:#{asset.content_type};#{encoding},#{data}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Surely there must be a gem/something written specifically for the purpose of converting binary data to data URIs.
Doing this by hand sounds wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, Base64
encodes data into data URIs 😜
Seriously though, Sprockets
does some of this, but it seems difficult to use outside of a stylesheet. You can compare this method with what I have. And why would we want another dependency?
Restart CI |
Restart CI |
@@ -157,6 +158,9 @@ def download_summary_pdf | |||
@embedded = true | |||
@showlinks = false | |||
|
|||
# encode images and embed in HTML that is sent to Prince | |||
@base64_encode_images = true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Upstream code does not have Prince by default, though I think the only other choice is the NullPdf plugin. Even so, if/when we ever create a new PDF plugin, will this base64 encoding of images still be needed there? If not, should this be a property of the PDF plugin system?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Additionally, I don't really like this instance variable hanging out here. I think it might be better if the ImageEncodeHelper has an attr_accessor for this value (it already has the predicate getter), and then either the default is set in that getter on first access, or the value is set here through the setter self.base64_encode_images = true
This might allow for better testing as well, so you can just call a method instead of doing some nasty instance_variable_set in the test.
spec/helpers/quadicon_helper_spec.rb
Outdated
@@ -98,6 +98,8 @@ | |||
# FIXME: complex describe blocks mirror the existing complex control flow | |||
|
|||
describe QuadiconHelper do | |||
helper(ImageEncodeHelper) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Super-minor, but helper
here is a DSL-like method, which usually we avoid the parens on
stub_generator_instance | ||
expect(PdfGenerator.pdf_from_string("html", "css")).to eq "pdf-data" | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this removed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moves the spec for PdfGenerator back to main repo
Oh duh... I need to lrn2read
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved it back to the main repo to be with the corresponding file.
Overall, LGTM. Most of my comments are nitpicks, which could be a follow up PR. Not sure about the svg thing, but it feels like that could be an issue that can be opened and worked on separately from this PR. This PR keeps it in a working state, and research on why it doesn't work as base64 can be a follow up. |
I'd say that with the exception of #1363 (review) -- there's a strong consensus that we don't need the alias -- we can merge this one. Can we, @himdel or have I overlooked something? |
@martinpovolny I'd like to see those issues fixed, which is why I haven't pushed the button. But agreed that there's no serious blocker here and definitely nothing that couldn't be fixed later. |
* Encode FontAwesome and Patternfly icon fonts * Add new image tag and path helpers to encode assets when necessary * Move pdf_generator_spec to main repo
Checked commits hayesr/manageiq-ui-classic@bd879b6~...4d2d963 with ruby 2.2.6, rubocop 0.47.1, and haml-lint 0.20.0 |
Base64 encode fonts and images for PDF rendering (cherry picked from commit 87ddd8f) https://bugzilla.redhat.com/show_bug.cgi?id=1460815
Fine backport details:
|
@dclarizio Backporting this to Euwe branch results in conflicts in multiple files, please create a separate Euwe PR or suggest other PR(s) to backport. |
@simaishi @dclarizio PDF styling seems to be fine in Euwe. I think it was fixed with this PR: ManageIQ/manageiq#15504 |
@miq-bot rm_label euwe/yes |
@miq-bot rm_label euwe/conflict |
Due to the repo split and image digests, the paths for images do not correspond to their location on disk, this prevents Prince from finding them and breaks any rendering with images.
Depends on ManageIQ/manageiq#15131 to write encoded files for Prince.
Problems to fix
Files to adjust
This change
Addresses
https://bugzilla.redhat.com/show_bug.cgi?id=1447940
Currently
After