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