Save This Page
Home » pdfbox-1.1.0-src » org.apache.fontbox.cff » [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.fontbox.cff;
   18   
   19   import java.util.ArrayList;
   20   import java.util.Arrays;
   21   import java.util.Collections;
   22   import java.util.List;
   23   
   24   /**
   25    * A class to translate Type2 CharString command sequence to Type1 CharString command sequence.
   26    * 
   27    * @author Villu Ruusmann
   28    * @version $Revision$
   29    */
   30   public class CharStringConverter extends CharStringHandler
   31   {
   32   
   33       private int defaultWidthX = 0;
   34       private int nominalWidthX = 0;
   35       private List<Object> sequence = null;
   36       private int pathCount = 0;
   37   
   38       /**
   39        * Constructor.
   40        * 
   41        * @param defaultWidth default width
   42        * @param nominalWidth nominal width
   43        */
   44       public CharStringConverter(int defaultWidth, int nominalWidth)
   45       {
   46           defaultWidthX = defaultWidth;
   47           nominalWidthX = nominalWidth;
   48       }
   49   
   50       /**
   51        * Converts a sequence of Type1/Type2 commands into a sequence of CharStringCommands.
   52        * @param commandSequence the type1/type2 sequence
   53        * @return the CHarStringCommandSequence
   54        */
   55       public List<Object> convert(List<Object> commandSequence)
   56       {
   57           sequence = new ArrayList<Object>();
   58           pathCount = 0;
   59           handleSequence(commandSequence);
   60           return sequence;
   61       }
   62   
   63       /**
   64        * {@inheritDoc}
   65        */
   66       @Override
   67       public void handleCommand(List<Integer> numbers, CharStringCommand command)
   68       {
   69   
   70           if (CharStringCommand.TYPE1_VOCABULARY.containsKey(command.getKey()))
   71           {
   72               handleType1Command(numbers, command);
   73           } 
   74           else
   75           {
   76               handleType2Command(numbers, command);
   77           }
   78       }
   79   
   80       private void handleType1Command(List<Integer> numbers,
   81               CharStringCommand command)
   82       {
   83           String name = CharStringCommand.TYPE1_VOCABULARY.get(command.getKey());
   84   
   85           if ("hstem".equals(name))
   86           {
   87               numbers = clearStack(numbers, numbers.size() % 2 != 0);
   88               expandStemHints(numbers, true);
   89           } 
   90           else if ("vstem".equals(name))
   91           {
   92               numbers = clearStack(numbers, numbers.size() % 2 != 0);
   93               expandStemHints(numbers, false);
   94           } 
   95           else if ("vmoveto".equals(name))
   96           {
   97               numbers = clearStack(numbers, numbers.size() > 1);
   98               markPath();
   99               addCommand(numbers, command);
  100           } 
  101           else if ("rlineto".equals(name))
  102           {
  103               addCommandList(split(numbers, 2), command);
  104           } 
  105           else if ("hlineto".equals(name))
  106           {
  107               drawAlternatingLine(numbers, true);
  108           } 
  109           else if ("vlineto".equals(name))
  110           {
  111               drawAlternatingLine(numbers, false);
  112           } 
  113           else if ("rrcurveto".equals(name))
  114           {
  115               addCommandList(split(numbers, 6), command);
  116           } 
  117           else if ("endchar".equals(name))
  118           {
  119               numbers = clearStack(numbers, numbers.size() > 0);
  120               closePath();
  121               addCommand(numbers, command);
  122           } 
  123           else if ("rmoveto".equals(name))
  124           {
  125               numbers = clearStack(numbers, numbers.size() > 2);
  126               markPath();
  127               addCommand(numbers, command);
  128           } 
  129           else if ("hmoveto".equals(name))
  130           {
  131               numbers = clearStack(numbers, numbers.size() > 1);
  132               markPath();
  133               addCommand(numbers, command);
  134           } 
  135           else if ("vhcurveto".equals(name))
  136           {
  137               drawAlternatingCurve(numbers, false);
  138           } 
  139           else if ("hvcurveto".equals(name))
  140           {
  141               drawAlternatingCurve(numbers, true);
  142           } 
  143           else
  144           {
  145               addCommand(numbers, command);
  146           }
  147       }
  148   
  149       @SuppressWarnings(value = { "unchecked" })
  150       private void handleType2Command(List<Integer> numbers,
  151               CharStringCommand command)
  152       {
  153           String name = CharStringCommand.TYPE2_VOCABULARY.get(command.getKey());
  154           if ("hflex".equals(name))
  155           {
  156               List<Integer> first = Arrays.asList(numbers.get(0), Integer.valueOf(0), 
  157                       numbers.get(1), numbers.get(2), numbers.get(3), Integer.valueOf(0));
  158               List<Integer> second = Arrays.asList(numbers.get(4), Integer.valueOf(0), 
  159                       numbers.get(5), Integer.valueOf(-numbers.get(2).intValue()), 
  160                       numbers.get(6), Integer.valueOf(0));
  161               addCommandList(Arrays.asList(first, second), new CharStringCommand(8));
  162           } 
  163           else if ("flex".equals(name))
  164           {
  165               List<Integer> first = numbers.subList(0, 6);
  166               List<Integer> second = numbers.subList(6, 12);
  167               addCommandList(Arrays.asList(first, second), new CharStringCommand(8));
  168           }
  169           else if ("hflex1".equals(name))
  170           {
  171               List<Integer> first = Arrays.asList(numbers.get(0), numbers.get(1), 
  172                       numbers.get(2), numbers.get(3), numbers.get(4), Integer.valueOf(0));
  173               List<Integer> second = Arrays.asList(numbers.get(5), Integer.valueOf(0),
  174                       numbers.get(6), numbers.get(7), numbers.get(8), Integer.valueOf(0));
  175               addCommandList(Arrays.asList(first, second), new CharStringCommand(8));
  176           }
  177           else if ("flex1".equals(name))
  178           {
  179               int dx = 0;
  180               int dy = 0;
  181               for(int i = 0; i < 5; i++){
  182                   dx += numbers.get(i * 2).intValue();
  183                   dy += numbers.get(i * 2 + 1).intValue();
  184               }
  185               List<Integer> first = numbers.subList(0, 6);
  186               List<Integer> second = Arrays.asList(numbers.get(6), numbers.get(7), numbers.get(8), 
  187                       numbers.get(9), (Math.abs(dx) > Math.abs(dy) ? numbers.get(10) : Integer.valueOf(-dx)), 
  188                       (Math.abs(dx) > Math.abs(dy) ? Integer.valueOf(-dy) : numbers.get(10)));
  189               addCommandList(Arrays.asList(first, second), new CharStringCommand(8));
  190           }
  191           else if ("hstemhm".equals(name))
  192           {
  193               numbers = clearStack(numbers, numbers.size() % 2 != 0);
  194               expandStemHints(numbers, true);
  195           } 
  196           else if ("hintmask".equals(name) || "cntrmask".equals(name))
  197           {
  198               numbers = clearStack(numbers, numbers.size() % 2 != 0);
  199               if (numbers.size() > 0)
  200               {
  201                   expandStemHints(numbers, false);
  202               }
  203           } 
  204           else if ("vstemhm".equals(name))
  205           {
  206               numbers = clearStack(numbers, numbers.size() % 2 != 0);
  207               expandStemHints(numbers, false);
  208           } 
  209           else if ("rcurveline".equals(name))
  210           {
  211               addCommandList(split(numbers.subList(0, numbers.size() - 2), 6),
  212                       new CharStringCommand(8));
  213               addCommand(numbers.subList(numbers.size() - 2, numbers.size()),
  214                       new CharStringCommand(5));
  215           } 
  216           else if ("rlinecurve".equals(name))
  217           {
  218               addCommandList(split(numbers.subList(0, numbers.size() - 6), 2),
  219                       new CharStringCommand(5));
  220               addCommand(numbers.subList(numbers.size() - 6, numbers.size()),
  221                       new CharStringCommand(8));
  222           } 
  223           else if ("vvcurveto".equals(name))
  224           {
  225               drawCurve(numbers, false);
  226           } 
  227           else if ("hhcurveto".equals(name))
  228           {
  229               drawCurve(numbers, true);
  230           } 
  231           else
  232           {
  233               // System.out.println("Not implemented: numbers=" + numbers +
  234               // " command=" +command+ " (" +name+ ")");
  235           }
  236       }
  237   
  238       private List<Integer> clearStack(List<Integer> numbers, boolean flag)
  239       {
  240   
  241           if (sequence.size() == 0)
  242           {
  243               if (flag)
  244               {
  245                   addCommand(Arrays.asList(Integer.valueOf(0), Integer
  246                           .valueOf(numbers.get(0).intValue() + nominalWidthX)),
  247                           new CharStringCommand(13));
  248   
  249                   numbers = numbers.subList(1, numbers.size());
  250               } 
  251               else
  252               {
  253                   addCommand(Arrays.asList(Integer.valueOf(0), Integer
  254                           .valueOf(defaultWidthX)), new CharStringCommand(13));
  255               }
  256           }
  257   
  258           return numbers;
  259       }
  260   
  261       private void expandStemHints(List<Integer> numbers, boolean horizontal)
  262       {
  263           // TODO
  264       }
  265   
  266       private void markPath()
  267       {
  268           if (pathCount > 0)
  269           {
  270               closePath();
  271           }
  272           pathCount++;
  273       }
  274   
  275       private void closePath()
  276       {
  277           CharStringCommand command = pathCount > 0 ? (CharStringCommand) sequence
  278                   .get(sequence.size() - 1)
  279                   : null;
  280   
  281           CharStringCommand closepathCommand = new CharStringCommand(9);
  282           if (command != null && !closepathCommand.equals(command))
  283           {
  284               addCommand(Collections.<Integer> emptyList(), closepathCommand);
  285           }
  286       }
  287   
  288       private void drawAlternatingLine(List<Integer> numbers, boolean horizontal)
  289       {
  290           while (numbers.size() > 0)
  291           {
  292               addCommand(numbers.subList(0, 1), new CharStringCommand(
  293                       horizontal ? 6 : 7));
  294               numbers = numbers.subList(1, numbers.size());
  295               horizontal = !horizontal;
  296           }
  297       }
  298   
  299       private void drawAlternatingCurve(List<Integer> numbers, boolean horizontal)
  300       {
  301           while (numbers.size() > 0)
  302           {
  303               boolean last = numbers.size() == 5;
  304               if (horizontal)
  305               {
  306                   addCommand(Arrays.asList(numbers.get(0), Integer.valueOf(0),
  307                           numbers.get(1), numbers.get(2), last ? numbers.get(4)
  308                                   : Integer.valueOf(0), numbers.get(3)),
  309                           new CharStringCommand(8));
  310               } 
  311               else
  312               {
  313                   addCommand(Arrays.asList(Integer.valueOf(0), numbers.get(0),
  314                           numbers.get(1), numbers.get(2), numbers.get(3),
  315                           last ? numbers.get(4) : Integer.valueOf(0)),
  316                           new CharStringCommand(8));
  317               }
  318               numbers = numbers.subList(last ? 5 : 4, numbers.size());
  319               horizontal = !horizontal;
  320           }
  321       }
  322   
  323       private void drawCurve(List<Integer> numbers, boolean horizontal)
  324       {
  325           while (numbers.size() > 0)
  326           {
  327               boolean first = numbers.size() % 4 == 1;
  328   
  329               if (horizontal)
  330               {
  331                   addCommand(Arrays.asList(numbers.get(first ? 1 : 0),
  332                           first ? numbers.get(0) : Integer.valueOf(0), numbers
  333                                   .get(first ? 2 : 1),
  334                           numbers.get(first ? 3 : 2), numbers.get(first ? 4 : 3),
  335                           Integer.valueOf(0)), new CharStringCommand(8));
  336               } 
  337               else
  338               {
  339                   addCommand(Arrays.asList(first ? numbers.get(0) : Integer
  340                           .valueOf(0), numbers.get(first ? 1 : 0), numbers
  341                           .get(first ? 2 : 1), numbers.get(first ? 3 : 2),
  342                           Integer.valueOf(0), numbers.get(first ? 4 : 3)),
  343                           new CharStringCommand(8));
  344               }
  345               numbers = numbers.subList(first ? 5 : 4, numbers.size());
  346           }
  347       }
  348   
  349       private void addCommandList(List<List<Integer>> numbers,
  350               CharStringCommand command)
  351       {
  352           for (int i = 0; i < numbers.size(); i++)
  353           {
  354               addCommand(numbers.get(i), command);
  355           }
  356       }
  357   
  358       private void addCommand(List<Integer> numbers, CharStringCommand command)
  359       {
  360           sequence.addAll(numbers);
  361           sequence.add(command);
  362       }
  363   
  364       private static <E> List<List<E>> split(List<E> list, int size)
  365       {
  366           List<List<E>> result = new ArrayList<List<E>>();
  367           for (int i = 0; i < list.size() / size; i++)
  368           {
  369               result.add(list.subList(i * size, (i + 1) * size));
  370           }
  371           return result;
  372       }
  373   }

Save This Page
Home » pdfbox-1.1.0-src » org.apache.fontbox.cff » [javadoc | source]