1 : /******************************************************************************
2 : * $Id: ogrpdfdatasource.cpp 24195 2012-04-02 20:05:33Z rouault $
3 : *
4 : * Project: PDF Translator
5 : * Purpose: Implements OGRPDFDataSource class
6 : * Author: Even Rouault, even dot rouault at mines dash paris dot org
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2012, Even Rouault <even dot rouault at mines dash paris dot org>
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "ogr_pdf.h"
31 : #include "ogr_p.h"
32 : #include "cpl_conv.h"
33 :
34 : #include "pdfdataset.h"
35 : #include "pdfcreatecopy.h"
36 :
37 : #include "memdataset.h"
38 :
39 : CPL_CVSID("$Id: ogrpdfdatasource.cpp 24195 2012-04-02 20:05:33Z rouault $");
40 :
41 : /************************************************************************/
42 : /* OGRPDFLayer() */
43 : /************************************************************************/
44 :
45 26 : OGRPDFLayer::OGRPDFLayer( OGRPDFDataSource* poDS,
46 : const char * pszName,
47 : OGRSpatialReference *poSRS,
48 : OGRwkbGeometryType eGeomType ) :
49 26 : OGRMemLayer(pszName, poSRS, eGeomType )
50 : {
51 26 : this->poDS = poDS;
52 26 : }
53 :
54 : /************************************************************************/
55 : /* CreateFeature() */
56 : /************************************************************************/
57 :
58 752 : OGRErr OGRPDFLayer::CreateFeature( OGRFeature *poFeature )
59 : {
60 752 : poDS->SetModified();
61 752 : return OGRMemLayer::CreateFeature(poFeature);
62 : }
63 :
64 : /************************************************************************/
65 : /* Fill() */
66 : /************************************************************************/
67 :
68 24 : void OGRPDFLayer::Fill( GDALPDFArray* poArray )
69 : {
70 24 : OGRwkbGeometryType eGeomType = wkbUnknown;
71 24 : int bGeomTypeSet = FALSE;
72 24 : int bGeomTypeMixed = FALSE;
73 :
74 768 : for(int i=0;i<poArray->GetLength();i++)
75 : {
76 744 : GDALPDFObject* poFeatureObj = poArray->Get(i);
77 744 : if (poFeatureObj->GetType() != PDFObjectType_Dictionary)
78 0 : continue;
79 :
80 744 : GDALPDFObject* poA = poFeatureObj->GetDictionary()->Get("A");
81 744 : if (!(poA != NULL && poA->GetType() == PDFObjectType_Dictionary))
82 0 : continue;
83 :
84 744 : GDALPDFObject* poP = poA->GetDictionary()->Get("P");
85 744 : if (!(poP != NULL && poP->GetType() == PDFObjectType_Array))
86 0 : continue;
87 :
88 744 : GDALPDFObject* poK = poFeatureObj->GetDictionary()->Get("K");
89 744 : int nK = -1;
90 744 : if (poK != NULL && poK->GetType() == PDFObjectType_Int)
91 744 : nK = poK->GetInt();
92 :
93 744 : GDALPDFArray* poPArray = poP->GetArray();
94 : int j;
95 2776 : for(j = 0;j<poPArray->GetLength();j++)
96 : {
97 2032 : GDALPDFObject* poKV = poPArray->Get(j);
98 2032 : if (poKV->GetType() == PDFObjectType_Dictionary)
99 : {
100 2032 : GDALPDFObject* poN = poKV->GetDictionary()->Get("N");
101 2032 : GDALPDFObject* poV = poKV->GetDictionary()->Get("V");
102 2032 : if (poN != NULL && poN->GetType() == PDFObjectType_String &&
103 : poV != NULL)
104 : {
105 2032 : int nIdx = GetLayerDefn()->GetFieldIndex( poN->GetString().c_str() );
106 2032 : OGRFieldType eType = OFTString;
107 2032 : if (poV->GetType() == PDFObjectType_Int)
108 2 : eType = OFTInteger;
109 2030 : else if (poV->GetType() == PDFObjectType_Real)
110 2 : eType = OFTReal;
111 2032 : if (nIdx < 0)
112 : {
113 84 : OGRFieldDefn oField(poN->GetString().c_str(), eType);
114 84 : CreateField(&oField);
115 : }
116 1948 : else if (GetLayerDefn()->GetFieldDefn(nIdx)->GetType() != eType &&
117 0 : GetLayerDefn()->GetFieldDefn(nIdx)->GetType() != OFTString)
118 : {
119 0 : OGRFieldDefn oField(poN->GetString().c_str(), OFTString);
120 0 : AlterFieldDefn( nIdx, &oField, ALTER_TYPE_FLAG );
121 : }
122 : }
123 : }
124 : }
125 :
126 744 : OGRFeature* poFeature = new OGRFeature(GetLayerDefn());
127 2776 : for(j = 0;j<poPArray->GetLength();j++)
128 : {
129 2032 : GDALPDFObject* poKV = poPArray->Get(j);
130 2032 : if (poKV->GetType() == PDFObjectType_Dictionary)
131 : {
132 2032 : GDALPDFObject* poN = poKV->GetDictionary()->Get("N");
133 2032 : GDALPDFObject* poV = poKV->GetDictionary()->Get("V");
134 2032 : if (poN != NULL && poN->GetType() == PDFObjectType_String &&
135 : poV != NULL)
136 : {
137 2032 : if (poV->GetType() == PDFObjectType_String)
138 2028 : poFeature->SetField(poN->GetString().c_str(), poV->GetString().c_str());
139 4 : else if (poV->GetType() == PDFObjectType_Int)
140 2 : poFeature->SetField(poN->GetString().c_str(), poV->GetInt());
141 2 : else if (poV->GetType() == PDFObjectType_Real)
142 2 : poFeature->SetField(poN->GetString().c_str(), poV->GetReal());
143 : }
144 : }
145 : }
146 :
147 744 : if (nK >= 0)
148 : {
149 744 : OGRGeometry* poGeom = poDS->GetGeometryFromMCID(nK);
150 744 : if (poGeom)
151 : {
152 744 : if (!bGeomTypeSet)
153 : {
154 24 : bGeomTypeSet = TRUE;
155 24 : eGeomType = poGeom->getGeometryType();
156 : }
157 720 : else if (eGeomType != poGeom->getGeometryType())
158 : {
159 16 : bGeomTypeMixed = TRUE;
160 : }
161 744 : poGeom->assignSpatialReference(GetSpatialRef());
162 744 : poFeature->SetGeometry(poGeom);
163 : }
164 : }
165 :
166 744 : CreateFeature(poFeature);
167 :
168 744 : delete poFeature;
169 : }
170 :
171 24 : if (bGeomTypeSet && !bGeomTypeMixed)
172 20 : GetLayerDefn()->SetGeomType(eGeomType);
173 24 : }
174 :
175 : /************************************************************************/
176 : /* TestCapability() */
177 : /************************************************************************/
178 :
179 0 : int OGRPDFLayer::TestCapability( const char * pszCap )
180 :
181 : {
182 0 : if( EQUAL(pszCap,OLCStringsAsUTF8) )
183 0 : return TRUE;
184 : else
185 0 : return OGRMemLayer::TestCapability(pszCap);
186 : }
187 :
188 : /************************************************************************/
189 : /* OGRPDFDataSource() */
190 : /************************************************************************/
191 :
192 6 : OGRPDFDataSource::OGRPDFDataSource()
193 :
194 : {
195 6 : pszName = NULL;
196 6 : papszOptions = NULL;
197 :
198 6 : nLayers = 0;
199 6 : papoLayers = NULL;
200 :
201 6 : bModified = FALSE;
202 6 : bWritable = FALSE;
203 :
204 6 : poGDAL_DS = NULL;
205 6 : poPageObj = NULL;
206 6 : poCatalogObj = NULL;
207 6 : dfPageWidth = dfPageHeight = 0;
208 :
209 6 : InitMapOperators();
210 6 : }
211 :
212 : /************************************************************************/
213 : /* ~OGRPDFDataSource() */
214 : /************************************************************************/
215 :
216 6 : OGRPDFDataSource::~OGRPDFDataSource()
217 :
218 : {
219 6 : SyncToDisk();
220 :
221 6 : CleanupIntermediateResources();
222 :
223 6 : CPLFree( pszName );
224 6 : CSLDestroy( papszOptions );
225 :
226 32 : for(int i=0;i<nLayers;i++)
227 26 : delete papoLayers[i];
228 6 : CPLFree( papoLayers );
229 6 : }
230 :
231 : /************************************************************************/
232 : /* CleanupIntermediateResources() */
233 : /************************************************************************/
234 :
235 10 : void OGRPDFDataSource::CleanupIntermediateResources()
236 : {
237 10 : std::map<int,OGRGeometry*>::iterator oMapIter = oMapMCID.begin();
238 754 : for( ; oMapIter != oMapMCID.end(); ++oMapIter)
239 744 : delete oMapIter->second;
240 10 : oMapMCID.erase(oMapMCID.begin(), oMapMCID.end());
241 :
242 10 : delete poGDAL_DS;
243 10 : poGDAL_DS = NULL;
244 :
245 10 : poPageObj = NULL;
246 10 : poCatalogObj = NULL;
247 10 : }
248 :
249 : /************************************************************************/
250 : /* InitMapOperators() */
251 : /************************************************************************/
252 :
253 6 : void OGRPDFDataSource::InitMapOperators()
254 : {
255 6 : oMapOperators["b"] = 0;
256 12 : oMapOperators["B"] = 0;
257 12 : oMapOperators["b*"] = 0;
258 12 : oMapOperators["B*"] = 0;
259 12 : oMapOperators["BDC"] = 2;
260 : // BI
261 : // BMC
262 : // BT
263 : // BX
264 12 : oMapOperators["c"] = 6;
265 12 : oMapOperators["cm"] = 6;
266 12 : oMapOperators["CS"] = 1;
267 12 : oMapOperators["cs"] = 1;
268 12 : oMapOperators["d"] = 1; /* we have ignored the first arg */
269 : // d0
270 : // d1
271 12 : oMapOperators["Do"] = 1;
272 : // DP
273 : // EI
274 12 : oMapOperators["EMC"] = 0;
275 : // ET
276 : // EX
277 12 : oMapOperators["f"] = 0;
278 12 : oMapOperators["F"] = 0;
279 12 : oMapOperators["f*"] = 0;
280 12 : oMapOperators["G"] = 1;
281 12 : oMapOperators["g"] = 1;
282 12 : oMapOperators["gs"] = 1;
283 12 : oMapOperators["h"] = 0;
284 12 : oMapOperators["i"] = 1;
285 : // ID
286 12 : oMapOperators["j"] = 1;
287 12 : oMapOperators["J"] = 1;
288 : // K
289 : // k
290 12 : oMapOperators["l"] = 2;
291 12 : oMapOperators["m"] = 2;
292 12 : oMapOperators["M"] = 1;
293 : // MP
294 12 : oMapOperators["n"] = 0;
295 12 : oMapOperators["q"] = 0;
296 12 : oMapOperators["Q"] = 0;
297 12 : oMapOperators["re"] = 4;
298 12 : oMapOperators["RG"] = 3;
299 12 : oMapOperators["rg"] = 3;
300 : // ri
301 12 : oMapOperators["s"] = 0;
302 12 : oMapOperators["S"] = 0;
303 : // SC
304 : // sc
305 12 : oMapOperators["SCN"] = -1;
306 12 : oMapOperators["scn"] = -1;
307 : // sh
308 : // T*
309 : // Tc
310 : // Td
311 : // TD
312 : // Tf
313 : // Tj
314 : // TJ
315 : // TL
316 : // Tm
317 : // Tr
318 : // Ts
319 : // Tw
320 : // Tz
321 12 : oMapOperators["v"] = 4;
322 12 : oMapOperators["w"] = 1;
323 12 : oMapOperators["W"] = 0;
324 12 : oMapOperators["W*"] = 0;
325 12 : oMapOperators["y"] = 4;
326 : // '
327 : // "
328 6 : }
329 :
330 : /************************************************************************/
331 : /* TestCapability() */
332 : /************************************************************************/
333 :
334 0 : int OGRPDFDataSource::TestCapability( const char * pszCap )
335 :
336 : {
337 0 : if( EQUAL(pszCap,ODsCCreateLayer) )
338 0 : return TRUE;
339 : else
340 0 : return FALSE;
341 : }
342 :
343 : /************************************************************************/
344 : /* GetLayer() */
345 : /************************************************************************/
346 :
347 58 : OGRLayer *OGRPDFDataSource::GetLayer( int iLayer )
348 :
349 : {
350 58 : if (iLayer < 0 || iLayer >= nLayers)
351 0 : return NULL;
352 :
353 58 : return papoLayers[iLayer];
354 : }
355 :
356 : /************************************************************************/
357 : /* GetLayerCount() */
358 : /************************************************************************/
359 :
360 18 : int OGRPDFDataSource::GetLayerCount()
361 : {
362 18 : return nLayers;
363 : }
364 :
365 : /************************************************************************/
366 : /* ExploreTree() */
367 : /************************************************************************/
368 :
369 54 : void OGRPDFDataSource::ExploreTree(GDALPDFObject* poObj)
370 : {
371 54 : if (poObj->GetType() != PDFObjectType_Dictionary)
372 0 : return;
373 :
374 54 : GDALPDFDictionary* poDict = poObj->GetDictionary();
375 :
376 54 : GDALPDFObject* poS = poDict->Get("S");
377 54 : CPLString osS;
378 54 : if (poS != NULL && poS->GetType() == PDFObjectType_Name)
379 : {
380 50 : osS = poS->GetName();
381 : }
382 :
383 54 : GDALPDFObject* poT = poDict->Get("T");
384 54 : CPLString osT;
385 54 : if (poT != NULL && poT->GetType() == PDFObjectType_String)
386 : {
387 46 : osT = poT->GetString();
388 : }
389 :
390 54 : GDALPDFObject* poK = poDict->Get("K");
391 54 : if (poK == NULL)
392 : return;
393 :
394 54 : if (poK->GetType() == PDFObjectType_Array)
395 : {
396 52 : GDALPDFArray* poArray = poK->GetArray();
397 520 : if (poArray->GetLength() > 0 &&
398 104 : poArray->Get(0)->GetType() == PDFObjectType_Dictionary &&
399 156 : poArray->Get(0)->GetDictionary()->Get("K") != NULL &&
400 208 : poArray->Get(0)->GetDictionary()->Get("K")->GetType() == PDFObjectType_Int)
401 : {
402 24 : CPLString osLayerName;
403 24 : if (osT.size())
404 22 : osLayerName = osT;
405 : else
406 : {
407 2 : if (osS.size())
408 2 : osLayerName = osS;
409 : else
410 0 : osLayerName = CPLSPrintf("Layer%d", nLayers + 1);
411 : }
412 :
413 24 : const char* pszWKT = poGDAL_DS->GetProjectionRef();
414 24 : OGRSpatialReference* poSRS = NULL;
415 24 : if (pszWKT && pszWKT[0] != '\0')
416 : {
417 24 : poSRS = new OGRSpatialReference();
418 24 : poSRS->importFromWkt((char**) &pszWKT);
419 : }
420 :
421 : OGRPDFLayer* poLayer =
422 24 : new OGRPDFLayer(this, osLayerName.c_str(), poSRS, wkbUnknown);
423 48 : delete poSRS;
424 :
425 24 : poLayer->Fill(poArray);
426 :
427 : papoLayers = (OGRLayer**)
428 24 : CPLRealloc(papoLayers, (nLayers + 1) * sizeof(OGRLayer*));
429 24 : papoLayers[nLayers] = poLayer;
430 24 : nLayers ++;
431 : }
432 : else
433 : {
434 76 : for(int i=0;i<poArray->GetLength();i++)
435 48 : ExploreTree(poArray->Get(i));
436 : }
437 : }
438 2 : else if (poK->GetType() == PDFObjectType_Dictionary)
439 : {
440 2 : ExploreTree(poK);
441 0 : }
442 : }
443 :
444 : /************************************************************************/
445 : /* GetGeometryFromMCID() */
446 : /************************************************************************/
447 :
448 1488 : OGRGeometry* OGRPDFDataSource::GetGeometryFromMCID(int nMCID)
449 : {
450 1488 : std::map<int,OGRGeometry*>::iterator oMapIter = oMapMCID.find(nMCID);
451 1488 : if (oMapIter != oMapMCID.end())
452 744 : return oMapIter->second;
453 : else
454 744 : return NULL;
455 : }
456 :
457 : /************************************************************************/
458 : /* GraphicState */
459 : /************************************************************************/
460 :
461 : class GraphicState
462 8 : {
463 : public:
464 : double adfCM[6];
465 :
466 752 : GraphicState()
467 : {
468 752 : adfCM[0] = 1;
469 752 : adfCM[1] = 0;
470 752 : adfCM[2] = 0;
471 752 : adfCM[3] = 1;
472 752 : adfCM[4] = 0;
473 752 : adfCM[5] = 0;
474 752 : }
475 :
476 0 : void MultiplyBy(double adfMatrix[6])
477 : {
478 : /*
479 : [ a b 0 ] [ a' b' 0] [ aa' + bc' ab' + bd' 0 ]
480 : [ c d 0 ] * [ c' d' 0] = [ ca' + dc' cb' + dd' 0 ]
481 : [ e f 1 ] [ e' f' 1] [ ea' + fc' + e' eb' + fd' + f' 1 ]
482 : */
483 :
484 0 : double a = adfCM[0];
485 0 : double b = adfCM[1];
486 0 : double c = adfCM[2];
487 0 : double d = adfCM[3];
488 0 : double e = adfCM[4];
489 0 : double f = adfCM[5];
490 0 : double ap = adfMatrix[0];
491 0 : double bp = adfMatrix[1];
492 0 : double cp = adfMatrix[2];
493 0 : double dp = adfMatrix[3];
494 0 : double ep = adfMatrix[4];
495 0 : double fp = adfMatrix[5];
496 0 : adfCM[0] = a*ap + b*cp;
497 0 : adfCM[1] = a*bp + b*dp;
498 0 : adfCM[2] = c*ap + d*cp;
499 0 : adfCM[3] = c*bp + d*dp;
500 0 : adfCM[4] = e*ap + f*cp + ep;
501 0 : adfCM[5] = e*bp + f*dp + fp;
502 0 : }
503 :
504 3068 : void ApplyMatrix(double adfCoords[2])
505 : {
506 3068 : double x = adfCoords[0];
507 3068 : double y = adfCoords[1];
508 :
509 3068 : adfCoords[0] = x * adfCM[0] + y * adfCM[2] + adfCM[4];
510 3068 : adfCoords[1] = x * adfCM[1] + y * adfCM[3] + adfCM[5];
511 3068 : }
512 : };
513 :
514 : /************************************************************************/
515 : /* PDFCoordsToSRSCoords() */
516 : /************************************************************************/
517 :
518 3356 : void OGRPDFDataSource::PDFCoordsToSRSCoords(double x, double y,
519 : double& X, double &Y)
520 : {
521 3356 : x = x / dfPageWidth * nXSize;
522 3356 : y = (1 - y / dfPageHeight) * nYSize;
523 :
524 3356 : X = adfGeoTransform[0] + x * adfGeoTransform[1] + y * adfGeoTransform[2];
525 3356 : Y = adfGeoTransform[3] + x * adfGeoTransform[4] + y * adfGeoTransform[5];
526 :
527 3356 : if( fabs(X - (int)floor(X + 0.5)) < 1e-8 )
528 28 : X = (int)floor(X + 0.5);
529 3356 : if( fabs(Y - (int)floor(Y + 0.5)) < 1e-8 )
530 30 : Y = (int)floor(Y + 0.5);
531 3356 : }
532 :
533 : /************************************************************************/
534 : /* UnstackTokens() */
535 : /************************************************************************/
536 :
537 2924 : int OGRPDFDataSource::UnstackTokens(const CPLString& osToken,
538 : std::stack<CPLString>& osTokenStack,
539 : double* adfCoords)
540 : {
541 2924 : int nArgs = oMapOperators[osToken];
542 9092 : for(int i=0;i<nArgs;i++)
543 : {
544 6168 : if (osTokenStack.empty())
545 : {
546 0 : CPLDebug("PDF", "not enough arguments for %s", osToken.c_str());
547 0 : return FALSE;
548 : }
549 6168 : adfCoords[nArgs-1-i] = atof(osTokenStack.top());
550 6168 : osTokenStack.pop();
551 : }
552 2924 : return TRUE;
553 : }
554 :
555 : /************************************************************************/
556 : /* ParseContent() */
557 : /************************************************************************/
558 :
559 : #define NEW_SUBPATH -99
560 : #define CLOSE_SUBPATH -98
561 : #define FILL_SUBPATH -97
562 :
563 752 : void OGRPDFDataSource::ParseContent(const char* pszContent,
564 : int nMCID,
565 : GDALPDFObject* poResources,
566 : int bInitBDCStack)
567 : {
568 752 : CPLString osToken;
569 : char ch;
570 752 : std::stack<CPLString> osTokenStack;
571 752 : int bInString = FALSE;
572 752 : int nBDCLevel = 0;
573 752 : int nParenthesisLevel = 0;
574 752 : int nArrayLevel = 0;
575 752 : int nBTLevel = 0;
576 :
577 752 : GraphicState oGS;
578 752 : std::stack<GraphicState> oGSStack;
579 :
580 752 : std::vector<double> oCoords;
581 752 : int bHasFoundFill = FALSE;
582 752 : int bHasMultiPart = FALSE;
583 752 : int bHasRe = FALSE;
584 :
585 752 : if (bInitBDCStack)
586 : {
587 744 : osTokenStack.push("dummy");
588 744 : osTokenStack.push("dummy");
589 : }
590 :
591 76280 : while((ch = *pszContent) != '\0')
592 : {
593 75520 : int bPushToken = FALSE;
594 :
595 75520 : if (!bInString && ch == '%')
596 : {
597 : /* Skip comments until end-of-line */
598 0 : while((ch = *pszContent) != '\0')
599 : {
600 0 : if (ch == '\r' || ch == '\n')
601 0 : break;
602 0 : pszContent ++;
603 : }
604 0 : if (ch == 0)
605 0 : break;
606 : }
607 87096 : else if (!bInString && (ch == ' ' || ch == '\r' || ch == '\n'))
608 : {
609 11576 : bPushToken = TRUE;
610 : }
611 :
612 : /* Ignore arrays */
613 63944 : else if (!bInString && osToken.size() == 0 && ch == '[')
614 : {
615 8 : nArrayLevel ++;
616 : }
617 63936 : else if (!bInString && nArrayLevel && osToken.size() == 0 && ch == ']')
618 : {
619 8 : nArrayLevel --;
620 : }
621 :
622 63928 : else if (!bInString && osToken.size() == 0 && ch == '(')
623 : {
624 0 : bInString = TRUE;
625 0 : nParenthesisLevel ++;
626 0 : osToken += ch;
627 : }
628 63928 : else if (bInString && ch == '(')
629 : {
630 0 : nParenthesisLevel ++;
631 0 : osToken += ch;
632 : }
633 63928 : else if (bInString && ch == ')')
634 : {
635 0 : nParenthesisLevel --;
636 0 : osToken += ch;
637 0 : if (nParenthesisLevel == 0)
638 : {
639 0 : bInString = FALSE;
640 0 : bPushToken = TRUE;
641 : }
642 : }
643 : else
644 : {
645 63928 : osToken += ch;
646 : }
647 :
648 75520 : pszContent ++;
649 75520 : if (pszContent[0] == '\0')
650 8 : bPushToken = TRUE;
651 :
652 75520 : if (bPushToken && osToken.size())
653 : {
654 11584 : if (osToken == "BDC")
655 : {
656 744 : int nArgs = oMapOperators[osToken];
657 2232 : for(int i=0;i<nArgs;i++)
658 : {
659 1488 : if (osTokenStack.empty())
660 : {
661 : CPLDebug("PDF",
662 : "not enough arguments for %s",
663 0 : osToken.c_str());
664 : return;
665 : }
666 1488 : osTokenStack.pop();
667 : }
668 744 : nBDCLevel ++;
669 : }
670 10840 : else if (osToken == "EMC")
671 : {
672 744 : nBDCLevel --;
673 744 : if (nBDCLevel == 0)
674 744 : break;
675 : }
676 :
677 : /* Ignore any text stuff */
678 10096 : else if (osToken == "BT")
679 0 : nBTLevel ++;
680 10096 : else if (osToken == "ET")
681 : {
682 0 : nBTLevel --;
683 0 : if (nBTLevel < 0)
684 : return;
685 : }
686 10096 : else if (!nArrayLevel && !nBTLevel)
687 : {
688 10096 : if (osToken == "q")
689 : {
690 8 : oGSStack.push(oGS);
691 : }
692 10088 : else if (osToken == "Q")
693 : {
694 8 : if (oGSStack.empty())
695 : {
696 0 : CPLDebug("PDF", "not enough arguments for %s", osToken.c_str());
697 : return;
698 : }
699 :
700 8 : oGS = oGSStack.top();
701 8 : oGSStack.pop();
702 : }
703 10080 : else if (osToken == "cm")
704 : {
705 : double adfMatrix[6];
706 0 : for(int i=0;i<6;i++)
707 : {
708 0 : if (osTokenStack.empty())
709 : {
710 0 : CPLDebug("PDF", "not enough arguments for %s", osToken.c_str());
711 : return;
712 : }
713 0 : adfMatrix[6-1-i] = atof(osTokenStack.top());
714 0 : osTokenStack.pop();
715 : }
716 :
717 0 : oGS.MultiplyBy(adfMatrix);
718 : }
719 10080 : else if (osToken == "b" ||
720 : osToken == "b*")
721 : {
722 6 : if (!(oCoords.size() > 0 &&
723 : oCoords[oCoords.size() - 2] == CLOSE_SUBPATH &&
724 : oCoords[oCoords.size() - 1] == CLOSE_SUBPATH))
725 : {
726 2 : oCoords.push_back(CLOSE_SUBPATH);
727 2 : oCoords.push_back(CLOSE_SUBPATH);
728 : }
729 6 : oCoords.push_back(FILL_SUBPATH);
730 6 : oCoords.push_back(FILL_SUBPATH);
731 6 : bHasFoundFill = TRUE;
732 : }
733 10074 : else if (osToken == "B" ||
734 : osToken == "B*" ||
735 : osToken == "f" ||
736 : osToken == "F" ||
737 : osToken == "f*")
738 : {
739 398 : oCoords.push_back(FILL_SUBPATH);
740 398 : oCoords.push_back(FILL_SUBPATH);
741 398 : bHasFoundFill = TRUE;
742 : }
743 9676 : else if (osToken == "h")
744 : {
745 6 : oCoords.push_back(CLOSE_SUBPATH);
746 6 : oCoords.push_back(CLOSE_SUBPATH);
747 : }
748 9670 : else if (osToken == "n")
749 : {
750 0 : oCoords.resize(0);
751 : }
752 9670 : else if (osToken == "m" || osToken == "l")
753 : {
754 : double adfCoords[2];
755 2772 : if (!UnstackTokens(osToken, osTokenStack, adfCoords))
756 : return;
757 :
758 2772 : if (osToken == "m")
759 : {
760 664 : if (oCoords.size() != 0)
761 64 : bHasMultiPart = TRUE;
762 664 : oCoords.push_back(NEW_SUBPATH);
763 664 : oCoords.push_back(NEW_SUBPATH);
764 : }
765 :
766 2772 : oGS.ApplyMatrix(adfCoords);
767 2772 : oCoords.push_back(adfCoords[0]);
768 2772 : oCoords.push_back(adfCoords[1]);
769 : }
770 6898 : else if (osToken == "c") /* Bezier curve */
771 : {
772 : double adfCoords[6];
773 8 : if (!UnstackTokens(osToken, osTokenStack, adfCoords))
774 : return;
775 :
776 8 : oGS.ApplyMatrix(adfCoords + 4);
777 8 : oCoords.push_back(adfCoords[4]);
778 8 : oCoords.push_back(adfCoords[5]);
779 : }
780 6890 : else if (osToken == "v" || osToken == "y") /* Bezier curve */
781 : {
782 : double adfCoords[4];
783 0 : if (!UnstackTokens(osToken, osTokenStack, adfCoords))
784 : return;
785 :
786 0 : oGS.ApplyMatrix(adfCoords + 2);
787 0 : oCoords.push_back(adfCoords[2]);
788 0 : oCoords.push_back(adfCoords[3]);
789 : }
790 6890 : else if (osToken == "re") /* Rectangle */
791 : {
792 : double adfCoords[4];
793 144 : if (!UnstackTokens(osToken, osTokenStack, adfCoords))
794 : return;
795 :
796 144 : adfCoords[2] += adfCoords[0];
797 144 : adfCoords[3] += adfCoords[1];
798 :
799 144 : oGS.ApplyMatrix(adfCoords);
800 144 : oGS.ApplyMatrix(adfCoords + 2);
801 :
802 144 : if (oCoords.size() != 0)
803 0 : bHasMultiPart = TRUE;
804 144 : oCoords.push_back(NEW_SUBPATH);
805 144 : oCoords.push_back(NEW_SUBPATH);
806 144 : oCoords.push_back(adfCoords[0]);
807 144 : oCoords.push_back(adfCoords[1]);
808 144 : oCoords.push_back(adfCoords[2]);
809 144 : oCoords.push_back(adfCoords[1]);
810 144 : oCoords.push_back(adfCoords[2]);
811 144 : oCoords.push_back(adfCoords[3]);
812 144 : oCoords.push_back(adfCoords[0]);
813 144 : oCoords.push_back(adfCoords[3]);
814 144 : oCoords.push_back(CLOSE_SUBPATH);
815 144 : oCoords.push_back(CLOSE_SUBPATH);
816 144 : bHasRe = TRUE;
817 : }
818 :
819 6746 : else if (osToken == "Do")
820 : {
821 8 : if (osTokenStack.empty())
822 : {
823 : CPLDebug("PDF",
824 : "not enough arguments for %s",
825 0 : osToken.c_str());
826 : return;
827 : }
828 :
829 8 : CPLString osObjectName = osTokenStack.top();
830 8 : osTokenStack.pop();
831 :
832 8 : if (osObjectName[0] != '/')
833 : return;
834 :
835 8 : if (poResources == NULL)
836 : return;
837 :
838 : GDALPDFObject* poXObject =
839 8 : poResources->GetDictionary()->Get("XObject");
840 16 : if (poXObject == NULL ||
841 8 : poXObject->GetType() != PDFObjectType_Dictionary)
842 : return;
843 :
844 : GDALPDFObject* poObject =
845 8 : poXObject->GetDictionary()->Get(osObjectName.c_str() + 1);
846 8 : if (poObject == NULL)
847 : return;
848 :
849 8 : GDALPDFStream* poStream = poObject->GetStream();
850 8 : if (!poStream)
851 : return;
852 :
853 8 : char* pszStr = poStream->GetBytes();
854 8 : ParseContent(pszStr, nMCID, NULL, FALSE);
855 8 : CPLFree(pszStr);
856 : }
857 6738 : else if (oMapOperators.find(osToken) != oMapOperators.end())
858 : {
859 466 : int nArgs = oMapOperators[osToken];
860 466 : if (nArgs < 0)
861 : {
862 0 : while( !osTokenStack.empty() )
863 : {
864 0 : CPLString osTopToken = osTokenStack.top();
865 0 : if (oMapOperators.find(osTopToken) != oMapOperators.end())
866 : break;
867 0 : osTokenStack.pop();
868 : }
869 : }
870 : else
871 : {
872 562 : for(int i=0;i<nArgs;i++)
873 : {
874 96 : if (osTokenStack.empty())
875 : {
876 : CPLDebug("PDF",
877 : "not enough arguments for %s",
878 0 : osToken.c_str());
879 : return;
880 : }
881 96 : osTokenStack.pop();
882 : }
883 : }
884 : }
885 : else
886 : {
887 : //printf("%s\n", osToken.c_str());
888 6272 : osTokenStack.push(osToken);
889 : }
890 : }
891 :
892 10840 : osToken = "";
893 : }
894 : }
895 :
896 752 : if (!osTokenStack.empty())
897 : {
898 0 : while(!osTokenStack.empty())
899 : {
900 : CPLDebug("PDF",
901 : "Remaing values in stack : %s",
902 0 : osTokenStack.top().c_str());
903 0 : osTokenStack.pop();
904 : }
905 : return;
906 : }
907 :
908 752 : if (!oCoords.size())
909 : return;
910 :
911 :
912 744 : OGRGeometry* poGeom = NULL;
913 744 : if (!bHasFoundFill)
914 : {
915 340 : OGRLineString* poLS = NULL;
916 340 : OGRMultiLineString* poMLS = NULL;
917 340 : if (bHasMultiPart)
918 : {
919 10 : poMLS = new OGRMultiLineString();
920 10 : poGeom = poMLS;
921 : }
922 :
923 1808 : for(size_t i=0;i<oCoords.size();i+=2)
924 : {
925 1468 : if (oCoords[i] == NEW_SUBPATH && oCoords[i+1] == NEW_SUBPATH)
926 : {
927 402 : poLS = new OGRLineString();
928 402 : if (poMLS)
929 72 : poMLS->addGeometryDirectly(poLS);
930 : else
931 330 : poGeom = poLS;
932 : }
933 1066 : else if (oCoords[i] == CLOSE_SUBPATH && oCoords[i+1] == CLOSE_SUBPATH)
934 : {
935 0 : if (poLS && poLS->getNumPoints() >= 2 &&
936 : !(poLS->getX(0) == poLS->getX(poLS->getNumPoints()-1) &&
937 : poLS->getY(0) == poLS->getY(poLS->getNumPoints()-1)))
938 : {
939 0 : poLS->addPoint(poLS->getX(0), poLS->getY(0));
940 : }
941 : }
942 1066 : else if (oCoords[i] == FILL_SUBPATH && oCoords[i+1] == FILL_SUBPATH)
943 : {
944 : /* Should not happen */
945 : }
946 : else
947 : {
948 1066 : if (poLS)
949 : {
950 : double X, Y;
951 1066 : PDFCoordsToSRSCoords(oCoords[i], oCoords[i+1], X, Y);
952 :
953 1066 : poLS->addPoint(X, Y);
954 : }
955 : }
956 : }
957 : }
958 : else
959 : {
960 404 : OGRLinearRing* poLS = NULL;
961 404 : int nPolys = 0;
962 404 : OGRGeometry** papoPoly = NULL;
963 :
964 3364 : for(size_t i=0;i<oCoords.size();i+=2)
965 : {
966 3106 : if (oCoords[i] == NEW_SUBPATH && oCoords[i+1] == NEW_SUBPATH)
967 : {
968 406 : delete poLS;
969 406 : poLS = new OGRLinearRing();
970 : }
971 2700 : else if ((oCoords[i] == CLOSE_SUBPATH && oCoords[i+1] == CLOSE_SUBPATH) ||
972 : (oCoords[i] == FILL_SUBPATH && oCoords[i+1] == FILL_SUBPATH))
973 : {
974 410 : if (poLS)
975 : {
976 406 : poLS->closeRings();
977 :
978 : /* Recognize points as outputed by GDAL */
979 406 : if (nPolys == 0 &&
980 : poLS->getNumPoints() == 5 &&
981 : poLS->getY(0) == poLS->getY(2) &&
982 : poLS->getX(1) == poLS->getX(3) &&
983 : fabs((poLS->getX(0) + poLS->getX(2)) / 2 - poLS->getX(1)) < 1e-5 &&
984 : fabs((poLS->getY(1) + poLS->getY(3)) / 2 - poLS->getY(0)) < 1e-5)
985 : {
986 : poGeom = new OGRPoint((poLS->getX(0) + poLS->getX(2)) / 2,
987 2 : (poLS->getY(1) + poLS->getY(3)) / 2);
988 2 : break;
989 : }
990 : /* ESRI points */
991 404 : else if (bHasRe && oCoords.size() == 14 && nPolys == 0 &&
992 : poLS->getNumPoints() == 5 &&
993 : poLS->getY(0) == poLS->getY(1) &&
994 : poLS->getX(1) == poLS->getX(2) &&
995 : poLS->getY(2) == poLS->getY(3) &&
996 : poLS->getX(3) == poLS->getX(0))
997 : {
998 : poGeom = new OGRPoint((poLS->getX(0) + poLS->getX(1)) / 2,
999 144 : (poLS->getY(0) + poLS->getY(2)) / 2);
1000 144 : break;
1001 : }
1002 : else
1003 : {
1004 260 : if (poLS->getNumPoints() >= 3)
1005 : {
1006 260 : OGRPolygon* poPoly = new OGRPolygon();
1007 260 : poPoly->addRingDirectly(poLS);
1008 260 : poLS = NULL;
1009 :
1010 260 : papoPoly = (OGRGeometry**) CPLRealloc(papoPoly, (nPolys + 1) * sizeof(OGRGeometry*));
1011 260 : papoPoly[nPolys ++] = poPoly;
1012 : }
1013 : else
1014 : {
1015 0 : delete poLS;
1016 0 : poLS = NULL;
1017 : }
1018 : }
1019 : }
1020 : }
1021 : else
1022 : {
1023 2290 : if (poLS)
1024 : {
1025 : double X, Y;
1026 2290 : PDFCoordsToSRSCoords(oCoords[i], oCoords[i+1], X, Y);
1027 :
1028 2290 : poLS->addPoint(X, Y);
1029 : }
1030 : }
1031 : }
1032 :
1033 404 : delete poLS;
1034 :
1035 : int bIsValidGeometry;
1036 408 : if (nPolys == 2 &&
1037 2 : ((OGRPolygon*)papoPoly[0])->getNumInteriorRings() == 0 &&
1038 2 : ((OGRPolygon*)papoPoly[1])->getNumInteriorRings() == 0)
1039 : {
1040 2 : OGRLinearRing* poRing0 = ((OGRPolygon*)papoPoly[0])->getExteriorRing();
1041 2 : OGRLinearRing* poRing1 = ((OGRPolygon*)papoPoly[1])->getExteriorRing();
1042 2 : if (poRing0->getNumPoints() == poRing1->getNumPoints())
1043 : {
1044 2 : int bSameRing = TRUE;
1045 2 : for(int i=0;i<poRing0->getNumPoints();i++)
1046 : {
1047 2 : if (poRing0->getX(i) != poRing1->getX(i))
1048 : {
1049 2 : bSameRing = FALSE;
1050 2 : break;
1051 : }
1052 0 : if (poRing0->getY(i) != poRing1->getY(i))
1053 : {
1054 0 : bSameRing = FALSE;
1055 0 : break;
1056 : }
1057 : }
1058 :
1059 : /* Just keep on ring if they are identical */
1060 2 : if (bSameRing)
1061 : {
1062 0 : delete papoPoly[1];
1063 0 : nPolys = 1;
1064 : }
1065 : }
1066 : }
1067 404 : if (nPolys)
1068 : {
1069 : poGeom = OGRGeometryFactory::organizePolygons(
1070 258 : papoPoly, nPolys, &bIsValidGeometry, NULL);
1071 : }
1072 404 : CPLFree(papoPoly);
1073 : }
1074 :
1075 : /* Save geometry in map */
1076 744 : oMapMCID[nMCID] = poGeom;
1077 : }
1078 :
1079 : /************************************************************************/
1080 : /* ExploreContents() */
1081 : /************************************************************************/
1082 :
1083 10 : void OGRPDFDataSource::ExploreContents(GDALPDFObject* poObj,
1084 : GDALPDFObject* poResources)
1085 : {
1086 10 : if (poObj->GetType() == PDFObjectType_Array)
1087 : {
1088 2 : GDALPDFArray* poArray = poObj->GetArray();
1089 8 : for(int i=0;i<poArray->GetLength();i++)
1090 6 : ExploreContents(poArray->Get(i), poResources);
1091 : }
1092 :
1093 10 : if (poObj->GetType() != PDFObjectType_Dictionary)
1094 2 : return;
1095 :
1096 8 : GDALPDFStream* poStream = poObj->GetStream();
1097 8 : if (!poStream)
1098 0 : return;
1099 :
1100 8 : char* pszStr = poStream->GetBytes();
1101 8 : const char* pszMCID = (const char*) pszStr;
1102 760 : while((pszMCID = strstr(pszMCID, "/MCID")) != NULL)
1103 : {
1104 744 : const char* pszBDC = strstr(pszMCID, "BDC");
1105 744 : if (pszBDC)
1106 : {
1107 744 : int nMCID = atoi(pszMCID + 6);
1108 744 : if (GetGeometryFromMCID(nMCID) == NULL)
1109 744 : ParseContent(pszBDC, nMCID, poResources, TRUE);
1110 : }
1111 744 : pszMCID += 5;
1112 : }
1113 8 : CPLFree(pszStr);
1114 : }
1115 :
1116 : /************************************************************************/
1117 : /* Open() */
1118 : /************************************************************************/
1119 :
1120 4 : int OGRPDFDataSource::Open( const char * pszName)
1121 : {
1122 4 : this->pszName = CPLStrdup(pszName);
1123 :
1124 4 : poGDAL_DS = GDALPDFOpen(pszName, GA_ReadOnly);
1125 4 : if (poGDAL_DS == NULL)
1126 0 : return FALSE;
1127 :
1128 4 : const char* pszPageObj = poGDAL_DS->GetMetadataItem("PDF_PAGE_OBJECT");
1129 4 : if (pszPageObj)
1130 4 : sscanf(pszPageObj, "%p", &poPageObj);
1131 4 : if (poPageObj == NULL || poPageObj->GetType() != PDFObjectType_Dictionary)
1132 0 : return FALSE;
1133 :
1134 4 : GDALPDFObject* poMediaBox = poPageObj->GetDictionary()->Get("MediaBox");
1135 12 : if (poMediaBox == NULL || poMediaBox->GetType() != PDFObjectType_Array ||
1136 8 : poMediaBox->GetArray()->GetLength() != 4)
1137 0 : return FALSE;
1138 :
1139 4 : if (poMediaBox->GetArray()->Get(2)->GetType() == PDFObjectType_Real)
1140 2 : dfPageWidth = poMediaBox->GetArray()->Get(2)->GetReal();
1141 2 : else if (poMediaBox->GetArray()->Get(2)->GetType() == PDFObjectType_Int)
1142 2 : dfPageWidth = poMediaBox->GetArray()->Get(2)->GetInt();
1143 : else
1144 0 : return FALSE;
1145 :
1146 4 : if (poMediaBox->GetArray()->Get(3)->GetType() == PDFObjectType_Real)
1147 2 : dfPageHeight = poMediaBox->GetArray()->Get(3)->GetReal();
1148 2 : else if (poMediaBox->GetArray()->Get(3)->GetType() == PDFObjectType_Int)
1149 2 : dfPageHeight = poMediaBox->GetArray()->Get(3)->GetInt();
1150 : else
1151 0 : return FALSE;
1152 :
1153 4 : GDALPDFObject* poContents = poPageObj->GetDictionary()->Get("Contents");
1154 4 : if (poContents == NULL)
1155 0 : return FALSE;
1156 :
1157 6 : if (poContents->GetType() != PDFObjectType_Dictionary &&
1158 2 : poContents->GetType() != PDFObjectType_Array)
1159 0 : return FALSE;
1160 :
1161 4 : GDALPDFObject* poResources = poPageObj->GetDictionary()->Get("Resources");
1162 4 : if (poResources == NULL || poResources->GetType() != PDFObjectType_Dictionary)
1163 0 : return FALSE;
1164 :
1165 4 : const char* pszCatalog = poGDAL_DS->GetMetadataItem("PDF_CATALOG_OBJECT");
1166 4 : if (pszCatalog)
1167 4 : sscanf(pszCatalog, "%p", &poCatalogObj);
1168 4 : if (poCatalogObj == NULL || poCatalogObj->GetType() != PDFObjectType_Dictionary)
1169 0 : return FALSE;
1170 :
1171 4 : GDALPDFObject* poStructTreeRoot = poCatalogObj->GetDictionary()->Get("StructTreeRoot");
1172 4 : if (poStructTreeRoot == NULL || poStructTreeRoot->GetType() != PDFObjectType_Dictionary)
1173 0 : return FALSE;
1174 :
1175 4 : nXSize = poGDAL_DS->GetRasterXSize();
1176 4 : nYSize = poGDAL_DS->GetRasterYSize();
1177 4 : poGDAL_DS->GetGeoTransform(adfGeoTransform);
1178 :
1179 4 : ExploreContents(poContents, poResources);
1180 4 : ExploreTree(poStructTreeRoot);
1181 :
1182 4 : CleanupIntermediateResources();
1183 :
1184 4 : int bEmptyDS = TRUE;
1185 4 : for(int i=0;i<nLayers;i++)
1186 : {
1187 4 : if (papoLayers[i]->GetFeatureCount() != 0)
1188 : {
1189 4 : bEmptyDS = FALSE;
1190 4 : break;
1191 : }
1192 : }
1193 4 : if (bEmptyDS)
1194 0 : return FALSE;
1195 :
1196 4 : return TRUE;
1197 : }
1198 :
1199 : /************************************************************************/
1200 : /* Create() */
1201 : /************************************************************************/
1202 :
1203 2 : int OGRPDFDataSource::Create( const char * pszName, char **papszOptions )
1204 : {
1205 2 : this->pszName = CPLStrdup(pszName);
1206 2 : this->papszOptions = CSLDuplicate(papszOptions);
1207 2 : bWritable = TRUE;
1208 :
1209 2 : return TRUE;
1210 : }
1211 :
1212 : /************************************************************************/
1213 : /* CreateLayer() */
1214 : /************************************************************************/
1215 :
1216 : OGRLayer *
1217 2 : OGRPDFDataSource::CreateLayer( const char * pszLayerName,
1218 : OGRSpatialReference *poSRS,
1219 : OGRwkbGeometryType eType,
1220 : char ** papszOptions )
1221 :
1222 : {
1223 : /* -------------------------------------------------------------------- */
1224 : /* Create the layer object. */
1225 : /* -------------------------------------------------------------------- */
1226 2 : OGRLayer* poLayer = new OGRPDFLayer(this, pszLayerName, poSRS, eType);
1227 :
1228 2 : papoLayers = (OGRLayer**)CPLRealloc(papoLayers, (nLayers + 1) * sizeof(OGRLayer*));
1229 2 : papoLayers[nLayers] = poLayer;
1230 2 : nLayers ++;
1231 :
1232 2 : return poLayer;
1233 : }
1234 :
1235 : /************************************************************************/
1236 : /* SyncToDisk() */
1237 : /************************************************************************/
1238 :
1239 6 : OGRErr OGRPDFDataSource::SyncToDisk()
1240 : {
1241 6 : if (nLayers == 0 || !bModified || !bWritable)
1242 4 : return OGRERR_NONE;
1243 :
1244 2 : bModified = FALSE;
1245 :
1246 2 : OGREnvelope sGlobalExtent;
1247 2 : int bHasExtent = FALSE;
1248 4 : for(int i=0;i<nLayers;i++)
1249 : {
1250 2 : OGREnvelope sExtent;
1251 2 : if (papoLayers[i]->GetExtent(&sExtent) == OGRERR_NONE)
1252 : {
1253 2 : bHasExtent = TRUE;
1254 2 : sGlobalExtent.Merge(sExtent);
1255 : }
1256 : }
1257 2 : if (!bHasExtent ||
1258 : sGlobalExtent.MinX == sGlobalExtent.MaxX ||
1259 : sGlobalExtent.MinY == sGlobalExtent.MaxY)
1260 : {
1261 : CPLError(CE_Failure, CPLE_AppDefined,
1262 0 : "Cannot compute spatial extent of features");
1263 0 : return OGRERR_FAILURE;
1264 : }
1265 :
1266 2 : PDFCompressMethod eStreamCompressMethod = COMPRESS_DEFLATE;
1267 2 : const char* pszStreamCompressMethod = CSLFetchNameValue(papszOptions, "STREAM_COMPRESS");
1268 2 : if (pszStreamCompressMethod)
1269 : {
1270 0 : if( EQUAL(pszStreamCompressMethod, "NONE") )
1271 0 : eStreamCompressMethod = COMPRESS_NONE;
1272 0 : else if( EQUAL(pszStreamCompressMethod, "DEFLATE") )
1273 0 : eStreamCompressMethod = COMPRESS_DEFLATE;
1274 : else
1275 : {
1276 : CPLError( CE_Warning, CPLE_NotSupported,
1277 0 : "Unsupported value for STREAM_COMPRESS.");
1278 : }
1279 : }
1280 :
1281 : const char* pszGEO_ENCODING =
1282 2 : CSLFetchNameValueDef(papszOptions, "GEO_ENCODING", "ISO32000");
1283 :
1284 2 : double dfDPI = atof(CSLFetchNameValueDef(papszOptions, "DPI", "72"));
1285 2 : if (dfDPI < 72.0)
1286 0 : dfDPI = 72.0;
1287 :
1288 2 : const char* pszNEATLINE = CSLFetchNameValue(papszOptions, "NEATLINE");
1289 :
1290 2 : int nMargin = atoi(CSLFetchNameValueDef(papszOptions, "MARGIN", "0"));
1291 :
1292 : PDFMargins sMargins;
1293 2 : sMargins.nLeft = nMargin;
1294 2 : sMargins.nRight = nMargin;
1295 2 : sMargins.nTop = nMargin;
1296 2 : sMargins.nBottom = nMargin;
1297 :
1298 2 : const char* pszLeftMargin = CSLFetchNameValue(papszOptions, "LEFT_MARGIN");
1299 2 : if (pszLeftMargin) sMargins.nLeft = atoi(pszLeftMargin);
1300 :
1301 2 : const char* pszRightMargin = CSLFetchNameValue(papszOptions, "RIGHT_MARGIN");
1302 2 : if (pszRightMargin) sMargins.nRight = atoi(pszRightMargin);
1303 :
1304 2 : const char* pszTopMargin = CSLFetchNameValue(papszOptions, "TOP_MARGIN");
1305 2 : if (pszTopMargin) sMargins.nTop = atoi(pszTopMargin);
1306 :
1307 2 : const char* pszBottomMargin = CSLFetchNameValue(papszOptions, "BOTTOM_MARGIN");
1308 2 : if (pszBottomMargin) sMargins.nBottom = atoi(pszBottomMargin);
1309 :
1310 2 : const char* pszExtraImages = CSLFetchNameValue(papszOptions, "EXTRA_IMAGES");
1311 2 : const char* pszExtraStream = CSLFetchNameValue(papszOptions, "EXTRA_STREAM");
1312 2 : const char* pszExtraLayerName = CSLFetchNameValue(papszOptions, "EXTRA_LAYER_NAME");
1313 :
1314 2 : const char* pszOGRDisplayField = CSLFetchNameValue(papszOptions, "OGR_DISPLAY_FIELD");
1315 2 : int bWriteOGRAttributes = CSLFetchBoolean(papszOptions, "OGR_WRITE_ATTRIBUTES", TRUE);
1316 :
1317 : /* -------------------------------------------------------------------- */
1318 : /* Create file. */
1319 : /* -------------------------------------------------------------------- */
1320 2 : VSILFILE* fp = VSIFOpenL(pszName, "wb");
1321 2 : if( fp == NULL )
1322 : {
1323 : CPLError( CE_Failure, CPLE_OpenFailed,
1324 : "Unable to create PDF file %s.\n",
1325 0 : pszName );
1326 0 : return OGRERR_FAILURE;
1327 : }
1328 :
1329 2 : GDALPDFWriter oWriter(fp);
1330 :
1331 2 : double dfRatio = (sGlobalExtent.MaxY - sGlobalExtent.MinY) / (sGlobalExtent.MaxX - sGlobalExtent.MinX);
1332 :
1333 : int nWidth, nHeight;
1334 :
1335 2 : if (dfRatio < 1)
1336 : {
1337 0 : nWidth = 1024;
1338 0 : nHeight = nWidth * dfRatio;
1339 : }
1340 : else
1341 : {
1342 2 : nHeight = 1024;
1343 2 : nWidth = nHeight / dfRatio;
1344 : }
1345 :
1346 2 : GDALDataset* poSrcDS = MEMDataset::Create( "MEM:::", nWidth, nHeight, 0, GDT_Byte, NULL );
1347 :
1348 : double adfGeoTransform[6];
1349 2 : adfGeoTransform[0] = sGlobalExtent.MinX;
1350 2 : adfGeoTransform[1] = (sGlobalExtent.MaxX - sGlobalExtent.MinX) / nWidth;
1351 2 : adfGeoTransform[2] = 0;
1352 2 : adfGeoTransform[3] = sGlobalExtent.MaxY;
1353 2 : adfGeoTransform[4] = 0;
1354 2 : adfGeoTransform[5] = - (sGlobalExtent.MaxY - sGlobalExtent.MinY) / nHeight;
1355 :
1356 2 : poSrcDS->SetGeoTransform(adfGeoTransform);
1357 :
1358 2 : OGRSpatialReference* poSRS = papoLayers[0]->GetSpatialRef();
1359 2 : if (poSRS)
1360 : {
1361 2 : char* pszWKT = NULL;
1362 2 : poSRS->exportToWkt(&pszWKT);
1363 2 : poSrcDS->SetProjection(pszWKT);
1364 2 : CPLFree(pszWKT);
1365 : }
1366 :
1367 2 : oWriter.SetInfo(poSrcDS, papszOptions);
1368 :
1369 : oWriter.StartPage(poSrcDS,
1370 : dfDPI,
1371 : pszGEO_ENCODING,
1372 : pszNEATLINE,
1373 : &sMargins,
1374 : eStreamCompressMethod,
1375 2 : bWriteOGRAttributes);
1376 :
1377 2 : int iObj = 0;
1378 4 : for(int i=0;i<nLayers;i++)
1379 : {
1380 : GDALPDFLayerDesc osVectorDesc =
1381 4 : oWriter.StartOGRLayer(papoLayers[i]->GetName(),
1382 6 : bWriteOGRAttributes);
1383 :
1384 2 : int iObjLayer = 0;
1385 10 : for(int j=0;j<papoLayers[i]->GetFeatureCount();j++)
1386 : {
1387 8 : OGRFeature* poFeature = papoLayers[i]->GetFeature(j);
1388 :
1389 : oWriter.WriteOGRFeature(osVectorDesc,
1390 : (OGRFeatureH) poFeature,
1391 : pszOGRDisplayField,
1392 : bWriteOGRAttributes,
1393 : iObj,
1394 8 : iObjLayer);
1395 :
1396 8 : delete poFeature;
1397 : }
1398 :
1399 2 : oWriter.EndOGRLayer(osVectorDesc);
1400 : }
1401 :
1402 :
1403 : oWriter.EndPage(pszExtraImages,
1404 : pszExtraStream,
1405 2 : pszExtraLayerName);
1406 :
1407 2 : oWriter.Close();
1408 :
1409 2 : delete poSrcDS;
1410 :
1411 2 : return OGRERR_NONE;
1412 : }
|