Module: PDF::Writer::Graphics

Included in:
PDF::Writer
Defined in:
lib/pdf/writer/graphics.rb

Overview

This module contains graphics primitives. Objects that include this module must respond to #add_content.

The PDF::Writer coordinate system is in PDF userspace units. The coordinate system in PDF::Writer is slightly different than might be expected, in that (0, 0) is at the lower left-hand corner of the canvas (page), not the normal top left-hand corner of the canvas. (See the diagram below.)

 Y     Y
0+-----+X
 |     |
 |     |
 |     |
0+-----+X
 0     0

Each primitive provided below indicates the New Point, or the coordinates new drawing point at the completion of the drawing operation. Drawing operations themselves do not draw or fill the path. This must be done by one of the stroke or fill operators, #stroke, #close_stroke, #fill, #close_fill, #fill_stroke, or #close_fill_stroke.

Drawing operations return self (the canvas) so that operations may be chained.

Defined Under Namespace

Classes: ImageInfo

Constant Summary collapse

KAPPA =

This constant is used to approximate a symmetrical arc using a cubic Bezier curve.

4.0 * ((Math.sqrt(2) - 1.0) / 3.0)

Instance Method Summary collapse

Instance Method Details

#add_image(image, x, y, width = nil, height = nil, image_info = nil, link = nil) ⇒ Object

Add an image from a loaded image (JPEG or PNG) resource at position (x, y) (the lower left-hand corner of the image) and scaled to width by height units. If provided, image_info is a PDF::Writer::Graphics::ImageInfo object.

In PDF::Writer 1.1 or later, the new link parameter is a hash with two keys:

:type

The type of link, either :internal or :external.

:target

The destination of the link. For an :internal link, this is an internal cross-reference destination. For an :external link, this is an URI.

This will automatically make the image a clickable link if set.


572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
# File 'lib/pdf/writer/graphics.rb', line 572

def add_image(image, x, y, width = nil, height = nil, image_info = nil, link = nil)
  if image.kind_of?(PDF::Writer::External::Image)
    label       = image.label
    image_obj   = image
    image_info ||= image.image_info
  else
    image_info ||= PDF::Writer::Graphics::ImageInfo.new(image)

    tt = Time.now
    @images << tt
    id = @images.index(tt)
    label = "I#{id}"
    image_obj = PDF::Writer::External::Image.new(self, image, image_info, label)
    @images[id] = image_obj
  end

  if width.nil? and height.nil?
    width   = image_info.width
    height  = image_info.height
  end

  width  ||= height / image_info.height.to_f * image_info.width
  height ||= width * image_info.height / image_info.width.to_f

  tt = "\nq\n%.3f 0 0 %.3f %.3f %.3f cm\n/%s Do\nQ"
  add_content(tt % [ width, height, x, y, label ])

  if link
    case link[:type]
    when :internal
      add_internal_link(link[:target], x, y, x + width, y + height)
    when :external
      add_link(link[:target], x, y, x + width, y + height)
    end
  end

  image_obj
end

#add_image_from_file(image, x, y, width = nil, height = nil, link = nil) ⇒ Object

Add an image from a file to the current page at position (x, y) (the lower left-hand corner of the image). The image will be scaled to width by height units. The image may be a PNG or JPEG image.

The image parameter may be a filename or an object that returns the full image data when #read is called with no parameters (such as an IO object). If 'open-uri' is loaded, then the image name may be an URI.

In PDF::Writer 1.1 or later, the new link parameter is a hash with two keys:

:type

The type of link, either :internal or :external.

:target

The destination of the link. For an :internal link, this is an internal cross-reference destination. For an :external link, this is an URI.

This will automatically make the image a clickable link if set.


540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
# File 'lib/pdf/writer/graphics.rb', line 540

def add_image_from_file(image, x, y, width = nil, height = nil, link = nil)
  data = nil

  if image.respond_to?(:read)
    data = image.read
  else
    if RUBY_VERSION >= '1.9'
      open(image,'rb:binary') { |ff| data = ff.read }
    else
      open(image,'rb') { |ff| data = ff.read }
    end
  end

  add_image(data, x, y, width, height, nil, link)
end

#circle_at(x, y, r) ⇒ Object

Draws a circle of radius r with the centre-point at (x, y) as a complete subpath. The drawing point will be moved to the centre-point upon completion of the drawing the circle.


227
228
229
# File 'lib/pdf/writer/graphics.rb', line 227

def circle_at(x, y, r)
  ellipse_at(x, y, r, r)
end

#closeObject

Close the current path by appending a straight line segment from the drawing point to the starting point of the path. If the path is closed, this does nothing. This operator terminates the current subpath.


50
51
52
53
# File 'lib/pdf/writer/graphics.rb', line 50

def close
  add_content(" h")
  self
end

#close_fill(rule = nil) ⇒ Object

Close the current path by appending a straight line segment from the drawing point to the starting point of the path, and then fill it. This does the same as #close followed by #fill.

See #fill for more information on fill rules.


92
93
94
95
96
# File 'lib/pdf/writer/graphics.rb', line 92

def close_fill(rule = nil)
  close
  fill(rule)
  self
end

#close_fill_stroke(rule = nil) ⇒ Object

Closes, fills and then strokes the path. Open subpaths are explicitly closed before being filled (as if #close and then #fill_stroke had been called). This is the same as constructing two identical path objects, calling #fill on one and #stroke on the other. Paths filled and stroked in this manner are treated as if they were one object for PDF transparency purposes (PDF transparency is not yet supported by PDF::Writer).

See #fill for more information on fill rules.


124
125
126
127
128
129
130
131
# File 'lib/pdf/writer/graphics.rb', line 124

def close_fill_stroke(rule = nil)
  if :even_odd == rule
    add_content(" b*")
  else
    add_content(" b")
  end
  self
end

#close_strokeObject

Close the current path by appending a straight line segment from the drawing point to the starting point of the path, and then stroke it. This does the same as #close followed by #stroke.


64
65
66
67
# File 'lib/pdf/writer/graphics.rb', line 64

def close_stroke
  add_content(" s")
  self
end

#curve(x0, y0, x1, y1, x2, y2, x3, y3) ⇒ Object

Draw a cubic Bezier curve from (x0, y0) to (x3, y3) using (x1, y1) and (x2, y2) as control points.

New Point

(x3, y3)

Subpath

New


198
199
200
# File 'lib/pdf/writer/graphics.rb', line 198

def curve(x0, y0, x1, y1, x2, y2, x3, y3)
  move_to(x0, y0).curve_to(x1, y1, x2, y2, x3, y3)
end

#curve_to(x0, y0, x1, y1, x2, y2) ⇒ Object

Draws a cubic Bezier curve from the drawing point to (x2, y2) using (x0, y0) and (x1, y1) as the control points for the curve.

New Point

(x2, y2)

Subpath

Current


157
158
159
160
# File 'lib/pdf/writer/graphics.rb', line 157

def curve_to(x0, y0, x1, y1, x2, y2)
  add_content("\n%.3f %.3f %.3f %.3f %.3f %.3f c" % [ x0, y0, x1, y1, x2, y2 ])
  self
end

#ecurve(x0, y0, x1, y1, x2, y2) ⇒ Object

Draw a cubic Bezier curve from (x0, y0) to (x2, y2) using (x1, y1) and (x2, y2) as control points.

New Point

(x2, y2)

Subpath

New


216
217
218
# File 'lib/pdf/writer/graphics.rb', line 216

def ecurve(x0, y0, x1, y1, x2, y2)
  move_to(x0, y0).ecurve_to(x1, y1, x2, y2)
end

#ecurve_to(x0, y0, x1, y1) ⇒ Object

Draws a cubic Bezier curve from the drawing point to (x1, y1) using (x0, y0) and (x1, y1) as the control points for the curve.

New Point

(x1, y1)

Subpath

Current


179
180
181
182
# File 'lib/pdf/writer/graphics.rb', line 179

def ecurve_to(x0, y0, x1, y1)
  add_content("\n%.3f %.3f %.3f %.3f y" % [ x0, y0, x1, y1 ])
  self
end

#ellipse2_at(x, y, r1, r2 = r1, start = 0, stop = 359.99, segments = 8) ⇒ Object

Draw an ellipse centered at (x, y) with x radius r1 and y radius r2. A partial ellipse can be drawn by specifying the starting and finishing angles.

New Point

(x, y)

Subpath

New


256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
# File 'lib/pdf/writer/graphics.rb', line 256

def ellipse2_at(x, y, r1, r2 = r1, start = 0, stop = 359.99, segments = 8)
  segments = 2 if segments < 2

  start = PDF::Math.deg2rad(start)
  stop  = PDF::Math.deg2rad(stop)

  arc     = stop - start
  segarc  = arc / segments.to_f
  dtm     = segarc / 3.0

  theta = start
  a0 = x + r1 * Math.cos(theta)
  b0 = y + r2 * Math.sin(theta)
  c0 = -r1 * Math.sin(theta)
  d0 = r2 * Math.cos(theta)

  move_to(a0, b0)

  (1..segments).each do |ii|
    theta = ii * segarc + start

    a1 = x + r1 * Math.cos(theta)
    b1 = y + r2 * Math.sin(theta)
    c1 = -r1 * Math.sin(theta)
    d1 = r2 * Math.cos(theta)

    curve_to(a0 + (c0 * dtm),
             b0 + (d0 * dtm),
             a1 - (c1 * dtm),
             b1 - (d1 * dtm), a1, b1)

    a0 = a1
    b0 = b1
    c0 = c1
    d0 = d1
  end

  move_to(x, y)
  self
end

#ellipse_at(x, y, r1, r2 = r1) ⇒ Object

Draws an ellipse of x radius r1 and y radius r2 with the centre-point at (x, y) as a complete subpath. The drawing point will be moved to the centre-point upon completion of the drawing the ellipse.


235
236
237
238
239
240
241
242
243
244
245
246
247
248
# File 'lib/pdf/writer/graphics.rb', line 235

def ellipse_at(x, y, r1, r2 = r1)
  l1 = r1 * KAPPA
  l2 = r2 * KAPPA
  move_to(x + r1, y)
    # Upper right hand corner
  curve_to(x + r1, y + l1, x + l2, y + r2, x,      y + r2)
    # Upper left hand corner
  curve_to(x - l2, y + r2, x - r1, y + l1, x - r1, y)
    # Lower left hand corner
  curve_to(x - r1, y - l1, x - l2, y - r2, x,      y - r2)
    # Lower right hand corner
  curve_to(x + l2, y - r2, x + r1, y - l1, x + r1, y)
  move_to(x, y)
end

#fill(rule = nil) ⇒ Object

Fills the path. Open subpaths are implicitly closed before being filled. PDF offers two methods for determining the fill region. The first is called the “nonzero winding number” and is the default fill. The second is called “even-odd”.

Use the even-odd rule (called with #fill(:even_odd)) with caution, as this will cause certain portions of the path to be considered outside of the fill region, resulting in interesting cutout patterns.


78
79
80
81
82
83
84
85
# File 'lib/pdf/writer/graphics.rb', line 78

def fill(rule = nil)
  if :even_odd == rule
    add_content(" f*")
  else
    add_content(" f")
  end
  self
end

#fill_color(color) ⇒ Object

Sets the color for fill operations.


483
484
485
# File 'lib/pdf/writer/graphics.rb', line 483

def fill_color(color)
  fill_color!(color) if @current_fill_color.nil? or color != @current_fill_color
end

#fill_color!(color = nil) ⇒ Object

Forces the color for fill operations to be set, even if the color is the same as the current color. Does nothing if nil is provided.


489
490
491
492
493
494
# File 'lib/pdf/writer/graphics.rb', line 489

def fill_color!(color = nil)
  if color
    @current_fill_color = color
    add_content "\n#{@current_fill_color.pdf_fill}"
  end
end

#fill_color?Boolean

Returns the current fill color.


497
498
499
# File 'lib/pdf/writer/graphics.rb', line 497

def fill_color?
  @current_fill_color
end

#fill_stroke(rule = nil) ⇒ Object

Fills and then strokes the path. Open subpaths are implicitly closed before being filled. This is the same as constructing two identical path objects, calling #fill on one and #stroke on the other. Paths filled and stroked in this manner are treated as if they were one object for PDF transparency purposes (the PDF transparency model is not yet supported by PDF::Writer).

See #fill for more information on fill rules.


106
107
108
109
110
111
112
113
# File 'lib/pdf/writer/graphics.rb', line 106

def fill_stroke(rule = nil)
  if :even_odd == rule
    add_content(" B*")
  else
    add_content(" B")
  end
  self
end

#image(image, options = {}) ⇒ Object

Add an image easily to a PDF document. image is the name of a JPG or PNG image. options is a Hash:

:pad

The number of PDF userspace units that will be on all sides of the image. The default is 5 units.

:width

The desired width of the image. The image will be resized to this width with the aspect ratio kept. If unspecified, the image's natural width will be used.

:resize

How to resize the image, either :width (resizes the image to be as wide as the margins) or :full (resizes the image to be as large as possible). May be a numeric value, used as a multiplier for the image size (e.g., 0.5 will shrink the image to half-sized). If this and :width are unspecified, the image's natural size will be used. Mutually exclusive with the <tt>:width<tt> option.

:justification

The placement of the image. May be :center, :right, or :left. Defaults to :left.

:border

The border options. No default border. If specified, must be either true, which uses the default border, or a Hash.

:link

Makes the image a clickable link.

Image borders are specified as a hash with two options:

:color

The colour of the border. Defaults to 50% grey.

:style

The stroke style of the border. This must be a StrokeStyle object and defaults to the default line.

Image links are defined as a hash with two options:

:type

The type of link, either :internal or :external.

:target

The destination of the link. For an :internal link, this is an internal cross-reference destination. For an :external link, this is an URI.


652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
# File 'lib/pdf/writer/graphics.rb', line 652

def image(image, options = {})
  width   = options[:width]
  pad     = options[:pad]           || 5
  resize  = options[:resize]
  just    = options[:justification] || :left
  border  = options[:border]
  link    = options[:link]

  if image.kind_of?(PDF::Writer::External::Image)
    info        = image.image_info
    image_data  = image
  else
    if image.respond_to?(:read)
      image_data = image.read
    else
      image_data = open(image, "rb") { |file| file.read }
    end
    info = PDF::Writer::Graphics::ImageInfo.new(image_data)
  end

  raise "Unsupported Image Type" unless %w(JPEG PNG).include?(info.format)

  width   = info.width if width.nil?
  aspect  = info.width.to_f / info.height.to_f

    # Get the maximum width of the image on insertion.
  if @columns_on
    max_width = @columns[:width] - (pad * 2)
  else
    max_width = @page_width - (pad * 2) - @left_margin - @right_margin
  end

  if resize == :full or resize == :width or width > max_width
    width = max_width
  end

    # Keep the height in an appropriate aspect ratio of the width.
  height = (width / aspect.to_f)

    # Resize the image.
  if resize.kind_of?(Numeric)
    width   *= resize
    height  *= resize
  end

    # Resize the image *again*, if it is wider than what is available.
  if width > max_width
    height = (width / aspect.to_f)
  end

    # If the height is greater than the available space:
  havail = @y - @bottom_margin - (pad * 2)
  if height > havail
      # If the image is to be resized to :full (remaining space
      # available), adjust the image size appropriately. Otherwise, start
      # a new page and flow to the next page.
    if resize == :full
      height = havail
      width = (height * aspect)
    else
      start_new_page
    end
  end

    # Find the x and y positions.
  y = @y - pad - height
  x = @left_margin + pad

  if (width < max_width)
    case just
    when :center
      x += (max_width - width) / 2.0
    when :right
      x += (max_width - width)
    end
  end

  image_obj = add_image(image_data, x, y, width, height, info)

  if border
    border = {} if true == border
    border[:color]  ||= Color::RGB::Grey50
    border[:style]  ||= PDF::Writer::StrokeStyle::DEFAULT

    save_state
    stroke_color border[:color] 
    stroke_style border[:style] 
    rectangle(x, y - pad, width, height - pad).stroke
    restore_state
  end

  if link
    case link[:type]
    when :internal
      add_internal_link(link[:target], x, y - pad, x + width, y + height - pad)
    when :external
      add_link(link[:target], x, y - pad, x + width, y + height - pad)
    end
  end

  @y = @y - pad - height

  image_obj
end

#line(x0, y0, x1, y1) ⇒ Object

Draw a straight line from (x0, y0) to (x1, y1). The line is a new subpath.

New Point

(x1, y1).

Subpath

New


189
190
191
# File 'lib/pdf/writer/graphics.rb', line 189

def line(x0, y0, x1, y1)
  move_to(x0, y0).line_to(x1, y1)
end

#line_to(x, y) ⇒ Object

Draw a straight line from the drawing point to (x, y).

New Point

(x, y)

Subpath

Current


146
147
148
149
# File 'lib/pdf/writer/graphics.rb', line 146

def line_to(x, y)
  add_content("\n%.3f %.3f l" % [ x, y ])
  self
end

#move_to(x, y) ⇒ Object

Move the drawing point to the specified coordinates (x, y).

New Point

(x, y)

Subpath

New


137
138
139
140
# File 'lib/pdf/writer/graphics.rb', line 137

def move_to(x, y)
  add_content("\n%.3f %.3f m" % [ x, y ])
  self
end

#polygon(points) ⇒ Object

Draw a polygon. points is an array of PolygonPoint objects, or an array that can be converted to an array of PolygonPoint objects with PDF::Writer::PolygonPoint.new(*value).

New Point

(points[-1].x, points[-1].y)

Subpath

New


325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
# File 'lib/pdf/writer/graphics.rb', line 325

def polygon(points)
  points = points.map { |pp|
    pp.kind_of?(Array) ? PDF::Writer::PolygonPoint.new(*pp) : pp
  }

  point = points.shift

  move_to(point.x, point.y)

  while not points.empty?
    point = points.shift

    case point.connector
    when :curve
      c1 = point
      c2 = points.shift
      point = points.shift

      curve_to(c1.x, c1.y, c2.x, c2.y, point.x, point.y)
    when :scurve
      c1 = point
      point = points.shift
      scurve_to(c1.x, c1.y, point.x, point.y)
    when :ecurve
      c1 = point
      point = points.shift
      ecurve_to(c1.x, c1.y, point.x, point.y)
    else
      line_to(point.x, point.y)
    end
  end

  self
end

#rectangle(x, y, w, h = w) ⇒ Object

Draw a rectangle. The first corner is (x, y) and the second corner is (x + w, y - h).

New Point

(x + w, y - h)

Subpath

Current


365
366
367
368
# File 'lib/pdf/writer/graphics.rb', line 365

def rectangle(x, y, w, h = w)
  add_content("\n%.3f %.3f %.3f %.3f re" % [ x, y, w, h ])
  self
end

#rotate_axis(angle) ⇒ Object

Rotate the axis of the coordinate system by the specified clockwise angle.


766
767
768
769
770
771
772
# File 'lib/pdf/writer/graphics.rb', line 766

def rotate_axis(angle)
  rad = PDF::Math.deg2rad(angle)
  tt  = "\n%.3f %.3f %.3f %.3f 0 0 cm"
  tx  = [ Math.cos(rad), Math.sin(rad), -Math.sin(rad), Math.cos(rad) ]
  add_content(tt % tx)
  self
end

#rounded_rectangle(x, y, w, h, r) ⇒ Object

Draw a rounded rectangle with corners (x, y) and (x + w, y - h) and corner radius r. The radius should be significantly smaller than h and w.

New Point

(x + w, y - h)

Subpath

New


376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
# File 'lib/pdf/writer/graphics.rb', line 376

def rounded_rectangle(x, y, w, h, r)
  x1 = x
  x2 = x1 + w
  y1 = y
  y2 = y1 - h

  r1 = r
  r2 = r / 2.0

  points = [
    [ x1 + r1, y1,      :line  ],
    [ x2 - r1, y1,      :line  ],
    [ x2 - r2, y1,      :curve ], # cp1
    [ x2,      y1 - r2,        ], # cp2
    [ x2,      y1 - r1,        ], # ep
    [ x2,      y2 + r1, :line  ],
    [ x2,      y2 + r2, :curve ], # cp1
    [ x2 - r2, y2,             ], # cp2
    [ x2 - r1, y2,             ], # ep
    [ x1 + r1, y2,      :line  ],
    [ x1 + r2, y2,      :curve ], # cp1
    [ x1,      y2 + r2,        ], # cp2
    [ x1,      y2 + r1,        ], # ep
    [ x1,      y1 - r1, :line  ],
    [ x1,      y1 - r2, :curve ], # cp1
    [ x1 + r2, y1,             ], # cp2
    [ x1 + r1, y1,             ], # ep
  ]
  polygon(points)
  move_to(x2, y2)
  self
end

#scale_axis(x = 1, y = 1) ⇒ Object

Scale the coordinate system axis by the specified factors.


775
776
777
778
# File 'lib/pdf/writer/graphics.rb', line 775

def scale_axis(x = 1, y = 1)
  add_content("\n%.3f 0 0 %.3f 0 0 cm" % [ x, y ])
  self
end

#scurve(x0, y0, x1, y1, x2, y2) ⇒ Object

Draw a cubic Bezier curve from (x0, y0) to (x2, y2) using (x0, y0) and (x1, y1) as control points.

New Point

(x2, y2)

Subpath

New


207
208
209
# File 'lib/pdf/writer/graphics.rb', line 207

def scurve(x0, y0, x1, y1, x2, y2)
  move_to(x0, y0).scurve_to(x1, y1, x2, y2)
end

#scurve_to(x0, y0, x1, y1) ⇒ Object

Draws a cubic Bezier curve from the drawing point to (x1, y1) using the drawing point and (x0, y0) as the control points for the curve.

New Point

(x1, y1)

Subpath

Current


168
169
170
171
# File 'lib/pdf/writer/graphics.rb', line 168

def scurve_to(x0, y0, x1, y1)
  add_content("\n%.3f %.3f %.3f %.3f v" % [ x0, y0, x1, y1 ])
  self
end

#segment_at(x, y, r1, r2 = r1, start = 0, stop = 360, segments = 8) ⇒ Object

Draws an ellipse segment. Draws a closed partial ellipse.

New Point

(x, y)

Subpath

New


301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
# File 'lib/pdf/writer/graphics.rb', line 301

def segment_at(x, y, r1, r2 = r1, start = 0, stop = 360, segments = 8)
  ellipse2_at(x, y, r1, r2, start, stop, segments)

  start = PDF::Math.deg2rad(start)
  stop  = PDF::Math.deg2rad(stop)

  ax = x + r1 * Math.cos(start)
  ay = y + r2 * Math.sin(start)
  bx = x + r1 * Math.cos(stop)
  by = y + r2 * Math.sin(stop)

  move_to(ax, ay)
  line_to(x, y)
  line_to(bx, by)
  move_to(x, y)
  self
end

#skew_axis(xangle = 0, yangle = 0) ⇒ Object

Skew the coordinate system axis by the specified angles.


781
782
783
784
785
786
787
788
789
790
# File 'lib/pdf/writer/graphics.rb', line 781

def skew_axis(xangle = 0, yangle = 0)
  xr = PDF::Math.deg2rad(xangle)
  yr = PDF::Math.deg2rad(yangle)

  xr = Math.tan(xr) if xangle != 0
  yr = Math.tan(yr) if yangle != 0

  add_content("\n1 %.3f %.3f 1 0 0 cm" % [ xr, yr ])
  self
end

#star(cx, cy, length, rays = 5) ⇒ Object

Draws a star centered on (x, y) with rays portions of length from the centre. Stars with an odd number of rays should have the top ray pointing toward the top of the document. This will not create a “star” with fewer than four points.

New Point

(cx, cy)

Subpath

New


416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
# File 'lib/pdf/writer/graphics.rb', line 416

def star(cx, cy, length, rays = 5)
  rays = 4 if rays < 4
  points = []
  part = Math::PI / rays.to_f

  0.step((rays * 4), 2) do |ray|
    if ((ray / 2) % 2 == 0)
      dist = length / 2.0
    else
      dist = length
    end

    x = cx + Math.cos((1.5 + ray / 2.0) * part) * dist
    y = cy + Math.sin((1.5 + ray / 2.0) * part) * dist
    points << [ x, y ]
  end

  polygon(points)
  move_to(cx, cy)
  self
end

#strokeObject

Stroke the path. This operation terminates a path object and draws it.


56
57
58
59
# File 'lib/pdf/writer/graphics.rb', line 56

def stroke
  add_content(" S")
  self
end

#stroke_color(color) ⇒ Object

Sets the color for stroke operations.


502
503
504
# File 'lib/pdf/writer/graphics.rb', line 502

def stroke_color(color)
  stroke_color!(color) if @current_stroke_color.nil? or color != @current_stroke_color
end

#stroke_color!(color = nil) ⇒ Object

Forces the color for stroke operations to be set, even if the color is the same as the current color. Does nothing if nil is provided.


508
509
510
511
512
513
# File 'lib/pdf/writer/graphics.rb', line 508

def stroke_color!(color = nil)
  if color
    @current_stroke_color = color
    add_content "\n#{@current_stroke_color.pdf_stroke}"
  end
end

#stroke_color?Boolean

Returns the current stroke color.


516
517
518
# File 'lib/pdf/writer/graphics.rb', line 516

def stroke_color?
  @current_stroke_color
end

#stroke_style(style) ⇒ Object

This sets the line drawing style. This must be a PDF::Writer::StrokeStyle object.


440
441
442
# File 'lib/pdf/writer/graphics.rb', line 440

def stroke_style(style)
  stroke_style!(style) if @current_stroke_style.nil? or style != @current_stroke_style
end

#stroke_style!(style = nil) ⇒ Object

Forces the line drawing style to be set, even if it's the same as the current color. Emits the current stroke style if nil is provided.


446
447
448
449
# File 'lib/pdf/writer/graphics.rb', line 446

def stroke_style!(style = nil)
  @current_stroke_style = style if style
  add_content "\n#{@current_stroke_style.render}" if @current_stroke_style
end

#stroke_style?Boolean

Returns the current stroke style.


452
453
454
# File 'lib/pdf/writer/graphics.rb', line 452

def stroke_style?
  @current_stroke_style
end

#text_render_style(style) ⇒ Object

Set the text rendering style. This may be one of the following options:

0

fill

1

stroke

2

fill then stroke

3

invisible

4

fill and add to clipping path

5

stroke and add to clipping path

6

fill and stroke and add to clipping path

7

add to clipping path


467
468
469
# File 'lib/pdf/writer/graphics.rb', line 467

def text_render_style(style)
  text_render_style!(style) unless @current_text_render_style and style == @current_text_render_style
end

#text_render_style!(style) ⇒ Object

Forces the text rendering style to be set, even if it's the same as the current style.


473
474
475
# File 'lib/pdf/writer/graphics.rb', line 473

def text_render_style!(style)
  @current_text_render_style = style
end

#text_render_style?Boolean

Reutnrs the current text rendering style.


478
479
480
# File 'lib/pdf/writer/graphics.rb', line 478

def text_render_style?
  @current_text_render_style
end

#transform_matrix(a, b, c, d, e, f) ⇒ Object

Transforms the coordinate axis with the appended matrix. All transformations (including those above) are performed with this matrix. The transformation matrix is:

+-     -+
| a c e |
| b d f |
| 0 0 1 |
+-     -+

The six values are represented as a six-digit vector: [ a b c d e f ]

  • Axis translation uses [ 1 0 0 1 x y ] where x and y are the new (0,0) coordinates in the old axis system.

  • Scaling uses [ sx 0 0 sy 0 0 ] where sx and sy are the scaling factors.

  • Rotation uses [ cos(a) sin(a) -sin(a) cos(a) 0 0 ] where a is the angle, measured in radians.

  • X axis skewing uses [ 1 0 tan(a) 1 0 0 ] where a is the angle, measured in radians.

  • Y axis skewing uses [ 1 tan(a) 0 1 0 0 ] where a is the angle, measured in radians.


814
815
816
# File 'lib/pdf/writer/graphics.rb', line 814

def transform_matrix(a, b, c, d, e, f)
  add_content("\n%.3f %.3f %.3f %.3f %.3f %.3f cm" % [ a, b, c, d, e, f ])
end

#translate_axis(x, y) ⇒ Object

Translate the coordinate system axis by the specified user space coordinates.


759
760
761
762
# File 'lib/pdf/writer/graphics.rb', line 759

def translate_axis(x, y)
  add_content("\n1 0 0 1 %.3f %.3f cm" % [ x, y ])
  self
end