<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="en"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>PDPageContentStream.java</title><link rel="stylesheet" href="../jacoco-resources/prettify.css" type="text/css"/><script type="text/javascript" src="../jacoco-resources/prettify.js"></script></head><body onload="window['PR_TAB_WIDTH']=4;prettyPrint()"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Apache PDFBox</a> &gt; <a href="index.source.html" class="el_package">org.apache.pdfbox.pdmodel</a> &gt; <span class="el_source">PDPageContentStream.java</span></div><h1>PDPageContentStream.java</h1><pre class="source lang-java linenums">/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the &quot;License&quot;); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an &quot;AS IS&quot; BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.pdfbox.pdmodel;

import java.io.Closeable;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.pdfbox.cos.COSArray;
import org.apache.pdfbox.cos.COSBase;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.pdmodel.common.PDStream;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceStream;

/**
 * Provides the ability to write to a page content stream.
 *
 * @author Ben Litchfield
 */
public final class PDPageContentStream extends PDAbstractContentStream implements Closeable
{
    /**
     * This is to choose what to do with the stream: overwrite, append or prepend.
     */
<span class="fc" id="L42">    public enum AppendMode</span>
    {
        /**
         * Overwrite the existing page content streams.
         */
<span class="fc" id="L47">        OVERWRITE, </span>
        /**
         * Append the content stream after all existing page content streams.
         */
<span class="fc" id="L51">        APPEND, </span>
        /**
         * Insert before all other page content streams.
         */
<span class="fc" id="L55">        PREPEND;</span>

        public boolean isOverwrite()
        {
<span class="fc bfc" id="L59" title="All 2 branches covered.">            return this == OVERWRITE;</span>
        }

        public boolean isPrepend()
        {
<span class="pc bpc" id="L64" title="1 of 2 branches missed.">            return this == PREPEND;</span>
        }
    }
  
<span class="fc" id="L68">    private static final Log LOG = LogFactory.getLog(PDPageContentStream.class);</span>

<span class="pc" id="L70">    private boolean sourcePageHadContents = false;</span>

    /**
     * Create a new PDPage content stream. This constructor overwrites all existing content streams
     * of this page.
     *
     * @param document The document the page is part of.
     * @param sourcePage The page to write the contents to.
     * @throws IOException If there is an error writing to the page contents.
     */
    public PDPageContentStream(PDDocument document, PDPage sourcePage) throws IOException
    {
<span class="fc" id="L82">        this(document, sourcePage, AppendMode.OVERWRITE, true, false);</span>
<span class="pc bpc" id="L83" title="1 of 2 branches missed.">        if (sourcePageHadContents)</span>
        {
<span class="nc" id="L85">            LOG.warn(&quot;You are overwriting an existing content, you should use the append mode&quot;);</span>
        }
<span class="fc" id="L87">    }</span>

    /**
     * Create a new PDPage content stream. If the appendContent parameter is set to
     * {@link AppendMode#APPEND}, you may want to use
     * {@link #PDPageContentStream(PDDocument, PDPage, PDPageContentStream.AppendMode, boolean, boolean)}
     * instead, with the fifth parameter set to true.
     *
     * @param document The document the page is part of.
     * @param sourcePage The page to write the contents to.
     * @param appendContent Indicates whether content will be overwritten, appended or prepended.
     * @param compress Tell if the content stream should compress the page contents.
     * @throws IOException If there is an error writing to the page contents.
     */
    public PDPageContentStream(PDDocument document, PDPage sourcePage, AppendMode appendContent,
                               boolean compress) throws IOException
    {
<span class="fc" id="L104">        this(document, sourcePage, appendContent, compress, false);</span>
<span class="fc" id="L105">    }</span>
    
    /**
     * Create a new PDPage content stream.
     *
     * @param document The document the page is part of.
     * @param sourcePage The page to write the contents to.
     * @param appendContent Indicates whether content will be overwritten, appended or prepended.
     * @param compress Tell if the content stream should compress the page contents.
     * @param resetContext Tell if the graphic context should be reset. This is only relevant when
     * the appendContent parameter is set to {@link AppendMode#APPEND}. You should use this when
     * appending to an existing stream, because the existing stream may have changed graphic
     * properties (e.g. scaling, rotation).
     * @throws IOException If there is an error writing to the page contents.
     */
    public PDPageContentStream(PDDocument document, PDPage sourcePage, AppendMode appendContent,
                               boolean compress, boolean resetContext) throws IOException
    {
<span class="fc" id="L123">        this(document, sourcePage, appendContent, compress, resetContext, new PDStream(document),</span>
<span class="fc bfc" id="L124" title="All 2 branches covered.">                sourcePage.getResources() != null ? sourcePage.getResources() : new PDResources());</span>
<span class="fc" id="L125">    }</span>

    private PDPageContentStream(PDDocument document, PDPage sourcePage, AppendMode appendContent,
                                boolean compress, boolean resetContext,PDStream stream,
                                PDResources resources) throws IOException
    {
<span class="fc bfc" id="L131" title="All 2 branches covered.">        super(document, stream.createOutputStream(compress ? COSName.FLATE_DECODE : null), resources);</span>

        // propagate resources to the page
<span class="fc bfc" id="L134" title="All 2 branches covered.">        if (sourcePage.getResources() == null)</span>
        {
<span class="fc" id="L136">            sourcePage.setResources(resources);</span>
        }

        // If request specifies the need to append/prepend to the document
<span class="fc bfc" id="L140" title="All 4 branches covered.">        if (!appendContent.isOverwrite() &amp;&amp; sourcePage.hasContents())</span>
        {
            // Add new stream to contents array
<span class="fc" id="L143">            COSBase contents = sourcePage.getCOSObject().getDictionaryObject(COSName.CONTENTS);</span>
            COSArray array;
<span class="fc bfc" id="L145" title="All 2 branches covered.">            if (contents instanceof COSArray)</span>
            {
                // If contents is already an array, a new stream is simply appended to it
<span class="fc" id="L148">                array = (COSArray) contents;</span>
            }
            else
            {
                // Creates a new array and adds the current stream plus a new one to it
<span class="fc" id="L153">                array = new COSArray();</span>
<span class="fc" id="L154">                array.add(contents);</span>
            }

<span class="pc bpc" id="L157" title="1 of 2 branches missed.">            if (appendContent.isPrepend())</span>
            {
<span class="nc" id="L159">                array.add(0, stream.getCOSObject());</span>
            }
            else
            {
<span class="fc" id="L163">                array.add(stream);</span>
            }

            // save the initial/unmodified graphics context
<span class="fc bfc" id="L167" title="All 2 branches covered.">            if (resetContext)</span>
            {
                // create a new stream to prefix existing stream
<span class="fc" id="L170">                PDStream prefixStream = new PDStream(document);</span>

                // save the pre-append graphics state
<span class="fc" id="L173">                try (OutputStream prefixOut = prefixStream.createOutputStream())</span>
                {
<span class="fc" id="L175">                    prefixOut.write(&quot;q&quot;.getBytes(StandardCharsets.US_ASCII));</span>
<span class="fc" id="L176">                    prefixOut.write('\n');</span>
                }

                // insert the new stream at the beginning
<span class="fc" id="L180">                array.add(0, prefixStream.getCOSObject());</span>
            }

            // Sets the compoundStream as page contents
<span class="fc" id="L184">            sourcePage.getCOSObject().setItem(COSName.CONTENTS, array);</span>

            // restore the pre-append graphics state
<span class="fc bfc" id="L187" title="All 2 branches covered.">            if (resetContext)</span>
            {
<span class="fc" id="L189">                restoreGraphicsState();</span>
            }
<span class="fc" id="L191">        }</span>
        else
        {
<span class="fc" id="L194">            sourcePageHadContents = sourcePage.hasContents();</span>
<span class="fc" id="L195">            sourcePage.setContents(stream);</span>
        }

        // configure NumberFormat
<span class="fc" id="L199">        setMaximumFractionDigits(5);</span>
<span class="fc" id="L200">    }</span>

    /**
     * Create a new appearance stream. Note that this is not actually a &quot;page&quot; content stream.
     *
     * @param doc The document the page is part of.
     * @param appearance The appearance stream to write to.
     * @throws IOException If there is an error writing to the page contents.
     */
    public PDPageContentStream(PDDocument doc, PDAppearanceStream appearance) throws IOException
    {
<span class="nc" id="L211">        this (doc, appearance, appearance.getStream().createOutputStream()); </span>
<span class="nc" id="L212">    }</span>
    
    /**
     * Create a new appearance stream. Note that this is not actually a &quot;page&quot; content stream.
     *
     * @param doc The document the appearance is part of.
     * @param appearance The appearance stream to add to.
     * @param outputStream The appearances output stream to write to.
     */
    public PDPageContentStream(PDDocument doc, PDAppearanceStream appearance, OutputStream outputStream)
    {
<span class="nc" id="L223">        super(doc, outputStream, appearance.getResources());</span>
<span class="nc" id="L224">    }</span>

    /**
     * This will append raw commands to the content stream.
     *
     * @param commands The commands to append to the stream.
     * @throws IOException If an error occurs while writing to the stream.
     * @deprecated Usage of this method is discouraged.
     */
    @Deprecated
    public void appendRawCommands(String commands) throws IOException
    {
<span class="nc" id="L236">        write(commands);</span>
<span class="nc" id="L237">    }</span>

    /**
     * This will append raw commands to the content stream.
     *
     * @param commands The commands to append to the stream.
     * @throws IOException If an error occurs while writing to the stream.
     * @deprecated Usage of this method is discouraged.
     */
    @Deprecated
    public void appendRawCommands(byte[] commands) throws IOException
    {
<span class="nc" id="L249">        write(commands);</span>
<span class="nc" id="L250">    }</span>

    /**
     * This will append raw commands to the content stream.
     *
     * @param data Append a raw byte to the stream.
     * @throws IOException If an error occurs while writing to the stream.
     * @deprecated Usage of this method is discouraged.
     */
    @Deprecated
    public void appendRawCommands(int data) throws IOException
    {
<span class="nc" id="L262">        writeOperand(data);</span>
<span class="nc" id="L263">    }</span>

    /**
     * This will append raw commands to the content stream.
     *
     * @param data Append a formatted double value to the stream.
     * @throws IOException If an error occurs while writing to the stream.
     * @deprecated Usage of this method is discouraged.
     */
    @Deprecated
    public void appendRawCommands(double data) throws IOException
    {
<span class="nc" id="L275">        writeOperand((float) data);</span>
<span class="nc" id="L276">    }</span>

    /**
     * This will append raw commands to the content stream.
     *
     * @param data Append a formatted float value to the stream.
     * @throws IOException If an error occurs while writing to the stream.
     * @deprecated Usage of this method is discouraged.
     */
    @Deprecated
    public void appendRawCommands(float data) throws IOException
    {
<span class="nc" id="L288">        writeOperand(data);</span>
<span class="nc" id="L289">    }</span>
}
</pre><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.8.202204050719</span></div></body></html>