Home » pdfbox-1.1.0-src » org.apache.pdfbox.pdmodel.documentinterchange.logicalstructure » [javadoc | source]

    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    *
    9    *      http://www.apache.org/licenses/LICENSE-2.0
   10    *
   11    * Unless required by applicable law or agreed to in writing, software
   12    * distributed under the License is distributed on an "AS IS" BASIS,
   13    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   14    * See the License for the specific language governing permissions and
   15    * limitations under the License.
   16    */
   17   package org.apache.pdfbox.pdmodel.documentinterchange.logicalstructure;
   18   
   19   import java.util.ArrayList;
   20   import java.util.Iterator;
   21   import java.util.List;
   22   
   23   import org.apache.pdfbox.cos.COSArray;
   24   import org.apache.pdfbox.cos.COSBase;
   25   import org.apache.pdfbox.cos.COSDictionary;
   26   import org.apache.pdfbox.cos.COSInteger;
   27   import org.apache.pdfbox.cos.COSName;
   28   import org.apache.pdfbox.cos.COSObject;
   29   import org.apache.pdfbox.pdmodel.common.COSArrayList;
   30   import org.apache.pdfbox.pdmodel.common.COSObjectable;
   31   import org.apache.pdfbox.pdmodel.graphics.xobject.PDXObject;
   32   import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotation;
   33   
   34   /**
   35    * A node in the structure tree.
   36    * 
   37    * @author Koch
   38    * @version $Revision: $
   39    */
   40   public abstract class PDStructureNode implements COSObjectable
   41   {
   42   
   43       /**
   44        * Creates a node in the structure tree. Can be either a structure tree root,
   45        *  or a structure element.
   46        * 
   47        * @param node the node dictionary
   48        * @return the structure node
   49        */
   50       public static PDStructureNode create(COSDictionary node)
   51       {
   52           String type = node.getNameAsString(COSName.TYPE);
   53           if ("StructTreeRoot".equals(type))
   54           {
   55               return new PDStructureTreeRoot(node);
   56           }
   57           if ((type == null) || "StructElem".equals(type))
   58           {
   59               return new PDStructureElement(node);
   60           }
   61           throw new IllegalArgumentException("Dictionary must not include a Type entry with a value that is neither StructTreeRoot nor StructElem.");
   62       }
   63   
   64   
   65       private COSDictionary dictionary;
   66   
   67       protected COSDictionary getCOSDictionary()
   68       {
   69           return dictionary;
   70       }
   71   
   72       /**
   73        * Constructor.
   74        *
   75        * @param type the type
   76        */
   77       protected PDStructureNode(String type)
   78       {
   79           this.dictionary = new COSDictionary();
   80           this.dictionary.setName(COSName.TYPE, type);
   81       }
   82   
   83       /**
   84        * Constructor for an existing structure node.
   85        *
   86        * @param dictionary The existing dictionary.
   87        */
   88       protected PDStructureNode(COSDictionary dictionary)
   89       {
   90           this.dictionary = dictionary;
   91       }
   92   
   93       /**
   94        * {@inheritDoc}
   95        */
   96       public COSBase getCOSObject()
   97       {
   98           return this.dictionary;
   99       }
  100   
  101       /**
  102        * Returns the type.
  103        * 
  104        * @return the type
  105        */
  106       public String getType()
  107       {
  108           return this.getCOSDictionary().getNameAsString(COSName.TYPE);
  109       }
  110   
  111       /**
  112        * Returns a list of objects for the kids (K).
  113        * 
  114        * @return a list of objects for the kids
  115        */
  116       public List<Object> getKids()
  117       {
  118           List<Object> kidObjects = new ArrayList<Object>();
  119           COSBase k = this.getCOSDictionary().getDictionaryObject(COSName.K);
  120           if (k instanceof COSArray)
  121           {
  122               Iterator<COSBase> kids = ((COSArray) k).iterator();
  123               while (kids.hasNext())
  124               {
  125                   COSBase kid = kids.next();
  126                   Object kidObject = this.createObject(kid);
  127                   if (kidObject != null)
  128                   {
  129                       kidObjects.add(kidObject);
  130                   }
  131               }
  132           }
  133           else
  134           {
  135               Object kidObject = this.createObject(k);
  136               if (kidObject != null)
  137               {
  138                   kidObjects.add(kidObject);
  139               }
  140           }
  141           return kidObjects;
  142       }
  143   
  144       /**
  145        * Sets the kids (K).
  146        * 
  147        * @param kids the kids
  148        */
  149       public void setKids(List<Object> kids)
  150       {
  151           this.getCOSDictionary().setItem(COSName.K,
  152               COSArrayList.converterToCOSArray(kids));
  153       }
  154   
  155       /**
  156        * Appends a structure element kid.
  157        * 
  158        * @param structureElement the structure element
  159        */
  160       public void appendKid(PDStructureElement structureElement)
  161       {
  162           this.appendObjectableKid(structureElement);
  163           structureElement.setParent(this);
  164       }
  165   
  166       /**
  167        * Appends an objectable kid.
  168        * 
  169        * @param objectable the objectable
  170        */
  171       protected void appendObjectableKid(COSObjectable objectable)
  172       {
  173           if (objectable == null)
  174           {
  175               return;
  176           }
  177           this.appendKid(objectable.getCOSObject());
  178       }
  179   
  180       /**
  181        * Appends a COS base kid.
  182        * 
  183        * @param object the COS base
  184        */
  185       protected void appendKid(COSBase object)
  186       {
  187           if (object == null)
  188           {
  189               return;
  190           }
  191           COSBase k = this.getCOSDictionary().getDictionaryObject(COSName.K);
  192           if (k == null)
  193           {
  194               // currently no kid: set new kid as kids
  195               this.getCOSDictionary().setItem(COSName.K, object);
  196           }
  197           else if (k instanceof COSArray)
  198           {
  199               // currently more than one kid: add new kid to existing array
  200               COSArray array = (COSArray) k;
  201               array.add(object);
  202           }
  203           else
  204           {
  205               // currently one kid: put current and new kid into array and set array as kids
  206               COSArray array = new COSArray();
  207               array.add(k);
  208               array.add(object);
  209               this.getCOSDictionary().setItem(COSName.K, array);
  210           }
  211       }
  212   
  213       /**
  214        * Inserts a structure element kid before a reference kid.
  215        * 
  216        * @param newKid the structure element
  217        * @param refKid the reference kid
  218        */
  219       public void insertBefore(PDStructureElement newKid, Object refKid)
  220       {
  221           this.insertObjectableBefore(newKid, refKid);
  222       }
  223   
  224       /**
  225        * Inserts an objectable kid before a reference kid.
  226        * 
  227        * @param newKid the objectable
  228        * @param refKid the reference kid
  229        */
  230       protected void insertObjectableBefore(COSObjectable newKid, Object refKid)
  231       {
  232           if (newKid == null)
  233           {
  234               return;
  235           }
  236           this.insertBefore(newKid.getCOSObject(), refKid);
  237       }
  238   
  239       /**
  240        * Inserts an COS base kid before a reference kid.
  241        * 
  242        * @param newKid the COS base
  243        * @param refKid the reference kid
  244        */
  245       protected void insertBefore(COSBase newKid, Object refKid)
  246       {
  247           if ((newKid == null) || (refKid == null))
  248           {
  249               return;
  250           }
  251           COSBase k = this.getCOSDictionary().getDictionaryObject(COSName.K);
  252           if (k == null)
  253           {
  254               return;
  255           }
  256           COSBase refKidBase = null;
  257           if (refKid instanceof COSObjectable)
  258           {
  259               refKidBase = ((COSObjectable) refKid).getCOSObject();
  260           }
  261           else if (refKid instanceof COSInteger)
  262           {
  263               refKidBase = (COSInteger) refKid;
  264           }
  265           if (k instanceof COSArray)
  266           {
  267               COSArray array = (COSArray) k;
  268               int refIndex = array.indexOfObject(refKidBase);
  269               array.add(refIndex, newKid.getCOSObject());
  270           }
  271           else
  272           {
  273               boolean onlyKid = k.equals(refKidBase);
  274               if (!onlyKid && (k instanceof COSObject))
  275               {
  276                   COSBase kObj = ((COSObject) k).getObject();
  277                   onlyKid = kObj.equals(refKidBase);
  278               }
  279               if (onlyKid)
  280               {
  281                   COSArray array = new COSArray();
  282                   array.add(newKid);
  283                   array.add(refKidBase);
  284                   this.getCOSDictionary().setItem(COSName.K, array);
  285               }
  286           }
  287       }
  288   
  289       /**
  290        * Removes a structure element kid.
  291        * 
  292        * @param structureElement the structure element
  293        * @return <code>true</code> if the kid was removed, <code>false</code> otherwise
  294        */
  295       public boolean removeKid(PDStructureElement structureElement)
  296       {
  297           boolean removed = this.removeObjectableKid(structureElement);
  298           if (removed)
  299           {
  300               structureElement.setParent(null);
  301           }
  302           return removed;
  303       }
  304   
  305       /**
  306        * Removes an objectable kid.
  307        * 
  308        * @param objectable the objectable
  309        * @return <code>true</code> if the kid was removed, <code>false</code> otherwise
  310        */
  311       protected boolean removeObjectableKid(COSObjectable objectable)
  312       {
  313           if (objectable == null)
  314           {
  315               return false;
  316           }
  317           return this.removeKid(objectable.getCOSObject());
  318       }
  319   
  320       /**
  321        * Removes a COS base kid.
  322        * 
  323        * @param object the COS base
  324        * @return <code>true</code> if the kid was removed, <code>false</code> otherwise
  325        */
  326       protected boolean removeKid(COSBase object)
  327       {
  328           if (object == null)
  329           {
  330               return false;
  331           }
  332           COSBase k = this.getCOSDictionary().getDictionaryObject(COSName.K);
  333           if (k == null)
  334           {
  335               // no kids: objectable is not a kid
  336               return false;
  337           }
  338           else if (k instanceof COSArray)
  339           {
  340               // currently more than one kid: remove kid from existing array
  341               COSArray array = (COSArray) k;
  342               boolean removed = array.removeObject(object);
  343               // if now only one kid: set remaining kid as kids
  344               if (array.size() == 1)
  345               {
  346                   this.getCOSDictionary().setItem(COSName.K, array.getObject(0));
  347               }
  348               return removed;
  349           }
  350           else
  351           {
  352               // currently one kid: if current kid equals given object, remove kids entry
  353               boolean onlyKid = k.equals(object);
  354               if (!onlyKid && (k instanceof COSObject))
  355               {
  356                   COSBase kObj = ((COSObject) k).getObject();
  357                   onlyKid = kObj.equals(object);
  358               }
  359               if (onlyKid)
  360               {
  361                   this.getCOSDictionary().setItem(COSName.K, null);
  362                   return true;
  363               }
  364               return false;
  365           }
  366       }
  367   
  368       /**
  369        * Creates an object for a kid of this structure node.
  370        * The type of object depends on the type of the kid. It can be
  371        * <ul>
  372        * <li>a {@link PDStructureElement},</li>
  373        * <li>a {@link PDAnnotation},</li>
  374        * <li>a {@link PDXObject},</li>
  375        * <li>a {@link PDMarkedContentReference}</li>
  376        * <li>a {@link Integer}</li>
  377        * </ul>
  378        * 
  379        * @param kid the kid
  380        * @return the object
  381        */
  382       protected Object createObject(COSBase kid)
  383       {
  384           COSDictionary kidDic = null;
  385           if (kid instanceof COSDictionary)
  386           {
  387               kidDic = (COSDictionary) kid;
  388           }
  389           else if (kid instanceof COSObject)
  390           {
  391               COSBase base = ((COSObject) kid).getObject();
  392               if (base instanceof COSDictionary)
  393               {
  394                   kidDic = (COSDictionary) base;
  395               }
  396           }
  397           if (kidDic != null)
  398           {
  399               String type = kidDic.getNameAsString(COSName.TYPE);
  400               if ((type == null) || PDStructureElement.TYPE.equals(type))
  401               {
  402                   // A structure element dictionary denoting another structure
  403                   // element
  404                   return new PDStructureElement(kidDic);
  405               }
  406               else if (PDObjectReference.TYPE.equals(type))
  407               {
  408                   // An object reference dictionary denoting a PDF object
  409                   return new PDObjectReference(kidDic);
  410               }
  411               else if (PDMarkedContentReference.TYPE.equals(type))
  412               {
  413                   // A marked-content reference dictionary denoting a
  414                   // marked-content sequence
  415                   return new PDMarkedContentReference(kidDic);
  416               }
  417           }
  418           else if (kid instanceof COSInteger)
  419           {
  420               // An integer marked-content identifier denoting a
  421               // marked-content sequence
  422               COSInteger mcid = (COSInteger) kid;
  423               return mcid.intValue();
  424           }
  425           return null;
  426       }
  427   
  428   }

Home » pdfbox-1.1.0-src » org.apache.pdfbox.pdmodel.documentinterchange.logicalstructure » [javadoc | source]