class Origami::ContentStream

A class representing a Stream containing the contents of a Page.

Forward declarations.

Constants

DEFAULT_DASHPATTERN
DEFAULT_FILL_COLOR
DEFAULT_FONT
DEFAULT_LEADING
DEFAULT_LINECAP
DEFAULT_LINEJOIN
DEFAULT_LINEWIDTH
DEFAULT_SIZE
DEFAULT_STROKE_COLOR

Attributes

canvas[RW]

Public Class Methods

new(data = "", dictionary = {}) click to toggle source
Calls superclass method
# File lib/origami/graphics/xobject.rb, line 40
def initialize(data = "", dictionary = {})
    super

    @instructions = nil
    @canvas = Graphics::DummyCanvas.new
end

Public Instance Methods

draw_image(name, attr = {}) click to toggle source
# File lib/origami/graphics/xobject.rb, line 75
def draw_image(name, attr = {})
    load!

    x, y = attr[:x], attr[:y]

    @instructions << PDF::Instruction.new('q')
    @instructions << PDF::Instruction.new('cm', 300, 0, 0, 300, x, y)
    @instructions << PDF::Instruction.new('Do', name)
    @instructions << PDF::Instruction.new('Q')
end
draw_line(from, to, attr = {}) click to toggle source

Draw a straight line from the point at coord from, to the point at coord to.

# File lib/origami/graphics/xobject.rb, line 89
def draw_line(from, to, attr = {})
    draw_polygon([from, to], attr)
end
draw_polygon(coords = [], attr = {}) click to toggle source

Draw a polygon from a array of coordinates.

# File lib/origami/graphics/xobject.rb, line 96
def draw_polygon(coords = [], attr = {})
    load!

    stroke_color  = attr.fetch(:stroke_color, DEFAULT_STROKE_COLOR)
    fill_color    = attr.fetch(:fill_color, DEFAULT_FILL_COLOR)
    line_cap      = attr.fetch(:line_cap, DEFAULT_LINECAP)
    line_join     = attr.fetch(:line_join, DEFAULT_LINEJOIN)
    line_width    = attr.fetch(:line_width, DEFAULT_LINEWIDTH)
    dash_pattern  = attr.fetch(:dash, DEFAULT_DASHPATTERN)

    stroke        = attr[:stroke].nil? ? true : attr[:stroke]
    fill          = attr[:fill].nil? ? false : attr[:fill]

    stroke = true if fill == false and stroke == false

    set_fill_color(fill_color) if fill
    set_stroke_color(stroke_color) if stroke
    set_line_width(line_width)
    set_line_cap(line_cap)
    set_line_join(line_join)
    set_dash_pattern(dash_pattern)

    if @canvas.gs.text_state.is_in_text_object?
        @instructions << PDF::Instruction.new('ET').render(@canvas)
    end

    unless coords.size < 1
        x,y = coords.slice!(0)
        @instructions << PDF::Instruction.new('m',x,y).render(@canvas)

        coords.each do |px,py|
            @instructions << PDF::Instruction.new('l',px,py).render(@canvas)
        end

        @instructions << (i =
            if stroke and not fill
                PDF::Instruction.new('s')
            elsif fill and not stroke
                PDF::Instruction.new('f')
            elsif fill and stroke
                PDF::Instruction.new('b')
            end
        )

        i.render(@canvas)
    end

    self
end
draw_rectangle(x, y, width, height, attr = {}) click to toggle source

Draw a rectangle at position (x,y) with defined width and height.

# File lib/origami/graphics/xobject.rb, line 149
def draw_rectangle(x, y, width, height, attr = {})
    load!

    stroke_color  = attr.fetch(:stroke_color, DEFAULT_STROKE_COLOR)
    fill_color    = attr.fetch(:fill_color, DEFAULT_FILL_COLOR)
    line_cap      = attr.fetch(:line_cap, DEFAULT_LINECAP)
    line_join     = attr.fetch(:line_join, DEFAULT_LINEJOIN)
    line_width    = attr.fetch(:line_width, DEFAULT_LINEWIDTH)
    dash_pattern  = attr.fetch(:dash, DEFAULT_DASHPATTERN)

    stroke        = attr[:stroke].nil? ? true : attr[:stroke]
    fill          = attr[:fill].nil? ? false : attr[:fill]

    stroke = true if fill == false and stroke == false

    set_fill_color(fill_color) if fill
    set_stroke_color(stroke_color) if stroke
    set_line_width(line_width)
    set_line_cap(line_cap)
    set_line_join(line_join)
    set_dash_pattern(dash_pattern)

    if @canvas.gs.text_state.is_in_text_object?
        @instructions << PDF::Instruction.new('ET').render(@canvas)
    end

    @instructions << PDF::Instruction.new('re', x,y,width,height).render(@canvas)

    @instructions << (i =
        if stroke and not fill
            PDF::Instruction.new('S')
        elsif fill and not stroke
            PDF::Instruction.new('f')
        elsif fill and stroke
            PDF::Instruction.new('B')
        end
    )

    i.render(@canvas)

    self
end
instructions() click to toggle source
# File lib/origami/graphics/xobject.rb, line 69
def instructions
    load!

    @instructions
end
paint_shading(shade) click to toggle source
# File lib/origami/graphics/xobject.rb, line 236
def paint_shading(shade)
    load!

    @instructions << PDF::Instruction.new('sh', shade).render(@canvas)

    self
end
render(engine) click to toggle source
# File lib/origami/graphics/xobject.rb, line 47
def render(engine)
    load!

    @instructions.each do |instruction|
        instruction.render(engine)
    end

    nil
end
set_dash_pattern(pattern) click to toggle source
# File lib/origami/graphics/xobject.rb, line 382
def set_dash_pattern(pattern)
    load!

    unless @canvas.gs.dash_pattern.eql? pattern
        @instructions << PDF::Instruction.new('d', pattern.array, pattern.phase).render(@canvas)
    end

    self
end
set_fill_color(color) click to toggle source
# File lib/origami/graphics/xobject.rb, line 322
def set_fill_color(color)
    load!

    @instructions << ( i =
        if (color.respond_to? :r and color.respond_to? :g and color.respond_to? :b) or (color.is_a?(::Array) and color.size == 3)
            r = (color.respond_to?(:r) ? color.r : color[0]).to_f / 255
            g = (color.respond_to?(:g) ? color.g : color[1]).to_f / 255
            b = (color.respond_to?(:b) ? color.b : color[2]).to_f / 255
            PDF::Instruction.new('rg', r, g, b) if @canvas.gs.nonstroking_color != [r,g,b]

        elsif (color.respond_to? :c and color.respond_to? :m and color.respond_to? :y and color.respond_to? :k) or (color.is_a?(::Array) and color.size == 4)
            c = (color.respond_to?(:c) ? color.c : color[0]).to_f
            m = (color.respond_to?(:m) ? color.m : color[1]).to_f
            y = (color.respond_to?(:y) ? color.y : color[2]).to_f
            k = (color.respond_to?(:k) ? color.k : color[3]).to_f
            PDF::Instruction.new('k', c, m, y, k) if @canvas.gs.nonstroking_color != [c,m,y,k]

        elsif color.respond_to?:g or (0.0..1.0) === color
            g = color.respond_to?(:g) ? color.g : color
            PDF::Instruction.new('g', g) if @canvas.gs.nonstroking_color != [ g ]

        else
            raise TypeError, "Invalid color : #{color}"
        end
    )

    i.render(@canvas) if i
    self
end
set_line_cap(cap) click to toggle source
# File lib/origami/graphics/xobject.rb, line 402
def set_line_cap(cap)
    load!

    if @canvas.gs.line_cap != cap
        @instructions << PDF::Instruction.new('J', cap).render(@canvas)
    end

    self
end
set_line_join(join) click to toggle source
# File lib/origami/graphics/xobject.rb, line 412
def set_line_join(join)
    load!

    if @canvas.gs.line_join != join
        @instructions << PDF::Instruction.new('j', join).render(@canvas)
    end

    self
end
set_line_width(width) click to toggle source
# File lib/origami/graphics/xobject.rb, line 392
def set_line_width(width)
    load!

    if @canvas.gs.line_width != width
        @instructions << PDF::Instruction.new('w', width).render(@canvas)
    end

    self
end
set_stroke_color(color) click to toggle source
# File lib/origami/graphics/xobject.rb, line 352
def set_stroke_color(color)
    load!

    @instructions << ( i =
        if (color.respond_to? :r and color.respond_to? :g and color.respond_to? :b) or (color.is_a?(::Array) and color.size == 3)
            r = (color.respond_to?(:r) ? color.r : color[0]).to_f / 255
            g = (color.respond_to?(:g) ? color.g : color[1]).to_f / 255
            b = (color.respond_to?(:b) ? color.b : color[2]).to_f / 255
            PDF::Instruction.new('RG', r, g, b) if @canvas.gs.stroking_color != [r,g,b]

        elsif (color.respond_to? :c and color.respond_to? :m and color.respond_to? :y and color.respond_to? :k) or (color.is_a?(::Array) and color.size == 4)
            c = (color.respond_to?(:c) ? color.c : color[0]).to_f
            m = (color.respond_to?(:m) ? color.m : color[1]).to_f
            y = (color.respond_to?(:y) ? color.y : color[2]).to_f
            k = (color.respond_to?(:k) ? color.k : color[3]).to_f
            PDF::Instruction.new('K', c, m, y, k) if @canvas.gs.stroking_color != [c,m,y,k]

        elsif color.respond_to?:g or (0.0..1.0) === color
            g = color.respond_to?(:g) ? color.g : color
            PDF::Instruction.new('G', g) if @canvas.gs.stroking_color != [ g ]

        else
            raise TypeError, "Invalid color : #{color}"
        end
    )

    i.render(@canvas) if i
    self
end
set_text_char_spacing(char_spacing) click to toggle source
# File lib/origami/graphics/xobject.rb, line 312
def set_text_char_spacing(char_spacing)
    load!

    if char_spacing != @canvas.gs.text_state.char_spacing
        @instructions << PDF::Instruction.new('Tc', char_spacing).render(@canvas)
    end

    self
end
set_text_font(fontname, size) click to toggle source
# File lib/origami/graphics/xobject.rb, line 244
def set_text_font(fontname, size)
    load!

    if fontname != @canvas.gs.text_state.font or size != @canvas.gs.text_state.font_size
        @instructions << PDF::Instruction.new('Tf', fontname, size).render(@canvas)
    end

    self
end
set_text_leading(leading) click to toggle source
# File lib/origami/graphics/xobject.rb, line 262
def set_text_leading(leading)
    load!

    if leading != @canvas.gs.text_state.leading
        @instructions << PDF::Instruction.new('TL', leading).render(@canvas)
    end

    self
end
set_text_pos(tx,ty) click to toggle source
# File lib/origami/graphics/xobject.rb, line 254
def set_text_pos(tx,ty)
    load!

    @instructions << PDF::Instruction.new('Td', tx, ty).render(@canvas)

    self
end
set_text_rendering(rendering) click to toggle source
# File lib/origami/graphics/xobject.rb, line 272
def set_text_rendering(rendering)
    load!

    if rendering != @canvas.gs.text_state.rendering_mode
        @instructions << PDF::Instruction.new('Tr', rendering).render(@canvas)
    end

    self
end
set_text_rise(rise) click to toggle source
# File lib/origami/graphics/xobject.rb, line 282
def set_text_rise(rise)
    load!

    if rise != @canvas.gs.text_state.text_rise
        @instructions << PDF::Instruction.new('Ts', rise).render(@canvas)
    end

    self
end
set_text_scale(scaling) click to toggle source
# File lib/origami/graphics/xobject.rb, line 292
def set_text_scale(scaling)
    load!

    if scaling != @canvas.gs.text_state.scaling
        @instructions << PDF::Instruction.new('Tz', scaling).render(@canvas)
    end

    self
end
set_text_word_spacing(word_spacing) click to toggle source
# File lib/origami/graphics/xobject.rb, line 302
def set_text_word_spacing(word_spacing)
    load!

    if word_spacing != @canvas.gs.text_state.word_spacing
        @instructions << PDF::Instruction.new('Tw', word_spacing).render(@canvas)
    end

    self
end
write(text, attr = {}) click to toggle source

Adds text to the content stream with custom formatting attributes.

text

Text to write.

attr

Formatting attributes.

# File lib/origami/graphics/xobject.rb, line 197
def write(text, attr = {})
    load!

    x, y      = attr[:x], attr[:y]
    font      = attr.fetch(:font, DEFAULT_FONT)
    size      = attr.fetch(:size, DEFAULT_SIZE)
    leading   = attr.fetch(:leading, DEFAULT_LEADING)
    color     = attr.fetch(:color, attr.fetch(:fill_color, DEFAULT_STROKE_COLOR))
    stroke_color = attr.fetch(:stroke_color, DEFAULT_STROKE_COLOR)
    line_width    = attr.fetch(:line_width, DEFAULT_LINEWIDTH)
    word_spacing  = attr.fetch(:word_spacing, @canvas.gs.text_state.word_spacing)
    char_spacing  = attr.fetch(:char_spacing, @canvas.gs.text_state.char_spacing)
    scale     = attr.fetch(:scale, @canvas.gs.text_state.scaling)
    rise      = attr.fetch(:rise, @canvas.gs.text_state.text_rise)
    rendering = attr.fetch(:rendering, @canvas.gs.text_state.rendering_mode)

    @instructions << PDF::Instruction.new('ET').render(@canvas) if (x or y) and @canvas.gs.text_state.is_in_text_object?

    unless @canvas.gs.text_state.is_in_text_object?
        @instructions << PDF::Instruction.new('BT').render(@canvas)
    end

    set_text_font(font, size)
    set_text_pos(x, y) if x or y
    set_text_leading(leading)
    set_text_rendering(rendering)
    set_text_rise(rise)
    set_text_scale(scale)
    set_text_word_spacing(word_spacing)
    set_text_char_spacing(char_spacing)
    set_fill_color(color)
    set_stroke_color(stroke_color)
    set_line_width(line_width)

    write_text_block(text)

    self
end

Private Instance Methods

load!() click to toggle source
# File lib/origami/graphics/xobject.rb, line 424
def load!
    return unless @instructions.nil?

    decode!

    code = StringScanner.new self.data
    @instructions = []

    until code.eos?
        insn = PDF::Instruction.parse(code)
        @instructions << insn if insn
    end

    self
end
write_text_block(text) click to toggle source
# File lib/origami/graphics/xobject.rb, line 440
def write_text_block(text)
    lines = text.split("\n").map!{|line| line.to_s}

    @instructions << PDF::Instruction.new('Tj', lines.slice!(0)).render(@canvas)
    lines.each do |line|
        @instructions << PDF::Instruction.new("'", line).render(@canvas)
    end
end