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
19 #include "pdfimport.h"
21 #include "shapesexceptions.h"
22 #include "pathtypes.h"
23 #include "drawabletypes.h"
24 #include "texlabelmanager.h"
26 using namespace Shapes
;
27 using namespace SimplePDF
;
29 Kernel::Import::Import( )
32 RefCountPtr
< const std::vector
< RefCountPtr
< const Shapes::Lang::XObject
> > >
33 Kernel::Import::addPagesAsXObjects( RefCountPtr
< PDF_in
> pdfi
)
35 using namespace Shapes
;
37 importSources_
.push_back( pdfi
); // Keep the source alive so that it can be used when finally producing output
38 IndirectRemapType indirectRemap
;
39 std::vector
< RefCountPtr
< const Lang::XObject
> > * res
= new std::vector
< RefCountPtr
< const Lang::XObject
> >;
40 for( size_t pageNumber( 0 ); pageNumber
< pdfi
->getPageCount( ); ++pageNumber
)
42 RefCountPtr
< PDF_Dictionary
> pageDic( pdfi
->getPage( pageNumber
) );
43 RefCountPtr
< PDF_Vector
> cropBox
= down_cast_follow
< PDF_Vector
>( pageDic
->getInheritable( "CropBox" ) );
44 if( cropBox
== NullPtr
< PDF_Vector
>( ) )
46 cropBox
= down_cast_follow
< PDF_Vector
>( pageDic
->getInheritable( "MediaBox" ) );
48 if( cropBox
== NullPtr
< PDF_Vector
>( ) )
50 throw Exceptions::InternalError( strrefdup( "Failed to find crop box of imported page. (Searched to the page tree root.)" ) );
52 RefCountPtr
< PDF_Stream_in
> original( pdfi
->follow
< PDF_Stream_in
>( (*pageDic
)[ "Contents" ] ) );
54 // RefCountPtr< PDF_Dictionary > xobjectDic( pdfi->follow< PDF_Dictionary >( (*pdfi->follow< PDF_Dictionary >( (*pageDic)[ "Resources" ] ))[ "XObject" ] ) );
55 // if( xobjectDic->dic.size( ) != 1 )
57 // throw Exceptions::InternalError( strrefdup( "Expected exactly 1 XObject on a TeX label input page" ) );
59 // RefCountPtr< PDF_Stream_in > original( pdfi->follow< PDF_Stream_in >( xobjectDic->dic.begin( )->second ) );
60 RefCountPtr
< PDF_Stream_in
> newObj( new PDF_Stream_in( original
->is
, original
->dataStart
) );
61 (*newObj
)[ "Subtype" ] = newName( "Form" );
62 (*newObj
)[ "FormType" ] = newInt( 1 );
63 (*newObj
)[ "BBox" ] = cropBox
; // ->rectangleIntersection( down_cast_follow< PDF_Vector >( (*original)[ "BBox" ] ) );
64 (*newObj
)[ "Matrix" ] = RefCountPtr
< PDF_Object
>( new PDF_Vector( 1, 0, 0, 1, 0, 0 ) );
65 (*newObj
)[ "Filter" ] = (*original
)[ "Filter" ];
66 (*newObj
)[ "Length" ] = RefCountPtr
< PDF_Object
>( new PDF_Int( pdfi
->follow
< PDF_Int
>( (*original
)[ "Length" ] )->value( ) ) );
67 (*newObj
)[ "Resources" ] = deepCopy( (*pageDic
)[ "Resources" ], & Kernel::theIndirectObjectCount
, & indirectRemap
);
69 Concrete::Length xmin
;
70 Concrete::Length xmax
;
71 Concrete::Length ymin
;
72 Concrete::Length ymax
;
75 RefCountPtr
< PDF_Vector
> bboxTyped
= pdfi
->follow
< PDF_Vector
>( (*newObj
)[ "BBox" ] );
76 if( bboxTyped
->vec
.size( ) != 4 )
78 throw Exceptions::InternalError( strrefdup( "The bbox of the imported page was not of size 4." ) );
80 xmin
= Concrete::Length( pdfi
->follow
< PDF_Float
>( bboxTyped
->vec
[ 0 ] )->value( ) );
81 xmax
= Concrete::Length( pdfi
->follow
< PDF_Float
>( bboxTyped
->vec
[ 2 ] )->value( ) );
82 ymin
= Concrete::Length( pdfi
->follow
< PDF_Float
>( bboxTyped
->vec
[ 1 ] )->value( ) );
83 ymax
= Concrete::Length( pdfi
->follow
< PDF_Float
>( bboxTyped
->vec
[ 3 ] )->value( ) );
85 catch( Exceptions::Exception
& ball
)
89 catch( const char * ball
)
91 std::ostringstream oss
;
92 oss
<< "An error occurred while evaluating the bbox of the imported page: " << ball
;
93 throw Exceptions::InternalError( strrefdup( oss
.str( ).c_str( ) ) );
97 throw Exceptions::InternalError( strrefdup( "An error occurred while evaluating the bbox of the imported page." ) );
99 Lang::ElementaryPath2D
* bboxpath
= new Lang::ElementaryPath2D
;
100 bboxpath
->push_back( new Concrete::PathPoint2D( xmin
, ymin
) );
101 bboxpath
->push_back( new Concrete::PathPoint2D( xmin
, ymax
) );
102 bboxpath
->push_back( new Concrete::PathPoint2D( xmax
, ymax
) );
103 bboxpath
->push_back( new Concrete::PathPoint2D( xmax
, ymin
) );
106 RefCountPtr
< PDF_Object
> indirection
= SimplePDF::indirect( newObj
, & Kernel::theIndirectObjectCount
);
107 RefCountPtr
< const Lang::ElementaryPath2D
> bbox
= RefCountPtr
< const Lang::ElementaryPath2D
>( bboxpath
);
108 res
->push_back( RefCountPtr
< Lang::XObject
>( new Lang::XObject( indirection
, bbox
, bbox
, Kernel::THE_DEFAULT_STATE
) ) );
110 return RefCountPtr
< const std::vector
< RefCountPtr
< const Lang::XObject
> > >( res
);
114 Kernel::Import::importBtexEtexThings( RefCountPtr
< PDF_in
> pdfi
, Shapes::Kernel::TeXLabelManager::MapType
* dstMap
, const std::string
& setupCodeHash
)
116 using namespace Shapes
;
118 importSources_
.push_back( pdfi
); // Keep the source alive so that it can be used when finally producing output
119 IndirectRemapType indirectRemap
;
121 PDF_in::PageIterator theEnd
= pdfi
->endPages( );
122 for( PDF_in::PageIterator i
= pdfi
->beginPages( ); i
!= theEnd
; ++i
)
124 RefCountPtr
< PDF_Dictionary
> xobjectDic( pdfi
->follow
< PDF_Dictionary
>( (*pdfi
->follow
< PDF_Dictionary
>( (**i
)[ "Resources" ] ))[ "XObject" ] ) );
125 if( xobjectDic
->dic
.size( ) != 1 )
127 throw Exceptions::InternalError( strrefdup( "Expected exactly 1 XObject on a TeX label input page" ) );
129 RefCountPtr
< PDF_Stream_in
> original( pdfi
->follow
< PDF_Stream_in
>( xobjectDic
->dic
.begin( )->second
) );
133 RefCountPtr
< PDF_Stream_in
> texStream( pdfi
->follow
< PDF_Stream_in
>( (*original
)[ "TeXsrc" ] ) );
134 std::ostringstream tmp
;
135 texStream
->writeDataDefilteredTo( tmp
);
138 if( i
== pdfi
->beginPages( ) )
140 /* This page only contains information about the TeX context */
141 if( texStr
!= setupCodeHash
)
143 throw Exceptions::TeXSetupHasChanged( );
147 Concrete::Length
height( pdfNameToDouble( (*original
)[ "TeXht" ] ) );
148 Concrete::Length
depth( pdfNameToDouble( (*original
)[ "TeXdp" ] ) );
149 Concrete::Length
width( pdfNameToDouble( (*original
)[ "TeXwd" ] ) );
151 const Concrete::Length bboxAddY
= 0.08 * ( depth
+ height
);
152 const Concrete::Length xmin
= Concrete::ZERO_LENGTH
;
153 const Concrete::Length xmax
= width
;
154 const Concrete::Length ymin
= -depth
- bboxAddY
;
155 const Concrete::Length ymax
= height
+ bboxAddY
;
157 RefCountPtr
< PDF_Stream_in
> newObj( new PDF_Stream_in( original
->is
, original
->dataStart
) );
158 (*newObj
)[ "Subtype" ] = newName( "Form" );
159 (*newObj
)[ "FormType" ] = newInt( 1 );
160 (*newObj
)[ "BBox" ] = RefCountPtr
< PDF_Object
>( new PDF_Vector( 0.0,
161 - bboxAddY
.offtype
< 1, 0 >( ),
162 ( xmax
- xmin
).offtype
< 1, 0 >( ),
163 ( ymax
- ymin
).offtype
< 1, 0 >( ) ) );
164 // (*newObj)[ "BBox" ] = (*original)[ "BBox" ]; /* This box is too small! */
165 (*newObj
)[ "Matrix" ] = RefCountPtr
< PDF_Object
>( new PDF_Vector( 1, 0, 0, 1, 0, - depth
.offtype
< 1, 0 >( ) ) );
166 (*newObj
)[ "Filter" ] = (*original
)[ "Filter" ];
167 (*newObj
)[ "Length" ] = RefCountPtr
< PDF_Object
>( new PDF_Int( pdfi
->follow
< PDF_Int
>( (*original
)[ "Length" ] )->value( ) ) );
168 (*newObj
)[ "Resources" ] = deepCopy( (*original
)[ "Resources" ], & Kernel::theIndirectObjectCount
, & indirectRemap
);
170 Lang::ElementaryPath2D
* bboxpath
= new Lang::ElementaryPath2D
;
171 bboxpath
->push_back( new Concrete::PathPoint2D( xmin
, ymin
) );
172 bboxpath
->push_back( new Concrete::PathPoint2D( xmin
, ymax
) );
173 bboxpath
->push_back( new Concrete::PathPoint2D( xmax
, ymax
) );
174 bboxpath
->push_back( new Concrete::PathPoint2D( xmax
, ymin
) );
177 if( dstMap
->find( texStr
) != dstMap
->end( ) )
179 throw Exceptions::InternalError( strrefdup( "Multiply generated TeX label: " + texStr
) );
182 RefCountPtr
< PDF_Object
> indirection
= SimplePDF::indirect( newObj
, & Kernel::theIndirectObjectCount
);
183 dstMap
->insert( Shapes::Kernel::TeXLabelManager::MapType::value_type( texStr
, RefCountPtr
< const Lang::XObject
>( new Lang::XObject( indirection
, RefCountPtr
< const Lang::ElementaryPath2D
>( bboxpath
) ) ) ) );
188 Kernel::Import::free( )
190 while( ! importSources_
.empty( ) )
192 importSources_
.pop_back( );
197 Kernel::Import::pdfNameToDouble( RefCountPtr
< PDF_Object
> nameObject
)
199 RefCountPtr
< PDF_Name
> name( nameObject
.down_cast
< PDF_Name
>( ) );
200 if( name
== NullPtr
< PDF_Name
>( ) )
202 throw( "PDF_out::pdfNameToDouble: The object was not a name" );
204 const double pointToBigPointFactor
= 72 / 72.27;
206 double res
= pointToBigPointFactor
* strtod( name
->name( ).c_str( ), & end
);
207 if( strcmp( end
, "pt" ) != 0 )
209 throw( "PDF_out::pdfNameToDouble: Expected \"pt\" to follow length number" );