# -*- encoding: utf-8; frozen_string_literal: true -*- # #-- # This file is part of HexaPDF. # # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby # Copyright (C) 2014-2023 Thomas Leitner # # HexaPDF is free software: you can redistribute it and/or modify it # under the terms of the GNU Affero General Public License version 3 as # published by the Free Software Foundation with the addition of the # following permission added to Section 15 as permitted in Section 7(a): # FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY # THOMAS LEITNER, THOMAS LEITNER DISCLAIMS THE WARRANTY OF NON # INFRINGEMENT OF THIRD PARTY RIGHTS. # # HexaPDF is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public # License for more details. # # You should have received a copy of the GNU Affero General Public License # along with HexaPDF. If not, see . # # The interactive user interfaces in modified source and object code # versions of HexaPDF must display Appropriate Legal Notices, as required # under Section 5 of the GNU Affero General Public License version 3. # # In accordance with Section 7(b) of the GNU Affero General Public # License, a covered work must retain the producer line in every PDF that # is created or manipulated using HexaPDF. # # If the GNU Affero General Public License doesn't fit your need, # commercial licenses are available at . #++ require 'hexapdf/error' require 'hexapdf/layout/style' require 'hexapdf/layout/frame' module HexaPDF module Layout # A PageStyle defines the initial look of a page and the placement of one or more frames. class PageStyle # The page size. # # Can be any valid predefined page size (see HexaPDF::Type::Page::PAPER_SIZE) or an array # [llx, lly, urx, ury] specifying a custom page size. # # Example: # # style.page_size = :A4 # style.page_size = [0, 0, 200, 200] attr_accessor :page_size # The page orientation, either +:portrait+ or +:landscape+. # # Only used if #page_size is one of the predefined page sizes and not an array. attr_accessor :orientation # A callable object that defines the initial content of a page created with #create_page. # # The callable object is given a canvas and the page style as arguments. It needs to draw the # initial content of the page. Note that the graphics state of the canvas is *not* saved # before executing the template code and restored afterwards. If this is needed, the object # needs to do it itself. # # Furthermore it should set the #frame and #next_style attributes appropriately, if not done # beforehand. The #create_frame method can be used for easily creating a rectangular frame. # # Example: # # page_style.template = lambda do |canvas, style # box = canvas.context.box # canvas.fill_color("fd0") do # canvas.rectangle(0, 0, box.width, box.height).fill # end # style.frame = style.create_frame(canvas.context, 72) # end attr_accessor :template # The HexaPDF::Layout::Frame object that defines the area on the page where content should be # placed. # # This can either be set beforehand or during execution of the #template. # # If no frame has been set, a frame covering the page except for a default margin on all sides # is set during #create_page. attr_accessor :frame # Defines the name of the page style that should be used for the next page. # # If this attribute is +nil+ (the default), it means that this style should be used again. attr_accessor :next_style # Creates a new page style instance for the given page size and orientation. If a block is # given, it is used as template for defining the initial content. # # Example: # # PageStyle.new(page_size: :Letter) do |canvas, style| # style.frame = style.create_frame(canvas.context, 72) # style.next_style = :other # canvas.fill_color("fd0") { canvas.circle(100, 100, 50).fill } # end def initialize(page_size: :A4, orientation: :portrait, &block) @page_size = page_size @orientation = orientation @template = block @frame = nil @next_style = nil end # Creates a new page in the given document with this page style and returns it. # # If #frame has not been set beforehand or during execution of the #template, a default frame # covering the whole page except a margin of 36 is created. def create_page(document) page = document.pages.create(media_box: page_size, orientation: orientation) template&.call(page.canvas, self) self.frame ||= create_frame(page, 36) page end # Creates a frame based on the given page's box and margin. # # The +margin+ can be any value allowed by HexaPDF::Layout::Style::Quad#set. # # *Note*: This is a helper method for use inside the #template callable. def create_frame(page, margin = 36) box = page.box margin = Layout::Style::Quad.new(margin) Layout::Frame.new(box.left + margin.left, box.bottom + margin.bottom, box.width - margin.left - margin.right, box.height - margin.bottom - margin.top) end end end end