1 /***************************************************************************
2 * Copyright (C) 2007 by Dominik Seichter *
3 * domseichter@web.de *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU Library General Public License as *
7 * published by the Free Software Foundation; either version 2 of the *
8 * License, or (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU Library General Public *
16 * License along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
20
21 #include "PdfTilingPattern.h"
22
23 #include "base/PdfDefinesPrivate.h"
24
25 #include "base/PdfArray.h"
26 #include "base/PdfColor.h"
27 #include "base/PdfDictionary.h"
28 #include "base/PdfLocale.h"
29 #include "base/PdfRect.h"
30 #include "base/PdfStream.h"
31 #include "base/PdfWriter.h"
32
33 #include "PdfFunction.h"
34 #include "PdfImage.h"
35
36 #include <iostream>
37 #include <iomanip>
38 #include <sstream>
39
40 namespace PoDoFo {
41
PdfTilingPattern(EPdfTilingPatternType eTilingType,double strokeR,double strokeG,double strokeB,bool doFill,double fillR,double fillG,double fillB,double offsetX,double offsetY,PdfImage * pImage,PdfVecObjects * pParent)42 PdfTilingPattern::PdfTilingPattern( EPdfTilingPatternType eTilingType,
43 double strokeR, double strokeG, double strokeB,
44 bool doFill, double fillR, double fillG, double fillB,
45 double offsetX, double offsetY,
46 PdfImage *pImage,
47 PdfVecObjects* pParent)
48 : PdfElement( "Pattern", pParent )
49 {
50 std::ostringstream out;
51 // We probably aren't doing anything locale sensitive here, but it's
52 // best to be sure.
53 PdfLocaleImbue(out);
54
55 // Implementation note: the identifier is always
56 // Prefix+ObjectNo. Prefix is /Ft for fonts.
57 out << "Ptrn" << this->GetObject()->Reference().ObjectNumber();
58 m_Identifier = PdfName( out.str().c_str() );
59
60 this->Init( eTilingType, strokeR, strokeG, strokeB,
61 doFill, fillR, fillG, fillB, offsetX, offsetY, pImage);
62 }
63
PdfTilingPattern(EPdfTilingPatternType eTilingType,double strokeR,double strokeG,double strokeB,bool doFill,double fillR,double fillG,double fillB,double offsetX,double offsetY,PdfImage * pImage,PdfDocument * pParent)64 PdfTilingPattern::PdfTilingPattern( EPdfTilingPatternType eTilingType,
65 double strokeR, double strokeG, double strokeB,
66 bool doFill, double fillR, double fillG, double fillB,
67 double offsetX, double offsetY,
68 PdfImage *pImage,
69 PdfDocument* pParent)
70 : PdfElement( "Pattern", pParent )
71 {
72 std::ostringstream out;
73 // We probably aren't doing anything locale sensitive here, but it's
74 // best to be sure.
75 PdfLocaleImbue(out);
76
77 // Implementation note: the identifier is always
78 // Prefix+ObjectNo. Prefix is /Ft for fonts.
79 out << "Ptrn" << this->GetObject()->Reference().ObjectNumber();
80
81 m_Identifier = PdfName( out.str().c_str() );
82
83 this->Init( eTilingType, strokeR, strokeG, strokeB,
84 doFill, fillR, fillG, fillB, offsetX, offsetY, pImage);
85 }
86
~PdfTilingPattern()87 PdfTilingPattern::~PdfTilingPattern()
88 {
89 }
90
AddToResources(const PdfName & rIdentifier,const PdfReference & rRef,const PdfName & rName)91 void PdfTilingPattern::AddToResources(const PdfName &rIdentifier, const PdfReference &rRef, const PdfName &rName)
92 {
93 PdfObject* pResource = GetObject()->GetDictionary().GetKey( "Resources" );
94
95 if( !pResource ) {
96 PODOFO_RAISE_ERROR( ePdfError_InvalidHandle );
97 }
98
99 if( !pResource->GetDictionary().HasKey( rName ) ) {
100 pResource->GetDictionary().AddKey( rName, PdfDictionary() );
101 }
102 if (ePdfDataType_Reference == pResource->GetDictionary().GetKey( rName )->GetDataType()) {
103 PdfObject *directObject = pResource->GetOwner()->GetObject(pResource->GetDictionary().GetKey( rName )->GetReference());
104
105 if (0 == directObject) {
106 PODOFO_RAISE_ERROR( ePdfError_NoObject );
107 }
108
109 if( !directObject->GetDictionary().HasKey( rIdentifier ) )
110 directObject->GetDictionary().AddKey( rIdentifier, rRef );
111 }else {
112 if( !pResource->GetDictionary().GetKey( rName )->GetDictionary().HasKey( rIdentifier ) )
113 pResource->GetDictionary().GetKey( rName )->GetDictionary().AddKey( rIdentifier, rRef );
114 }
115 }
116
Init(EPdfTilingPatternType eTilingType,double strokeR,double strokeG,double strokeB,bool doFill,double fillR,double fillG,double fillB,double offsetX,double offsetY,PdfImage * pImage)117 void PdfTilingPattern::Init( EPdfTilingPatternType eTilingType,
118 double strokeR, double strokeG, double strokeB,
119 bool doFill, double fillR, double fillG, double fillB,
120 double offsetX, double offsetY,
121 PdfImage *pImage)
122 {
123 if (eTilingType == ePdfTilingPatternType_Image && pImage == NULL) {
124 PODOFO_RAISE_ERROR( ePdfError_InvalidHandle );
125 }
126
127 if (eTilingType != ePdfTilingPatternType_Image && pImage != NULL) {
128 PODOFO_RAISE_ERROR( ePdfError_InvalidHandle );
129 }
130
131 PdfRect rRect;
132 rRect.SetLeft(0);
133 rRect.SetBottom(0);
134
135 if (pImage) {
136 rRect.SetWidth(pImage->GetWidth());
137 rRect.SetHeight(-pImage->GetHeight());
138 } else {
139 rRect.SetWidth(8);
140 rRect.SetHeight(8);
141 }
142
143 PdfVariant var;
144 rRect.ToVariant( var );
145
146 this->GetObject()->GetDictionary().AddKey( PdfName("PatternType"), static_cast<pdf_int64>(1L) ); // Tiling pattern
147 this->GetObject()->GetDictionary().AddKey( PdfName("PaintType"), static_cast<pdf_int64>(1L) ); // Colored
148 this->GetObject()->GetDictionary().AddKey( PdfName("TilingType"), static_cast<pdf_int64>(1L) ); // Constant spacing
149 this->GetObject()->GetDictionary().AddKey( PdfName("BBox"), var );
150 this->GetObject()->GetDictionary().AddKey( PdfName("XStep"), static_cast<pdf_int64>(rRect.GetWidth()) );
151 this->GetObject()->GetDictionary().AddKey( PdfName("YStep"), static_cast<pdf_int64>(rRect.GetHeight()) );
152 this->GetObject()->GetDictionary().AddKey( PdfName("Resources"), PdfObject( PdfDictionary() ) );
153
154 if (offsetX < -1e-9 || offsetX > 1e-9 || offsetY < -1e-9 || offsetY > 1e-9) {
155 PdfArray array;
156
157 array.push_back (static_cast<pdf_int64>(1));
158 array.push_back (static_cast<pdf_int64>(0));
159 array.push_back (static_cast<pdf_int64>(0));
160 array.push_back (static_cast<pdf_int64>(1));
161 array.push_back (offsetX);
162 array.push_back (offsetY);
163
164 this->GetObject()->GetDictionary().AddKey( PdfName("Matrix"), array );
165 }
166
167 std::ostringstream out;
168 out.flags( std::ios_base::fixed );
169 out.precision( 1L /* clPainterDefaultPrecision */ );
170 PdfLocaleImbue(out);
171
172 if (pImage) {
173 AddToResources(pImage->GetIdentifier(), pImage->GetObjectReference(), PdfName("XObject"));
174
175 out << rRect.GetWidth() << " 0 0 "
176 << rRect.GetHeight() << " "
177 << rRect.GetLeft() << " "
178 << rRect.GetBottom() << " cm" << std::endl;
179 out << "/" << pImage->GetIdentifier().GetName() << " Do" << std::endl;
180 } else {
181 if (doFill) {
182 out << fillR << " " << fillG << " " << fillB << " rg" << " ";
183 out << rRect.GetLeft() << " " << rRect.GetBottom() << " " << rRect.GetWidth() << " " << rRect.GetHeight() << " re" << " ";
184 out << "f" << " "; //fill rect
185 }
186
187 out << strokeR << " " << strokeG << " " << strokeB << " RG" << " ";
188 out << "2 J" << " "; // line capability style
189 out << "0.5 w" << " "; //line width
190
191 double left, bottom, right, top, whalf, hhalf;
192 left = rRect.GetLeft();
193 bottom = rRect.GetBottom();
194 right = left + rRect.GetWidth();
195 top = bottom + rRect.GetHeight();
196 whalf = rRect.GetWidth() / 2;
197 hhalf = rRect.GetHeight() / 2;
198
199 switch (eTilingType) {
200 case ePdfTilingPatternType_BDiagonal:
201 out << left << " " << bottom << " m " << right << " " << top << " l ";
202 out << left - whalf << " " << top - hhalf << " m " << left + whalf << " " << top + hhalf << " l ";
203 out << right - whalf << " " << bottom - hhalf << " m " << right + whalf << " " << bottom + hhalf << " l" << std::endl;
204 break;
205 case ePdfTilingPatternType_Cross:
206 out << left << " " << bottom + hhalf << " m " << right << " " << bottom + hhalf << " l ";
207 out << left + whalf << " " << bottom << " m " << left + whalf << " " << top << " l" << std::endl;
208 break;
209 case ePdfTilingPatternType_DiagCross:
210 out << left << " " << bottom << " m " << right << " " << top << " l ";
211 out << left << " " << top << " m " << right << " " << bottom << " l" << std::endl;
212 break;
213 case ePdfTilingPatternType_FDiagonal:
214 out << left << " " << top << " m " << right << " " << bottom << " l ";
215 out << left - whalf << " " << bottom + hhalf << " m " << left + whalf << " " << bottom - hhalf << " l ";
216 out << right - whalf << " " << top + hhalf << " m " << right + whalf << " " << top - hhalf << " l" << std::endl;
217 break;
218 case ePdfTilingPatternType_Horizontal:
219 out << left << " " << bottom + hhalf << " m " << right << " " << bottom + hhalf << " l ";
220 break;
221 case ePdfTilingPatternType_Vertical:
222 out << left + whalf << " " << bottom << " m " << left + whalf << " " << top << " l" << std::endl;
223 break;
224 case ePdfTilingPatternType_Image:
225 /* This is handled above, based on the 'pImage' variable */
226 default:
227 PODOFO_RAISE_ERROR (ePdfError_InvalidEnumValue);
228 break;
229
230 }
231
232 out << "S"; //stroke path
233 }
234
235 TVecFilters vecFlate;
236 vecFlate.push_back( ePdfFilter_FlateDecode );
237
238 std::string str = out.str();
239 PdfMemoryInputStream stream(str.c_str(), str.length());
240
241 this->GetObject()->GetStream()->Set(&stream, vecFlate);
242 }
243
244 } // end namespace
245