How do you add a border to an image with Prawn? - ruby

How can I add a border to an image with Prawn (pdf library)? If this is possible, can you add padding as well?

You can add a border using a bounding_box and stroke_bounds. In this example, I've put a border around an image. I've even given it padding of 15. It should be relatively easy to make this a function where a padding parameter could be used to calculate the difference between the image width and the bounding_box width.
require 'prawn'
Prawn::Document.generate("test.pdf") do
text "Boxed Image", :align=>:center, :size=>20
bounding_box([0, cursor], :width => 330) do
move_down 15
image "image.jpg", :fit => [300, 600], :position => :center
move_down 15
stroke_bounds
end
end

Related

prawn gem: Problem with positioning the text

I'm using prawn gem to display a text in a pdf in two different positions and rotations as shown in the below image
I've managed to get the first one working but I couldn't able to get the second. Below is the image of what I got now
Here is the code
require "prawn"
Prawn::Document.generate("hello.pdf") do
text "{rquestID hashtag}", align: :left, valign: :left, rotate: -90
text "{rquestID hashtag}", align: :right, valign: :bottom, rotate: 90
end
Any help would be appreciated, Thanks!
I'm not sure why your code isn't producing the results you want, but you can use text_box to get around it, e.g.:
text_box "{rquestID hashtag}", align: :right, valign: :bottom, rotate: 90,
:width => 100, :height => 100, :at => [500, 100]
(You may have to play around with the numbers.)

Prawn doesn't seem to push layout down when using repeat(:all)

I am generating a document with data that flows onto each subsequent page, each page has a standard header. However, when I use repeat(:all) to put the header on each page, I find that on every page but the first page, the next content is not being moved down by the size of the header banner I have put on the page.
My code for generating the banner:
class SmartsoftPdf < Prawn::Document
BOX_MARGIN = 30
RHYTHM = 10
INNER_MARGIN = 30
# Colors
#
BLACK = "000000"
LIGHT_GRAY = "F2F2F2"
GRAY = "DDDDDD"
DARK_GRAY = "333333"
BROWN = "A4441C"
ORANGE = "F28157"
LIGHT_GOLD = "FBFBBE"
DARK_GOLD = "EBE389"
BLUE = "08C"
GREEN = "00ff00"
RED = "ff0000"
def show_header(text,date)
header_box do
image "#{Rails.root}/app/assets/images/smart_records_logo_h60.png", :height => 40
draw_text text,
:at => [80,25], :size => 12, :style => :bold, :color => BLUE
draw_text "Date: #{ausDate(date)}",
:at => [bounds.right - 100,bounds.top - 15], :size => 10 if date
end
end
def header_box(&block)
bounding_box([-bounds.absolute_left, cursor + BOX_MARGIN + 8],
:width => bounds.absolute_left + bounds.absolute_right,
:height => BOX_MARGIN*2) do
fill_color LIGHT_GRAY
fill_rectangle([bounds.left, bounds.top],
bounds.right,
bounds.top - bounds.bottom)
fill_color BLACK
move_down(RHYTHM)
indent(BOX_MARGIN, &block)
end
stroke_color GRAY
stroke_horizontal_line(-BOX_MARGIN, bounds.width + BOX_MARGIN, :at => cursor)
stroke_color BLACK
move_down(RHYTHM*4)
end
end
Then within the pdf generation itself I do:
repeat(:all) do
show_header("Custom Report",DateTime.now())
end
However, when I start putting content onto the pages, I expect when the content overflows onto the next page that the content will show up after the header. I'm finding that the header overlaps the content instead.
Here is an image which illustrates the problem: http://i.imgur.com/mSy2but.png
Am I building the header box incorrectly? Do I need to do something additional to make it so that the content which spills into the next page gets pushed down the appropriate amount?
Okay. I have solved this myself. Most recent version of Prawn has a better way to handle this case. When you use repeat(:all) the page is reopened AFTER document creation and your content creation items are then added. This doesn't push the page down. The correct way to add this header to every page is to use the "canvas" method which allows you to operate out of the bounds of the page margin. Use canvas to draw a box at the top of the page, and set the top_margin of the page to push all content below the banner.
canvas do
bounding_box([bounds.left,bounds.top],
:width => bounds.absolute_left + bounds.absolute_right,
:height => BOX_MARGIN*2) do
fill_color LIGHT_GRAY
fill_rectangle([bounds.left, bounds.top],
bounds.right,
bounds.top - bounds.bottom)
fill_color BLACK
move_down(RHYTHM)
indent(BOX_MARGIN, &block)
end
stroke_color GRAY
stroke_horizontal_line(-BOX_MARGIN, bounds.width + BOX_MARGIN, :at => cursor)
stroke_color BLACK
end
at document creation...
def initialize(options = {})
super(:page_layout => :landscape,:top_margin => HEIGHT_OF_BANNER)
end

Watermarking with Prawn (using templates)

I need to be able to watermark a document that was created from a template. I have the following code right now:
# Note: the raw PDF text (body variable below) is sent from a remote server.
Prawn::Document.new(:template => StringIO.new(body), :page_size =>
'A4') do |document|
# ... including other pages and sections to the template here ...
# watermark
d.page_count.times do |i|
d.go_to_page i
d.stroke_line [d.bounds.left, d.bounds.bottom], [d.bounds.right, d.bounds.top]
d.draw_text "Watermark", :rotate => 45, :at => [100,100], :size => 100
end
end
This is ignoring the templated pages for some reason that I can't comprehend. Now here's where the plot thickens: if the server adds a watermark, then this code will work as expected (e.g. straight Ruby code = no overlaying text on the non-prawn-generated pages, yet watermarking works on a pre-watermarked template). My only guess is there is some way to create a z-index/layer that the server is doing but Prawn itself cannot.
Here is a portion of the code from the server that does the PDF
generation itself, this does the watermarking using iText:
PdfStamper stamper = new PdfStamper(...);
PdfContentByte over = stamper.GetOverContent(i + 1);
over.BeginText();
over.SetTextMatrix(20, 40);
over.SetFontAndSize(bf, 20);
over.SetColorFill(new Color(97, 150, 58));
over.ShowTextAligned(Element.ALIGN_CENTER,
watermarkText,
document.PageSize.Width / 2,
document.PageSize.Height / 2,
55);
over.EndText();
over.Stroke();
If that runs before I use the raw data in Prawn I can watermark, go
figure.
So my questions are:
Anyone know how I can achieve the same effect using prawn instead
of a hybrid? I'd rather handle the watermarking locally.
Is there a basic equivalent to GetOverContent() in Prawn?
Is there a better way to get a string of raw PDF data into Prawn
without using :template and StringIO? (I saw the #add_content method
but that didn't work)
TL;DR: I need to float text above the Prawn templated text a la
watermarking the document.
Any insight or paths I can research will be appreciated. If this
makes no sense I can clarify.
You could try stamping the document.
create_stamp("watermark") do
rotate(30, :origin => [-5, -5]) do
stroke_color "FF3333"
stroke_ellipse [0, 0], 29, 15
stroke_color "000000"
fill_color "993333"
font("Times-Roman") do
draw_text "Watermark", :at => [-23, -3]
end
fill_color "000000"
end
end
stamp_at "watermark", [210, 210]
create_stamp("stamp") do
fill_color "cc0000"
text_rendering_mode(:fill_stroke) do
transparent(0.5){
text_box "WATERMARK",
:size => 50,
:width => bounds.width,
:height => bounds.height,
:align => :center,
:valign => :center,
:at => [0, bounds.height],
:rotate => 45,
:rotate_around => :center
}
end
end
repeat (:all) do
stamp("stamp")
end

Appending a line of text in a Text_Box in ruby shoes

How do you append a line of text in a Text_Box in ruby shoes? I can see no way of doing this. Currently I am writing to a text file then opening that text file to get newly appended content.
here two ways, one with the initialisation and one after
Shoes.app :width => 300, :height => 450 do
#text = edit_box :width => 1.0, :height => 400, :text =>'test'
#text.text = "test2"
end
You have 7 forms of Text_Box:
banner, a 48 pixel font.
title, a 34 pixel font.
subtitle, a 26 pixel font.
tagline, an 18 pixel font.
caption, a 14 pixel font.
para, a 12 pixel font.
inscription, a 10 pixel font.
To create a Text_Box of 12 pixel font you need to do that:
Shoes.app do
#text_box_example = para "Some text \n"
#To append line:
#text_box_example.replace #text_box_example + "New line of text\n"
end
This is a little late but you can do it like this:
require 'green_shoes'
Shoes.app do
background "#EFC"
flow :width=>'100%', :margin=>10 do
stack do
title "Green shoes append example"
end
#j=edit_box("Data")
stack :width=>150 do
b=button "Click me"
b.click{
#j.text= "#{#j.text} New line of text\n"
}
end
end
end
j is the name of the edit_box.

Centring a flow in Shoes

Can I center the contents of a flow in Shoes?
I know that a paragraph can be centred like:
para 'Centred paragrpah', :align=>'center'
However, this does not work with flows:
flow(:align=>'center') do
…
end
No errors are brought up, but the contents remain left justified.
Not completely sure. What is it in your flow you are trying to centre? You can try a margin left trick as per HTML and CSS.
This gives a flow with left, centre and right justified text that remains centred in the window as it is resized:
Shoes.app do
flow do
style(:margin_left => '50%', :left => '-25%')
border blue
para "Some left justified text\n", :align => 'left'
para "Some centred text\n", :align => 'center'
para "some right justified text\n", :align => 'right'
end
end

Resources