Package org.pdfclown.documents.interaction.annotations

Source Code of org.pdfclown.documents.interaction.annotations.Annotation

/*
  Copyright 2008-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.interaction.annotations;

import java.awt.geom.Rectangle2D;
import java.util.Date;
import java.util.EnumSet;

import org.pdfclown.PDF;
import org.pdfclown.VersionEnum;
import org.pdfclown.documents.Document;
import org.pdfclown.documents.Page;
import org.pdfclown.documents.interaction.actions.Action;
import org.pdfclown.files.File;
import org.pdfclown.objects.PdfArray;
import org.pdfclown.objects.PdfDate;
import org.pdfclown.objects.PdfDictionary;
import org.pdfclown.objects.PdfDirectObject;
import org.pdfclown.objects.PdfIndirectObject;
import org.pdfclown.objects.PdfInteger;
import org.pdfclown.objects.PdfName;
import org.pdfclown.objects.PdfObjectWrapper;
import org.pdfclown.objects.PdfReference;
import org.pdfclown.objects.PdfTextString;
import org.pdfclown.util.NotImplementedException;

/**
  Annotation [PDF:1.6:8.4].

  @author Stefano Chizzolini (http://www.stefanochizzolini.it)
  @since 0.0.7
  @version 0.1.0
*/
@PDF(VersionEnum.PDF10)
public class Annotation
  extends PdfObjectWrapper<PdfDictionary>
{
  // <class>
  // <classes>
  /**
    Field flags [PDF:1.6:8.4.2].
  */
  public enum FlagsEnum
  {
    // <class>
    // <static>
    // <fields>
    /**
      Hide the annotation, both on screen and on print,
      if it does not belong to one of the standard annotation types
      and no annotation handler is available.
    */
    Invisible(0x1),
    /**
      Hide the annotation, both on screen and on print
      (regardless of its annotation type or whether an annotation handler is available).
    */
    Hidden(0x2),
    /**
      Print the annotation when the page is printed.
    */
    Print(0x4),
    /**
      Do not scale the annotation's appearance to match the magnification of the page.
    */
    NoZoom(0x8),
    /**
      Do not rotate the annotation's appearance to match the rotation of the page.
    */
    NoRotate(0x10),
    /**
      Hide the annotation on the screen.
    */
    NoView(0x20),
    /**
      Do not allow the annotation to interact with the user.
    */
    ReadOnly(0x40),
    /**
      Do not allow the annotation to be deleted or its properties to be modified by the user.
    */
    Locked(0x80),
    /**
      Invert the interpretation of the NoView flag.
    */
    ToggleNoView(0x100);
    // </fields>

    // <interface>
    // <public>
    /**
      Converts an enumeration set into its corresponding bit mask representation.
    */
    public static int toInt(
      EnumSet<FlagsEnum> flags
      )
    {
      int flagsMask = 0;
      for(FlagsEnum flag : flags)
      {flagsMask |= flag.getCode();}

      return flagsMask;
    }

    /**
      Converts a bit mask into its corresponding enumeration representation.
    */
    public static EnumSet<FlagsEnum> toEnumSet(
      int flagsMask
      )
    {
      EnumSet<FlagsEnum> flags = EnumSet.noneOf(FlagsEnum.class);
      for(FlagsEnum flag : FlagsEnum.values())
      {
        if((flagsMask & flag.getCode()) > 0)
        {flags.add(flag);}
      }

      return flags;
    }
    // </public>
    // </interface>
    // </static>

    // <dynamic>
    // <fields>
    /**
      <h3>Remarks</h3>
      <p>Bitwise code MUST be explicitly distinct from the ordinal position of the enum constant
      as they don't coincide.</p>
    */
    private final int code;
    // </fields>

    // <constructors>
    private FlagsEnum(
      int code
      )
    {this.code = code;}
    // </constructors>

    // <interface>
    // <public>
    public int getCode(
      )
    {return code;}
    // </public>
    // </interface>
    // </dynamic>
    // </class>
  }
  // </classes>

  // <static>
  // <fields>
  // </fields>

  // <interface>
  // <public>
  /**
    Wraps an annotation reference into an annotation object.

    @param reference Reference to an annotation object.
    @return Annotation object associated to the reference.
  */
  public static final Annotation wrap(
    PdfReference reference
    )
  {return wrap(reference,null);}

  /**
    Wraps an annotation base object into an annotation object.

    @param baseObject Annotation base object.
    @param container Annotation base object container.
    @return Annotation object associated to the base object.
  */
  public static final Annotation wrap(
    PdfDirectObject baseObject,
    PdfIndirectObject container
    )
  {
    /*
      NOTE: This is a factory method for any annotation-derived object.
    */
    if(baseObject == null)
      return null;

    PdfDictionary dataObject = (PdfDictionary)File.resolve(baseObject);
    if(!dataObject.get(PdfName.Type).equals(PdfName.Annot))
      return null;

    PdfName annotationType = (PdfName)dataObject.get(PdfName.Subtype);
    if(annotationType.equals(PdfName.Text))
      return new Note(baseObject,container);
    else if(annotationType.equals(PdfName.Link))
      return new Link(baseObject,container);
    else if(annotationType.equals(PdfName.FreeText))
      return new CalloutNote(baseObject,container);
    else if(annotationType.equals(PdfName.Line))
      return new Line(baseObject,container);
    else if(annotationType.equals(PdfName.Square))
      return new Rectangle(baseObject,container);
    else if(annotationType.equals(PdfName.Circle))
      return new Ellipse(baseObject,container);
    else if(annotationType.equals(PdfName.Polygon))
      return new Polygon(baseObject,container);
    else if(annotationType.equals(PdfName.PolyLine))
      return new Polyline(baseObject,container);
    else if(annotationType.equals(PdfName.Highlight)
      || annotationType.equals(PdfName.Underline)
      || annotationType.equals(PdfName.Squiggly)
      || annotationType.equals(PdfName.StrikeOut))
      return new TextMarkup(baseObject,container);
    else if(annotationType.equals(PdfName.Stamp))
      return new RubberStamp(baseObject,container);
    else if(annotationType.equals(PdfName.Caret))
      return new Caret(baseObject,container);
    else if(annotationType.equals(PdfName.Ink))
      return new Scribble(baseObject,container);
    else if(annotationType.equals(PdfName.Popup))
      return new Popup(baseObject,container);
    else if(annotationType.equals(PdfName.FileAttachment))
      return new FileAttachment(baseObject,container);
    else if(annotationType.equals(PdfName.Sound))
      return new Sound(baseObject,container);
    else if(annotationType.equals(PdfName.Movie))
      return new Movie(baseObject,container);
    else if(annotationType.equals(PdfName.Widget))
      return new Widget(baseObject,container);
//TODO
//     else if(annotationType.equals(PdfName.Screen)) return new Screen(baseObject,container);
//     else if(annotationType.equals(PdfName.PrinterMark)) return new PrinterMark(baseObject,container);
//     else if(annotationType.equals(PdfName.TrapNet)) return new TrapNet(baseObject,container);
//     else if(annotationType.equals(PdfName.Watermark)) return new Watermark(baseObject,container);
//     else if(annotationType.equals(PdfName.3DAnnotation)) return new 3DAnnotation(baseObject,container);
    else // Other annotation type.
      return new Annotation(baseObject,container);
  }
  // </public>
  // </interface>
  // </static>

  // <dynamic>
  // <constructors>
  protected Annotation(
    Document context,
    PdfName subtype,
    Rectangle2D box,
    Page page
    )
  {
    super(
      context.getFile(),
      new PdfDictionary(
        new PdfName[]
        {
          PdfName.Type,
          PdfName.Subtype,
          PdfName.P,
          PdfName.Border
        },
        new PdfDirectObject[]
        {
          PdfName.Annot,
          subtype,
          page.getBaseObject(),
          new PdfArray(new PdfDirectObject[]{new PdfInteger(0),new PdfInteger(0),new PdfInteger(0)}) // NOTE: Hide border by default.
        }
        )
      );

    {
      setBox(box);

      PdfArray pageAnnotsObject = (PdfArray)File.resolve(page.getBaseDataObject().get(PdfName.Annots));
      if(pageAnnotsObject == null)
      {page.getBaseDataObject().put(PdfName.Annots,pageAnnotsObject = new PdfArray());}
      pageAnnotsObject.add(getBaseObject());
    }
  }

  protected Annotation(
    PdfDirectObject baseObject,
    PdfIndirectObject container
    )
  {super(baseObject,container);}
  // </constructors>

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

  /**
    Gets the action to be performed when the annotation is activated.
  */
  @PDF(VersionEnum.PDF11)
  public Action getAction(
    )
  {return Action.wrap(getBaseDataObject().get(PdfName.A), getContainer());}

  /**
    Gets the annotation's behavior in response to various trigger events.
  */
  @PDF(VersionEnum.PDF12)
  public AnnotationActions getActions(
    )
  {
    PdfDirectObject actionsObject = getBaseDataObject().get(PdfName.AA);
    return actionsObject == null ? null : new AnnotationActions(this, actionsObject, getContainer());
  }

  /**
    Gets the appearance specifying how the annotation is presented visually on the page.
  */
  @PDF(VersionEnum.PDF12)
  public Appearance getAppearance(
    )
  {
    PdfDirectObject appearanceObject = getBaseDataObject().get(PdfName.AP);
    return appearanceObject == null ? null : new Appearance(appearanceObject, getContainer());
  }

  /**
    Gets the border style.
  */
  @PDF(VersionEnum.PDF11)
  public Border getBorder(
    )
  {
    PdfDirectObject borderObject = getBaseDataObject().get(PdfName.BS);
    return borderObject == null ? null : new Border(borderObject, getContainer());
  }

  /**
    Gets the annotation rectangle.
  */
  public Rectangle2D getBox(
    )
  {
    /*
      NOTE: 'Rect' entry MUST be defined.
    */
    org.pdfclown.objects.Rectangle box = new org.pdfclown.objects.Rectangle(getBaseDataObject().get(PdfName.Rect));
    return new Rectangle2D.Double(
      box.getLeft(),
      getPageHeight() - box.getTop(),
      box.getWidth(),
      box.getHeight()
      );
  }

  /**
    Gets the annotation flags.
  */
  @PDF(VersionEnum.PDF11)
  public EnumSet<FlagsEnum> getFlags(
    )
  {
    PdfInteger flagsObject = (PdfInteger)getBaseDataObject().get(PdfName.F);
    return flagsObject == null
      ? EnumSet.noneOf(FlagsEnum.class)
      : FlagsEnum.toEnumSet(flagsObject.getValue());
  }

  /**
    Gets the date and time when the annotation was most recently modified.
  */
  @PDF(VersionEnum.PDF11)
  public Date getModificationDate(
    )
  {
    PdfDirectObject modificationDateObject = getBaseDataObject().get(PdfName.M);
    if(modificationDateObject == null
      || !(modificationDateObject instanceof PdfDate)) // NOTE: Non-well-formed dates are ignored.
      return null;

    return ((PdfDate)modificationDateObject).getValue();
  }

  /**
    Gets the annotation name.
    <p>The annotation name uniquely identifies the annotation among all the annotations on its page.</p>
  */
  @PDF(VersionEnum.PDF14)
  public String getName(
    )
  {
    PdfTextString nameObject = (PdfTextString)getBaseDataObject().get(PdfName.NM);
    return nameObject == null ? null : nameObject.getValue();
  }

  /**
    Gets the associated page.
  */
  @PDF(VersionEnum.PDF13)
  public Page getPage(
    )
  {return Page.wrap(getBaseDataObject().get(PdfName.P));}

  /**
    Gets the annotation text.
    <h3>Remarks</h3>
    <p>Depending on the annotation type, the text may be either directly displayed
    or (in case of non-textual annotations) used as alternate description.</p>
  */
  public String getText(
    )
  {
    PdfTextString textObject = (PdfTextString)getBaseDataObject().get(PdfName.Contents);
    return textObject == null ? null : textObject.getValue();
  }

  /**
    Gets whether to print the annotation when the page is printed.
  */
  @PDF(VersionEnum.PDF11)
  public boolean isPrintable(
    )
  {return getFlags().contains(FlagsEnum.Print);}

  /**
    Gets whether the annotation is visible.
  */
  @PDF(VersionEnum.PDF11)
  public boolean isVisible(
    )
  {return !getFlags().contains(FlagsEnum.Hidden);}

  /**
    @see #getAction()
  */
  public void setAction(
    Action value
    )
  {
    if(value == null)
    {getBaseDataObject().remove(PdfName.A);}
    else
    {getBaseDataObject().put(PdfName.A,value.getBaseObject());}
  }

  /**
    @see #getActions()
  */
  public void setActions(
    AnnotationActions value
    )
  {
    if(value == null)
    {getBaseDataObject().remove(PdfName.AA);}
    else
    {getBaseDataObject().put(PdfName.AA,value.getBaseObject());}
  }

  /**
    @see #getAppearance()
  */
  public void setAppearance(
    Appearance value
    )
  {
    if(value == null)
    {getBaseDataObject().remove(PdfName.AP);}
    else
    {getBaseDataObject().put(PdfName.AP, value.getBaseObject());}
  }

  /**
    @see #getBorder()
  */
  public void setBorder(
    Border value
    )
  {
    if(value == null)
    {getBaseDataObject().remove(PdfName.BS);}
    else
    {
      getBaseDataObject().put(PdfName.BS, value.getBaseObject());
      getBaseDataObject().remove(PdfName.Border);
    }
  }

  /**
    @see #getBox()
  */
  public void setBox(
    Rectangle2D value
    )
  {
    getBaseDataObject().put(
      PdfName.Rect,
      new org.pdfclown.objects.Rectangle(
        value.getX(),
        getPageHeight() - value.getY(),
        value.getWidth(),
        value.getHeight()
        ).getBaseDataObject()
      );
  }

  /**
    @see #getFlags()
  */
  public void setFlags(
    EnumSet<FlagsEnum> value
    )
  {getBaseDataObject().put(PdfName.F, new PdfInteger(FlagsEnum.toInt(value)));}

  /**
    @see #getModificationDate()
  */
  public void setModificationDate(
    Date value
    )
  {getBaseDataObject().put(PdfName.M, new PdfDate(value));}

  /**
    @see #getName()
  */
  public void setName(
    String value
    )
  {getBaseDataObject().put(PdfName.NM, new PdfTextString(value));}

  /**
    @see #getPage()
  */
  public void setPage(
    Page value
    )
  {getBaseDataObject().put(PdfName.P, value.getBaseObject());}

  /**
    @see #isPrintable()
  */
  public void setPrintable(
    boolean value
    )
  {
    EnumSet<FlagsEnum> flags = getFlags();
    if(value)
    {flags.add(FlagsEnum.Print);}
    else
    {flags.remove(FlagsEnum.Print);}
    setFlags(flags);
  }

  /**
    @see #getText()
  */
  public void setText(
    String value
    )
  {
    if(value == null)
    {getBaseDataObject().remove(PdfName.Contents);}
    else
    {getBaseDataObject().put(PdfName.Contents, new PdfTextString(value));}
  }

  /**
    @see #isVisible()
  */
  public void setVisible(
    boolean value
    )
  {
    EnumSet<FlagsEnum> flags = getFlags();
    if(value)
    {flags.remove(FlagsEnum.Hidden);}
    else
    {flags.add(FlagsEnum.Hidden);}
    setFlags(flags);
  }
  // </public>

  // <private>
  private double getPageHeight(
    )
  {
    Page page = getPage();
    return (page != null
        ? page.getBox().getHeight()
        : getDocument().getSize().getHeight());
  }
  // </private>
  // </interface>
  // </dynamic>
  // </class>
}
TOP

Related Classes of org.pdfclown.documents.interaction.annotations.Annotation

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.