Updating the changelog in the VERSION file, and version_sync.
[shapes.git] / source / simplepdfo.cc
blobc66e61c133bc6bcdd2726d079be79f6134bddd69
1 /* This file is part of Shapes.
3 * Shapes is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * any later version.
8 * Shapes is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with Shapes. If not, see <http://www.gnu.org/licenses/>.
16 * Copyright 2008 Henrik Tidefelt
19 #include <iomanip>
21 #include "simplepdfo.h"
22 #include "simplepdfi.h"
23 #include "pdfversion.h"
24 #include "shapesexceptions.h"
25 #include "texlabelmanager.h"
26 #include "shapestypes.h"
27 #include "globals.h"
29 using namespace std;
31 using namespace SimplePDF;
33 PDF_Resources::PDF_Resources( )
34 : counter( 0 ),
35 xobject( new PDF_Dictionary ),
36 graphicsStates( new PDF_Dictionary ),
37 colorSpaces( new PDF_Dictionary ),
38 fonts( new PDF_Dictionary ),
39 shadings( new PDF_Dictionary ),
40 procSetsVector( new PDF_Vector )
41 { }
43 PDF_Resources::~PDF_Resources( )
44 { }
46 void
47 PDF_Resources::writeTo( std::ostream & os, SimplePDF::PDF_xref * xref, const RefCountPtr< const PDF_Object > & self ) const
49 RefCountPtr< PDF_Dictionary > dic( new PDF_Dictionary );
50 if( ! xobject->dic.empty( ) )
52 (*dic)[ "XObject" ] = SimplePDF::indirect( xobject, & Shapes::Kernel::theIndirectObjectCount );
54 if( ! graphicsStates->dic.empty( ) )
56 (*dic)[ "ExtGState" ] = SimplePDF::indirect( graphicsStates, & Shapes::Kernel::theIndirectObjectCount );
58 if( ! colorSpaces->dic.empty( ) )
60 (*dic)[ "ColorSpaces" ] = SimplePDF::indirect( colorSpaces, & Shapes::Kernel::theIndirectObjectCount );
62 if( !fonts->dic.empty( ) )
64 (*dic)[ "Font" ] = SimplePDF::indirect( fonts, & Shapes::Kernel::theIndirectObjectCount );
66 if( ! procSetsVector->vec.empty( ) )
68 (*dic)[ "ProcSet" ] = procSetsVector;
70 if( ! shadings->dic.empty( ) )
72 (*dic)[ "Shading" ] = SimplePDF::indirect( shadings, & Shapes::Kernel::theIndirectObjectCount );
74 dic->writeTo( os, xref, dic );
77 const SimplePDF::PDF_Name &
78 PDF_Resources::nameof( const RefCountPtr< PDF_Object > & obj, ReverseMap * reverseMap, RefCountPtr< PDF_Dictionary > * dic, const char * prefix, size_t * counter )
80 ReverseMap::iterator i = reverseMap->find( obj.getPtr( ) );
81 if( i == reverseMap->end( ) )
83 ostringstream reference;
84 reference << prefix << *counter ;
85 ++*counter;
87 (*dic)->dic[ reference.str( ) ] = obj;
88 reverseMap->insert( ReverseMap::value_type( obj.getPtr( ), PDF_Name( reference.str( ) ) ) );
89 i = reverseMap->find( obj.getPtr( ) );
91 return i->second;
94 const PDF_Name &
95 SimplePDF::PDF_Resources::nameofXObject( const RefCountPtr< PDF_Object > & obj )
97 return nameof( obj, & reverse_xobject, & xobject, "x", & counter );
100 const PDF_Name &
101 SimplePDF::PDF_Resources::nameofGraphicsState( const RefCountPtr< PDF_Object > & obj )
103 return nameof( obj, & reverse_graphicsStates, & graphicsStates, "g", & counter );
106 const PDF_Name &
107 SimplePDF::PDF_Resources::nameofColorSpace( const RefCountPtr< PDF_Object > & obj )
109 return nameof( obj, & reverse_colorSpaces, & colorSpaces, "c", & counter );
112 const PDF_Name &
113 SimplePDF::PDF_Resources::nameofFont( const RefCountPtr< PDF_Object > & obj )
115 return nameof( obj, & reverse_fonts, & fonts, "f", & counter );
118 const PDF_Name &
119 SimplePDF::PDF_Resources::nameofShading( const RefCountPtr< PDF_Object > & obj )
121 return nameof( obj, & reverse_shadings, & shadings, "s", & counter );
125 void
126 SimplePDF::PDF_Resources::requireProcedureSet( ProcSet procSet )
128 if( procSets.find( procSet ) == procSets.end( ) )
130 switch( procSet )
132 case PROC_SET_PDF:
133 procSetsVector->vec.push_back( SimplePDF::newName( "PDF" ) );
134 break;
135 case PROC_SET_TEXT:
136 procSetsVector->vec.push_back( SimplePDF::newName( "Text" ) );
137 break;
138 case PROC_SET_IMAGE_GRAY:
139 procSetsVector->vec.push_back( SimplePDF::newName( "ImageB" ) );
140 break;
141 case PROC_SET_IMAGE_COLOR:
142 procSetsVector->vec.push_back( SimplePDF::newName( "ImageC" ) );
143 break;
144 case PROC_SET_IMAGE_INDEXED:
145 procSetsVector->vec.push_back( SimplePDF::newName( "ImageI" ) );
146 break;
147 default:
148 throw "SimplePDF::PDF_Resources: Internal error: An unexpected procedure set was requested.";
150 procSets.insert( procSets.begin( ), procSet );
154 SimplePDF::DocumentInfo::DocumentInfo( )
155 : finalized_( false ),
156 info_( new PDF_Dictionary ),
157 i_info_( NullPtr< PDF_Indirect_out >( ) )
159 (*info_)[ "Producer" ] = newString( "Shapes" );
162 void
163 SimplePDF::DocumentInfo::addExtensionAuthorString( const std::string & str )
165 if( finalized_ )
167 throw "Internal error: DocumentInfo::addExtensionAuthorString: Already finalized.";
169 extensionAuthorStrings.push_back( str );
172 bool
173 SimplePDF::DocumentInfo::addInfo( const char * key, const RefCountPtr< PDF_Object > & datum )
175 if( finalized_ )
177 throw "Internal error: DocumentInfo::addInfo: Already finalized.";
180 if( info_->hasKey( key ) )
182 return false;
184 (*info_)[ key ] = datum;
185 return true;
189 RefCountPtr< SimplePDF::PDF_Indirect_out >
190 SimplePDF::DocumentInfo::getIndirect( size_t * indirectObjectCounter )
192 if( ! finalized_ )
194 if( ! extensionAuthorStrings.empty( ) )
196 std::ostringstream oss;
197 typedef typeof extensionAuthorStrings ListType;
198 ListType::const_iterator i = extensionAuthorStrings.begin( );
199 oss << *i ;
200 ++i;
201 for( ; i != extensionAuthorStrings.end( ); ++i )
203 oss << "; " << *i ;
205 (*info_)[ "ExtensionAuthors" ] = newString( oss.str( ).c_str( ) );
207 finalized_ = true;
208 i_info_ = SimplePDF::indirect( info_, indirectObjectCounter );
210 return i_info_;
215 SimplePDF::PDF_out::PDF_out( const RefCountPtr< SimplePDF::PDF_Indirect_out > & i_root, const RefCountPtr< SimplePDF::PDF_Indirect_out > & i_info, const RefCountPtr< const char > & firstPageLabel )
216 : i_root_( i_root ),
217 i_info_( i_info ),
218 firstPageLabel_( firstPageLabel )
221 SimplePDF::PDF_out::~PDF_out( )
224 RefCountPtr< const char >
225 SimplePDF::PDF_out::getFirstPageLabel( ) const
227 return firstPageLabel_;
230 void
231 SimplePDF::PDF_out::writeFile( std::ostream & os, SimplePDF::PDF_Version & pdfVersion )
233 std::streamoff os_start = static_cast< streamoff >( os.tellp( ) );
234 SimplePDF::PDF_xref my_xref;
238 os << std::fixed ;
239 os << "%" << pdfVersion.maxRequestVersionString( ) << endl
240 << "%"
241 << static_cast< char >( 129 ) << static_cast< char >( 130 )
242 << static_cast< char >( 131 ) << static_cast< char >( 132 )
243 << " Treat as binary" << endl ;
245 my_xref.enqueue( i_root_ );
246 my_xref.enqueue( i_info_ );
247 my_xref.writeRecursive( os );
249 streamoff xref( static_cast< streamoff >( os.tellp( ) ) );
250 my_xref.writeTable( os );
251 os << "trailer" << endl ;
253 RefCountPtr< PDF_Dictionary > trailer( new PDF_Dictionary );
254 trailer->dic[ "Size" ] = newInt( my_xref.size( ) );
255 trailer->dic[ "Root" ] = i_root_;
256 trailer->dic[ "Info" ] = i_info_;
257 trailer->writeTo( os, & my_xref, trailer ); /* This will not affect the xref, since the indirect objects were put in queue before calling writeTable. */
259 os << endl << "startxref" << endl ;
260 os << xref - os_start << endl ;
261 os << "%%EOF" << endl ;
263 catch( const char * ball )
265 std::ostringstream msg;
266 msg << "SimplePDF::PDF_out::writeFile: Caught (char*) ball at top level:" << endl
267 << " " << ball << endl ;
268 throw msg.str( );
270 catch( const string & ball )
272 std::ostringstream msg;
273 msg << "SimplePDF::PDF_out::writeFile: Caught (string) ball at top level:" << endl
274 << " " << ball << endl ;
275 throw msg.str( );
277 catch( ... )
279 throw "SimplePDF::PDF_out::writeFile: Caught (...) ball at top level.";
284 RefCountPtr<PDF_Object>
285 SimplePDF::newName( const char * str )
287 return RefCountPtr<PDF_Name>( new PDF_Name( str ) );
290 RefCountPtr<PDF_Object>
291 SimplePDF::newString( const char * str )
293 return RefCountPtr< PDF_String >( new PDF_LiteralString( str ) );
296 RefCountPtr<PDF_Object>
297 SimplePDF::newInt( PDF_Int::ValueType val )
299 return RefCountPtr<PDF_Int>( new PDF_Int( val ) );
302 RefCountPtr<PDF_Object>
303 SimplePDF::newBoolean( PDF_Boolean::ValueType val )
305 if( val )
307 return theTrue;
309 return theFalse;
312 RefCountPtr<PDF_Object>
313 SimplePDF::newFloat( PDF_Float::ValueType val )
315 return RefCountPtr<PDF_Float>( new PDF_Float( val ) );
319 RefCountPtr<PDF_Object> SimplePDF::theTrue( new PDF_Boolean( true ) );
320 RefCountPtr<PDF_Object> SimplePDF::theFalse( new PDF_Boolean( false ) );
323 SimplePDF::OutlineItem::OutlineItem( const RefCountPtr< PDF_Object > & destination, const RefCountPtr< const char > & title, bool isOpen, bool fontBold, bool fontItalic, const Shapes::Concrete::RGB & color )
324 : destination_( destination ), title_( title ), isOpen_( isOpen ), fontBold_( fontBold ), fontItalic_( fontItalic ), color_( color )
327 SimplePDF::OutlineItem::~OutlineItem( )
330 void
331 SimplePDF::OutlineItem::addKid( const RefCountPtr< OutlineItem > & kid )
333 kids_.push_back( kid );
336 bool
337 SimplePDF::OutlineItem::hasKids( ) const
339 return ! kids_.empty( );
342 RefCountPtr< SimplePDF::PDF_Indirect_out >
343 SimplePDF::OutlineItem::getTopIndirectDictionary( SimplePDF::PDF_Version & pdfVersion ) const
345 RefCountPtr< SimplePDF::PDF_Dictionary > res( new SimplePDF::PDF_Dictionary );
346 RefCountPtr< SimplePDF::PDF_Indirect_out > i_res = SimplePDF::indirect( res, & Shapes::Kernel::theIndirectObjectCount );
347 res->dic[ "Type" ] = SimplePDF::newName( "Outlines" );
349 if( ! kids_.empty( ) )
351 size_t openCount = 0;
353 typedef typeof kids_ ListType;
354 ListType::const_iterator i = kids_.begin( );
356 RefCountPtr< SimplePDF::PDF_Dictionary > newKid( new SimplePDF::PDF_Dictionary );
357 newKid->dic[ "Parent" ] = i_res;
358 RefCountPtr< SimplePDF::PDF_Indirect_out > i_newKid = SimplePDF::indirect( newKid, & Shapes::Kernel::theIndirectObjectCount );
359 openCount += (*i)->fillInDictionary( newKid, i_newKid, pdfVersion );
361 RefCountPtr< SimplePDF::PDF_Indirect_out > i_first = i_newKid;
363 ++i;
364 for( ; i != kids_.end( ); ++i )
366 RefCountPtr< SimplePDF::PDF_Dictionary > lastKid = newKid;
367 newKid = RefCountPtr< SimplePDF::PDF_Dictionary >( new SimplePDF::PDF_Dictionary );
368 newKid->dic[ "Prev" ] = i_newKid;
369 i_newKid = SimplePDF::indirect( newKid, & Shapes::Kernel::theIndirectObjectCount );
370 lastKid->dic[ "Next" ] = i_newKid;
371 newKid->dic[ "Parent" ] = i_res;
372 openCount += (*i)->fillInDictionary( newKid, i_newKid, pdfVersion );
375 res->dic[ "First" ] = i_first;
376 res->dic[ "Last" ] = i_newKid;
378 if( openCount > 0 )
380 res->dic[ "Count" ] = SimplePDF::newInt( openCount );
384 return i_res;
387 size_t
388 SimplePDF::OutlineItem::fillInDictionary( RefCountPtr< SimplePDF::PDF_Dictionary > dstDic, const RefCountPtr< SimplePDF::PDF_Indirect_out > & i_dstDic, SimplePDF::PDF_Version & pdfVersion ) const
390 dstDic->dic[ "Title" ] = SimplePDF::newString( title_.getPtr( ) );
391 dstDic->dic[ "Dest" ] = destination_;
392 const SimplePDF::PDF_Version::Version FANCY_OUTLINE_VERSION = SimplePDF::PDF_Version::PDF_1_3;
393 if( fontBold_ || fontItalic_ )
395 if( pdfVersion.greaterOrEqual( FANCY_OUTLINE_VERSION ) )
397 dstDic->dic[ "F" ] = SimplePDF::newInt( ( fontBold_ ? 2 : 0 ) + ( fontItalic_ ? 1 : 0 ) );
399 else
401 pdfVersion.message( FANCY_OUTLINE_VERSION, "The outline item font flags were ignored." );
404 if( color_.mean( ) > 0 )
406 if( pdfVersion.greaterOrEqual( FANCY_OUTLINE_VERSION ) )
408 dstDic->dic[ "C" ] = color_.componentVector( );
410 else
412 pdfVersion.message( FANCY_OUTLINE_VERSION, "The outline item color was ignored." );
417 size_t openCount = 0;
419 if( ! kids_.empty( ) )
421 typedef typeof kids_ ListType;
422 ListType::const_iterator i = kids_.begin( );
424 RefCountPtr< SimplePDF::PDF_Dictionary > newKid( new SimplePDF::PDF_Dictionary );
425 newKid->dic[ "Parent" ] = i_dstDic;
426 RefCountPtr< SimplePDF::PDF_Indirect_out > i_newKid = SimplePDF::indirect( newKid, & Shapes::Kernel::theIndirectObjectCount );
427 openCount += (*i)->fillInDictionary( newKid, i_newKid, pdfVersion );
429 RefCountPtr< SimplePDF::PDF_Indirect_out > i_first = i_newKid;
431 ++i;
432 for( ; i != kids_.end( ); ++i )
434 RefCountPtr< SimplePDF::PDF_Dictionary > lastKid = newKid;
435 newKid = RefCountPtr< SimplePDF::PDF_Dictionary >( new SimplePDF::PDF_Dictionary );
436 newKid->dic[ "Prev" ] = i_newKid;
437 i_newKid = SimplePDF::indirect( newKid, & Shapes::Kernel::theIndirectObjectCount );
438 lastKid->dic[ "Next" ] = i_newKid;
439 newKid->dic[ "Parent" ] = i_dstDic;
440 openCount += (*i)->fillInDictionary( newKid, i_newKid, pdfVersion );
443 dstDic->dic[ "First" ] = i_first;
444 dstDic->dic[ "Last" ] = i_newKid;
448 if( openCount > 0 )
450 if( isOpen_ )
452 dstDic->dic[ "Count" ] = SimplePDF::newInt( openCount );
454 else
456 dstDic->dic[ "Count" ] = SimplePDF::newInt( -openCount );
460 if( isOpen_ )
462 return openCount + 1;
464 return 1;