module Thinreports::Generator::PDF::Graphics
Constants
- BASE_LINE_WIDTH
- STROKE_DASH
Public Instance Methods
@param [String] base64_data @param [Numeric, Strng] x @param [Numeric, Strng] y @param [Numeric, Strng] w @param [Numeric, Strng] h
# File lib/thinreports/generator/pdf/document/graphics/image.rb, line 26 def base64image(base64_data, x, y, w, h) image_data = Base64.decode64(base64_data) image_id = Digest::MD5.hexdigest(base64_data) image_path = create_temp_imagefile(image_id, image_data) image(image_path, x, y, w, h) end
@param [Hash] styles @return [Hash, nil]
# File lib/thinreports/generator/pdf/document/graphics/basic.rb, line 126 def build_fill_styles(styles) color = styles[:fill] return nil unless color && color != 'none' { color: parse_color(color) } end
@param [Hash] style @yield [attrs] @yieldparam [Hash] attrs @return [Hash]
# File lib/thinreports/generator/pdf/document/graphics/attributes.rb, line 11 def build_graphic_attributes(style, &block) graphic_attributes = { stroke: style['border-color'], stroke_width: style['border-width'], stroke_type: style['border-style'], fill: style['fill-color'] } block.call(graphic_attributes) if block_given? graphic_attributes end
@param [Hash] styles @return [Hash, nil]
# File lib/thinreports/generator/pdf/document/graphics/basic.rb, line 111 def build_stroke_styles(styles) color = styles[:stroke] width = styles[:stroke_width] return nil unless color && color != 'none' return nil unless width && width != 0 { color: parse_color(color), width: s2f(width), dash: STROKE_DASH[styles[:stroke_type].to_sym] } end
@param [Hash] style @yield [attrs] @yieldparam [Hash] attrs @return [Hash]
# File lib/thinreports/generator/pdf/document/graphics/attributes.rb, line 26 def build_text_attributes(style, &block) text_attributes = { font: font_family(style['font-family']), size: style['font-size'], color: style['color'], align: text_align(style['text-align']), valign: text_valign(style['vertical-align']), styles: font_styles(style['font-style']), letter_spacing: letter_spacing(style['letter-spacing']), line_height: line_height(style['line-height']), overflow: text_overflow(style['overflow']), word_wrap: word_wrap(style['word-wrap']) } block.call(text_attributes) if block_given? text_attributes end
# File lib/thinreports/generator/pdf/document/graphics/image.rb, line 72 def clean_temp_images temp_image_registry.each_value do |image_path| File.delete(image_path) if File.exist?(image_path) end end
@param [String] image_id @param [String] image_data @return [String] Path to imagefile
# File lib/thinreports/generator/pdf/document/graphics/image.rb, line 85 def create_temp_imagefile(image_id, image_data) temp_image_registry[image_id] ||= begin file = Tempfile.new('temp-image') file.binmode file.write(image_data) file.open file end temp_image_registry[image_id].path end
@param [Numeric, String] x center-x @param [Numeric, String] y center-y @param [Numeric, String] rx @param [Numeric, String] ry @param [Hash] attrs ({}) @option attrs [String] :stroke @option attrs [Numeric, String] :stroke_width @option attrs [Array<Integer, String>] :stroke_dash @option attrs [“solid”, “dashed”, “dotted”] :stroke_type @option attrs [String] :fill
# File lib/thinreports/generator/pdf/document/graphics/basic.rb, line 59 def ellipse(x, y, rx, ry, attrs = {}) rx, ry = s2f(rx, ry) with_graphic_styles(attrs) do pdf.ellipse(pos(x, y), rx, ry) end end
@param [Array<String>] font_names @return [String]
# File lib/thinreports/generator/pdf/document/graphics/attributes.rb, line 45 def font_family(font_names) font_name = font_names.first default_family_if_missing(font_name) end
@param [Array<String>] styles @return [Array<Symbol>]
# File lib/thinreports/generator/pdf/document/graphics/attributes.rb, line 52 def font_styles(styles) styles.map do |font_style| case font_style when 'bold' then :bold when 'italic' then :italic when 'underline' then :underline when 'linethrough' then :strikethrough end end end
@param [String, IO] filename_or_io @param [Numeric, Strng] x @param [Numeric, Strng] y @param [Numeric, Strng] w @param [Numeric, Strng] h
# File lib/thinreports/generator/pdf/document/graphics/image.rb, line 16 def image(filename_or_io, x, y, w, h) w, h = s2f(w, h) pdf.image(filename_or_io, at: pos(x, y), width: w, height: h) end
@param [String, IO] filename_or_io @param [Numeric, Strng] x @param [Numeric, Strng] y @param [Numeric, Strng] w @param [Numeric, Strng] h @param [Hash] options @option options [:left, :center, :right] :position_x (:left) @option options [:top, :center, :bottom] :position_y (:top) @option options [Numeric] :offset_x @option options [Numeric] :offset_y
# File lib/thinreports/generator/pdf/document/graphics/image.rb, line 44 def image_box(filename_or_io, x, y, w, h, options = {}) w, h = s2f(w, h) computed_position = pos( x + (options[:offset_x] || 0), y + (options[:offset_y] || 0) ) pdf.bounding_box(computed_position, width: w, height: h) do pdf.image( filename_or_io, position: options[:position_x] || :left, vposition: options[:position_y] || :top, auto_fit: [w, h] ) end end
# File lib/thinreports/generator/pdf/document/graphics/image.rb, line 61 def image_dimensions(filename_or_io, x, y, w, h, options = {}) w, h = s2f(w, h) # XXX: Calling @private method _pdf_obj, info = pdf.build_image_object(filename_or_io) info.calc_image_dimensions( position: options[:position_x] || :left, vposition: options[:position_y] || :top, auto_fit: [w, h] ) end
@param [“left”, “center”, “right”, “”] position @return [:left, :center, :right]
# File lib/thinreports/generator/pdf/document/graphics/attributes.rb, line 123 def image_position_x(position) case position when 'left' then :left when 'center' then :center when 'right' then :right when '' then :left else :left end end
@param [“top”, “middle”, “bottom”, “”] position @return [:left, :center, :right]
# File lib/thinreports/generator/pdf/document/graphics/attributes.rb, line 135 def image_position_y(position) case position when 'top' then :top when 'middle' then :center when 'bottom' then :bottom when '' then :top else :top end end
@param [Float, “”, nil] spacing @return [Float, nil]
# File lib/thinreports/generator/pdf/document/graphics/attributes.rb, line 65 def letter_spacing(spacing) blank_value?(spacing) ? nil : spacing end
@param [Numeric, String] x1 @param [Numeric, String] y1 @param [Numeric, String] x2 @param [Numeric, String] y2 @param [Hash] attrs ({}) @option attrs [String] :stroke @option attrs [Numeric, String] :stroke_width @option attrs [“solid”, “dashed”, “dotted”] :stroke_type
# File lib/thinreports/generator/pdf/document/graphics/basic.rb, line 20 def line(x1, y1, x2, y2, attrs = {}) with_graphic_styles(attrs) do pdf.line(pos(x1, y1), pos(x2, y2)) end end
@param [Float, “”, nil] height @return [Float, nil]
# File lib/thinreports/generator/pdf/document/graphics/attributes.rb, line 117 def line_height(height) blank_value?(height) ? nil : height end
@param [Numeric, String] x @param [Numeric, String] y @param [Numeric, String] w width @param [Numeric, String] h height @param [Hash] attrs ({}) @option attrs [Integer, String] :radius @option attrs [String] :stroke @option attrs [Numeric, String] :stroke_width @option attrs [“solid”, “dashed”, “dotted”] :stroke_type @option attrs [String] :fill
# File lib/thinreports/generator/pdf/document/graphics/basic.rb, line 36 def rect(x, y, w, h, attrs = {}) w, h = s2f(w, h) radius = s2f(attrs[:radius]) with_graphic_styles(attrs) do if radius && !radius.zero? pdf.rounded_rectangle(pos(x, y), w, h, radius) else pdf.rectangle(pos(x, y), w, h) end end end
# File lib/thinreports/generator/pdf/document/graphics/image.rb, line 78 def temp_image_registry @temp_image_registry ||= {} end
@see text_box
# File lib/thinreports/generator/pdf/document/graphics/text.rb, line 57 def text(content, x, y, w, h, attrs = {}) # Set the :overflow property to :shirink_to_fit. text_box(content, x, y, w, h, { overflow: :shirink_to_fit }.merge(attrs)) end
@param [“left”, “center”, “right”, “”] align @return [:left, :center, :right]
# File lib/thinreports/generator/pdf/document/graphics/attributes.rb, line 71 def text_align(align) case align when 'left' then :left when 'center' then :center when 'right' then :right when '' then :left else :left end end
@param [String] content @param [Numeric, String] x @param [Numeric, String] y @param [Numeric, String] w @param [Numeric, String] h @param [Hash] attrs ({}) @option attrs [String] :font @option attrs [Numeric, String] :size @option attrs [String] :color @option attrs [Array<:bold, :italic, :underline, :strikethrough>]
:styles (nil)
@option attrs [:left, :center, :right] :align (:left) @option attrs [:top, :center, :bottom] :valign (:top) @option attrs [Numeric, String] :line_height The total height of an text line. @option attrs [Numeric, String] :letter_spacing @option attrs [Boolean] :single (false) @option attrs [:trancate, :shrink_to_fit, :expand] :overflow (:trancate) @option attrs [:none, :break_word] :word_wrap (:none)
# File lib/thinreports/generator/pdf/document/graphics/text.rb, line 25 def text_box(content, x, y, w, h, attrs = {}, &block) w, h = s2f(w, h) box_attrs = text_box_attrs( x, y, w, h, single: attrs.delete(:single), overflow: attrs[:overflow] ) # Do not break by word unless :word_wrap is :break_word content = text_without_line_wrap(content) if attrs[:word_wrap] == :none with_text_styles(attrs) do |built_attrs, font_styles| if block block.call [{ text: content, styles: font_styles }], built_attrs.merge(box_attrs) else pdf.formatted_text_box( [{ text: content, styles: font_styles }], built_attrs.merge(box_attrs) ) end end rescue Prawn::Errors::CannotFit # Nothing to do. # # When the area is too small compared # with the content and the style of the text. # (See prawn/core/text/formatted/line_wrap.rb#L185) end
@param [“truncate”, “fit”, “expand”, “”, nil] overflow @return [:truncate, :shrink_to_fit, :expand]
# File lib/thinreports/generator/pdf/document/graphics/attributes.rb, line 95 def text_overflow(overflow) case overflow when 'truncate' then :truncate when 'fit' then :shrink_to_fit when 'expand' then :expand when '' then :truncate else :truncate end end
@param [“top”, “middle”, “bottom”, “”, nil] valign @return [:top, :center, :bottom]
# File lib/thinreports/generator/pdf/document/graphics/attributes.rb, line 83 def text_valign(valign) case valign when 'top' then :top when 'middle' then :center when 'bottom' then :bottom when '' then :top else :top end end
@param [Hash] attrs
# File lib/thinreports/generator/pdf/document/graphics/basic.rb, line 68 def with_graphic_styles(attrs, &block) stroke = build_stroke_styles(attrs) fill = build_fill_styles(attrs) # Do not draw if no colors given. return unless fill || stroke save_graphics_state # Apply stroke-dashed. if stroke && stroke[:dash] length, space = stroke[:dash] pdf.dash(length, space: space) end # Draw with fill and stroke. if fill && stroke pdf.fill_and_stroke do line_width(stroke[:width]) pdf.fill_color(fill[:color]) pdf.stroke_color(stroke[:color]) block.call end # Draw only with fill. elsif fill pdf.fill do pdf.fill_color(fill[:color]) block.call end # Draw only with stroke. elsif stroke pdf.stroke do line_width(stroke[:width]) pdf.stroke_color(stroke[:color]) block.call end end restore_graphics_state end
@param [“break-word”, “none”, “”, nil] word_wrap
@return [:break_word, :none]
# File lib/thinreports/generator/pdf/document/graphics/attributes.rb, line 107 def word_wrap(word_wrap) case word_wrap when 'break-word' then :break_word when 'none' then :none else :none end end
Private Instance Methods
@param [Numeric] width
# File lib/thinreports/generator/pdf/document/graphics.rb, line 17 def line_width(width) pdf.line_width(width * BASE_LINE_WIDTH) end
Delegate to Prawn::Document#restore_graphic_state @see Prawn::Document#restore_graphics_state
# File lib/thinreports/generator/pdf/document/graphics.rb, line 29 def restore_graphics_state pdf.restore_graphics_state end
Delegate to Prawn::Document#save_graphic_state @see Prawn::Document#save_graphics_state
# File lib/thinreports/generator/pdf/document/graphics.rb, line 23 def save_graphics_state pdf.save_graphics_state end
Change the default graphic states defined by Prawn.
# File lib/thinreports/generator/pdf/document/graphics.rb, line 12 def setup_custom_graphic_states pdf.line_width(BASE_LINE_WIDTH) end
@param x (see text_box
) @param y (see text_box
) @param w (see text_box
) @param h (see text_box
) @param [Hash] states @option states [Boolean] :single @option states [Symbold] :overflow @return [Hash]
# File lib/thinreports/generator/pdf/document/graphics/text.rb, line 72 def text_box_attrs(x, y, w, h, states = {}) attrs = { at: pos(x, y), width: s2f(w) } if states[:single] states[:overflow] != :expand ? attrs.merge(single_line: true) : attrs else attrs.merge(height: s2f(h)) end end
@param [Numeric] line_height
@param [Hash] font @option font [String] :name Name of font. @option font [Numeric] :size Size of font. @return [Numeric]
# File lib/thinreports/generator/pdf/document/graphics/text.rb, line 127 def text_line_leading(line_height, font) line_height - pdf.font(font[:name], size: font[:size]).height end
@param [String] content @return [String]
# File lib/thinreports/generator/pdf/document/graphics/text.rb, line 133 def text_without_line_wrap(content) content.gsub(/ /, Prawn::Text::NBSP) end
@param [Hash] attrs @param [Hash] font @option font [String] :color @option font [Numeric] :size @option font [String] :name @yield [attributes, styles] @yieldparam [Hash] modified_attrs @yieldparam [Array] styles
# File lib/thinreports/generator/pdf/document/graphics/text.rb, line 145 def with_font_styles(attrs, font, &block) # Building font styles. styles = attrs.delete(:styles) if styles manual, styles = styles.partition do |style| %i[bold italic].include?(style) && !font_has_style?(font[:name], style) end end # Emulate bold style. if manual && manual.include?(:bold) pdf.stroke_color(font[:color]) pdf.line_width(font[:size] * 0.025) # Change rendering mode to :fill_stroke. attrs[:mode] = :fill_stroke end # Emulate italic style. if manual && manual.include?(:italic) # FIXME # pdf.transformation_matrix(1, 0, 0.26, 1, 0, 0) end pdf.font(font[:name], size: font[:size]) do pdf.fill_color(font[:color]) block.call(attrs, styles || []) end end
@param attrs (see text
) @yield [built_attrs, font_styles
] @yieldparam [Hash] built_attrs The finalized attributes. @yieldparam [Array] font_styles
The finalized styles.
# File lib/thinreports/generator/pdf/document/graphics/text.rb, line 88 def with_text_styles(attrs, &block) # When no color is given, do not draw. return unless attrs.key?(:color) && attrs[:color] != 'none' save_graphics_state fontinfo = { name: attrs.delete(:font).to_s, color: parse_color(attrs.delete(:color)), size: s2f(attrs.delete(:size)) } # Add the specified value to :leading option. line_height = attrs.delete(:line_height) if line_height attrs[:leading] = text_line_leading( s2f(line_height), name: fontinfo[:name], size: fontinfo[:size] ) end # Set the :character_spacing option. spacing = attrs.delete(:letter_spacing) attrs[:character_spacing] = s2f(spacing) if spacing # Or... with_font_styles(attrs, fontinfo, &block) with_font_styles(attrs, fontinfo) do |modified_attrs, styles| block.call(modified_attrs, styles) end restore_graphics_state end