1 /*
2 Source File : CIDFontWriter.cpp
3
4
5 Copyright 2011 Gal Kahana PDFWriter
6
7 Licensed under the Apache License, Version 2.0 (the "License");
8 you may not use this file except in compliance with the License.
9 You may obtain a copy of the License at
10
11 http://www.apache.org/licenses/LICENSE-2.0
12
13 Unless required by applicable law or agreed to in writing, software
14 distributed under the License is distributed on an "AS IS" BASIS,
15 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 See the License for the specific language governing permissions and
17 limitations under the License.
18
19
20 */
21 #include "CIDFontWriter.h"
22 #include "DictionaryContext.h"
23 #include "ObjectsContext.h"
24 #include "FreeTypeFaceWrapper.h"
25 #include "Trace.h"
26 #include "PDFStream.h"
27 #include "IByteWriter.h"
28 #include "SafeBufferMacrosDefs.h"
29 #include "CFFDescendentFontWriter.h"
30 #include "IDescendentFontWriter.h"
31 #include "UnicodeString.h"
32
33 #include <ft2build.h>
34 #include FT_FREETYPE_H
35
36 #include <algorithm>
37
38
39 using namespace PDFHummus;
40
CIDFontWriter(void)41 CIDFontWriter::CIDFontWriter(void)
42 {
43 }
44
~CIDFontWriter(void)45 CIDFontWriter::~CIDFontWriter(void)
46 {
47 }
48
49 static const std::string scType = "Type";
50 static const std::string scFont = "Font";
51 static const std::string scSubtype = "Subtype";
52 static const std::string scType0 = "Type0";
53 static const std::string scBaseFont = "BaseFont";
54 static const std::string scPlus = "+";
55 static const std::string scDescendantFonts = "DescendantFonts";
56 static const std::string scToUnicode = "ToUnicode";
57
WriteFont(FreeTypeFaceWrapper & inFontInfo,WrittenFontRepresentation * inFontOccurrence,ObjectsContext * inObjectsContext,IDescendentFontWriter * inDescendentFontWriter)58 EStatusCode CIDFontWriter::WriteFont(FreeTypeFaceWrapper& inFontInfo,
59 WrittenFontRepresentation* inFontOccurrence,
60 ObjectsContext* inObjectsContext,
61 IDescendentFontWriter* inDescendentFontWriter)
62 {
63
64 EStatusCode status = PDFHummus::eSuccess;
65 inObjectsContext->StartNewIndirectObject(inFontOccurrence->mWrittenObjectID);
66
67 mFontInfo = &inFontInfo;
68 mFontOccurrence = inFontOccurrence;
69 mObjectsContext = inObjectsContext;
70
71 do
72 {
73 DictionaryContext* fontContext = inObjectsContext->StartDictionary();
74
75 // Type
76 fontContext->WriteKey(scType);
77 fontContext->WriteNameValue(scFont);
78
79 // SubType
80 fontContext->WriteKey(scSubtype);
81 fontContext->WriteNameValue(scType0);
82
83 // BaseFont
84 fontContext->WriteKey(scBaseFont);
85 const char* postscriptFontName = FT_Get_Postscript_Name(inFontInfo);
86 if(!postscriptFontName)
87 {
88 TRACE_LOG("CIDFontWriter::WriteFont, unexpected failure. no postscript font name for font");
89 status = PDFHummus::eFailure;
90 break;
91 }
92 std::string subsetFontName = inObjectsContext->GenerateSubsetFontPrefix() + scPlus + postscriptFontName;
93 fontContext->WriteNameValue(subsetFontName);
94
95 WriteEncoding(fontContext);
96
97 // DescendantFonts
98 ObjectIDType descendantFontID = mObjectsContext->GetInDirectObjectsRegistry().AllocateNewObjectID();
99
100 fontContext->WriteKey(scDescendantFonts);
101 mObjectsContext->StartArray();
102 mObjectsContext->WriteNewIndirectObjectReference(descendantFontID);
103 mObjectsContext->EndArray(eTokenSeparatorEndLine);
104
105 CalculateCharacterEncodingArray(); // put the charachter in the order of encoding, for the ToUnicode map
106
107 // ToUnicode
108 fontContext->WriteKey(scToUnicode);
109 ObjectIDType toUnicodeMapObjectID = mObjectsContext->GetInDirectObjectsRegistry().AllocateNewObjectID();
110 fontContext->WriteNewObjectReferenceValue(toUnicodeMapObjectID);
111
112 status = inObjectsContext->EndDictionary(fontContext);
113 if(status != PDFHummus::eSuccess)
114 {
115 TRACE_LOG("CIDFontWriter::WriteFont, unexpected failure. Failed to end dictionary in font write.");
116 break;
117 }
118 inObjectsContext->EndIndirectObject();
119 WriteToUnicodeMap(toUnicodeMapObjectID);
120
121 // Write the descendant font
122 status = inDescendentFontWriter->WriteFont(descendantFontID,subsetFontName,*mFontInfo,mCharactersVector,mObjectsContext);
123
124 } while(false);
125
126 return status;
127 }
128
129 static const std::string scEncoding = "Encoding";
130 static const std::string scIdentityH = "Identity-H";
WriteEncoding(DictionaryContext * inFontContext)131 void CIDFontWriter::WriteEncoding(DictionaryContext* inFontContext)
132 {
133 // Encoding
134 inFontContext->WriteKey(scEncoding);
135 inFontContext->WriteNameValue(scIdentityH);
136 }
137
sUShortSort(const UIntAndGlyphEncodingInfo & inLeft,const UIntAndGlyphEncodingInfo & inRight)138 static bool sUShortSort(const UIntAndGlyphEncodingInfo& inLeft, const UIntAndGlyphEncodingInfo& inRight)
139 {
140 return inLeft.second.mEncodedCharacter < inRight.second.mEncodedCharacter;
141 }
142
CalculateCharacterEncodingArray()143 void CIDFontWriter::CalculateCharacterEncodingArray()
144 {
145 // first we need to sort the fonts charachters by character code
146 UIntToGlyphEncodingInfoMap::iterator it = mFontOccurrence->mGlyphIDToEncodedChar.begin();
147
148 for(; it != mFontOccurrence->mGlyphIDToEncodedChar.end();++it)
149 mCharactersVector.push_back(UIntAndGlyphEncodingInfo(it->first,it->second));
150
151 std::sort(mCharactersVector.begin(),mCharactersVector.end(),sUShortSort);
152 }
153
154
155 static const char* scCmapHeader =
156 "/CIDInit /ProcSet findresource begin\n\
157 12 dict begin\n\
158 begincmap\n\
159 /CIDSystemInfo\n\
160 << /Registry (Adobe)\n\
161 /Ordering (UCS) /Supplement 0 >> def\n\
162 /CMapName /Adobe-Identity-UCS def\n\
163 /CMapType 2 def\n\
164 1 begincodespacerange\n";
165 static const char* scFourByteRangeStart = "0000";
166 static const char* scFourByteRangeEnd = "FFFF";
167 static const char* scEndCodeSpaceRange = "endcodespacerange\n";
168 static const std::string scBeginBFChar = "beginbfchar";
169 static const std::string scEndBFChar = "endbfchar";
170 static const char* scCmapFooter = "endcmap CMapName currentdict /CMap defineresource pop end end\n";
171
WriteToUnicodeMap(ObjectIDType inToUnicodeMap)172 void CIDFontWriter::WriteToUnicodeMap(ObjectIDType inToUnicodeMap)
173 {
174 mObjectsContext->StartNewIndirectObject(inToUnicodeMap);
175 PDFStream* pdfStream = mObjectsContext->StartPDFStream();
176 IByteWriter* cmapWriteContext = pdfStream->GetWriteStream();
177 PrimitiveObjectsWriter primitiveWriter(cmapWriteContext);
178 unsigned long i = 1;
179 UIntAndGlyphEncodingInfoVector::iterator it = mCharactersVector.begin() + 1; // skip 0 glyph
180 unsigned long vectorSize = (unsigned long)mCharactersVector.size() - 1; // cause 0 is not there
181
182 cmapWriteContext->Write((const Byte*)scCmapHeader,strlen(scCmapHeader));
183 primitiveWriter.WriteHexString(scFourByteRangeStart);
184 primitiveWriter.WriteHexString(scFourByteRangeEnd,eTokenSeparatorEndLine);
185 cmapWriteContext->Write((const Byte*)scEndCodeSpaceRange,strlen(scEndCodeSpaceRange));
186
187 if(vectorSize < 100)
188 primitiveWriter.WriteInteger(vectorSize);
189 else
190 primitiveWriter.WriteInteger(100);
191 primitiveWriter.WriteKeyword(scBeginBFChar);
192
193 WriteGlyphEntry(cmapWriteContext,it->second.mEncodedCharacter,it->second.mUnicodeCharacters);
194 ++it;
195 for(; it != mCharactersVector.end(); ++it,++i)
196 {
197 if(i % 100 == 0)
198 {
199 primitiveWriter.WriteKeyword(scEndBFChar);
200 if(vectorSize - i < 100)
201 primitiveWriter.WriteInteger(vectorSize - i);
202 else
203 primitiveWriter.WriteInteger(100);
204 primitiveWriter.WriteKeyword(scBeginBFChar);
205 }
206 WriteGlyphEntry(cmapWriteContext,it->second.mEncodedCharacter,it->second.mUnicodeCharacters);
207 }
208 primitiveWriter.WriteKeyword(scEndBFChar);
209 cmapWriteContext->Write((const Byte*)scCmapFooter,strlen(scCmapFooter));
210 mObjectsContext->EndPDFStream(pdfStream);
211 delete pdfStream;
212 }
213
214 static const Byte scEntryEnding[2] = {'>','\n'};
215 static const Byte scAllZeros[4] = {'0','0','0','0'};
WriteGlyphEntry(IByteWriter * inWriter,unsigned short inEncodedCharacter,const ULongVector & inUnicodeValues)216 void CIDFontWriter::WriteGlyphEntry(IByteWriter* inWriter,unsigned short inEncodedCharacter,const ULongVector& inUnicodeValues)
217 {
218 UnicodeString unicode;
219 char formattingBuffer[17];
220 ULongVector::const_iterator it = inUnicodeValues.begin();
221
222 SAFE_SPRINTF_1(formattingBuffer,17,"<%04x> <",inEncodedCharacter);
223 inWriter->Write((const Byte*)formattingBuffer,8);
224
225 if(inUnicodeValues.size() == 0)
226 {
227 inWriter->Write(scAllZeros,4);
228 }
229 else
230 {
231 for(; it != inUnicodeValues.end(); ++it)
232 {
233 unicode.GetUnicodeList().push_back(*it);
234 EStatusCodeAndUShortList utf16Result = unicode.ToUTF16UShort();
235 unicode.GetUnicodeList().clear();
236
237 if(utf16Result.second.size() == 2)
238 {
239 SAFE_SPRINTF_2(formattingBuffer,17,"%04x%04x",
240 utf16Result.second.front(),
241 utf16Result.second.back());
242 inWriter->Write((const Byte*)formattingBuffer,8);
243 }
244 else // 1
245 {
246 SAFE_SPRINTF_1(formattingBuffer,17,"%04x",utf16Result.second.front());
247 inWriter->Write((const Byte*)formattingBuffer,4);
248 }
249 }
250 }
251 inWriter->Write(scEntryEnding,2);
252 }
253