module Prawn::Images

Public Instance Methods

build_image_object(file) click to toggle source

Builds an info object (Prawn::Images::*) and a PDF reference representing the given image. Return a pair: [pdf_obj, info].

# File lib/prawn/images.rb, line 78
def build_image_object(file)
  # Rewind if the object we're passed is an IO, so that multiple embeds of
  # the same IO object will work
  file.rewind  if file.respond_to?(:rewind)
  # read the file as binary so the size is calculated correctly
  file.binmode if file.respond_to?(:binmode)

  if file.respond_to?(:read)
    image_content = file.read
  else
    raise ArgumentError, "#{file} not found" unless File.file?(file)  
    image_content = File.binread(file)
  end
  
  image_sha1 = Digest::SHA1.hexdigest(image_content)

  # if this image has already been embedded, just reuse it
  if image_registry[image_sha1]
    info = image_registry[image_sha1][:info]
    image_obj = image_registry[image_sha1][:obj]
  else
    # Build the image object
    klass = case Image.detect_image_format(image_content)
            when :jpg then Prawn::Images::JPG
            when :png then Prawn::Images::PNG
            end
    info = klass.new(image_content)

    # Bump PDF version if the image requires it
    min_version(info.min_pdf_version) if info.respond_to?(:min_pdf_version)

    # Add the image to the PDF and register it in case we see it again.
    image_obj = info.build_pdf_object(self)
    image_registry[image_sha1] = {:obj => image_obj, :info => info}
  end

  [image_obj, info]
end
embed_image(pdf_obj, info, options) click to toggle source

Given a PDF image resource pdf_obj that has been added to the page's resources and an info object (the pair returned from #build_image_object), embed the image according to the options given.

# File lib/prawn/images.rb, line 122
def embed_image(pdf_obj, info, options)
  # find where the image will be placed and how big it will be  
  w,h = info.calc_image_dimensions(options)

  if options[:at]     
    x,y = map_to_absolute(options[:at]) 
  else                  
    x,y = image_position(w,h,options) 
    move_text_position h   
  end

  # add a reference to the image object to the current page
  # resource list and give it a label
  label = "I#{next_image_id}"
  state.page.xobjects.merge!(label => pdf_obj)

  # add the image to the current page
  instruct = "\nq\n%.3f 0 0 %.3f %.3f %.3f cm\n/%s Do\nQ"
  add_content instruct % [ w, h, x, y - h, label ]
end
image(file, options={}) click to toggle source

Add the image at filename to the current page. Currently only JPG and PNG files are supported.

NOTE: Prawn is very slow at rendering PNGs with alpha channels, and this uses a lot of RAM. The workaround for those who don't mind installing RMagick is to use:

github.com/amberbit/prawn-fast-png

Arguments:

file

path to file or an object that responds to read

Options:

:at

an array [x,y] with the location of the top left corner of the image.

:position

One of (:left, :center, :right) or an x-offset

:vposition

One of (:top, :center, :center) or an y-offset

:height

the height of the image [actual height of the image]

:width

the width of the image [actual width of the image]

:scale

scale the dimensions of the image proportionally

:fit

scale the dimensions of the image proportionally to fit inside [width,height]

Prawn::Document.generate("image2.pdf", :page_layout => :landscape) do     
  pigs = "#{Prawn::DATADIR}/images/pigs.jpg" 
  image pigs, :at => [50,450], :width => 450                                      

  dice = "#{Prawn::DATADIR}/images/dice.png"
  image dice, :at => [50, 450], :scale => 0.75 
end

If only one of :width / :height are provided, the image will be scaled proportionally. When both are provided, the image will be stretched to fit the dimensions without maintaining the aspect ratio.

If :at is provided, the image will be place in the current page but the text position will not be changed.

If instead of an explicit filename, an object with a read method is passed as file, you can embed images from IO objects and things that act like them (including Tempfiles and open-uri objects).

require "open-uri"

Prawn::Document.generate("remote_images.pdf") do 
  image open("http://prawn.majesticseacreature.com/media/prawn_logo.png")
end

This method returns an image info object which can be used to check the dimensions of an image object if needed. (See also: Prawn::Images::PNG , Prawn::Images::JPG)

# File lib/prawn/images.rb, line 65
def image(file, options={})
  Prawn.verify_options [:at, :position, :vposition, :height, 
                        :width, :scale, :fit], options

  pdf_obj, info = build_image_object(file)
  embed_image(pdf_obj, info, options)

  info
end

Private Instance Methods

determine_y_with_page_flow(h) click to toggle source
# File lib/prawn/images.rb, line 175
def determine_y_with_page_flow(h)
  if overruns_page?(h)
    bounds.move_past_bottom
  end
  self.y
end
image_position(w,h,options) click to toggle source
# File lib/prawn/images.rb, line 145
def image_position(w,h,options)
  options[:position] ||= :left
  
  y = case options[:vposition]
  when :top
    bounds.absolute_top
  when :center
    bounds.absolute_top - (bounds.height - h) / 2.0
  when :bottom
    bounds.absolute_bottom + h
  when Numeric
    bounds.absolute_top - options[:vposition]
  else
    determine_y_with_page_flow(h)
  end

  x = case options[:position] 
  when :left
    bounds.left_side
  when :center
    bounds.left_side + (bounds.width - w) / 2.0 
  when :right
    bounds.right_side - w
  when Numeric
    options[:position] + bounds.left_side
  end

  return [x,y]
end
image_registry() click to toggle source
# File lib/prawn/images.rb, line 186
def image_registry
  @image_registry ||= {}
end
next_image_id() click to toggle source
# File lib/prawn/images.rb, line 190
def next_image_id
  @image_counter ||= 0
  @image_counter += 1
end
overruns_page?(h) click to toggle source
# File lib/prawn/images.rb, line 182
def overruns_page?(h)
  (self.y - h) < reference_bounds.absolute_bottom 
end