Failed to execute: Error: "\xFE" from ASCII-8BIT to UTF-8 - ruby-on-rails

Rails 4
*Mac OSX 10.8.4*
I'm using the following Gem for wicked_pdf pdf generation:
gem 'wkhtmltopdf-binary'
gem 'wicked_pdf'
Rendering Views as pdfs works fine and Google displays it's PDF viewer correctly. My PDFs look exactly how I want them to.
The problem arises when I try to save a pdf to disc, for the purpose of emailing them to a user.
For example, this works fine:
def command
#event = Event.find(params[:id])
#client = Contact.find(#event.client_id)
#organizer = Contact.find(#event.organizer_id)
render layout: 'command',
pdf: 'Event Command',
show_as_html: params[:debug].present?,
dpi: 300,
print_media_type: true,
margin: {
top: 0,
bottom: 0,
left: 0,
right: 0
}
end
That will render the pdf in the Google Chrome PDF viewer.
But here, is where I want to generate a PDF and save to file.
def send_email
#event = Event.find(params[:id])
#client = Contact.find(#event.client_id)
#organizer = Contact.find(#event.organizer_id)
proforma = render_to_string(
pdf: 'proforma.pdf',
template: 'events/proforma',
layout: 'proforma'
)
pdf = WickedPdf.new.pdf_from_string(
proforma
)
save_path = Rails.root.join('public','proforma.pdf')
File.open(save_path, 'wb') do |file|
file << pdf
end
end
But I'm getting the error:
Failed to execute:
Error: "\xFE" from ASCII-8BIT to UTF-8

Try this:
File.open(save_path, 'w:ASCII-8BIT') do |file|
file << pdf
end
The PDF rendered as a string in memory seems to be in ASCII, so save it as such :)

Related

Combine_PDF in Ruby on Rails Active Storage Parsing Error

I have been tinkering with Combine_PDF to add a watermark to uploaded documents. I have managed to get it to work combining files locally hosted or through using net/http requests. I would like for it to watermark the file stored in active storage when it is downloaded by a user. I keep getting this error in the terminal:
Warning: parser advancing for unknown reason. Potential data-loss.
And this on the webpage:
Unknown PDF parsing error - malformed PDF file?
Checking documentation this is a very generic error for this gem. The PDF file uploaded to Active Storage is the same one downloaded from the website I used in the net/http parse function. Here is my code:
require 'combine_pdf'
require 'net/http'
def show
user = User.last
respond_to do |format|
format.html
format.pdf do
pdf = CombinePDF.new
url = url_for(#script.document)
pdf = CombinePDF.parse Net::HTTP.get_response(URI.parse(url)).body
pdf.pages.each {|page| page.textbox "#{user.first_name} #{user.last_name}", height: 70, width: 400, y: 200, x: 25}
send_data pdf.to_pdf, filename: "combined.pdf",
type: "application/pdf",
disposition: "inline"
end
end
end
As I stated before this setup works fine when pulling from external hosted pdfs:
require 'combine_pdf'
require 'net/http'
def show
user = User.last
respond_to do |format|
format.html
format.pdf do
pdf = CombinePDF.new
url = "https://www.americanexpress.com/content/dam/amex/us/staticassets/pdf/GCO/Test_PDF.pdf"
pdf = CombinePDF.parse Net::HTTP.get_response(URI.parse(url)).body
pdf.pages.each {|page| page.textbox "#{user.first_name} #{user.last_name}", height: 70, width: 400, y: 200, x: 25}
send_data pdf.to_pdf, filename: "combined.pdf",
type: "application/pdf",
disposition: "inline"
end
end
end
As you can see I used a test PDF from American Express and it works just fine. Its just an issue with Active Storage I can assume. I would prefer not to mess with temp files if at all possible.
Any help is greatly appreciated! Thanks to all in advance.
Try replacing:
pdf = CombinePDF.new
url = url_for(#script.document)
pdf = CombinePDF.parse Net::HTTP.get_response(URI.parse(url)).body
…with:
pdf = #script.document.open { |f| CombinePDF.load(f.path) }

Wicked pdf gem not creating correct data in pdf on rails production server

I am using Wicked pdf gem for creating pdf. It is absolutely working fine on my local. But on production it is giving serious issues. The pdf is generated but in spite of generating a single page it generates 14-15 pages with data like this:
")),this.$.write(e),this.$.close()},find:function(e){return new CKEDITOR.dom.nodeList(this.$.querySelectorAll(e))},findOne:function(e){return(e=this.$.querySelector(e))?new CKEDITOR.dom.element(e):null},_getHtml5ShivFrag:function(){var e=this.getCustomData("html5ShivFrag");return e||
(e=this.$.createDocumentFragment(),CKEDITOR.tools.enableHtml5Elements(e,!0),this.setCustomData("html5ShivFrag",e)),e}}),CKEDITOR.dom.nodeList=function(e){this.$=e},CKEDITOR.dom.nodeList.prototype={count:function(){return this.$.length},getItem:function(e){return
0>e||e>=this.$.length?null:(e=this.$[e])?new CKEDITOR.dom.node(e):null}},CKEDITOR.dom.element=function(e,t){"string"==typeof e&&(e=(t?t.$:document).createElement(e)),CKEDITOR.dom.domObject.call(this,e)},CKEDITOR.dom.element.get=function(e){return(e="string"==typeof e?
document.getElementById(e)||document.getElementsByName(e)[0]:e)&&(e.$?e:new CKEDITOR.dom.element(e))},CKEDITOR.dom.element.prototype=new CKEDITOR.dom.node,CKEDITOR.dom.element.createFromHtml=function(e,t){var n=new CKEDITOR.dom.element("div",t);return
n.setHtml(e),n.getFirst().remove()},CKEDITOR.dom.element.setMarker=function(e,t,n,i){var
r=t.getCustomData("list_marker_id")||t.setCustomData("list_marker_id",CKEDITOR.tools.getNextNumber()).getCustomData("list_marker_id"),o=t.getCustomData("list_marker_names")||t.setCustomData("list_marker_names",{}).getCustomData("list_marker_names");return
e[r]=t,o[n]=1,t.setCustomData(n,i)},CKEDITOR.dom.element.clearAllMarkers=function(e){for(var t in e)CKEDITOR.dom.element.clearMarkers(e,e[t],1)},CKEDITOR.dom.element.clearMarkers=function(e,t,n){var
i,r=t.getCustomData("list_marker_names"),o=t.getCustomData("list_marker_id");for(i in r)t.removeCustomData(i);t.removeCustomData("list_marker_names"),n&&(t.removeCustomData("list_marker_id"),delete e[o])},function(){function e(e,t){return-1<(" "+e+" ").replace(o," ").indexOf(" "+t+"
")}function t(e){var t=!0;return e.$.id||(e.$.id="cke_tmp_"+CKEDITOR.tools.getNextNumber(),t=!1),function(){t||e.removeAttribute("id")}}function n(e,t){var n=CKEDITOR.tools.escapeCss(e.$.id);return"#"+n+" "+t.split(/,\s*/).join(", #"+n+" ")}function i(e){for(var
t=0,n=0,i=a[e].length;i>n;n++)t+=parseInt(this.getComputedStyle(a[e][n])||0,10)||0;return t}var r=document.createElement("_").classList,r="undefined"!=typeof r&&null!==String(r.add).match(/[Native code]/gi),o=/[\n\t\r]/g;CKEDITOR.tools.extend(CKEDITOR.dom.element.prototype,
{type:CKEDITOR.NODE_ELEMENT,addClass:r?function(e){return this.$.classList.add(e),this}:function(t){var n=this.$.className;return n&&(e(n,t)||(n+=" "+t)),this.$.className=n||t,this},removeClass:r?function(e){var t=this.$;retur
The entire 14-15 pages are like this.
This is the method that creates pdf.
def generate_supplier_commission_pdf
#start_date = params[:start_date].to_date.strftime('%d/%m/%Y')
#end_date = params[:end_date].to_date.strftime('%d/%m/%Y')
if params[:sec_filter].present?
sec_filter = true
else
sec_filter = false
end
results = get_report_results_by_type(params[:report_type], #start_date, #end_date, sec_filter)
#results = JSON.parse(results)
#type = params[:report_type].to_i
respond_to do |format|
format.html
format.pdf do
render pdf: "report",
layout: 'pdf_layout',
template: 'reports/generate_supplier_commission_pdf.html.erb',
encoding: 'UTF8',
print_media_type: true,
disposition: 'attachment',
page_size: 'letter',
orientation: 'landscape',
lowquality: 'false',
debug: true
end
end
end
Each and everything like the wkhtml path or anything that can be taken of care of in the code is fine. The only difference I saw is in the logs i.e after this line
***************WICKED***************
Rendered reports/generate_supplier_commission_pdf.html.erb within layouts/pdf_layout (5.2ms)
The following line is not present on server logs.
"***************[\"/usr/bin/wkhtmltopdf\", \"-q\", \"--orientation\", \"landscape\", \"--page-size\", \"letter\", \"--encoding\", \"UTF8\", \"--lowquality\", \"--print-media-type\", \"file:///tmp/wicked_pdf20160903-24256-1v1ay70.html\", \"/tmp/wicked_pdf_generated_file20160903-24256-1da8k68.pdf\"]***************"
I will be really grateful if someone could point out what is going wrong in this case. Thanks in advance.
I managed to resolve this issue by commenting this line in my config/environments/production.rb
# config.assets.js_compressor = :uglifier
and adding this line in it's place:
config.assets.compress = true

How to customize the attachment file name in ROR?

I have a file which returns a pdf attachment as an output. I am using wicked pdf to generate this pdf.
def generate_pdf
render pdf: "#{#user.name}",
template: 'api/v1/doctors/get_report_4.html.erb',
:page_size => 'Letter',
layout: false, disposition: 'attachment',
:margin => {bottom: #margin_bottom, top: #margin_top, left: #margin_left, right: #margin_right},
wkhtmltopdf: %x(bundle exec which wkhtmltopdf).to_s.strip.presence || %x(which wkhtmltopdf).to_s.strip}
end
But while calling this API. I am getting the attachment with name "response.pdf" instead of username.pdf. Please help me with this.

Rails 3 Wicked PDF - include Paperclip S3 pdf files

I have a Rails 3 app that uses these gems:
gem 'paperclip'
gem 'wicked_pdf'
gem 'combine_pdf'
I'm using wicked_pdf to open a pdf for a costproject. The costproject has an HTML page called viewproject.pdf.erb.
I'm trying to combine the wicked pdf with the costproject attachments into a single pdf.
This is my controller code:
def viewproject
#costproject = Costproject.find(params[:costproject_id])
respond_to do |format|
format.html
format.pdf do
pdf = CombinePDF.new
pdf2 = render_to_string pdf: "Costproject.pdf", template: "costprojects/viewproject", encoding: "UTF-8"
pdf << CombinePDF.new(pdf2)
#costproject.attachments.each do |attachment|
pdf << CombinePDF.new(attachment.attach.path)
end
send_data pdf.to_pdf, :disposition => 'inline', :type => "application/pdf"
end
end
end
The line pdf << CombinePDF.new(pdf2) is giving me:
string contains null byte
If I look at pdf2, it starts like this - so it looks like a pdf:
>> pdf2
=> "%PDF-1.4\n1 0 obj\n<<\n/Title (\xFE\xFF)\n/Producer (wkhtmltopdf)\n/CreationDate (D:20150405202628)\n>>\nendobj\n4 0 obj\n<<\n/Type /ExtGState\n/SA true\n/SM 0.02\n/ca 1.0\n/CA 1.0\n/AIS false\n/SMask /None>>\nendobj\n5 0 obj\n[/Pattern /DeviceRGB]\nendobj\n8 0 obj\n<<\n/Type /XObject\n/Subtype /Image\n/Width 71\n/Height 75\n/BitsPerComponent 8\n/ColorSpace /DeviceRGB\n/Length 9 0 R\n/Filter
I also tried pdf << CombinePDF.new(pdf2.to_pdf)
Thanks for the help!
UPDATE1
As a test, to see if pdf2 is working, I did this successfully:
def viewproject
#costproject = Costproject.find(params[:costproject_id])
respond_to do |format|
format.html
format.pdf do
pdf2 = render_to_string pdf: "Costproject.pdf", template: "costprojects/viewproject", encoding: "UTF-8"
send_data pdf2, :disposition => 'inline', :type => "application/pdf"
end
end
end
UPDATE2
Myst was correct about using parse. Thanks!
I am now using this line in the controller code:
pdf << CombinePDF.new(attachment.attach.url)
I get this error:
No such file or directory - http://s3.amazonaws.com/ ...
But, if I copy the http address and paste into the browser the pdf shows up.
I am editing this answer to reflect the issue of remotely stored PDF files.
I should point out that without a persistent connection to the S3 storage and without using the S3 API, the following solution WILL effect performance*.
As I pointed out, the CombinePDF.new method is the same as the CombinePDF.load method. It accepts a file name and attempts to open the file. The CombinePDF.parse method will accept raw PDF data and parses it into a PDF Object.
In the following code I use Net::HTTP.get(URI.parse(url)) to get the raw PDF data.
I recommend replacing this solution with a S3 native solution, so that the whole application can share one or more persistent connections. This is a performance issue that may or may not be important for you.
require 'net/http'
def viewproject
#costproject = Costproject.find(params[:costproject_id])
respond_to do |format|
format.html
format.pdf do
pdf = CombinePDF.new
pdf2 = render_to_string pdf: "Costproject.pdf", template: "costprojects/viewproject", encoding: "UTF-8"
pdf << CombinePDF.parse(pdf2)
#costproject.attachments.each do |attachment|
pdf << CombinePDF.parse( Net::HTTP.get( URI.parse( attachment.attach.url ) ) )
end
send_data pdf.to_pdf, :disposition => 'inline', :type => "application/pdf"
end
end
end
* The performance hit is dependent on the amount of PDF attachments you have, on the number of users your app has, on network traffic, on your framework (single/multi-thread) and other factors.
A persistent connection should reduce the performance hit in a dramatic way, mainly due to the fact that establishing connections is an expensive action.

Rails + Prawn_rails: How do I add an image to my PDF?

I'm using this gem to use Prawn to create a PDF: https://github.com/Whoops/prawn-rails
However, I can't seem to figure out how to add an image. I've tried pdf.image "path/to/img.jpg but it would say the file is not a recognized format.
I've also looked into this on page 101: http://prawn.majesticseacreature.com/manual.pdf , but it doesn't work.
This is happening in the views:
prawn_document() do |pdf|
pdf.image "#{Rails.root}/public/logo.gif"
end
This throws:
Prawn::Errors::UnsupportedImageType at /admin/purchases/6188.pdf
image file is an unrecognised format
Same happens for a .jpg image
I would do something like this.
gem 'prawn'
bundle install
In your controller.
def controller_method
pdf = Prawn::Document.new
begin
pdf_file_path = "#{Rails.root}/public/output"
full_doc = "#{Rails.root}/public/something.png"
pdf.image full_doc
pdf.start_new_page
pdf.render_file pdf_file_path
rescue Prawn::Errors::UnsupportedImageType
flash[:notice] = "Image unsupported"
redirect_to '/handle'
end
end
Adding an image is easy enough.
def download
#document = Document.find(params[:id])
tmp_file = Tempfile.new(Digest::MD5.hexdigest(rand(12).to_s))
pdf = Prawn::Document.generate(tmp_file.path, :margin => 0, :page_size => "A4", :skip_page_creation => true) do |posting|
posting.start_new_page
posting.image #document.user.logo.path
send_data posting.render, :filename => "whatever.pdf", :type => "application/pdf"
end
end
Obviously #document.user.logo.path could be a literal path, that's just a Paperclip attachment in this case.
UPDATE
If it's a literal path you might need to do something like this:
require "open-uri"
def download
...
posting.image File.open("/path/to/image.jpg")
...
end
It seems the latest prawn (version 1.0.0) has changed. You'll get
undefined method `image=' for #<Prawn::Document
if you try and apply something to pdf.image.
This worked for me:
img = "#{Rails.root}/public/my_lovely_image.png"
Prawn::Document.new(background: img)

Resources