lib/prawn/images.rb in prawn-0.2.3 vs lib/prawn/images.rb in prawn-0.3.0
- old
+ new
@@ -16,15 +16,17 @@
#
# Arguments:
# <tt>file</tt>:: path to file or an object that responds to #read
#
# Options:
- # <tt>:at</tt>:: the location of the top left corner of the image.
+ # <tt>:at</tt>:: an array [x,y] with the location of the top left corner of the image.
# <tt>:position</tt>:: One of (:left, :center, :right) or an x-offset
+ # <tt>:vposition</tt>:: One of (:top, :center, :center) or an y-offset
# <tt>:height</tt>:: the height of the image [actual height of the image]
# <tt>:width</tt>:: the width of the image [actual width of the image]
- # <tt>:scale</tt>:: scale the dimensions of the image proportionally
+ # <tt>:scale</tt>:: scale the dimensions of the image proportionally
+ # <tt>:fit</tt>:: scale the dimensions of the image proportionally to fit inside [width,height]
#
# Prawn::Document.generate("image2.pdf", :page_layout => :landscape) do
# pigs = "#{Prawn::BASEDIR}/data/images/pigs.jpg"
# image pigs, :at => [50,450], :width => 450
#
@@ -34,10 +36,15 @@
#
# 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"
@@ -48,18 +55,19 @@
#
# 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)
#
- def image(file, options={})
- Prawn.verify_options [:at,:position, :height, :width, :scale], options
-
+ def image(file, options={})
+ Prawn.verify_options [:at, :position, :vposition, :height,
+ :width, :scale, :fit], options
+
if file.respond_to?(:read)
image_content = file.read
else
raise ArgumentError, "#{file} not found" unless File.file?(file)
- image_content = File.read_binary(file)
+ image_content = File.binread(file)
end
image_sha1 = Digest::SHA1.hexdigest(image_content)
# register the fact that the current page uses images
@@ -84,11 +92,12 @@
image_registry[image_sha1] = {:obj => image_obj, :info => info}
end
# find where the image will be placed and how big it will be
w,h = calc_image_dimensions(info, options)
- if options[:at]
+
+ if options[:at]
x,y = translate(options[:at])
else
x,y = image_position(w,h,options)
move_text_position h
end
@@ -107,41 +116,64 @@
private
def image_position(w,h,options)
options[:position] ||= :left
+
x = case options[:position]
when :left
bounds.absolute_left
when :center
bounds.absolute_left + (bounds.width - w) / 2.0
when :right
bounds.absolute_right - w
when Numeric
options[:position] + bounds.absolute_left
- end
-
+ end
+
+ 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
+ self.y
+ end
return [x,y]
end
def build_jpg_object(data, jpg)
color_space = case jpg.channels
when 1
:DeviceGray
+ when 3
+ :DeviceRGB
when 4
:DeviceCMYK
else
- :DeviceRGB
+ raise ArgumentError, 'JPG uses an unsupported number of channels'
end
obj = ref(:Type => :XObject,
:Subtype => :Image,
:Filter => :DCTDecode,
:ColorSpace => color_space,
:BitsPerComponent => jpg.bits,
:Width => jpg.width,
:Height => jpg.height,
:Length => data.size )
+
+ # add extra decode params for CMYK images. By swapping the
+ # min and max values from the default, we invert the colours. See
+ # section 4.8.4 of the spec.
+ if color_space == :DeviceCMYK
+ obj.data[:Decode] = [ 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0 ]
+ end
+
obj << data
return obj
end
def build_png_object(data, png)
@@ -250,11 +282,10 @@
return obj
end
def calc_image_dimensions(info, options)
- # TODO: allow the image to be aligned in a box
w = options[:width] || info.width
h = options[:height] || info.height
if options[:width] && !options[:height]
wp = w / info.width.to_f
@@ -265,11 +296,23 @@
w = info.width * hp
h = info.height * hp
elsif options[:scale]
w = info.width * options[:scale]
h = info.height * options[:scale]
+ elsif options[:fit]
+ bw, bh = options[:fit]
+ bp = bw / bh.to_f
+ ip = info.width / info.height.to_f
+ if ip > bp
+ w = bw
+ h = bw / ip
+ else
+ h = bh
+ w = bh * ip
+ end
end
-
+ info.scaled_width = w
+ info.scaled_height = h
[w,h]
end
def detect_image_format(content)
top = content[0,128]