# -*- 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-2019 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/cli/command' module HexaPDF module CLI # Uses one or more pages of one PDF and underlays/overlays it/them onto another. class Watermark < Command def initialize #:nodoc: super('watermark', takes_commands: false) short_desc("Put one or more PDF pages onto another PDF") long_desc(<<~EOF) This command uses one ore more pages from a PDF file and applies them as background or stamp on another PDF file. If multiple pages are selected from the watermark PDF, the --repeat option can be used to specify how they should be applied: 'last' (the default) will only repeat the last watermark page whereas 'all' will cyclically repeat all watermark pages. EOF options.on("-w", "--watermark-file FILE", "The PDF used as watermark") do |watermark_file| @watermark_file = watermark_file end options.on("-i", "--pages PAGES", "The pages of the watermark file that should be used " \ "(default: 1)") do |pages| @pages = pages end options.on("-r", "--repeat REPEAT_MODE", [:last, :all], "Specifies how the watermark pages should be repeated. Either last or " \ "all (default: last)") do |repeat| @repeat = repeat end options.on("-t", "--type WATERMARK_TYPE", [:background, :stamp], "Specifies how the watermark is applied: background applies it below the page " \ "contents and stamp applies it above. Default: background") do |type| @type = (type == :background ? :underlay : :overlay) end options.on("--password PASSWORD", "-p", String, "The password for decrypting the input PDF. Use - for reading from " \ "standard input.") do |pwd| @password = (pwd == '-' ? read_password : pwd) end define_optimization_options define_encryption_options @watermark_file = nil @pages = "1" @repeat = :last @type = :underlay @password = nil end def execute(in_file, out_file) #:nodoc: maybe_raise_on_existing_file(out_file) watermark = HexaPDF::Document.open(@watermark_file) indices = page_index_generator(watermark) xobject_map = {} with_document(in_file, password: @password, out_file: out_file) do |doc| doc.pages.each do |page| index = indices.next xobject = xobject_map[index] ||= doc.import(watermark.pages[index].to_form_xobject) pw = page.box(:media).width.to_f ph = page.box(:media).height.to_f xw = xobject.width.to_f xh = xobject.height.to_f canvas = page.canvas(type: @type) ratio = [pw / xw, ph / xh].min xw, xh = xw * ratio, xh * ratio x, y = (pw - xw) / 2, (ph - xh) / 2 canvas.xobject(xobject, at: [x, y], width: xw, height: xh) end end end private # Returns an Enumerator instance that returns the indices of the watermark pages that should # be used. def page_index_generator(watermark) pages = parse_pages_specification(@pages, watermark.pages.count) Enumerator.new do |y| loop do pages.each {|index, _rotation| y << index } if @repeat == :last y << pages.last[0] while true end end end end end end end