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
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
21 #include "simplepdfo.h"
22 #include "simplepdfi.h"
23 #include "pdfversion.h"
24 #include "shapesexceptions.h"
25 #include "texlabelmanager.h"
26 #include "shapestypes.h"
31 using namespace SimplePDF
;
33 PDF_Resources::PDF_Resources( )
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
)
43 PDF_Resources::~PDF_Resources( )
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
;
87 (*dic
)->dic
[ reference
.str( ) ] = obj
;
88 reverseMap
->insert( ReverseMap::value_type( obj
.getPtr( ), PDF_Name( reference
.str( ) ) ) );
89 i
= reverseMap
->find( obj
.getPtr( ) );
95 SimplePDF::PDF_Resources::nameofXObject( const RefCountPtr
< PDF_Object
> & obj
)
97 return nameof( obj
, & reverse_xobject
, & xobject
, "x", & counter
);
101 SimplePDF::PDF_Resources::nameofGraphicsState( const RefCountPtr
< PDF_Object
> & obj
)
103 return nameof( obj
, & reverse_graphicsStates
, & graphicsStates
, "g", & counter
);
107 SimplePDF::PDF_Resources::nameofColorSpace( const RefCountPtr
< PDF_Object
> & obj
)
109 return nameof( obj
, & reverse_colorSpaces
, & colorSpaces
, "c", & counter
);
113 SimplePDF::PDF_Resources::nameofFont( const RefCountPtr
< PDF_Object
> & obj
)
115 return nameof( obj
, & reverse_fonts
, & fonts
, "f", & counter
);
119 SimplePDF::PDF_Resources::nameofShading( const RefCountPtr
< PDF_Object
> & obj
)
121 return nameof( obj
, & reverse_shadings
, & shadings
, "s", & counter
);
126 SimplePDF::PDF_Resources::requireProcedureSet( ProcSet procSet
)
128 if( procSets
.find( procSet
) == procSets
.end( ) )
133 procSetsVector
->vec
.push_back( SimplePDF::newName( "PDF" ) );
136 procSetsVector
->vec
.push_back( SimplePDF::newName( "Text" ) );
138 case PROC_SET_IMAGE_GRAY
:
139 procSetsVector
->vec
.push_back( SimplePDF::newName( "ImageB" ) );
141 case PROC_SET_IMAGE_COLOR
:
142 procSetsVector
->vec
.push_back( SimplePDF::newName( "ImageC" ) );
144 case PROC_SET_IMAGE_INDEXED
:
145 procSetsVector
->vec
.push_back( SimplePDF::newName( "ImageI" ) );
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" );
163 SimplePDF::DocumentInfo::addExtensionAuthorString( const std::string
& str
)
167 throw "Internal error: DocumentInfo::addExtensionAuthorString: Already finalized.";
169 extensionAuthorStrings
.push_back( str
);
173 SimplePDF::DocumentInfo::addInfo( const char * key
, const RefCountPtr
< PDF_Object
> & datum
)
177 throw "Internal error: DocumentInfo::addInfo: Already finalized.";
180 if( info_
->hasKey( key
) )
184 (*info_
)[ key
] = datum
;
189 RefCountPtr
< SimplePDF::PDF_Indirect_out
>
190 SimplePDF::DocumentInfo::getIndirect( size_t * indirectObjectCounter
)
194 if( ! extensionAuthorStrings
.empty( ) )
196 std::ostringstream oss
;
197 typedef typeof extensionAuthorStrings ListType
;
198 ListType::const_iterator i
= extensionAuthorStrings
.begin( );
201 for( ; i
!= extensionAuthorStrings
.end( ); ++i
)
205 (*info_
)[ "ExtensionAuthors" ] = newString( oss
.str( ).c_str( ) );
208 i_info_
= SimplePDF::indirect( info_
, indirectObjectCounter
);
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
)
218 firstPageLabel_( firstPageLabel
)
221 SimplePDF::PDF_out::~PDF_out( )
224 RefCountPtr
< const char >
225 SimplePDF::PDF_out::getFirstPageLabel( ) const
227 return firstPageLabel_
;
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
;
239 os
<< "%" << pdfVersion
.maxRequestVersionString( ) << endl
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
;
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
;
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
)
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( )
331 SimplePDF::OutlineItem::addKid( const RefCountPtr
< OutlineItem
> & kid
)
333 kids_
.push_back( kid
);
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
;
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
;
380 res
->dic
[ "Count" ] = SimplePDF::newInt( openCount
);
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 ) );
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( );
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
;
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
;
452 dstDic
->dic
[ "Count" ] = SimplePDF::newInt( openCount
);
456 dstDic
->dic
[ "Count" ] = SimplePDF::newInt( -openCount
);
462 return openCount
+ 1;