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 
18 /* $Id$ */
19 
20 package org.apache.fop.render.pcl.fonts;
21 
22 import java.io.ByteArrayOutputStream;
23 import java.io.IOException;
24 import java.util.ArrayList;
25 import java.util.List;
26 
27 public class PCLCharacterDefinition {
28     private int charCode;
29     private int charDefinitionSize;
30     private byte[] glyfData;
31     private boolean hasContinuation;
32     private PCLCharacterFormat charFormat;
33     private PCLCharacterClass charClass;
34     private List<PCLCharacterDefinition> composites;
35     private boolean isComposite;
36 
PCLCharacterDefinition(int charCode, PCLCharacterFormat charFormat, PCLCharacterClass charClass, byte[] glyfData, boolean isComposite)37     public PCLCharacterDefinition(int charCode, PCLCharacterFormat charFormat,
38             PCLCharacterClass charClass, byte[] glyfData, boolean isComposite) {
39         this.charCode = charCode;
40         this.charFormat = charFormat;
41         this.charClass = charClass;
42         this.glyfData = glyfData;
43         this.isComposite = isComposite;
44         // Glyph Data + (Descriptor Size) + (Character Data Size) + (Glyph ID) must
45         // be less than 32767 otherwise it will result in a continuation structure.
46         charDefinitionSize = glyfData.length + 4 + 2 + 2;
47         hasContinuation = charDefinitionSize > 32767;
48         composites = new ArrayList<PCLCharacterDefinition>();
49     }
50 
getCharacterCommand()51     public byte[] getCharacterCommand() throws IOException {
52         return PCLByteWriterUtil.writeCommand(String.format("*c%dE", (isComposite) ? 65535 : charCode));
53     }
54 
getCharacterDefinitionCommand()55     public byte[] getCharacterDefinitionCommand() throws IOException {
56         return PCLByteWriterUtil.writeCommand(String.format("(s%dW", 10 + glyfData.length));
57     }
58 
getData()59     public byte[] getData() throws IOException {
60         ByteArrayOutputStream baos = new ByteArrayOutputStream();
61 
62         // Write Character Descriptor
63         if (!hasContinuation) {
64             writeCharacterDescriptorHeader(0, baos);
65             baos.write(glyfData);
66         } else {
67             int continuations = glyfData.length / 32767;
68             for (int i = 0; i < continuations; i++) {
69                 writeCharacterDescriptorHeader(i == 0 ? 0 : 1, baos);
70                 int continuationStart = i * 32767;
71                 int continuationLength = continuationStart - glyfData.length < 32767
72                         ? continuationStart - glyfData.length : 32767;
73                 baos.write(glyfData, continuationStart, continuationLength);
74             }
75         }
76         baos.write(0); // Reserved
77         byte[] charBytes = baos.toByteArray();
78         long sum = 0;
79         for (int i = 4; i < charBytes.length; i++) {
80             sum += charBytes[i];
81         }
82         int remainder = (int) (sum % 256);
83         baos.write(256 - remainder); // Checksum
84 
85         return baos.toByteArray();
86     }
87 
88     private void writeCharacterDescriptorHeader(int continuation, ByteArrayOutputStream baos) throws IOException {
89         baos.write(PCLByteWriterUtil.unsignedByte(charFormat.getValue()));
90         baos.write(continuation);
91         baos.write(PCLByteWriterUtil.unsignedByte(2)); // Descriptor size (from this byte to character data)
92         baos.write(PCLByteWriterUtil.unsignedByte(charClass.getValue()));
93         baos.write(PCLByteWriterUtil.unsignedInt(glyfData.length + 4));
94         baos.write(PCLByteWriterUtil.unsignedInt(charCode));
95     }
96 
97     public void addCompositeGlyph(PCLCharacterDefinition composite) {
98         composites.add(composite);
99     }
100 
101     public List<PCLCharacterDefinition> getCompositeGlyphs() {
102         return composites;
103     }
104 
105     /**
106      * Character Format used in PCL Character Descriptor See Table 11-50 from PCL 5 Specification
107      */
108     public enum PCLCharacterFormat {
109         LaserJet_Raster(4),
110         Intellifont(10),
111         TrueType(15);
112 
113         private int value;
114 
115         PCLCharacterFormat(int value) {
116             this.value = value;
117         }
118 
119         public int getValue() {
120             return value;
121         }
122     }
123 
124     /**
125      * Character Class used in PCL Character Descriptor See Table 11-51 from PCL 5 Specification
126      */
127     public enum PCLCharacterClass {
128         Bitmap(1),
129         CompressedBitmap(2),
130         Contour_Intellifont(3),
131         Compound_Contour_Intellifont(4),
132         TrueType(15);
133 
134         private int value;
135 
136         PCLCharacterClass(int value) {
137             this.value = value;
138         }
139 
140         public int getValue() {
141             return value;
142         }
143     }
144 }
145