All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.itextpdf.kernel.pdf.action.PdfAction Maven / Gradle / Ivy

There is a newer version: 9.0.0
Show newest version
/*
    This file is part of the iText (R) project.
    Copyright (c) 1998-2024 Apryse Group NV
    Authors: Apryse Software.

    This program is offered under a commercial and under the AGPL license.
    For commercial licensing, contact us at https://itextpdf.com/sales.  For AGPL licensing, see below.

    AGPL licensing:
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program 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 this program.  If not, see .
 */
package com.itextpdf.kernel.pdf.action;

import com.itextpdf.io.logs.IoLogMessageConstant;
import com.itextpdf.kernel.exceptions.PdfException;
import com.itextpdf.kernel.pdf.PdfArray;
import com.itextpdf.kernel.pdf.PdfBoolean;
import com.itextpdf.kernel.pdf.PdfDictionary;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfName;
import com.itextpdf.kernel.pdf.PdfNumber;
import com.itextpdf.kernel.pdf.PdfObject;
import com.itextpdf.kernel.pdf.PdfObjectWrapper;
import com.itextpdf.kernel.pdf.PdfStream;
import com.itextpdf.kernel.pdf.PdfString;
import com.itextpdf.kernel.pdf.annot.PdfAnnotation;
import com.itextpdf.kernel.pdf.filespec.PdfFileSpec;
import com.itextpdf.kernel.pdf.filespec.PdfStringFS;
import com.itextpdf.kernel.pdf.navigation.PdfDestination;
import com.itextpdf.kernel.pdf.navigation.PdfExplicitDestination;
import com.itextpdf.kernel.pdf.navigation.PdfExplicitRemoteGoToDestination;
import com.itextpdf.kernel.pdf.navigation.PdfStringDestination;
import com.itextpdf.kernel.pdf.navigation.PdfStructureDestination;
import org.slf4j.LoggerFactory;

import java.util.List;

/**
 * A wrapper for action dictionaries (ISO 32000-1 section 12.6).
 * An action dictionary defines the characteristics and behaviour of an action.
 */
public class PdfAction extends PdfObjectWrapper {


    /**
     * A possible submit value
     */
    public static final int SUBMIT_EXCLUDE = 1;
    /**
     * A possible submit value
     */
    public static final int SUBMIT_INCLUDE_NO_VALUE_FIELDS = 2;
    /**
     * A possible submit value
     */
    public static final int SUBMIT_HTML_FORMAT = 4;
    /**
     * A possible submit value
     */
    public static final int SUBMIT_HTML_GET = 8;
    /**
     * A possible submit value
     */
    public static final int SUBMIT_COORDINATES = 16;
    /**
     * A possible submit value
     */
    public static final int SUBMIT_XFDF = 32;
    /**
     * A possible submit value
     */
    public static final int SUBMIT_INCLUDE_APPEND_SAVES = 64;
    /**
     * A possible submit value
     */
    public static final int SUBMIT_INCLUDE_ANNOTATIONS = 128;
    /**
     * A possible submit value
     */
    public static final int SUBMIT_PDF = 256;
    /**
     * A possible submit value
     */
    public static final int SUBMIT_CANONICAL_FORMAT = 512;
    /**
     * A possible submit value
     */
    public static final int SUBMIT_EXCL_NON_USER_ANNOTS = 1024;
    /**
     * A possible submit value
     */
    public static final int SUBMIT_EXCL_F_KEY = 2048;
    /**
     * A possible submit value
     */
    public static final int SUBMIT_EMBED_FORM = 8196;
    /**
     * A possible submit value
     */
    public static final int RESET_EXCLUDE = 1;

    /**
     * Constructs an empty action that can be further modified.
     */
    public PdfAction() {
        this(new PdfDictionary());
        put(PdfName.Type, PdfName.Action);
    }

    /**
     * Constructs a {@link PdfAction} instance with a given dictionary. It can be used for handy
     * property reading in reading mode or modifying in stamping mode.
     *
     * @param pdfObject the dictionary to construct the wrapper around
     */
    public PdfAction(PdfDictionary pdfObject) {
        super(pdfObject);
        markObjectAsIndirect(getPdfObject());
    }

    /**
     * Creates a GoTo action (section 12.6.4.2 of ISO 32000-1) via a given destination.
     *
     * @param destination the desired destination of the action
     * @return created action
     */
    public static PdfAction createGoTo(PdfDestination destination) {
        validateNotRemoteDestination(destination);
        return new PdfAction().put(PdfName.S, PdfName.GoTo).put(PdfName.D, destination.getPdfObject());
    }

    /**
     * Creates a GoTo action (section 12.6.4.2 of ISO 32000-1) via a given {@link PdfStringDestination} name.
     *
     * @param destination {@link PdfStringDestination} name
     * @return created action
     */
    public static PdfAction createGoTo(String destination) {
        return createGoTo(new PdfStringDestination(destination));
    }

    /**
     * Creates a GoToR action, or remote action (section 12.6.4.3 of ISO 32000-1).
     *
     * @param fileSpec    the file in which the destination shall be located
     * @param destination the destination in the remote document to jump to
     * @param newWindow   a flag specifying whether to open the destination document in a new window
     * @return created action
     */
    public static PdfAction createGoToR(PdfFileSpec fileSpec, PdfDestination destination, boolean newWindow) {
        return createGoToR(fileSpec, destination).put(PdfName.NewWindow, PdfBoolean.valueOf(newWindow));
    }

    /**
     * Creates a GoToR action, or remote action (section 12.6.4.3 of ISO 32000-1).
     *
     * @param fileSpec    the file in which the destination shall be located
     * @param destination the destination in the remote document to jump to
     * @return created action
     */
    public static PdfAction createGoToR(PdfFileSpec fileSpec, PdfDestination destination) {
        validateRemoteDestination(destination);
        return new PdfAction().put(PdfName.S, PdfName.GoToR).put(PdfName.F, fileSpec.getPdfObject()).
                put(PdfName.D, destination.getPdfObject());
    }

    /**
     * Creates a GoToR action, or remote action (section 12.6.4.3 of ISO 32000-1).
     *
     * @param filename the remote destination file to jump to
     * @param pageNum  the remote destination document page to jump to
     * @return created action
     */
    public static PdfAction createGoToR(String filename, int pageNum) {
        return createGoToR(filename, pageNum, false);
    }

    /**
     * Creates a GoToR action, or remote action (section 12.6.4.3 of ISO 32000-1).
     *
     * @param filename  the remote destination file to jump to
     * @param pageNum   the remote destination document page to jump to
     * @param newWindow a flag specifying whether to open the destination document in a new window
     * @return created action
     */
    public static PdfAction createGoToR(String filename, int pageNum, boolean newWindow) {
        return createGoToR(new PdfStringFS(filename), PdfExplicitRemoteGoToDestination.createFitH(pageNum, 10000), newWindow);
    }

    /**
     * Creates a GoToR action, or remote action (section 12.6.4.3 of ISO 32000-1).
     *
     * @param filename    the remote destination file to jump to
     * @param destination the string destination in the remote document to jump to
     * @param newWindow   a flag specifying whether to open the destination document in a new window
     * @return created action
     */
    public static PdfAction createGoToR(String filename, String destination, boolean newWindow) {
        return createGoToR(new PdfStringFS(filename), new PdfStringDestination(destination), newWindow);
    }

    /**
     * Creates a GoToR action, or remote action (section 12.6.4.3 of ISO 32000-1).
     *
     * @param filename    the remote destination file to jump to
     * @param destination the string destination in the remote document to jump to
     * @return created action
     */
    public static PdfAction createGoToR(String filename, String destination) {
        return createGoToR(filename, destination, false);
    }

    /**
     * Creates a GoToE action, or embedded file action (section 12.6.4.4 of ISO 32000-1).
     *
     * @param destination      the destination in the target to jump to
     * @param newWindow        if true, the destination document should be opened in a new window;
     *                         if false, the destination document should replace the current document in the same window
     * @param targetDictionary A target dictionary specifying path information to the target document.
     *                         Each target dictionary specifies one element in the full path to the target and
     *                         may have nested target dictionaries specifying additional elements
     * @return created action
     */
    public static PdfAction createGoToE(PdfDestination destination, boolean newWindow, PdfTarget targetDictionary) {
        return createGoToE(null, destination, newWindow, targetDictionary);
    }

    /**
     * Creates a GoToE action, or embedded file action (section 12.6.4.4 of ISO 32000-1).
     *
     * @param fileSpec         The root document of the target relative to the root document of the source
     * @param destination      the destination in the target to jump to
     * @param newWindow        if true, the destination document should be opened in a new window;
     *                         if false, the destination document should replace the current document in the same window
     * @param targetDictionary A target dictionary specifying path information to the target document.
     *                         Each target dictionary specifies one element in the full path to the target and
     *                         may have nested target dictionaries specifying additional elements
     * @return created action
     */
    public static PdfAction createGoToE(PdfFileSpec fileSpec, PdfDestination destination, boolean newWindow, PdfTarget targetDictionary) {
        PdfAction action = new PdfAction().put(PdfName.S, PdfName.GoToE).put(PdfName.NewWindow, PdfBoolean.valueOf(newWindow));
        if (fileSpec != null) {
            action.put(PdfName.F, fileSpec.getPdfObject());
        }
        if (destination != null) {
            validateRemoteDestination(destination);
            action.put(PdfName.D, destination.getPdfObject());
        } else {
            LoggerFactory.getLogger(PdfAction.class).warn(IoLogMessageConstant.EMBEDDED_GO_TO_DESTINATION_NOT_SPECIFIED);
        }
        if (targetDictionary != null) {
            action.put(PdfName.T, targetDictionary.getPdfObject());
        }
        return action;
    }

    /**
     * Creates a Launch action (section 12.6.4.5 of ISO 32000-1).
     *
     * @param fileSpec  the application that shall be launched or the document that shall beopened or printed
     * @param newWindow a flag specifying whether to open the destination document in a new window
     * @return created action
     */
    public static PdfAction createLaunch(PdfFileSpec fileSpec, boolean newWindow) {
        return createLaunch(fileSpec).put(PdfName.NewWindow, new PdfBoolean(newWindow));
    }

    /**
     * Creates a Launch action (section 12.6.4.5 of ISO 32000-1).
     *
     * @param fileSpec the application that shall be launched or the document that shall beopened or printed
     * @return created action
     */
    public static PdfAction createLaunch(PdfFileSpec fileSpec) {
        PdfAction action = new PdfAction().put(PdfName.S, PdfName.Launch);
        if (fileSpec != null) {
            action.put(PdfName.F, fileSpec.getPdfObject());
        }
        return action;
    }

    /**
     * Creates a Thread action (section 12.6.4.6 of ISO 32000-1).
     * A thread action jumps to a specified bead on an article thread (see 12.4.3, "Articles"),
     * in either the current document or a different one. Table 205 shows the action dictionary
     * entries specific to this type of action.
     *
     * @param fileSpec          the file containing the thread. If this entry is absent, the thread is in the current file
     * @param destinationThread the destination thread
     * @param bead              the bead in the destination thread
     * @return created action
     */
    public static PdfAction createThread(PdfFileSpec fileSpec, PdfObject destinationThread, PdfObject bead) {
        PdfAction action = new PdfAction().put(PdfName.S, PdfName.Launch).put(PdfName.D, destinationThread).put(PdfName.B, bead);
        if (fileSpec != null) {
            action.put(PdfName.F, fileSpec.getPdfObject());
        }
        return action;
    }

    /**
     * Creates a Thread action (section 12.6.4.6 of ISO 32000-1).
     * A thread action jumps to a specified bead on an article thread (see 12.4.3, "Articles"),
     * in either the current document or a different one. Table 205 shows the action dictionary
     * entries specific to this type of action.
     *
     * @param fileSpec the file containing the thread. If this entry is absent, the thread is in the current file
     * @return created action
     */
    public static PdfAction createThread(PdfFileSpec fileSpec) {
        return createThread(fileSpec, null, null);
    }

    /**
     * Creates a URI action (section 12.6.4.7 of ISO 32000-1).
     *
     * @param uri the uniform resource identifier to resolve
     * @return created action
     */
    public static PdfAction createURI(String uri) {
        return createURI(uri, false);
    }

    /**
     * Creates a URI action (section 12.6.4.7 of ISO 32000-1).
     *
     * @param uri   the uniform resource identifier to resolve
     * @param isMap a flag specifying whether to track the mouse position when the URI is resolved
     * @return created action
     */
    public static PdfAction createURI(String uri, boolean isMap) {
        return new PdfAction().put(PdfName.S, PdfName.URI).put(PdfName.URI, new PdfString(uri)).put(PdfName.IsMap, PdfBoolean.valueOf(isMap));
    }

    /**
     * Creates a Sound action (section 12.6.4.8 of ISO 32000-1). Deprecated in PDF 2.0.
     *
     * @param sound a sound object defining the sound that shall be played (see section 13.3 of ISO 32000-1)
     * @return created action
     */
    public static PdfAction createSound(PdfStream sound) {
        return new PdfAction().put(PdfName.S, PdfName.Sound).put(PdfName.Sound, sound);
    }

    /**
     * Creates a Sound action (section 12.6.4.8 of ISO 32000-1). Deprecated in PDF 2.0.
     *
     * @param sound       a sound object defining the sound that shall be played (see section 13.3 of ISO 32000-1)
     * @param volume      the volume at which to play the sound, in the range -1.0 to 1.0. Default value: 1.0
     * @param synchronous a flag specifying whether to play the sound synchronously or asynchronously.
     *                    If this flag is true, the conforming reader retains control, allowing no further user
     *                    interaction other than canceling the sound, until the sound has been completely played.
     *                    Default value: false
     * @param repeat      a flag specifying whether to repeat the sound indefinitely
     *                    If this entry is present, the Synchronous entry shall be ignored. Default value: false
     * @param mix         a flag specifying whether to mix this sound with any other sound already playing
     * @return created action
     */
    public static PdfAction createSound(PdfStream sound, float volume, boolean synchronous, boolean repeat, boolean mix) {
        if (volume < -1 || volume > 1) {
            throw new IllegalArgumentException("volume");
        }
        return new PdfAction().put(PdfName.S, PdfName.Sound).put(PdfName.Sound, sound).
                put(PdfName.Volume, new PdfNumber(volume)).put(PdfName.Synchronous, PdfBoolean.valueOf(synchronous)).
                put(PdfName.Repeat, PdfBoolean.valueOf(repeat)).put(PdfName.Mix, PdfBoolean.valueOf(mix));
    }

    /**
     * Creates a Movie annotation (section 12.6.4.9 of ISO 32000-1). Deprecated in PDF 2.0.
     *
     * @param annotation a movie annotation identifying the movie that shall be played
     * @param title      the title of a movie annotation identifying the movie that shall be played
     * @param operation  the operation that shall be performed on the movie. Shall be one of the following:
     *                   {@link PdfName#Play}, {@link PdfName#Stop}, {@link PdfName#Pause}, {@link PdfName#Resume}
     * @return created annotation
     */
    public static PdfAction createMovie(PdfAnnotation annotation, String title, PdfName operation) {
        PdfAction action = new PdfAction().put(PdfName.S, PdfName.Movie).put(PdfName.T, new PdfString(title))
                .put(PdfName.Operation, operation);
        if (annotation != null) {
            action.put(PdfName.Annotation, annotation.getPdfObject());
        }
        return action;
    }

    /**
     * Creates a Hide action (section 12.6.4.10 of ISO 32000-1).
     *
     * @param annotation the annotation to be hidden or shown
     * @param hidden     a flag indicating whether to hide the annotation (true) or show it (false)
     * @return created action
     */
    public static PdfAction createHide(PdfAnnotation annotation, boolean hidden) {
        return new PdfAction().put(PdfName.S, PdfName.Hide).put(PdfName.T, annotation.getPdfObject()).
                put(PdfName.H, PdfBoolean.valueOf(hidden));
    }

    /**
     * Creates a Hide action (section 12.6.4.10 of ISO 32000-1).
     *
     * @param annotations the annotations to be hidden or shown
     * @param hidden      a flag indicating whether to hide the annotation (true) or show it (false)
     * @return created action
     */
    public static PdfAction createHide(PdfAnnotation[] annotations, boolean hidden) {
        return new PdfAction().put(PdfName.S, PdfName.Hide).put(PdfName.T, getPdfArrayFromAnnotationsList(annotations)).
                put(PdfName.H, PdfBoolean.valueOf(hidden));
    }

    /**
     * Creates a Hide action (section 12.6.4.10 of ISO 32000-1).
     *
     * @param text   a text string giving the fully qualified field name of an interactive form field whose
     *               associated widget annotation or annotations are to be affected
     * @param hidden a flag indicating whether to hide the annotation (true) or show it (false)
     * @return created action
     */
    public static PdfAction createHide(String text, boolean hidden) {
        return new PdfAction().put(PdfName.S, PdfName.Hide).put(PdfName.T, new PdfString(text)).
                put(PdfName.H, PdfBoolean.valueOf(hidden));
    }

    /**
     * Creates a Hide action (section 12.6.4.10 of ISO 32000-1).
     *
     * @param text   a text string array giving the fully qualified field names of interactive form fields whose
     *               associated widget annotation or annotations are to be affected
     * @param hidden a flag indicating whether to hide the annotation (true) or show it (false)
     * @return created action
     */
    public static PdfAction createHide(String[] text, boolean hidden) {
        return new PdfAction().put(PdfName.S, PdfName.Hide).put(PdfName.T, getArrayFromStringList(text)).
                put(PdfName.H, PdfBoolean.valueOf(hidden));
    }

    /**
     * Creates a Named action (section 12.6.4.11 of ISO 32000-1).
     *
     * @param namedAction the name of the action that shall be performed. Shall be one of the following:
     *                    {@link PdfName#NextPage}, {@link PdfName#PrevPage}, {@link PdfName#FirstPage}, {@link PdfName#LastPage}
     * @return created action
     */
    public static PdfAction createNamed(PdfName namedAction) {
        return new PdfAction().put(PdfName.S, PdfName.Named).put(PdfName.N, namedAction);
    }

    /**
     * Creates a Set-OCG-State action (section 12.6.4.12 of ISO 32000-1).
     *
     * @param states a list of {@link PdfActionOcgState} state descriptions
     * @return created action
     */
    public static PdfAction createSetOcgState(List states) {
        return createSetOcgState(states, false);
    }

    /**
     * Creates a Set-OCG-State action (section 12.6.4.12 of ISO 32000-1).
     *
     * @param states     states a list of {@link PdfActionOcgState} state descriptions
     * @param preserveRb If true, indicates that radio-button state relationships between optional content groups
     *                   should be preserved when the states are applied
     * @return created action
     */
    public static PdfAction createSetOcgState(List states, boolean preserveRb) {
        PdfArray stateArr = new PdfArray();
        for (PdfActionOcgState state : states)
            stateArr.addAll(state.getObjectList());
        return new PdfAction().put(PdfName.S, PdfName.SetOCGState).put(PdfName.State, stateArr).put(PdfName.PreserveRB, PdfBoolean.valueOf(preserveRb));
    }

    /**
     * Creates a Rendition action (section 12.6.4.13 of ISO 32000-1).
     *
     * @param file             the name of the media clip, for use in the user interface.
     * @param fileSpec         a full file specification or form XObject that specifies the actual media data
     * @param mimeType         an ASCII string identifying the type of data
     * @param screenAnnotation a screen annotation
     * @return created action
     */
    public static PdfAction createRendition(String file, PdfFileSpec fileSpec, String mimeType, PdfAnnotation screenAnnotation) {
        return new PdfAction().put(PdfName.S, PdfName.Rendition).
                put(PdfName.OP, new PdfNumber(0)).put(PdfName.AN, screenAnnotation.getPdfObject()).
                put(PdfName.R, new PdfRendition(file, fileSpec, mimeType).getPdfObject());
    }

    /**
     * Creates a JavaScript action (section 12.6.4.16 of ISO 32000-1).
     *
     * @param javaScript a text string containing the JavaScript script to be executed.
     * @return created action
     */
    public static PdfAction createJavaScript(String javaScript) {
        return new PdfAction().put(PdfName.S, PdfName.JavaScript).put(PdfName.JS, new PdfString(javaScript));
    }

    /**
     * Creates a Submit-Form Action (section 12.7.5.2 of ISO 32000-1).
     *
     * @param file  a uniform resource locator, as described in 7.11.5, "URL Specifications"
     * @param names an array identifying which fields to include in the submission or which to exclude,
     *              depending on the setting of the Include/Exclude flag in the Flags entry.
     *              This is an optional parameter and can be null
     * @param flags a set of flags specifying various characteristics of the action (see Table 237 of ISO 32000-1).
     *              Default value to be passed: 0.
     * @return created action
     */
    public static PdfAction createSubmitForm(String file, Object[] names, int flags) {
        PdfAction action = new PdfAction();
        action.put(PdfName.S, PdfName.SubmitForm);

        PdfDictionary urlFileSpec = new PdfDictionary();
        urlFileSpec.put(PdfName.F, new PdfString(file));
        urlFileSpec.put(PdfName.FS, PdfName.URL);
        action.put(PdfName.F, urlFileSpec);

        if (names != null) {
            action.put(PdfName.Fields, buildArray(names));
        }
        action.put(PdfName.Flags, new PdfNumber(flags));
        return action;
    }

    /**
     * Creates a Reset-Form Action (section 12.7.5.3 of ISO 32000-1).
     *
     * @param names an array identifying which fields to reset or which to exclude from resetting,
     *              depending on the setting of the Include/Exclude flag in the Flags entry (see Table 239 of ISO 32000-1).
     * @param flags a set of flags specifying various characteristics of the action (see Table 239 of ISO 32000-1).
     *              Default value to be passed: 0.
     * @return created action
     */
    public static PdfAction createResetForm(Object[] names, int flags) {
        PdfAction action = new PdfAction();
        action.put(PdfName.S, PdfName.ResetForm);
        if (names != null) {
            action.put(PdfName.Fields, buildArray(names));
        }
        action.put(PdfName.Flags, new PdfNumber(flags));
        return action;
    }

    /**
     * Adds an additional action to the provided {@link PdfObjectWrapper}<{@link PdfDictionary}> wrapper.
     *
     * @param wrapper the wrapper to add an additional action to
     * @param key     a {@link PdfName} specifying the name of an additional action
     * @param action  the {@link PdfAction} to add as an additional action
     */
    public static void setAdditionalAction(PdfObjectWrapper wrapper, PdfName key, PdfAction action) {
        PdfDictionary dic;
        PdfObject obj = wrapper.getPdfObject().get(PdfName.AA);
        boolean aaExists = obj != null && obj.isDictionary();
        if (aaExists) {
            dic = (PdfDictionary) obj;
        } else {
            dic = new PdfDictionary();
        }
        dic.put(key, action.getPdfObject());
        dic.setModified();
        wrapper.getPdfObject().put(PdfName.AA, dic);
        if (!aaExists || !dic.isIndirect()) {
            wrapper.getPdfObject().setModified();
        }
    }

    /**
     * Adds a chained action.
     *
     * @param nextAction the next action or sequence of actions that shall be performed after the current action
     */
    public void next(PdfAction nextAction) {
        PdfObject currentNextAction = getPdfObject().get(PdfName.Next);
        if (currentNextAction == null) {
            put(PdfName.Next, nextAction.getPdfObject());
        } else if (currentNextAction.isDictionary()) {
            PdfArray array = new PdfArray(currentNextAction);
            array.add(nextAction.getPdfObject());
            put(PdfName.Next, array);
        } else {
            ((PdfArray) currentNextAction).add(nextAction.getPdfObject());
        }
    }

    /**
     * Inserts the value into the underlying object of this {@link PdfAction} and associates it with the specified key.
     * If the key is already present in this {@link PdfAction}, this method will override the old value with the specified one.
     *
     * @param key   key to insert or to override
     * @param value the value to associate with the specified key
     * @return this {@link PdfAction} instance
     */
    public PdfAction put(PdfName key, PdfObject value) {
        getPdfObject().put(key, value);
        setModified();
        return this;
    }

    /**
     * To manually flush a {@code PdfObject} behind this wrapper, you have to ensure
     * that this object is added to the document, i.e. it has an indirect reference.
     * Basically this means that before flushing you need to explicitly call {@link #makeIndirect(PdfDocument)}.
     * For example: wrapperInstance.makeIndirect(document).flush();
     * Note that not every wrapper require this, only those that have such warning in documentation.
     */
    @Override
    public void flush() {
        super.flush();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected boolean isWrappedObjectMustBeIndirect() {
        return true;
    }

    private static PdfArray getPdfArrayFromAnnotationsList(PdfAnnotation[] wrappers) {
        PdfArray arr = new PdfArray();
        for (PdfAnnotation wrapper : wrappers) {
            arr.add(wrapper.getPdfObject());
        }
        return arr;
    }

    private static PdfArray getArrayFromStringList(String[] strings) {
        PdfArray arr = new PdfArray();
        for (String string : strings) {
            arr.add(new PdfString(string));
        }
        return arr;
    }

    private static PdfArray buildArray(Object[] names) {
        PdfArray array = new PdfArray();
        for (Object obj : names) {
            if (obj instanceof String) {
                array.add(new PdfString((String) obj));
            } else if (obj instanceof PdfAnnotation) {
                array.add(((PdfAnnotation) obj).getPdfObject());
            } else {
                throw new PdfException("The array must contain string or PDFAnnotation");
            }
        }
        return array;
    }

    private static void validateRemoteDestination(PdfDestination destination) {
        // No page object can be specified for a destination associated with a remote go-to action because the
        // destination page is in a different PDF document. In this case, the page parameter specifies an integer
        // page number within the remote document instead of a page object in the current document.
        // See section 12.3.2.2 of ISO 32000-1.
        if (destination instanceof PdfExplicitDestination) {
            PdfObject firstObj = ((PdfArray)destination.getPdfObject()).get(0);
            if (firstObj.isDictionary()) {
                throw new IllegalArgumentException("Explicit destinations shall specify page number in remote go-to actions instead of page dictionary");
            }
        } else if (destination instanceof PdfStructureDestination) {
            // No structure element dictionary can be specified for a structure destination associated with a remote
            // go-to action because the destination structure element is in a
            // different PDF document. In this case, the indirect reference to the structure element dictionary shall be
            // replaced by a byte string representing a structure element ID
            PdfObject firstObj = ((PdfArray)destination.getPdfObject()).get(0);
            if (firstObj.isDictionary()) {
                PdfDictionary structElemObj = (PdfDictionary)firstObj;
                PdfString id = structElemObj.getAsString(PdfName.ID);
                if (id == null) {
                    throw new IllegalArgumentException("Structure destinations shall specify structure element ID in remote go-to actions. Structure element that has no ID is specified instead");
                } else {
                    LoggerFactory.getLogger(PdfAction.class)
                            .warn(IoLogMessageConstant.STRUCTURE_ELEMENT_REPLACED_BY_ITS_ID_IN_STRUCTURE_DESTINATION);
                    ((PdfArray)destination.getPdfObject()).set(0, id);
                    destination.getPdfObject().setModified();
                }
            }
        }
    }

    /**
     * Validates not remote destination against the PDF specification and in case of invalidity logs a warning.
     * See section 12.3.2.2 of ISO 32000-1.
     *
     * @param destination the {@link PdfDestination destination} to be validated
     */
    private static void validateNotRemoteDestination(PdfDestination destination) {
        if (destination instanceof PdfExplicitRemoteGoToDestination) {
            LoggerFactory.getLogger(PdfAction.class).warn(IoLogMessageConstant.INVALID_DESTINATION_TYPE);
        } else if (destination instanceof PdfExplicitDestination) {
            // No page number can be specified for a destination associated with a not remote go-to action because the
            // destination page is in a current PDF document. See section 12.3.2.2 of ISO 32000-1.
            PdfObject firstObj = ((PdfArray)destination.getPdfObject()).get(0);
            if (firstObj.isNumber()) {
                LoggerFactory.getLogger(PdfAction.class).warn(IoLogMessageConstant.INVALID_DESTINATION_TYPE);
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy