Package org.pdfclown.documents

Source Code of org.pdfclown.documents.Document$Configuration

/*
  Copyright 2006-2010 Stefano Chizzolini. http://www.pdfclown.org

  Contributors:
    * Stefano Chizzolini (original code developer, http://www.stefanochizzolini.it)

  This file should be part of the source code distribution of "PDF Clown library"
  (the Program): see the accompanying README files for more info.

  This Program is free software; you can redistribute it and/or modify it under the terms
  of the GNU Lesser 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,
  either expressed or implied; without even the implied warranty of MERCHANTABILITY or
  FITNESS FOR A PARTICULAR PURPOSE. See the License for more details.

  You should have received a copy of the GNU Lesser General Public License along with this
  Program (see README files); if not, go to the GNU website (http://www.gnu.org/licenses/).

  Redistribution and use, with or without modification, are permitted provided that such
  redistributions retain the above copyright notice, license and disclaimer, along with
  this list of conditions.
*/

package org.pdfclown.documents;

import java.awt.Dimension;
import java.awt.geom.Dimension2D;
import java.awt.geom.Rectangle2D;
import java.awt.print.Pageable;
import java.awt.print.Paper;
import java.awt.print.Printable;
import java.util.ArrayList;
import java.util.Collection;

import org.pdfclown.PDF;
import org.pdfclown.Version;
import org.pdfclown.VersionEnum;
import org.pdfclown.documents.contents.Resources;
import org.pdfclown.documents.interaction.forms.Form;
import org.pdfclown.documents.interaction.navigation.document.Bookmarks;
import org.pdfclown.documents.interaction.navigation.document.Destination;
import org.pdfclown.documents.interaction.viewer.ViewerPreferences;
import org.pdfclown.documents.interchange.metadata.Information;
import org.pdfclown.files.File;
import org.pdfclown.objects.PdfArray;
import org.pdfclown.objects.PdfDictionary;
import org.pdfclown.objects.PdfDirectObject;
import org.pdfclown.objects.PdfIndirectObject;
import org.pdfclown.objects.PdfName;
import org.pdfclown.objects.PdfNumber;
import org.pdfclown.objects.PdfObjectWrapper;
import org.pdfclown.objects.PdfReal;
import org.pdfclown.objects.PdfReference;
import org.pdfclown.objects.PdfString;
import org.pdfclown.objects.Rectangle;
import org.pdfclown.util.NotImplementedException;

/**
  PDF document [PDF:1.6:3.6.1].

  @author Stefano Chizzolini (http://www.stefanochizzolini.it)
  @version 0.1.0
*/
@PDF(VersionEnum.PDF10)
public final class Document
  extends PdfObjectWrapper<PdfDictionary>
  implements Pageable
{
  // <class>
  // <classes>
  /**
    Document configuration.

    @author Stefano Chizzolini (http://www.stefanochizzolini.it)
    @since 0.1.0
  */
  public static final class Configuration
  {
    /**
      Version compatibility mode.
    */
    public enum CompatibilityModeEnum
    {
      /**
        Document's conformance version is ignored;
        any feature is accepted without checking its compatibility.
      */
      Passthrough,
      /**
        Document's conformance version is automatically updated
        to support used features.
      */
      Loose,
      /**
        Document's conformance version is mandatory;
        any unsupported feature is forbidden and causes an exception
        to be thrown in case of attempted use.
      */
      Strict
    }

    /**
      Cross-reference mode [PDF:1.6:3.4].
    */
    public enum XRefModeEnum
    {
      /**
        Cross-reference table [PDF:1.6:3.4.3].
      */
      @PDF(VersionEnum.PDF10)
      Plain,
      /**
        Cross-reference stream [PDF:1.6:3.4.7].
      */
      @PDF(VersionEnum.PDF15)
      Compressed
    }

    private CompatibilityModeEnum compatibilityMode = CompatibilityModeEnum.Loose;
    private XRefModeEnum xrefMode = XRefModeEnum.Plain;

    private Document document;

    Configuration(
      Document document
      )
    {this.document = document;}

    /**
      Gets the document's version compatibility mode.
    */
    public CompatibilityModeEnum getCompatibilityMode(
      )
    {return compatibilityMode;}

    /**
      Gets the document associated with this configuration.
    */
    public Document getDocument(
      )
    {return document;}

    /**
      Gets the document's cross-reference mode.
    */
    public XRefModeEnum getXrefMode(
      )
    {return xrefMode;}

    /**
      @see #getCompatibilityMode()
    */
    public void setCompatibilityMode(
      CompatibilityModeEnum value
      )
    {compatibilityMode = value;}

    /**
      @see #getXrefMode()
    */
    public void setXrefMode(
      XRefModeEnum value
      )
    {document.checkCompatibility(xrefMode = value);}
  }

  public enum PageLayoutEnum
  {
    SinglePage,
    OneColumn,
    TwoColumns
  }

  public enum PageModeEnum
  {
    /**
      Neither document outline nor thumbnail images visible.
    */
    Simple,
    /**
      Document outline visible.
    */
    Bookmarks,
    /**
      Thumbnail images visible.
    */
    Thumbnails,
    /**
      Full-screen mode, with no menu bar, window controls, or any other window visible.
    */
    FullScreen,
    /**
      Optional content group panel visible.
    */
    @PDF(VersionEnum.PDF15)
    OCG,
    /**
      Attachments panel visible.
    */
    @PDF(VersionEnum.PDF16)
    Attachments
  }
  // </classes>

  // <static>
  // <interface>
  // <public>
  @SuppressWarnings("unchecked")
  public static <T extends PdfObjectWrapper<?>> T resolve(
    Class<T> type,
    PdfDirectObject baseObject,
    PdfIndirectObject container
    )
  {
    if(Destination.class.isAssignableFrom(type))
      return (T)Destination.wrap(baseObject,container,null);
    else
      throw new UnsupportedOperationException("Type '" + type.getName() + "' wrapping is not supported.");
  }

  /**
    Forces a named base object to be expressed as its corresponding
    high-level representation.
  */
  public static <T extends PdfObjectWrapper<?>> T resolveName(
    Class<T> type,
    PdfDirectObject namedBaseObject,
    PdfIndirectObject container
    )
  {
    if(namedBaseObject instanceof PdfString) // Named destination.
      return container.getFile().getDocument().getNames().resolve(type,(PdfString)namedBaseObject);
    else // Explicit destination.
      return resolve(type,namedBaseObject,container);
  }
  // </public>
  // </interface>
  // </static>

  // <dynamic>
  // <fields>
  /**
    For internal use only.
  */
  public java.util.Hashtable<PdfReference,Object> cache = new java.util.Hashtable<PdfReference,Object>();

  private Configuration configuration = new Configuration(this);
  // </fields>

  // <constructors>
  /**
    For internal use only.
  */
  public Document(
    File context
    )
  {
    super(
      context,
      new PdfDictionary(
        new PdfName[]{PdfName.Type},
        new PdfDirectObject[]{PdfName.Catalog}
        ) // Document catalog [PDF:1.6:3.6.1].
      );

    /*
      NOTE: Here it is just a minimal initialization;
      any further customization is upon client's responsibility.
    */
    // Link the document to the file!
    context.getTrailer().put(PdfName.Root,getBaseObject()); // Attaches the catalog reference to the file trailer.

    // Initialize the pages collection (page-tree root node)!
    setPages(new Pages(this)); // NOTE: The page-tree root node is required [PDF:1.6:3.6.1].

    // Default page size.
    setPageSize(PageFormat.getSize());

    // Default resources collection.
    setResources(new Resources(this));
  }

  /**
    For internal use only.
  */
  public Document(
    PdfDirectObject baseObject // Catalog.
    )
  {
    super(
      baseObject,
      null // NO container (catalog MUST be an indirect object [PDF:1.6:3.4.4]).
      );
  }
  // </constructors>

  // <interface>
  // <public>
  @Override
  public Document clone(
    Document context
    )
  {throw new NotImplementedException();}

  /**
    Clones the object within this document context.
  */
  public Object contextualize(
    PdfObjectWrapper<?> object
    )
  {
    if(object.getFile() == getFile())
      return object;

    return object.clone(this);
  }

  /**
    Clones the collection objects within this document context.
  */
  public Collection<? extends PdfObjectWrapper<?>> contextualize(
    Collection<? extends PdfObjectWrapper<?>> objects
    )
  {
    ArrayList<PdfObjectWrapper<?>> contextualizedObjects = new ArrayList<PdfObjectWrapper<?>>(objects.size());
    for(PdfObjectWrapper<?> object : objects)
    {contextualizedObjects.add((PdfObjectWrapper<?>)contextualize(object));}

    return contextualizedObjects;
  }

  /**
    Drops the object from this document context.
  */
  public void decontextualize(
    PdfObjectWrapper<?> object
    )
  {
    if(object.getFile() != getFile())
      return;

    object.delete();
  }

  /**
    Drops the collection's objects from this document context.
  */
  public void decontextualize(
    Collection<? extends PdfObjectWrapper<?>> objects
    )
  {
    for(PdfObjectWrapper<?> object : objects)
    {decontextualize(object);}
  }

  /**
    Gets the document's behavior in response to trigger events.

    @since 0.0.7
  */
  @PDF(VersionEnum.PDF14)
  public DocumentActions getActions(
    )
  {
    PdfDirectObject actionsObject = getBaseDataObject().get(PdfName.AA);
    if(actionsObject == null)
      return null;

    return new DocumentActions(actionsObject, getContainer());
  }

  /**
    Gets the bookmark collection [PDF:1.6:8.2.2].
  */
  public Bookmarks getBookmarks(
    )
  {
    PdfDirectObject bookmarksObject = getBaseDataObject().get(PdfName.Outlines);
    if(bookmarksObject == null)
      return null;

    return new Bookmarks(bookmarksObject);
  }

  /**
    Gets the configuration of this document.
  */
  public final Configuration getConfiguration(
    )
  {return configuration;}

  /**
    Gets the interactive form (AcroForm) [PDF:1.6:8.6.1].

    @since 0.0.7
  */
  @PDF(VersionEnum.PDF12)
  public Form getForm(
    )
  {
    PdfDirectObject formObject = getBaseDataObject().get(PdfName.AcroForm);
    if(formObject == null)
      return null;

    return new Form(formObject, getContainer());
  }

  /**
    Gets the document information dictionary [PDF:1.6:10.2.1].
  */
  public Information getInformation(
    )
  {
    PdfDirectObject informationObject = getFile().getTrailer().get(PdfName.Info);
    if(informationObject == null)
      return null;

    return new Information(informationObject);
  }

  /**
    Gets the name dictionary [PDF:1.6:3.6.3].
  */
  @PDF(VersionEnum.PDF12)
  public Names getNames(
    )
  {
    PdfDirectObject namesObject = getBaseDataObject().get(PdfName.Names);
    if(namesObject == null)
      return null;

    return new Names(namesObject, getContainer());
  }

  /**
    Gets the page layout to be used when the document is opened.
  */
  public PageLayoutEnum getPageLayout(
    )
  {
    PdfName value = (PdfName)getBaseDataObject().get(PdfName.PageLayout);
    if(value.equals(PdfName.OneColumn))
      return PageLayoutEnum.OneColumn;
    else if(value.equals(PdfName.TwoColumnLeft))
      return PageLayoutEnum.TwoColumns;
    else
      return PageLayoutEnum.SinglePage;
  }

  /**
    Gets the page mode, that is how the document should be displayed when is opened.
  */
  public PageModeEnum getPageMode(
    )
  {
    PdfName value = (PdfName)getBaseDataObject().get(PdfName.PageMode);
    if(value == null
      || value.equals(PdfName.UseNone))
      return PageModeEnum.Simple;
    else if(value.equals(PdfName.UseOutlines))
      return PageModeEnum.Bookmarks;
    else if(value.equals(PdfName.UseThumbs))
      return PageModeEnum.Thumbnails;
    else if(value.equals(PdfName.FullScreen))
      return PageModeEnum.FullScreen;
    else if(value.equals(PdfName.UseOC))
      return PageModeEnum.OCG;
    else if(value.equals(PdfName.UseAttachments))
      return PageModeEnum.Attachments;
    else
      throw new UnsupportedOperationException("Page mode unknown: " + value);
  }

  /**
    Gets the page collection [PDF:1.6:3.6.2].
  */
  public Pages getPages(
    )
  {return new Pages(getBaseDataObject().get(PdfName.Pages));}

  /**
    Gets the default page size [PDF:1.6:3.6.2].
  */
  public Dimension2D getPageSize(
    )
  {
    /*
      NOTE: Due to the contract,
      we cannot force the existence of the default media box at document level.
    */
    PdfArray mediaBox = getMediaBox();
    if(mediaBox == null)
      return null;

    return new Dimension(
      ((PdfNumber<?>)mediaBox.get(2)).getValue().intValue(),
      ((PdfNumber<?>)mediaBox.get(3)).getValue().intValue()
      );
  }

  /**
    Gets the <b>default resource collection</b> [PDF:1.6:3.6.2].
    <p>The default resource collection is used as last resort by every page
    that doesn't reference one explicitly (and doesn't reference an intermediate one
    implicitly).</p>
  */
  public Resources getResources(
    )
  {
    PdfReference pagesReference = (PdfReference)getBaseDataObject().get(PdfName.Pages);
    return Resources.wrap(
      ((PdfDictionary)File.resolve(pagesReference)).get(PdfName.Resources),
      pagesReference.getIndirectObject()
      );
  }

  /**
    Gets the document size, that is the maximum page dimensions across the whole document.
  */
  public Dimension2D getSize(
    )
  {
    double height = 0, width = 0;
    for(Page page : getPages())
    {
      Dimension2D pageSize = page.getSize();
      height = Math.max(height,pageSize.getHeight());
      width = Math.max(width,pageSize.getWidth());
    }
    return new org.pdfclown.util.math.geom.Dimension(width,height);
  }

  /**
    Gets the version of the PDF specification this document conforms to [PDF:1.6:3.6.1].
  */
  @PDF(VersionEnum.PDF14)
  public Version getVersion(
    )
  {
    /*
      NOTE: If the header specifies a later version, or if this entry is absent,
      the document conforms to the version specified in the header.
    */
    Version fileVersion = getFile().getVersion();

    PdfName versionObject = (PdfName)getBaseDataObject().get(PdfName.Version);
    if(versionObject == null)
      return fileVersion;

    Version version = Version.get(versionObject.getRawValue());
    if(getFile().getReader() == null)
      return version;

    return (version.compareTo(fileVersion) > 0 ? version : fileVersion);
  }

  /**
    Gets the way the document is to be presented [PDF:1.6:8.1].
  */
  @PDF(VersionEnum.PDF12)
  public ViewerPreferences getViewerPreferences(
    )
  {
    PdfDirectObject viewerPreferencesObject = getBaseDataObject().get(PdfName.ViewerPreferences);
    if(viewerPreferencesObject == null)
      return null;

    return new ViewerPreferences(viewerPreferencesObject, getContainer());
  }

  /**
    @see #getActions()
  */
  public void setActions(
    DocumentActions value
    )
  {getBaseDataObject().put(PdfName.AA, value.getBaseObject());}

  /**
    @see #getBookmarks()
  */
  public void setBookmarks(
    Bookmarks value
    )
  {getBaseDataObject().put(PdfName.Outlines,value.getBaseObject());}

  /**
    @see #getConfiguration()
    @since 0.1.0
  */
  public void setConfiguration(
    Configuration value
    )
  {configuration = value;}

  /**
    @see #getForm()
    @since 0.0.7
  */
  public void setForm(
    Form value
    )
  {getBaseDataObject().put(PdfName.AcroForm,value.getBaseObject());}

  /**
    @see #getInformation()
  */
  public void setInformation(
    Information value
    )
  {getFile().getTrailer().put(PdfName.Info,value.getBaseObject());}

  /**
    @see #getNames()
    @since 0.0.4
  */
  public void setNames(
    Names value
    )
  {getBaseDataObject().put(PdfName.Names,value.getBaseObject());}

  /**
    @see #getPageLayout()
  */
  public void setPageLayout(
    PageLayoutEnum value
    )
  {
    switch(value)
    {
      case SinglePage:
        getBaseDataObject().put(PdfName.PageLayout,PdfName.SinglePage);
        break;
      case OneColumn:
        getBaseDataObject().put(PdfName.PageLayout,PdfName.OneColumn);
        break;
      case TwoColumns:
        getBaseDataObject().put(PdfName.PageLayout,PdfName.TwoColumnLeft);
        break;
    }
  }

  /**
    @see #getPageMode()
  */
  public void setPageMode(
    PageModeEnum value
    )
  {
    PdfName valueObject;
    switch(value)
    {
      case Simple:
        valueObject = PdfName.UseNone;
        break;
      case Bookmarks:
        valueObject = PdfName.UseOutlines;
        break;
      case Thumbnails:
        valueObject = PdfName.UseThumbs;
        break;
      case FullScreen:
        valueObject = PdfName.FullScreen;
        break;
      case OCG:
        valueObject = PdfName.UseOC;
        break;
      case Attachments:
        valueObject = PdfName.UseAttachments;
        break;
      default:
        throw new UnsupportedOperationException("Page mode unknown: " + value);
    }
    getBaseDataObject().put(PdfName.PageMode, valueObject);
  }

  /**
    @see #getPages()
  */
  public void setPages(
    Pages value
    )
  {getBaseDataObject().put(PdfName.Pages,value.getBaseObject());}

  /**
    @see #getPageSize()
  */
  public void setPageSize(
    Dimension2D value
    )
  {
    PdfArray mediaBox = getMediaBox();
    if(mediaBox == null)
    {
      // Create default media box!
      mediaBox = new Rectangle(0,0,0,0).getBaseDataObject();
      // Assign the media box to the document!
      ((PdfDictionary)getBaseDataObject().resolve(PdfName.Pages)).put(PdfName.MediaBox,mediaBox);
    }
    mediaBox.set(2,new PdfReal(value.getWidth()));
    mediaBox.set(3,new PdfReal(value.getHeight()));
  }

  /**
    @see #getResources()
  */
  public void setResources(
    Resources value
    )
  {
    PdfReference pages = (PdfReference)getBaseDataObject().get(PdfName.Pages);
    ((PdfDictionary)File.resolve(pages)).put(PdfName.Resources, value.getBaseObject());
  }

  /**
    @see #getVersion()
  */
  public void setVersion(
    Version value
    )
  {
    if(value == null)
    {getBaseDataObject().remove(PdfName.Version);}
    else
    {
      checkCompatibility("version");
      getBaseDataObject().put(PdfName.Version, new PdfName(value.toString()));
    }
  }

  /**
    @see #getViewerPreferences()
  */
  public void setViewerPreferences(
    ViewerPreferences value
    )
  {getBaseDataObject().put(PdfName.ViewerPreferences, value.getBaseObject());}

  // <Pageable>
  @Override
  public int getNumberOfPages(
    )
  {return getPages().size();}

  @Override
  public java.awt.print.PageFormat getPageFormat(
    int pageIndex
    ) throws IndexOutOfBoundsException
  {
    java.awt.print.PageFormat pageFormat = new java.awt.print.PageFormat();
    {
      Page page = getPages().get(pageIndex);
      Paper paper = new Paper();
      {
        Rectangle2D pageBox = page.getBox();
        paper.setSize(pageBox.getWidth(),pageBox.getHeight());
      }
      pageFormat.setPaper(paper);
    }
    return pageFormat;
  }

  @Override
  public Printable getPrintable(
    int pageIndex
    ) throws IndexOutOfBoundsException
  {return getPages().get(pageIndex);}
  // </Pageable>
  // </public>

  // <private>
  /**
    Gets the default media box.
  */
  private PdfArray getMediaBox(
    )
  {
    /*
      NOTE: Document media box MUST be associated with the page-tree root node
      in order to be inheritable by all the pages.
    */
    return (PdfArray)((PdfDictionary)getBaseDataObject().resolve(PdfName.Pages)).resolve(PdfName.MediaBox);
  }
  // </private>
  // </interface>
  // </dynamic>
  // </class>
}
TOP

Related Classes of org.pdfclown.documents.Document$Configuration

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.