Method: HexaPDF::Type::Page#canvas

Defined in:
lib/hexapdf/type/page.rb

#canvas(type: :page, translate_origin: true) ⇒ Object

Returns the requested type of canvas for the page.

There are potentially three different canvas objects, one for each of the types :underlay, :page, and :overlay. The canvas objects are cached once they are created so that their graphics states are correctly retained without the need for parsing the contents. This also means that on subsequent invocations the graphic states of the canvases might already be changed.

type

Can either be

  • :page for getting the canvas for the page itself (only valid for initially empty pages)

  • :overlay for getting the canvas for drawing over the page contents

  • :underlay for getting the canvas for drawing unter the page contents

translate_origin

Specifies whether the origin should automatically be translated into the lower-left corner of the crop box.

Note that this argument is only used for the first invocation for every canvas type. So if a canvas was initially requested with this argument set to false and then with true, it won’t have any effect as the cached canvas is returned.

To check whether the origin has been translated or not, use

canvas.pos(0, 0)

and check whether the result is [0, 0]. If it is, then the origin has not been translated.



458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
# File 'lib/hexapdf/type/page.rb', line 458

def canvas(type: :page, translate_origin: true)
  unless [:page, :overlay, :underlay].include?(type)
    raise ArgumentError, "Invalid value for 'type', expected: :page, :underlay or :overlay"
  end
  cache_key = "#{type}_canvas".intern
  return cache(cache_key) if cached?(cache_key)

  if type == :page && key?(:Contents)
    raise HexaPDF::Error, "Cannot get the canvas for a page with contents"
  end

  create_canvas = lambda do
    Content::Canvas.new(self).tap do |canvas|
      next unless translate_origin
      crop_box = box(:crop)
      if crop_box.left != 0 || crop_box.bottom != 0
        canvas.translate(crop_box.left, crop_box.bottom)
      end
    end
  end

  contents = self[:Contents]
  if contents.nil?
    page_canvas = cache(:page_canvas, create_canvas.call)
    self[:Contents] = document.add({Filter: :FlateDecode},
                                   stream: page_canvas.stream_data)
  end

  if type == :overlay || type == :underlay
    underlay_canvas = cache(:underlay_canvas, create_canvas.call)
    overlay_canvas = cache(:overlay_canvas, create_canvas.call)

    stream = HexaPDF::StreamData.new do
      Fiber.yield(" q ")
      fiber = underlay_canvas.stream_data.fiber
      while fiber.alive? && (data = fiber.resume)
        Fiber.yield(data)
      end
      " Q q "
    end
    underlay = document.add({Filter: :FlateDecode}, stream: stream)

    stream = HexaPDF::StreamData.new do
      Fiber.yield(" Q q ")
      fiber = overlay_canvas.stream_data.fiber
      while fiber.alive? && (data = fiber.resume)
        Fiber.yield(data)
      end
      " Q "
    end
    overlay = document.add({Filter: :FlateDecode}, stream: stream)

    self[:Contents] = [underlay, *self[:Contents], overlay]
  end

  cache(cache_key)
end