1 : /******************************************************************************
2 : * $Id: ogrpdfdatasource.cpp 25325 2012-12-16 21:25:25Z 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 : #define SQUARE(x) ((x)*(x))
40 : #define EPSILON 1e-5
41 :
42 : CPL_CVSID("$Id: ogrpdfdatasource.cpp 25325 2012-12-16 21:25:25Z rouault $");
43 :
44 : /************************************************************************/
45 : /* OGRPDFLayer() */
46 : /************************************************************************/
47 :
48 20 : OGRPDFLayer::OGRPDFLayer( OGRPDFDataSource* poDS,
49 : const char * pszName,
50 : OGRSpatialReference *poSRS,
51 : OGRwkbGeometryType eGeomType ) :
52 20 : OGRMemLayer(pszName, poSRS, eGeomType )
53 : {
54 20 : this->poDS = poDS;
55 20 : bGeomTypeSet = FALSE;
56 20 : bGeomTypeMixed = FALSE;
57 20 : }
58 :
59 : /************************************************************************/
60 : /* CreateFeature() */
61 : /************************************************************************/
62 :
63 451 : OGRErr OGRPDFLayer::CreateFeature( OGRFeature *poFeature )
64 : {
65 451 : OGRGeometry* poGeom = poFeature->GetGeometryRef();
66 451 : if( !bGeomTypeMixed && poGeom != NULL )
67 : {
68 378 : if (!bGeomTypeSet)
69 : {
70 18 : bGeomTypeSet = TRUE;
71 18 : GetLayerDefn()->SetGeomType(poGeom->getGeometryType());
72 : }
73 360 : else if (GetLayerDefn()->GetGeomType() != poGeom->getGeometryType())
74 : {
75 7 : bGeomTypeMixed = TRUE;
76 7 : GetLayerDefn()->SetGeomType(wkbUnknown);
77 : }
78 : }
79 :
80 451 : poDS->SetModified();
81 451 : return OGRMemLayer::CreateFeature(poFeature);
82 : }
83 :
84 : /************************************************************************/
85 : /* Fill() */
86 : /************************************************************************/
87 :
88 14 : void OGRPDFLayer::Fill( GDALPDFArray* poArray )
89 : {
90 405 : for(int i=0;i<poArray->GetLength();i++)
91 : {
92 391 : GDALPDFObject* poFeatureObj = poArray->Get(i);
93 391 : if (poFeatureObj->GetType() != PDFObjectType_Dictionary)
94 0 : continue;
95 :
96 391 : GDALPDFObject* poA = poFeatureObj->GetDictionary()->Get("A");
97 391 : if (!(poA != NULL && poA->GetType() == PDFObjectType_Dictionary))
98 0 : continue;
99 :
100 391 : GDALPDFObject* poP = poA->GetDictionary()->Get("P");
101 391 : if (!(poP != NULL && poP->GetType() == PDFObjectType_Array))
102 0 : continue;
103 :
104 391 : GDALPDFObject* poK = poFeatureObj->GetDictionary()->Get("K");
105 391 : int nK = -1;
106 391 : if (poK != NULL && poK->GetType() == PDFObjectType_Int)
107 391 : nK = poK->GetInt();
108 :
109 391 : GDALPDFArray* poPArray = poP->GetArray();
110 : int j;
111 1424 : for(j = 0;j<poPArray->GetLength();j++)
112 : {
113 1033 : GDALPDFObject* poKV = poPArray->Get(j);
114 1033 : if (poKV->GetType() == PDFObjectType_Dictionary)
115 : {
116 1033 : GDALPDFObject* poN = poKV->GetDictionary()->Get("N");
117 1033 : GDALPDFObject* poV = poKV->GetDictionary()->Get("V");
118 1033 : if (poN != NULL && poN->GetType() == PDFObjectType_String &&
119 : poV != NULL)
120 : {
121 1033 : int nIdx = GetLayerDefn()->GetFieldIndex( poN->GetString().c_str() );
122 1033 : OGRFieldType eType = OFTString;
123 1033 : if (poV->GetType() == PDFObjectType_Int)
124 9 : eType = OFTInteger;
125 1024 : else if (poV->GetType() == PDFObjectType_Real)
126 1 : eType = OFTReal;
127 1033 : if (nIdx < 0)
128 : {
129 47 : OGRFieldDefn oField(poN->GetString().c_str(), eType);
130 47 : CreateField(&oField);
131 : }
132 986 : else if (GetLayerDefn()->GetFieldDefn(nIdx)->GetType() != eType &&
133 0 : GetLayerDefn()->GetFieldDefn(nIdx)->GetType() != OFTString)
134 : {
135 0 : OGRFieldDefn oField(poN->GetString().c_str(), OFTString);
136 0 : AlterFieldDefn( nIdx, &oField, ALTER_TYPE_FLAG );
137 : }
138 : }
139 : }
140 : }
141 :
142 391 : OGRFeature* poFeature = new OGRFeature(GetLayerDefn());
143 1424 : for(j = 0;j<poPArray->GetLength();j++)
144 : {
145 1033 : GDALPDFObject* poKV = poPArray->Get(j);
146 1033 : if (poKV->GetType() == PDFObjectType_Dictionary)
147 : {
148 1033 : GDALPDFObject* poN = poKV->GetDictionary()->Get("N");
149 1033 : GDALPDFObject* poV = poKV->GetDictionary()->Get("V");
150 1033 : if (poN != NULL && poN->GetType() == PDFObjectType_String &&
151 : poV != NULL)
152 : {
153 1033 : if (poV->GetType() == PDFObjectType_String)
154 1023 : poFeature->SetField(poN->GetString().c_str(), poV->GetString().c_str());
155 10 : else if (poV->GetType() == PDFObjectType_Int)
156 9 : poFeature->SetField(poN->GetString().c_str(), poV->GetInt());
157 1 : else if (poV->GetType() == PDFObjectType_Real)
158 1 : poFeature->SetField(poN->GetString().c_str(), poV->GetReal());
159 : }
160 : }
161 : }
162 :
163 391 : if (nK >= 0)
164 : {
165 391 : OGRGeometry* poGeom = poDS->GetGeometryFromMCID(nK);
166 391 : if (poGeom)
167 : {
168 391 : poGeom->assignSpatialReference(GetSpatialRef());
169 391 : poFeature->SetGeometry(poGeom);
170 : }
171 : }
172 :
173 391 : CreateFeature(poFeature);
174 :
175 391 : delete poFeature;
176 : }
177 14 : }
178 :
179 : /************************************************************************/
180 : /* TestCapability() */
181 : /************************************************************************/
182 :
183 0 : int OGRPDFLayer::TestCapability( const char * pszCap )
184 :
185 : {
186 0 : if( EQUAL(pszCap,OLCStringsAsUTF8) )
187 0 : return TRUE;
188 : else
189 0 : return OGRMemLayer::TestCapability(pszCap);
190 : }
191 :
192 : /************************************************************************/
193 : /* OGRPDFDataSource() */
194 : /************************************************************************/
195 :
196 8 : OGRPDFDataSource::OGRPDFDataSource()
197 :
198 : {
199 8 : pszName = NULL;
200 8 : papszOptions = NULL;
201 :
202 8 : nLayers = 0;
203 8 : papoLayers = NULL;
204 :
205 8 : bModified = FALSE;
206 8 : bWritable = FALSE;
207 :
208 8 : poGDAL_DS = NULL;
209 8 : poPageObj = NULL;
210 8 : poCatalogObj = NULL;
211 8 : dfPageWidth = dfPageHeight = 0;
212 :
213 8 : bSetStyle = CSLTestBoolean(CPLGetConfigOption("OGR_PDF_SET_STYLE", "YES"));
214 :
215 8 : InitMapOperators();
216 8 : }
217 :
218 : /************************************************************************/
219 : /* ~OGRPDFDataSource() */
220 : /************************************************************************/
221 :
222 8 : OGRPDFDataSource::~OGRPDFDataSource()
223 :
224 : {
225 8 : SyncToDisk();
226 :
227 8 : CleanupIntermediateResources();
228 :
229 8 : CPLFree( pszName );
230 8 : CSLDestroy( papszOptions );
231 :
232 26 : for(int i=0;i<nLayers;i++)
233 18 : delete papoLayers[i];
234 8 : CPLFree( papoLayers );
235 8 : }
236 :
237 : /************************************************************************/
238 : /* CleanupIntermediateResources() */
239 : /************************************************************************/
240 :
241 14 : void OGRPDFDataSource::CleanupIntermediateResources()
242 : {
243 14 : std::map<int,OGRGeometry*>::iterator oMapIter = oMapMCID.begin();
244 405 : for( ; oMapIter != oMapMCID.end(); ++oMapIter)
245 391 : delete oMapIter->second;
246 14 : oMapMCID.erase(oMapMCID.begin(), oMapMCID.end());
247 :
248 14 : delete poGDAL_DS;
249 14 : poGDAL_DS = NULL;
250 :
251 14 : poPageObj = NULL;
252 14 : poCatalogObj = NULL;
253 14 : }
254 :
255 : /************************************************************************/
256 : /* InitMapOperators() */
257 : /************************************************************************/
258 :
259 : typedef struct
260 : {
261 : char szOpName[4];
262 : char nArgs;
263 : } PDFOperator;
264 :
265 : static const PDFOperator asPDFOperators [] =
266 : {
267 : { "b", 0 },
268 : { "B", 0 },
269 : { "b*", 0 },
270 : { "B*", 0 },
271 : { "BDC", 2 },
272 : // BI
273 : { "BMC", 1 },
274 : // BT
275 : { "BX", 0 },
276 : { "c", 6 },
277 : { "cm", 6 },
278 : { "CS", 1 },
279 : { "cs", 1 },
280 : { "d", 1 }, /* we have ignored the first arg */
281 : // d0
282 : // d1
283 : { "Do", 1 },
284 : { "DP", 2 },
285 : // EI
286 : { "EMC", 0 },
287 : // ET
288 : { "EX", 0 },
289 : { "f", 0 },
290 : { "F", 0 },
291 : { "f*", 0 },
292 : { "G", 1 },
293 : { "g", 1 },
294 : { "gs", 1 },
295 : { "h", 0 },
296 : { "i", 1 },
297 : // ID
298 : { "j", 1 },
299 : { "J", 1 },
300 : { "K", 4 },
301 : { "k", 4 },
302 : { "l", 2 },
303 : { "m", 2 },
304 : { "M", 1 },
305 : { "MP", 1 },
306 : { "n", 0 },
307 : { "q", 0 },
308 : { "Q", 0 },
309 : { "re", 4 },
310 : { "RG", 3 },
311 : { "rg", 3 },
312 : { "ri", 1 },
313 : { "s", 0 },
314 : { "S", 0 },
315 : { "SC", -1 },
316 : { "sc", -1 },
317 : { "SCN", -1 },
318 : { "scn", -1 },
319 : { "sh", 1 },
320 : // T*
321 : { "Tc", 1},
322 : { "Td", 2},
323 : { "TD", 2},
324 : { "Tf", 1},
325 : { "Tj", 1},
326 : { "TJ", 1},
327 : { "TL", 1},
328 : { "Tm", 6},
329 : { "Tr", 1},
330 : { "Ts", 1},
331 : { "Tw", 1},
332 : { "Tz", 1},
333 : { "v", 4 },
334 : { "w", 1 },
335 : { "W", 0 },
336 : { "W*", 0 },
337 : { "y", 4 },
338 : // '
339 : // "
340 : };
341 :
342 8 : void OGRPDFDataSource::InitMapOperators()
343 : {
344 1024 : for(size_t i=0;i<sizeof(asPDFOperators) / sizeof(asPDFOperators[0]); i++)
345 504 : oMapOperators[asPDFOperators[i].szOpName] = asPDFOperators[i].nArgs;
346 8 : }
347 :
348 : /************************************************************************/
349 : /* TestCapability() */
350 : /************************************************************************/
351 :
352 0 : int OGRPDFDataSource::TestCapability( const char * pszCap )
353 :
354 : {
355 0 : if( bWritable && EQUAL(pszCap,ODsCCreateLayer) )
356 0 : return TRUE;
357 : else
358 0 : return FALSE;
359 : }
360 :
361 : /************************************************************************/
362 : /* GetLayer() */
363 : /************************************************************************/
364 :
365 39 : OGRLayer *OGRPDFDataSource::GetLayer( int iLayer )
366 :
367 : {
368 39 : if (iLayer < 0 || iLayer >= nLayers)
369 0 : return NULL;
370 :
371 39 : return papoLayers[iLayer];
372 : }
373 :
374 : /************************************************************************/
375 : /* GetLayerCount() */
376 : /************************************************************************/
377 :
378 23 : int OGRPDFDataSource::GetLayerCount()
379 : {
380 23 : return nLayers;
381 : }
382 :
383 : /************************************************************************/
384 : /* ExploreTree() */
385 : /************************************************************************/
386 :
387 31 : void OGRPDFDataSource::ExploreTree(GDALPDFObject* poObj, int nRecLevel)
388 : {
389 31 : if (nRecLevel == 16)
390 0 : return;
391 :
392 31 : if (poObj->GetType() != PDFObjectType_Dictionary)
393 0 : return;
394 :
395 31 : GDALPDFDictionary* poDict = poObj->GetDictionary();
396 :
397 31 : GDALPDFObject* poS = poDict->Get("S");
398 31 : CPLString osS;
399 31 : if (poS != NULL && poS->GetType() == PDFObjectType_Name)
400 : {
401 27 : osS = poS->GetName();
402 : }
403 :
404 31 : GDALPDFObject* poT = poDict->Get("T");
405 31 : CPLString osT;
406 31 : if (poT != NULL && poT->GetType() == PDFObjectType_String)
407 : {
408 26 : osT = poT->GetString();
409 : }
410 :
411 31 : GDALPDFObject* poK = poDict->Get("K");
412 31 : if (poK == NULL)
413 : return;
414 :
415 31 : if (poK->GetType() == PDFObjectType_Array)
416 : {
417 30 : GDALPDFArray* poArray = poK->GetArray();
418 300 : if (poArray->GetLength() > 0 &&
419 60 : poArray->Get(0)->GetType() == PDFObjectType_Dictionary &&
420 90 : poArray->Get(0)->GetDictionary()->Get("K") != NULL &&
421 120 : poArray->Get(0)->GetDictionary()->Get("K")->GetType() == PDFObjectType_Int)
422 : {
423 14 : CPLString osLayerName;
424 14 : if (osT.size())
425 14 : osLayerName = osT;
426 : else
427 : {
428 0 : if (osS.size())
429 0 : osLayerName = osS;
430 : else
431 0 : osLayerName = CPLSPrintf("Layer%d", nLayers + 1);
432 : }
433 :
434 14 : const char* pszWKT = poGDAL_DS->GetProjectionRef();
435 14 : OGRSpatialReference* poSRS = NULL;
436 14 : if (pszWKT && pszWKT[0] != '\0')
437 : {
438 14 : poSRS = new OGRSpatialReference();
439 14 : poSRS->importFromWkt((char**) &pszWKT);
440 : }
441 :
442 : OGRPDFLayer* poLayer =
443 14 : new OGRPDFLayer(this, osLayerName.c_str(), poSRS, wkbUnknown);
444 28 : delete poSRS;
445 :
446 14 : poLayer->Fill(poArray);
447 :
448 : papoLayers = (OGRLayer**)
449 14 : CPLRealloc(papoLayers, (nLayers + 1) * sizeof(OGRLayer*));
450 14 : papoLayers[nLayers] = poLayer;
451 14 : nLayers ++;
452 : }
453 : else
454 : {
455 42 : for(int i=0;i<poArray->GetLength();i++)
456 26 : ExploreTree(poArray->Get(i), nRecLevel + 1);
457 : }
458 : }
459 1 : else if (poK->GetType() == PDFObjectType_Dictionary)
460 : {
461 1 : ExploreTree(poK, nRecLevel + 1);
462 0 : }
463 : }
464 :
465 : /************************************************************************/
466 : /* GetGeometryFromMCID() */
467 : /************************************************************************/
468 :
469 784 : OGRGeometry* OGRPDFDataSource::GetGeometryFromMCID(int nMCID)
470 : {
471 784 : std::map<int,OGRGeometry*>::iterator oMapIter = oMapMCID.find(nMCID);
472 784 : if (oMapIter != oMapMCID.end())
473 393 : return oMapIter->second;
474 : else
475 391 : return NULL;
476 : }
477 :
478 : /************************************************************************/
479 : /* GraphicState */
480 : /************************************************************************/
481 :
482 : class GraphicState
483 55 : {
484 : public:
485 : double adfCM[6];
486 : double adfStrokeColor[3];
487 : double adfFillColor[3];
488 :
489 448 : GraphicState()
490 : {
491 448 : adfCM[0] = 1;
492 448 : adfCM[1] = 0;
493 448 : adfCM[2] = 0;
494 448 : adfCM[3] = 1;
495 448 : adfCM[4] = 0;
496 448 : adfCM[5] = 0;
497 448 : adfStrokeColor[0] = 0.0;
498 448 : adfStrokeColor[1] = 0.0;
499 448 : adfStrokeColor[2] = 0.0;
500 448 : adfFillColor[0] = 1.0;
501 448 : adfFillColor[1] = 1.0;
502 448 : adfFillColor[2] = 1.0;
503 448 : }
504 :
505 3 : void MultiplyBy(double adfMatrix[6])
506 : {
507 : /*
508 : [ a b 0 ] [ a' b' 0] [ aa' + bc' ab' + bd' 0 ]
509 : [ c d 0 ] * [ c' d' 0] = [ ca' + dc' cb' + dd' 0 ]
510 : [ e f 1 ] [ e' f' 1] [ ea' + fc' + e' eb' + fd' + f' 1 ]
511 : */
512 :
513 3 : double a = adfCM[0];
514 3 : double b = adfCM[1];
515 3 : double c = adfCM[2];
516 3 : double d = adfCM[3];
517 3 : double e = adfCM[4];
518 3 : double f = adfCM[5];
519 3 : double ap = adfMatrix[0];
520 3 : double bp = adfMatrix[1];
521 3 : double cp = adfMatrix[2];
522 3 : double dp = adfMatrix[3];
523 3 : double ep = adfMatrix[4];
524 3 : double fp = adfMatrix[5];
525 3 : adfCM[0] = a*ap + b*cp;
526 3 : adfCM[1] = a*bp + b*dp;
527 3 : adfCM[2] = c*ap + d*cp;
528 3 : adfCM[3] = c*bp + d*dp;
529 3 : adfCM[4] = e*ap + f*cp + ep;
530 3 : adfCM[5] = e*bp + f*dp + fp;
531 3 : }
532 :
533 1781 : void ApplyMatrix(double adfCoords[2])
534 : {
535 1781 : double x = adfCoords[0];
536 1781 : double y = adfCoords[1];
537 :
538 1781 : adfCoords[0] = x * adfCM[0] + y * adfCM[2] + adfCM[4];
539 1781 : adfCoords[1] = x * adfCM[1] + y * adfCM[3] + adfCM[5];
540 1781 : }
541 : };
542 :
543 : /************************************************************************/
544 : /* PDFCoordsToSRSCoords() */
545 : /************************************************************************/
546 :
547 1928 : void OGRPDFDataSource::PDFCoordsToSRSCoords(double x, double y,
548 : double& X, double &Y)
549 : {
550 1928 : x = x / dfPageWidth * nXSize;
551 1928 : y = (1 - y / dfPageHeight) * nYSize;
552 :
553 1928 : X = adfGeoTransform[0] + x * adfGeoTransform[1] + y * adfGeoTransform[2];
554 1928 : Y = adfGeoTransform[3] + x * adfGeoTransform[4] + y * adfGeoTransform[5];
555 :
556 1928 : if( fabs(X - (int)floor(X + 0.5)) < 1e-8 )
557 64 : X = (int)floor(X + 0.5);
558 1928 : if( fabs(Y - (int)floor(Y + 0.5)) < 1e-8 )
559 65 : Y = (int)floor(Y + 0.5);
560 1928 : }
561 :
562 : /************************************************************************/
563 : /* PDFGetCircleCenter() */
564 : /************************************************************************/
565 :
566 : /* Return the center of a circle, or NULL if it is not recognized */
567 :
568 158 : static OGRPoint* PDFGetCircleCenter(OGRLineString* poLS)
569 : {
570 158 : if (poLS == NULL || poLS->getNumPoints() != 5)
571 0 : return NULL;
572 :
573 158 : if (poLS->getY(0) == poLS->getY(2) &&
574 : poLS->getX(1) == poLS->getX(3) &&
575 : fabs((poLS->getX(0) + poLS->getX(2)) / 2 - poLS->getX(1)) < EPSILON &&
576 : fabs((poLS->getY(1) + poLS->getY(3)) / 2 - poLS->getY(0)) < EPSILON)
577 : {
578 : return new OGRPoint((poLS->getX(0) + poLS->getX(2)) / 2,
579 15 : (poLS->getY(1) + poLS->getY(3)) / 2);
580 : }
581 143 : return NULL;
582 : }
583 :
584 : /************************************************************************/
585 : /* PDFGetSquareCenter() */
586 : /************************************************************************/
587 :
588 : /* Return the center of a square, or NULL if it is not recognized */
589 :
590 147 : static OGRPoint* PDFGetSquareCenter(OGRLineString* poLS)
591 : {
592 147 : if (poLS == NULL || poLS->getNumPoints() < 4 || poLS->getNumPoints() > 5)
593 0 : return NULL;
594 :
595 147 : if (poLS->getX(0) == poLS->getX(3) &&
596 : poLS->getY(0) == poLS->getY(1) &&
597 : poLS->getX(1) == poLS->getX(2) &&
598 : poLS->getY(2) == poLS->getY(3) &&
599 : fabs(fabs(poLS->getX(0) - poLS->getX(1)) - fabs(poLS->getY(0) - poLS->getY(3))) < EPSILON)
600 : {
601 : return new OGRPoint((poLS->getX(0) + poLS->getX(1)) / 2,
602 6 : (poLS->getY(0) + poLS->getY(3)) / 2);
603 : }
604 141 : return NULL;
605 : }
606 :
607 : /************************************************************************/
608 : /* PDFGetTriangleCenter() */
609 : /************************************************************************/
610 :
611 : /* Return the center of a equilateral triangle, or NULL if it is not recognized */
612 :
613 16 : static OGRPoint* PDFGetTriangleCenter(OGRLineString* poLS)
614 : {
615 16 : if (poLS == NULL || poLS->getNumPoints() < 3 || poLS->getNumPoints() > 4)
616 0 : return NULL;
617 :
618 16 : double dfSqD1 = SQUARE(poLS->getX(0) - poLS->getX(1)) + SQUARE(poLS->getY(0) - poLS->getY(1));
619 16 : double dfSqD2 = SQUARE(poLS->getX(1) - poLS->getX(2)) + SQUARE(poLS->getY(1) - poLS->getY(2));
620 16 : double dfSqD3 = SQUARE(poLS->getX(0) - poLS->getX(2)) + SQUARE(poLS->getY(0) - poLS->getY(2));
621 16 : if (fabs(dfSqD1 - dfSqD2) < EPSILON && fabs(dfSqD2 - dfSqD3) < EPSILON)
622 : {
623 : return new OGRPoint((poLS->getX(0) + poLS->getX(1) + poLS->getX(2)) / 3,
624 6 : (poLS->getY(0) + poLS->getY(1) + poLS->getY(2)) / 3);
625 : }
626 10 : return NULL;
627 : }
628 :
629 : /************************************************************************/
630 : /* PDFGetStarCenter() */
631 : /************************************************************************/
632 :
633 : /* Return the center of a 5-point star, or NULL if it is not recognized */
634 :
635 8 : static OGRPoint* PDFGetStarCenter(OGRLineString* poLS)
636 : {
637 8 : if (poLS == NULL || poLS->getNumPoints() < 10 || poLS->getNumPoints() > 11)
638 0 : return NULL;
639 :
640 : double dfSqD01 = SQUARE(poLS->getX(0) - poLS->getX(1)) +
641 8 : SQUARE(poLS->getY(0) - poLS->getY(1));
642 : double dfSqD02 = SQUARE(poLS->getX(0) - poLS->getX(2)) +
643 8 : SQUARE(poLS->getY(0) - poLS->getY(2));
644 : double dfSqD13 = SQUARE(poLS->getX(1) - poLS->getX(3)) +
645 8 : SQUARE(poLS->getY(1) - poLS->getY(3));
646 8 : const double dfSin18divSin126 = 0.38196601125;
647 8 : int bOK = fabs(dfSqD13 / dfSqD02 - SQUARE(dfSin18divSin126)) < EPSILON;
648 62 : for(int i=1;i<10 && bOK;i++)
649 : {
650 : double dfSqDiip1 = SQUARE(poLS->getX(i) - poLS->getX((i+1)%10)) +
651 54 : SQUARE(poLS->getY(i) - poLS->getY((i+1)%10));
652 54 : if (fabs(dfSqDiip1 - dfSqD01) > EPSILON)
653 : {
654 0 : bOK = FALSE;
655 : }
656 : double dfSqDiip2 = SQUARE(poLS->getX(i) - poLS->getX((i+2)%10)) +
657 54 : SQUARE(poLS->getY(i) - poLS->getY((i+2)%10));
658 54 : if ( (i%2) == 1 && fabs(dfSqDiip2 - dfSqD13) > EPSILON )
659 : {
660 0 : bOK = FALSE;
661 : }
662 54 : if ( (i%2) == 0 && fabs(dfSqDiip2 - dfSqD02) > EPSILON )
663 : {
664 0 : bOK = FALSE;
665 : }
666 : }
667 8 : if (bOK)
668 : {
669 : return new OGRPoint((poLS->getX(0) + poLS->getX(2) + poLS->getX(4) +
670 : poLS->getX(6) + poLS->getX(8)) / 5,
671 : (poLS->getY(0) + poLS->getY(2) + poLS->getY(4) +
672 6 : poLS->getY(6) + poLS->getY(8)) / 5);
673 : }
674 2 : return NULL;
675 : }
676 :
677 : /************************************************************************/
678 : /* UnstackTokens() */
679 : /************************************************************************/
680 :
681 1812 : int OGRPDFDataSource::UnstackTokens(const char* pszToken,
682 : int nRequiredArgs,
683 : char aszTokenStack[TOKEN_STACK_SIZE][MAX_TOKEN_SIZE],
684 : int& nTokenStackSize,
685 : double* adfCoords)
686 : {
687 1812 : if (nTokenStackSize < nRequiredArgs)
688 : {
689 0 : CPLDebug("PDF", "not enough arguments for %s", pszToken);
690 0 : return FALSE;
691 : }
692 1812 : nTokenStackSize -= nRequiredArgs;
693 5932 : for(int i=0;i<nRequiredArgs;i++)
694 : {
695 4120 : adfCoords[i] = atof(aszTokenStack[nTokenStackSize+i]);
696 : }
697 1812 : return TRUE;
698 : }
699 :
700 : /************************************************************************/
701 : /* ParseContent() */
702 : /************************************************************************/
703 :
704 : #define NEW_SUBPATH -99
705 : #define CLOSE_SUBPATH -98
706 : #define FILL_SUBPATH -97
707 :
708 448 : OGRGeometry* OGRPDFDataSource::ParseContent(const char* pszContent,
709 : GDALPDFObject* poResources,
710 : int bInitBDCStack,
711 : int bMatchQ,
712 : std::map<CPLString, OGRPDFLayer*>& oMapPropertyToLayer,
713 : OGRPDFLayer* poCurLayer)
714 : {
715 :
716 : #define PUSH(aszTokenStack, str, strlen) \
717 : do \
718 : { \
719 : if(nTokenStackSize < TOKEN_STACK_SIZE) \
720 : memcpy(aszTokenStack[nTokenStackSize ++], str, strlen + 1); \
721 : else \
722 : { \
723 : CPLError(CE_Failure, CPLE_AppDefined, "Max token stack size reached");\
724 : return NULL; \
725 : }; \
726 : } while(0)
727 :
728 : #define ADD_CHAR(szToken, c) \
729 : do \
730 : { \
731 : if(nTokenSize < MAX_TOKEN_SIZE-1) \
732 : { \
733 : szToken[nTokenSize ++ ] = c; \
734 : szToken[nTokenSize ] = '\0'; \
735 : } \
736 : else \
737 : { \
738 : CPLError(CE_Failure, CPLE_AppDefined, "Max token size reached");\
739 : return NULL; \
740 : }; \
741 : } while(0)
742 :
743 : char szToken[MAX_TOKEN_SIZE];
744 448 : int nTokenSize = 0;
745 : char ch;
746 : char aszTokenStack[TOKEN_STACK_SIZE][MAX_TOKEN_SIZE];
747 448 : int nTokenStackSize = 0;
748 448 : int bInString = FALSE;
749 448 : int nBDCLevel = 0;
750 448 : int nParenthesisLevel = 0;
751 448 : int nArrayLevel = 0;
752 448 : int nBTLevel = 0;
753 :
754 448 : int bCollectAllObjects = poResources != NULL && !bInitBDCStack && !bMatchQ;
755 :
756 448 : GraphicState oGS;
757 448 : std::stack<GraphicState> oGSStack;
758 448 : std::stack<OGRPDFLayer*> oLayerStack;
759 :
760 448 : std::vector<double> oCoords;
761 448 : int bHasFoundFill = FALSE;
762 448 : int bHasMultiPart = FALSE;
763 :
764 448 : szToken[0] = '\0';
765 :
766 448 : if (bInitBDCStack)
767 : {
768 391 : PUSH(aszTokenStack, "dummy", 5);
769 782 : PUSH(aszTokenStack, "dummy", 5);
770 391 : oLayerStack.push(NULL);
771 : }
772 :
773 52255 : while((ch = *pszContent) != '\0')
774 : {
775 51750 : int bPushToken = FALSE;
776 :
777 51750 : if (!bInString && ch == '%')
778 : {
779 : /* Skip comments until end-of-line */
780 0 : while((ch = *pszContent) != '\0')
781 : {
782 0 : if (ch == '\r' || ch == '\n')
783 0 : break;
784 0 : pszContent ++;
785 : }
786 0 : if (ch == 0)
787 0 : break;
788 : }
789 59733 : else if (!bInString && (ch == ' ' || ch == '\r' || ch == '\n'))
790 : {
791 7983 : bPushToken = TRUE;
792 : }
793 :
794 : /* Ignore arrays */
795 43817 : else if (!bInString && nTokenSize == 0 && ch == '[')
796 : {
797 50 : nArrayLevel ++;
798 : }
799 43767 : else if (!bInString && nArrayLevel && nTokenSize == 0 && ch == ']')
800 : {
801 50 : nArrayLevel --;
802 : }
803 :
804 43669 : else if (!bInString && nTokenSize == 0 && ch == '(')
805 : {
806 2 : bInString = TRUE;
807 2 : nParenthesisLevel ++;
808 2 : ADD_CHAR(szToken, ch);
809 : }
810 43665 : else if (bInString && ch == '(')
811 : {
812 0 : nParenthesisLevel ++;
813 0 : ADD_CHAR(szToken, ch);
814 : }
815 43667 : else if (bInString && ch == ')')
816 : {
817 2 : nParenthesisLevel --;
818 2 : ADD_CHAR(szToken, ch);
819 2 : if (nParenthesisLevel == 0)
820 : {
821 2 : bInString = FALSE;
822 2 : bPushToken = TRUE;
823 : }
824 : }
825 43663 : else if (ch == '<' && pszContent[1] == '<' && nTokenSize == 0)
826 : {
827 0 : int nDictDepth = 0;
828 :
829 0 : while(*pszContent != '\0')
830 : {
831 0 : if (pszContent[0] == '<' && pszContent[1] == '<')
832 : {
833 0 : ADD_CHAR(szToken, '<');
834 0 : ADD_CHAR(szToken, '<');
835 0 : nDictDepth ++;
836 0 : pszContent += 2;
837 : }
838 0 : else if (pszContent[0] == '>' && pszContent[1] == '>')
839 : {
840 0 : ADD_CHAR(szToken, '>');
841 0 : ADD_CHAR(szToken, '>');
842 0 : nDictDepth --;
843 0 : pszContent += 2;
844 0 : if (nDictDepth == 0)
845 0 : break;
846 : }
847 : else
848 : {
849 0 : ADD_CHAR(szToken, *pszContent);
850 0 : pszContent ++;
851 : }
852 : }
853 0 : if (nDictDepth == 0)
854 : {
855 0 : bPushToken = TRUE;
856 0 : pszContent --;
857 : }
858 : else
859 0 : break;
860 : }
861 : else
862 : {
863 43663 : ADD_CHAR(szToken, ch);
864 : }
865 :
866 51750 : pszContent ++;
867 51750 : if (pszContent[0] == '\0')
868 57 : bPushToken = TRUE;
869 :
870 : #define EQUAL1(szToken, s) (szToken[0] == s[0] && szToken[1] == '\0')
871 : #define EQUAL2(szToken, s) (szToken[0] == s[0] && szToken[1] == s[1] && szToken[2] == '\0')
872 : #define EQUAL3(szToken, s) (szToken[0] == s[0] && szToken[1] == s[1] && szToken[2] == s[2] && szToken[3] == '\0')
873 :
874 51750 : if (bPushToken && nTokenSize)
875 : {
876 8038 : if (EQUAL2(szToken, "BI"))
877 : {
878 0 : while(*pszContent != '\0')
879 : {
880 0 : if( pszContent[0] == 'E' && pszContent[1] == 'I' && pszContent[2] == ' ' )
881 : {
882 0 : break;
883 : }
884 0 : pszContent ++;
885 : }
886 0 : if( pszContent[0] == 'E' )
887 0 : pszContent += 3;
888 : else
889 0 : return NULL;
890 : }
891 8435 : else if (EQUAL3(szToken, "BDC"))
892 : {
893 397 : if (nTokenStackSize < 2)
894 : {
895 : CPLDebug("PDF",
896 : "not enough arguments for %s",
897 0 : szToken);
898 0 : return NULL;
899 : }
900 397 : nTokenStackSize -= 2;
901 397 : const char* pszOC = aszTokenStack[nTokenStackSize];
902 397 : const char* pszOCGName = aszTokenStack[nTokenStackSize+1];
903 :
904 397 : nBDCLevel ++;
905 :
906 397 : if( EQUAL3(pszOC, "/OC") && pszOCGName[0] == '/' )
907 : {
908 : std::map<CPLString, OGRPDFLayer*>::iterator oIter =
909 6 : oMapPropertyToLayer.find(pszOCGName + 1);
910 6 : if( oIter != oMapPropertyToLayer.end() )
911 : {
912 6 : poCurLayer = oIter->second;
913 : //CPLDebug("PDF", "Cur layer : %s", poCurLayer->GetName());
914 : }
915 : }
916 :
917 397 : oLayerStack.push(poCurLayer);
918 : //CPLDebug("PDF", "%s %s BDC", osOC.c_str(), osOCGName.c_str());
919 : }
920 7647 : else if (EQUAL3(szToken, "EMC"))
921 : {
922 : //CPLDebug("PDF", "EMC");
923 374 : if( !oLayerStack.empty() )
924 : {
925 374 : oLayerStack.pop();
926 374 : if( !oLayerStack.empty() )
927 370 : poCurLayer = oLayerStack.top();
928 : else
929 4 : poCurLayer = NULL;
930 :
931 : /*if (poCurLayer)
932 : {
933 : CPLDebug("PDF", "Cur layer : %s", poCurLayer->GetName());
934 : }*/
935 : }
936 : else
937 : {
938 0 : CPLDebug("PDF", "Should not happen at line %d", __LINE__);
939 0 : poCurLayer = NULL;
940 : //return NULL;
941 : }
942 :
943 374 : nBDCLevel --;
944 374 : if (nBDCLevel == 0 && bInitBDCStack)
945 368 : break;
946 : }
947 :
948 : /* Ignore any text stuff */
949 7269 : else if (EQUAL2(szToken, "BT"))
950 2 : nBTLevel ++;
951 7267 : else if (EQUAL2(szToken, "ET"))
952 : {
953 2 : nBTLevel --;
954 2 : if (nBTLevel < 0)
955 : {
956 0 : CPLDebug("PDF", "Should not happen at line %d", __LINE__);
957 0 : return NULL;
958 : }
959 : }
960 7263 : else if (!nArrayLevel && !nBTLevel)
961 : {
962 7237 : int bEmitFeature = FALSE;
963 :
964 7237 : if( szToken[0] < 'A' )
965 : {
966 4493 : PUSH(aszTokenStack, szToken, nTokenSize);
967 : }
968 2799 : else if (EQUAL1(szToken, "q"))
969 : {
970 55 : oGSStack.push(oGS);
971 : }
972 2744 : else if (EQUAL1(szToken, "Q"))
973 : {
974 55 : if (oGSStack.empty())
975 : {
976 0 : CPLDebug("PDF", "not enough arguments for %s", szToken);
977 0 : return NULL;
978 : }
979 :
980 55 : oGS = oGSStack.top();
981 55 : oGSStack.pop();
982 :
983 55 : if (oGSStack.empty() && bMatchQ)
984 0 : break;
985 : }
986 2637 : else if (EQUAL2(szToken, "cm"))
987 : {
988 : double adfMatrix[6];
989 3 : if (!UnstackTokens(szToken, 6, aszTokenStack, nTokenStackSize, adfMatrix))
990 : {
991 0 : CPLDebug("PDF", "Should not happen at line %d", __LINE__);
992 0 : return NULL;
993 : }
994 :
995 3 : oGS.MultiplyBy(adfMatrix);
996 : }
997 5346 : else if (EQUAL1(szToken, "b") || /* closepath, fill, stroke */
998 2687 : EQUAL2(szToken, "b*") /* closepath, eofill, stroke */)
999 : {
1000 28 : if (!(oCoords.size() > 0 &&
1001 : oCoords[oCoords.size() - 2] == CLOSE_SUBPATH &&
1002 : oCoords[oCoords.size() - 1] == CLOSE_SUBPATH))
1003 : {
1004 21 : oCoords.push_back(CLOSE_SUBPATH);
1005 21 : oCoords.push_back(CLOSE_SUBPATH);
1006 : }
1007 28 : oCoords.push_back(FILL_SUBPATH);
1008 28 : oCoords.push_back(FILL_SUBPATH);
1009 28 : bHasFoundFill = TRUE;
1010 :
1011 28 : bEmitFeature = TRUE;
1012 : }
1013 12418 : else if (EQUAL1(szToken, "B") || /* fill, stroke */
1014 2404 : EQUAL2(szToken, "B*") || /* eofill, stroke */
1015 2404 : EQUAL1(szToken, "f") || /* fill */
1016 2404 : EQUAL1(szToken, "F") || /* fill */
1017 2404 : EQUAL2(szToken, "f*") /* eofill */ )
1018 : {
1019 199 : oCoords.push_back(FILL_SUBPATH);
1020 199 : oCoords.push_back(FILL_SUBPATH);
1021 199 : bHasFoundFill = TRUE;
1022 :
1023 199 : bEmitFeature = TRUE;
1024 : }
1025 2416 : else if (EQUAL1(szToken, "h")) /* close subpath */
1026 : {
1027 12 : if (!(oCoords.size() > 0 &&
1028 : oCoords[oCoords.size() - 2] == CLOSE_SUBPATH &&
1029 : oCoords[oCoords.size() - 1] == CLOSE_SUBPATH))
1030 : {
1031 12 : oCoords.push_back(CLOSE_SUBPATH);
1032 12 : oCoords.push_back(CLOSE_SUBPATH);
1033 : }
1034 : }
1035 2392 : else if (EQUAL1(szToken, "n")) /* new subpath without stroking or filling */
1036 : {
1037 0 : oCoords.resize(0);
1038 : }
1039 2404 : else if (EQUAL1(szToken, "s")) /* close and stroke */
1040 : {
1041 12 : if (!(oCoords.size() > 0 &&
1042 : oCoords[oCoords.size() - 2] == CLOSE_SUBPATH &&
1043 : oCoords[oCoords.size() - 1] == CLOSE_SUBPATH))
1044 : {
1045 12 : oCoords.push_back(CLOSE_SUBPATH);
1046 12 : oCoords.push_back(CLOSE_SUBPATH);
1047 : }
1048 :
1049 12 : bEmitFeature = TRUE;
1050 : }
1051 2590 : else if (EQUAL1(szToken, "S")) /* stroke */
1052 : {
1053 210 : bEmitFeature = TRUE;
1054 : }
1055 3747 : else if (EQUAL1(szToken, "m") || EQUAL1(szToken, "l"))
1056 : {
1057 : double adfCoords[2];
1058 1577 : if (!UnstackTokens(szToken, 2, aszTokenStack, nTokenStackSize, adfCoords))
1059 : {
1060 0 : CPLDebug("PDF", "Should not happen at line %d", __LINE__);
1061 0 : return NULL;
1062 : }
1063 :
1064 1577 : if (EQUAL1(szToken, "m"))
1065 : {
1066 388 : if (oCoords.size() != 0)
1067 42 : bHasMultiPart = TRUE;
1068 388 : oCoords.push_back(NEW_SUBPATH);
1069 388 : oCoords.push_back(NEW_SUBPATH);
1070 : }
1071 :
1072 1577 : oGS.ApplyMatrix(adfCoords);
1073 1577 : oCoords.push_back(adfCoords[0]);
1074 1577 : oCoords.push_back(adfCoords[1]);
1075 : }
1076 653 : else if (EQUAL1(szToken, "c")) /* Bezier curve */
1077 : {
1078 : double adfCoords[6];
1079 60 : if (!UnstackTokens(szToken, 6, aszTokenStack, nTokenStackSize, adfCoords))
1080 : {
1081 0 : CPLDebug("PDF", "Should not happen at line %d", __LINE__);
1082 0 : return NULL;
1083 : }
1084 :
1085 60 : oGS.ApplyMatrix(adfCoords + 4);
1086 60 : oCoords.push_back(adfCoords[4]);
1087 60 : oCoords.push_back(adfCoords[5]);
1088 : }
1089 533 : else if (EQUAL1(szToken, "v") || EQUAL1(szToken, "y")) /* Bezier curve */
1090 : {
1091 : double adfCoords[4];
1092 0 : if (!UnstackTokens(szToken, 4, aszTokenStack, nTokenStackSize, adfCoords))
1093 : {
1094 0 : CPLDebug("PDF", "Should not happen at line %d", __LINE__);
1095 0 : return NULL;
1096 : }
1097 :
1098 0 : oGS.ApplyMatrix(adfCoords + 2);
1099 0 : oCoords.push_back(adfCoords[2]);
1100 0 : oCoords.push_back(adfCoords[3]);
1101 : }
1102 605 : else if (EQUAL2(szToken, "re")) /* Rectangle */
1103 : {
1104 : double adfCoords[4];
1105 72 : if (!UnstackTokens(szToken, 4, aszTokenStack, nTokenStackSize, adfCoords))
1106 : {
1107 0 : CPLDebug("PDF", "Should not happen at line %d", __LINE__);
1108 0 : return NULL;
1109 : }
1110 :
1111 72 : adfCoords[2] += adfCoords[0];
1112 72 : adfCoords[3] += adfCoords[1];
1113 :
1114 72 : oGS.ApplyMatrix(adfCoords);
1115 72 : oGS.ApplyMatrix(adfCoords + 2);
1116 :
1117 72 : if (oCoords.size() != 0)
1118 0 : bHasMultiPart = TRUE;
1119 72 : oCoords.push_back(NEW_SUBPATH);
1120 72 : oCoords.push_back(NEW_SUBPATH);
1121 72 : oCoords.push_back(adfCoords[0]);
1122 72 : oCoords.push_back(adfCoords[1]);
1123 72 : oCoords.push_back(adfCoords[2]);
1124 72 : oCoords.push_back(adfCoords[1]);
1125 72 : oCoords.push_back(adfCoords[2]);
1126 72 : oCoords.push_back(adfCoords[3]);
1127 72 : oCoords.push_back(adfCoords[0]);
1128 72 : oCoords.push_back(adfCoords[3]);
1129 72 : oCoords.push_back(CLOSE_SUBPATH);
1130 72 : oCoords.push_back(CLOSE_SUBPATH);
1131 : }
1132 :
1133 495 : else if (EQUAL2(szToken, "Do"))
1134 : {
1135 58 : if (nTokenStackSize == 0)
1136 : {
1137 : CPLDebug("PDF",
1138 : "not enough arguments for %s",
1139 0 : szToken);
1140 0 : return NULL;
1141 : }
1142 :
1143 58 : CPLString osObjectName = aszTokenStack[--nTokenStackSize];
1144 :
1145 58 : if (osObjectName[0] != '/')
1146 : {
1147 0 : CPLDebug("PDF", "Should not happen at line %d", __LINE__);
1148 0 : return NULL;
1149 : }
1150 :
1151 58 : if (poResources == NULL)
1152 : {
1153 3 : if (osObjectName.find("/SymImage") == 0)
1154 : {
1155 3 : oCoords.push_back(oGS.adfCM[4] + oGS.adfCM[0] / 2);
1156 3 : oCoords.push_back(oGS.adfCM[5] + oGS.adfCM[3] / 2);
1157 :
1158 3 : szToken[0] = '\0';
1159 3 : nTokenSize = 0;
1160 :
1161 3 : if( poCurLayer != NULL)
1162 2 : bEmitFeature = TRUE;
1163 : else
1164 1 : continue;
1165 : }
1166 : else
1167 : {
1168 : //CPLDebug("PDF", "Should not happen at line %d", __LINE__);
1169 0 : return NULL;
1170 : }
1171 : }
1172 :
1173 57 : if( !bEmitFeature )
1174 : {
1175 : GDALPDFObject* poXObject =
1176 55 : poResources->GetDictionary()->Get("XObject");
1177 110 : if (poXObject == NULL ||
1178 55 : poXObject->GetType() != PDFObjectType_Dictionary)
1179 : {
1180 0 : CPLDebug("PDF", "Should not happen at line %d", __LINE__);
1181 0 : return NULL;
1182 : }
1183 :
1184 : GDALPDFObject* poObject =
1185 55 : poXObject->GetDictionary()->Get(osObjectName.c_str() + 1);
1186 55 : if (poObject == NULL)
1187 : {
1188 0 : CPLDebug("PDF", "Should not happen at line %d", __LINE__);
1189 0 : return NULL;
1190 : }
1191 :
1192 55 : int bParseStream = TRUE;
1193 : /* Check if the object is an image. If so, no need to try to parse */
1194 : /* it. */
1195 55 : if (poObject->GetType() == PDFObjectType_Dictionary)
1196 : {
1197 55 : GDALPDFObject* poSubtype = poObject->GetDictionary()->Get("Subtype");
1198 165 : if (poSubtype != NULL &&
1199 55 : poSubtype->GetType() == PDFObjectType_Name &&
1200 55 : poSubtype->GetName() == "Image" )
1201 : {
1202 0 : bParseStream = FALSE;
1203 : }
1204 : }
1205 :
1206 55 : if( bParseStream )
1207 : {
1208 55 : GDALPDFStream* poStream = poObject->GetStream();
1209 55 : if (!poStream)
1210 : {
1211 0 : CPLDebug("PDF", "Should not happen at line %d", __LINE__);
1212 0 : return NULL;
1213 : }
1214 :
1215 55 : char* pszStr = poStream->GetBytes();
1216 55 : if( pszStr )
1217 : {
1218 : OGRGeometry* poGeom = ParseContent(pszStr, NULL, FALSE, FALSE,
1219 55 : oMapPropertyToLayer, poCurLayer);
1220 55 : CPLFree(pszStr);
1221 55 : if (poGeom && !bCollectAllObjects)
1222 23 : return poGeom;
1223 32 : delete poGeom;
1224 : }
1225 : }
1226 0 : }
1227 : }
1228 503 : else if( EQUAL2(szToken, "RG") || EQUAL2(szToken, "rg") )
1229 : {
1230 100 : double* padf = ( EQUAL2(szToken, "RG") ) ? oGS.adfStrokeColor : oGS.adfFillColor;
1231 100 : if (!UnstackTokens(szToken, 3, aszTokenStack, nTokenStackSize, padf))
1232 : {
1233 0 : CPLDebug("PDF", "Should not happen at line %d", __LINE__);
1234 0 : return NULL;
1235 : }
1236 : }
1237 303 : else if (oMapOperators.find(szToken) != oMapOperators.end())
1238 : {
1239 303 : int nArgs = oMapOperators[szToken];
1240 303 : if (nArgs < 0)
1241 : {
1242 0 : while( nTokenStackSize != 0 )
1243 : {
1244 0 : CPLString osTopToken = aszTokenStack[--nTokenStackSize];
1245 0 : if (oMapOperators.find(osTopToken) != oMapOperators.end())
1246 : break;
1247 : }
1248 : }
1249 : else
1250 : {
1251 303 : if( nArgs > nTokenStackSize )
1252 : {
1253 : CPLDebug("PDF",
1254 : "not enough arguments for %s",
1255 0 : szToken);
1256 0 : return NULL;
1257 : }
1258 303 : nTokenStackSize -= nArgs;
1259 : }
1260 : }
1261 : else
1262 : {
1263 0 : PUSH(aszTokenStack, szToken, nTokenSize);
1264 : }
1265 :
1266 7213 : if( bEmitFeature && poCurLayer != NULL)
1267 : {
1268 30 : OGRGeometry* poGeom = BuildGeometry(oCoords, bHasFoundFill, bHasMultiPart);
1269 30 : bHasFoundFill = bHasMultiPart = FALSE;
1270 30 : if (poGeom)
1271 : {
1272 30 : OGRFeature* poFeature = new OGRFeature(poCurLayer->GetLayerDefn());
1273 30 : if( bSetStyle )
1274 : {
1275 30 : OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
1276 32 : if( eType == wkbLineString || eType == wkbMultiLineString )
1277 : {
1278 : poFeature->SetStyleString(CPLSPrintf("PEN(c:#%02X%02X%02X)",
1279 2 : (int)(oGS.adfStrokeColor[0] * 255 + 0.5),
1280 2 : (int)(oGS.adfStrokeColor[1] * 255 + 0.5),
1281 6 : (int)(oGS.adfStrokeColor[2] * 255 + 0.5)));
1282 : }
1283 28 : else if( eType == wkbPolygon || eType == wkbMultiPolygon )
1284 : {
1285 : poFeature->SetStyleString(CPLSPrintf("PEN(c:#%02X%02X%02X);BRUSH(fc:#%02X%02X%02X)",
1286 4 : (int)(oGS.adfStrokeColor[0] * 255 + 0.5),
1287 4 : (int)(oGS.adfStrokeColor[1] * 255 + 0.5),
1288 4 : (int)(oGS.adfStrokeColor[2] * 255 + 0.5),
1289 4 : (int)(oGS.adfFillColor[0] * 255 + 0.5),
1290 4 : (int)(oGS.adfFillColor[1] * 255 + 0.5),
1291 24 : (int)(oGS.adfFillColor[2] * 255 + 0.5)));
1292 : }
1293 : }
1294 30 : poGeom->assignSpatialReference(poCurLayer->GetSpatialRef());
1295 30 : poFeature->SetGeometryDirectly(poGeom);
1296 30 : poCurLayer->CreateFeature(poFeature);
1297 30 : delete poFeature;
1298 : }
1299 :
1300 30 : oCoords.resize(0);
1301 : }
1302 : }
1303 :
1304 7646 : szToken[0] = '\0';
1305 7646 : nTokenSize = 0;
1306 : }
1307 : }
1308 :
1309 425 : if (nTokenStackSize != 0)
1310 : {
1311 0 : while(nTokenStackSize != 0)
1312 : {
1313 0 : nTokenStackSize--;
1314 : CPLDebug("PDF",
1315 : "Remaing values in stack : %s",
1316 0 : aszTokenStack[nTokenStackSize]);
1317 : }
1318 0 : return NULL;
1319 : }
1320 :
1321 425 : if (bCollectAllObjects)
1322 2 : return NULL;
1323 :
1324 423 : return BuildGeometry(oCoords, bHasFoundFill, bHasMultiPart);
1325 : }
1326 :
1327 : /************************************************************************/
1328 : /* BuildGeometry() */
1329 : /************************************************************************/
1330 :
1331 453 : OGRGeometry* OGRPDFDataSource::BuildGeometry(std::vector<double>& oCoords,
1332 : int bHasFoundFill,
1333 : int bHasMultiPart)
1334 : {
1335 453 : OGRGeometry* poGeom = NULL;
1336 :
1337 453 : if (!oCoords.size())
1338 32 : return NULL;
1339 :
1340 421 : if (oCoords.size() == 2)
1341 : {
1342 : double X, Y;
1343 3 : PDFCoordsToSRSCoords(oCoords[0], oCoords[1], X, Y);
1344 3 : poGeom = new OGRPoint(X, Y);
1345 : }
1346 418 : else if (!bHasFoundFill)
1347 : {
1348 191 : OGRLineString* poLS = NULL;
1349 191 : OGRMultiLineString* poMLS = NULL;
1350 191 : if (bHasMultiPart)
1351 : {
1352 11 : poMLS = new OGRMultiLineString();
1353 11 : poGeom = poMLS;
1354 : }
1355 :
1356 1060 : for(size_t i=0;i<oCoords.size();i+=2)
1357 : {
1358 869 : if (oCoords[i] == NEW_SUBPATH && oCoords[i+1] == NEW_SUBPATH)
1359 : {
1360 228 : poLS = new OGRLineString();
1361 228 : if (poMLS)
1362 48 : poMLS->addGeometryDirectly(poLS);
1363 : else
1364 180 : poGeom = poLS;
1365 : }
1366 641 : else if (oCoords[i] == CLOSE_SUBPATH && oCoords[i+1] == CLOSE_SUBPATH)
1367 : {
1368 12 : if (poLS && poLS->getNumPoints() >= 2 &&
1369 : !(poLS->getX(0) == poLS->getX(poLS->getNumPoints()-1) &&
1370 : poLS->getY(0) == poLS->getY(poLS->getNumPoints()-1)))
1371 : {
1372 9 : poLS->addPoint(poLS->getX(0), poLS->getY(0));
1373 : }
1374 : }
1375 629 : else if (oCoords[i] == FILL_SUBPATH && oCoords[i+1] == FILL_SUBPATH)
1376 : {
1377 : /* Should not happen */
1378 : }
1379 : else
1380 : {
1381 629 : if (poLS)
1382 : {
1383 : double X, Y;
1384 629 : PDFCoordsToSRSCoords(oCoords[i], oCoords[i+1], X, Y);
1385 :
1386 629 : poLS->addPoint(X, Y);
1387 : }
1388 : }
1389 : }
1390 :
1391 : /* Recognize points as outputed by GDAL (ogr-sym-2 : circle (not filled)) */
1392 191 : OGRGeometry* poCenter = NULL;
1393 191 : if (poCenter == NULL && poLS != NULL && poLS->getNumPoints() == 5)
1394 : {
1395 6 : poCenter = PDFGetCircleCenter(poLS);
1396 : }
1397 :
1398 : /* Recognize points as outputed by GDAL (ogr-sym-4: square (not filled)) */
1399 191 : if (poCenter == NULL && poLS != NULL && (poLS->getNumPoints() == 4 || poLS->getNumPoints() == 5))
1400 : {
1401 7 : poCenter = PDFGetSquareCenter(poLS);
1402 : }
1403 :
1404 : /* Recognize points as outputed by GDAL (ogr-sym-6: triangle (not filled)) */
1405 191 : if (poCenter == NULL && poLS != NULL && (poLS->getNumPoints() == 3 || poLS->getNumPoints() == 4))
1406 : {
1407 13 : poCenter = PDFGetTriangleCenter(poLS);
1408 : }
1409 :
1410 : /* Recognize points as outputed by GDAL (ogr-sym-8: star (not filled)) */
1411 191 : if (poCenter == NULL && poLS != NULL && (poLS->getNumPoints() == 10 || poLS->getNumPoints() == 11))
1412 : {
1413 4 : poCenter = PDFGetStarCenter(poLS);
1414 : }
1415 :
1416 191 : if (poCenter == NULL && poMLS != NULL && poMLS->getNumGeometries() == 2)
1417 : {
1418 6 : OGRLineString* poLS1 = (OGRLineString* )poMLS->getGeometryRef(0);
1419 6 : OGRLineString* poLS2 = (OGRLineString* )poMLS->getGeometryRef(1);
1420 :
1421 : /* Recognize points as outputed by GDAL (ogr-sym-0: cross (+) ) */
1422 6 : if (poLS1->getNumPoints() == 2 && poLS2->getNumPoints() == 2 &&
1423 : poLS1->getY(0) == poLS1->getY(1) &&
1424 : poLS2->getX(0) == poLS2->getX(1) &&
1425 : fabs(fabs(poLS1->getX(0) - poLS1->getX(1)) - fabs(poLS2->getY(0) - poLS2->getY(1))) < EPSILON &&
1426 : fabs((poLS1->getX(0) + poLS1->getX(1)) / 2 - poLS2->getX(0)) < EPSILON &&
1427 : fabs((poLS2->getY(0) + poLS2->getY(1)) / 2 - poLS1->getY(0)) < EPSILON)
1428 : {
1429 3 : poCenter = new OGRPoint(poLS2->getX(0), poLS1->getY(0));
1430 : }
1431 : /* Recognize points as outputed by GDAL (ogr-sym-1: diagcross (X) ) */
1432 3 : else if (poLS1->getNumPoints() == 2 && poLS2->getNumPoints() == 2 &&
1433 : poLS1->getX(0) == poLS2->getX(0) &&
1434 : poLS1->getY(0) == poLS2->getY(1) &&
1435 : poLS1->getX(1) == poLS2->getX(1) &&
1436 : poLS1->getY(1) == poLS2->getY(0) &&
1437 : fabs(fabs(poLS1->getX(0) - poLS1->getX(1)) - fabs(poLS1->getY(0) - poLS1->getY(1))) < EPSILON)
1438 : {
1439 : poCenter = new OGRPoint((poLS1->getX(0) + poLS1->getX(1)) / 2,
1440 3 : (poLS1->getY(0) + poLS1->getY(1)) / 2);
1441 : }
1442 : }
1443 :
1444 191 : if (poCenter)
1445 : {
1446 18 : delete poGeom;
1447 18 : poGeom = poCenter;
1448 : }
1449 : }
1450 : else
1451 : {
1452 227 : OGRLinearRing* poLS = NULL;
1453 227 : int nPolys = 0;
1454 227 : OGRGeometry** papoPoly = NULL;
1455 :
1456 1901 : for(size_t i=0;i<oCoords.size();i+=2)
1457 : {
1458 1767 : if (oCoords[i] == NEW_SUBPATH && oCoords[i+1] == NEW_SUBPATH)
1459 : {
1460 232 : delete poLS;
1461 232 : poLS = new OGRLinearRing();
1462 : }
1463 1535 : else if ((oCoords[i] == CLOSE_SUBPATH && oCoords[i+1] == CLOSE_SUBPATH) ||
1464 : (oCoords[i] == FILL_SUBPATH && oCoords[i+1] == FILL_SUBPATH))
1465 : {
1466 239 : if (poLS)
1467 : {
1468 232 : poLS->closeRings();
1469 :
1470 232 : OGRPoint* poCenter = NULL;
1471 :
1472 232 : if (nPolys == 0 &&
1473 : poLS &&
1474 : poLS->getNumPoints() == 5)
1475 : {
1476 : /* Recognize points as outputed by GDAL (ogr-sym-3 : circle (filled)) */
1477 152 : poCenter = PDFGetCircleCenter(poLS);
1478 :
1479 : /* Recognize points as outputed by GDAL (ogr-sym-5: square (filled)) */
1480 152 : if (poCenter == NULL)
1481 140 : poCenter = PDFGetSquareCenter(poLS);
1482 :
1483 : /* ESRI points */
1484 152 : if (poCenter == NULL &&
1485 : oCoords.size() == 14 &&
1486 : poLS->getY(0) == poLS->getY(1) &&
1487 : poLS->getX(1) == poLS->getX(2) &&
1488 : poLS->getY(2) == poLS->getY(3) &&
1489 : poLS->getX(3) == poLS->getX(0))
1490 : {
1491 : poCenter = new OGRPoint((poLS->getX(0) + poLS->getX(1)) / 2,
1492 72 : (poLS->getY(0) + poLS->getY(2)) / 2);
1493 : }
1494 : }
1495 : /* Recognize points as outputed by GDAL (ogr-sym-7: triangle (filled)) */
1496 80 : else if (nPolys == 0 &&
1497 : poLS &&
1498 : poLS->getNumPoints() == 4)
1499 : {
1500 3 : poCenter = PDFGetTriangleCenter(poLS);
1501 : }
1502 : /* Recognize points as outputed by GDAL (ogr-sym-9: star (filled)) */
1503 77 : else if (nPolys == 0 &&
1504 : poLS &&
1505 : poLS->getNumPoints() == 11)
1506 : {
1507 4 : poCenter = PDFGetStarCenter(poLS);
1508 : }
1509 :
1510 232 : if (poCenter)
1511 : {
1512 93 : poGeom = poCenter;
1513 93 : break;
1514 : }
1515 :
1516 139 : if (poLS->getNumPoints() >= 3)
1517 : {
1518 139 : OGRPolygon* poPoly = new OGRPolygon();
1519 139 : poPoly->addRingDirectly(poLS);
1520 139 : poLS = NULL;
1521 :
1522 139 : papoPoly = (OGRGeometry**) CPLRealloc(papoPoly, (nPolys + 1) * sizeof(OGRGeometry*));
1523 139 : papoPoly[nPolys ++] = poPoly;
1524 : }
1525 : else
1526 : {
1527 0 : delete poLS;
1528 0 : poLS = NULL;
1529 : }
1530 : }
1531 : }
1532 : else
1533 : {
1534 1296 : if (poLS)
1535 : {
1536 : double X, Y;
1537 1296 : PDFCoordsToSRSCoords(oCoords[i], oCoords[i+1], X, Y);
1538 :
1539 1296 : poLS->addPoint(X, Y);
1540 : }
1541 : }
1542 : }
1543 :
1544 227 : delete poLS;
1545 :
1546 : int bIsValidGeometry;
1547 233 : if (nPolys == 2 &&
1548 3 : ((OGRPolygon*)papoPoly[0])->getNumInteriorRings() == 0 &&
1549 3 : ((OGRPolygon*)papoPoly[1])->getNumInteriorRings() == 0)
1550 : {
1551 3 : OGRLinearRing* poRing0 = ((OGRPolygon*)papoPoly[0])->getExteriorRing();
1552 3 : OGRLinearRing* poRing1 = ((OGRPolygon*)papoPoly[1])->getExteriorRing();
1553 3 : if (poRing0->getNumPoints() == poRing1->getNumPoints())
1554 : {
1555 3 : int bSameRing = TRUE;
1556 3 : for(int i=0;i<poRing0->getNumPoints();i++)
1557 : {
1558 3 : if (poRing0->getX(i) != poRing1->getX(i))
1559 : {
1560 3 : bSameRing = FALSE;
1561 3 : break;
1562 : }
1563 0 : if (poRing0->getY(i) != poRing1->getY(i))
1564 : {
1565 0 : bSameRing = FALSE;
1566 0 : break;
1567 : }
1568 : }
1569 :
1570 : /* Just keep on ring if they are identical */
1571 3 : if (bSameRing)
1572 : {
1573 0 : delete papoPoly[1];
1574 0 : nPolys = 1;
1575 : }
1576 : }
1577 : }
1578 227 : if (nPolys)
1579 : {
1580 : poGeom = OGRGeometryFactory::organizePolygons(
1581 134 : papoPoly, nPolys, &bIsValidGeometry, NULL);
1582 : }
1583 227 : CPLFree(papoPoly);
1584 : }
1585 :
1586 421 : return poGeom;
1587 : }
1588 :
1589 : /************************************************************************/
1590 : /* ExploreContents() */
1591 : /************************************************************************/
1592 :
1593 7 : void OGRPDFDataSource::ExploreContents(GDALPDFObject* poObj,
1594 : GDALPDFObject* poResources)
1595 : {
1596 7 : std::map<CPLString, OGRPDFLayer*> oMapPropertyToLayer;
1597 :
1598 7 : if (poObj->GetType() == PDFObjectType_Array)
1599 : {
1600 1 : GDALPDFArray* poArray = poObj->GetArray();
1601 4 : for(int i=0;i<poArray->GetLength();i++)
1602 3 : ExploreContents(poArray->Get(i), poResources);
1603 : }
1604 :
1605 7 : if (poObj->GetType() != PDFObjectType_Dictionary)
1606 : return;
1607 :
1608 6 : GDALPDFStream* poStream = poObj->GetStream();
1609 6 : if (!poStream)
1610 : return;
1611 :
1612 6 : char* pszStr = poStream->GetBytes();
1613 6 : if (!pszStr)
1614 : return;
1615 :
1616 6 : const char* pszMCID = (const char*) pszStr;
1617 405 : while((pszMCID = strstr(pszMCID, "/MCID")) != NULL)
1618 : {
1619 393 : const char* pszBDC = strstr(pszMCID, "BDC");
1620 393 : if (pszBDC)
1621 : {
1622 : /* Hack for http://www.avenza.com/sites/default/files/spatialpdf/US_County_Populations.pdf */
1623 : /* FIXME: that logic is too fragile. */
1624 393 : const char* pszStartParsing = pszBDC;
1625 393 : const char* pszAfterBDC = pszBDC + 3;
1626 393 : int bMatchQ = FALSE;
1627 1179 : while (pszAfterBDC[0] == ' ' || pszAfterBDC[0] == '\r' || pszAfterBDC[0] == '\n')
1628 393 : pszAfterBDC ++;
1629 393 : if (strncmp(pszAfterBDC, "0 0 m", 5) == 0)
1630 : {
1631 0 : const char* pszLastq = pszBDC;
1632 0 : while(pszLastq > pszStr && *pszLastq != 'q')
1633 0 : pszLastq --;
1634 :
1635 0 : if (pszLastq > pszStr && *pszLastq == 'q' &&
1636 0 : (pszLastq[-1] == ' ' || pszLastq[-1] == '\r' || pszLastq[-1] == '\n') &&
1637 0 : (pszLastq[1] == ' ' || pszLastq[1] == '\r' || pszLastq[1] == '\n'))
1638 : {
1639 0 : pszStartParsing = pszLastq;
1640 0 : bMatchQ = TRUE;
1641 : }
1642 : }
1643 :
1644 393 : int nMCID = atoi(pszMCID + 6);
1645 393 : if (GetGeometryFromMCID(nMCID) == NULL)
1646 : {
1647 : OGRGeometry* poGeom = ParseContent(pszStartParsing, poResources,
1648 391 : !bMatchQ, bMatchQ, oMapPropertyToLayer, NULL);
1649 391 : if( poGeom != NULL )
1650 : {
1651 : /* Save geometry in map */
1652 391 : oMapMCID[nMCID] = poGeom;
1653 : }
1654 : }
1655 : }
1656 393 : pszMCID += 5;
1657 : }
1658 6 : CPLFree(pszStr);
1659 : }
1660 :
1661 : /************************************************************************/
1662 : /* PDFSanitizeLayerName() */
1663 : /************************************************************************/
1664 :
1665 : static
1666 4 : CPLString PDFSanitizeLayerName(const char* pszName)
1667 : {
1668 4 : CPLString osName;
1669 46 : for(int i=0; pszName[i] != '\0'; i++)
1670 : {
1671 43 : if (pszName[i] == ' ' || pszName[i] == '.' || pszName[i] == ',')
1672 1 : osName += "_";
1673 : else
1674 41 : osName += pszName[i];
1675 : }
1676 0 : return osName;
1677 : }
1678 :
1679 : /************************************************************************/
1680 : /* ExploreContentsNonStructured() */
1681 : /************************************************************************/
1682 :
1683 2 : void OGRPDFDataSource::ExploreContentsNonStructuredInternal(GDALPDFObject* poContents,
1684 : GDALPDFObject* poResources,
1685 : std::map<CPLString, OGRPDFLayer*>& oMapPropertyToLayer)
1686 : {
1687 2 : if (poContents->GetType() == PDFObjectType_Array)
1688 : {
1689 0 : GDALPDFArray* poArray = poContents->GetArray();
1690 0 : char* pszConcatStr = NULL;
1691 0 : int nConcatLen = 0;
1692 0 : for(int i=0;i<poArray->GetLength();i++)
1693 : {
1694 0 : GDALPDFObject* poObj = poArray->Get(i);
1695 0 : if( poObj->GetType() != PDFObjectType_Dictionary)
1696 0 : break;
1697 0 : GDALPDFStream* poStream = poObj->GetStream();
1698 0 : if (!poStream)
1699 0 : break;
1700 0 : char* pszStr = poStream->GetBytes();
1701 0 : if (!pszStr)
1702 0 : break;
1703 0 : int nLen = (int)strlen(pszStr);
1704 0 : char* pszConcatStrNew = (char*)CPLRealloc(pszConcatStr, nConcatLen + nLen + 1);
1705 0 : if( pszConcatStrNew == NULL )
1706 : {
1707 0 : CPLFree(pszStr);
1708 0 : break;
1709 : }
1710 0 : pszConcatStr = pszConcatStrNew;
1711 0 : memcpy(pszConcatStr + nConcatLen, pszStr, nLen+1);
1712 0 : nConcatLen += nLen;
1713 0 : CPLFree(pszStr);
1714 : }
1715 0 : if( pszConcatStr )
1716 0 : ParseContent(pszConcatStr, poResources, FALSE, FALSE, oMapPropertyToLayer, NULL);
1717 0 : CPLFree(pszConcatStr);
1718 0 : return;
1719 : }
1720 :
1721 2 : if (poContents->GetType() != PDFObjectType_Dictionary)
1722 0 : return;
1723 :
1724 2 : GDALPDFStream* poStream = poContents->GetStream();
1725 2 : if (!poStream)
1726 0 : return;
1727 :
1728 2 : char* pszStr = poStream->GetBytes();
1729 2 : if( !pszStr )
1730 0 : return;
1731 2 : ParseContent(pszStr, poResources, FALSE, FALSE, oMapPropertyToLayer, NULL);
1732 2 : CPLFree(pszStr);
1733 : }
1734 :
1735 2 : void OGRPDFDataSource::ExploreContentsNonStructured(GDALPDFObject* poContents,
1736 : GDALPDFObject* poResources)
1737 : {
1738 2 : std::map<CPLString, OGRPDFLayer*> oMapPropertyToLayer;
1739 4 : if (poResources != NULL &&
1740 2 : poResources->GetType() == PDFObjectType_Dictionary)
1741 : {
1742 : GDALPDFObject* poProperties =
1743 2 : poResources->GetDictionary()->Get("Properties");
1744 4 : if (poProperties != NULL &&
1745 2 : poProperties->GetType() == PDFObjectType_Dictionary)
1746 : {
1747 2 : CPLAssert(poGDAL_DS != NULL);
1748 2 : char** papszLayersWithRef = poGDAL_DS->GetMetadata("LAYERS_WITH_REF");
1749 2 : char** papszIter = papszLayersWithRef;
1750 2 : std::map< std::pair<int, int>, OGRPDFLayer *> oMapNumGenToLayer;
1751 6 : while(papszIter && *papszIter)
1752 : {
1753 4 : char** papszTokens = CSLTokenizeString(*papszIter);
1754 :
1755 4 : if( CSLCount(papszTokens) != 3 ) {
1756 0 : CSLDestroy(papszTokens);
1757 0 : CPLDebug("PDF", "Ignore '%s', unparsable.", *papszIter);
1758 0 : papszIter ++;
1759 0 : continue;
1760 : }
1761 :
1762 4 : const char* pszLayerName = papszTokens[0];
1763 4 : int nNum = atoi(papszTokens[1]);
1764 4 : int nGen = atoi(papszTokens[2]);
1765 :
1766 4 : CPLString osSanitizedName(PDFSanitizeLayerName(pszLayerName));
1767 :
1768 4 : OGRPDFLayer* poLayer = (OGRPDFLayer*) GetLayerByName(osSanitizedName.c_str());
1769 4 : if (poLayer == NULL)
1770 : {
1771 4 : const char* pszWKT = poGDAL_DS->GetProjectionRef();
1772 4 : OGRSpatialReference* poSRS = NULL;
1773 4 : if (pszWKT && pszWKT[0] != '\0')
1774 : {
1775 4 : poSRS = new OGRSpatialReference();
1776 4 : poSRS->importFromWkt((char**) &pszWKT);
1777 : }
1778 :
1779 : poLayer =
1780 4 : new OGRPDFLayer(this, osSanitizedName.c_str(), poSRS, wkbUnknown);
1781 8 : delete poSRS;
1782 :
1783 : papoLayers = (OGRLayer**)
1784 4 : CPLRealloc(papoLayers, (nLayers + 1) * sizeof(OGRLayer*));
1785 4 : papoLayers[nLayers] = poLayer;
1786 4 : nLayers ++;
1787 : }
1788 :
1789 4 : oMapNumGenToLayer[ std::pair<int,int>(nNum, nGen) ] = poLayer;
1790 :
1791 4 : CSLDestroy(papszTokens);
1792 4 : papszIter ++;
1793 : }
1794 :
1795 : std::map<CPLString, GDALPDFObject*>& oMap =
1796 2 : poProperties->GetDictionary()->GetValues();
1797 2 : std::map<CPLString, GDALPDFObject*>::iterator oIter = oMap.begin();
1798 2 : std::map<CPLString, GDALPDFObject*>::iterator oEnd = oMap.end();
1799 :
1800 6 : for(; oIter != oEnd; ++oIter)
1801 : {
1802 4 : const char* pszKey = oIter->first.c_str();
1803 4 : GDALPDFObject* poObj = oIter->second;
1804 4 : if( poObj->GetRefNum() != 0 )
1805 : {
1806 : std::map< std::pair<int, int>, OGRPDFLayer *>::iterator
1807 : oIterNumGenToLayer = oMapNumGenToLayer.find(
1808 4 : std::pair<int,int>(poObj->GetRefNum(), poObj->GetRefGen()) );
1809 4 : if( oIterNumGenToLayer != oMapNumGenToLayer.end() )
1810 : {
1811 4 : oMapPropertyToLayer[pszKey] = oIterNumGenToLayer->second;
1812 : }
1813 : }
1814 2 : }
1815 : }
1816 : }
1817 :
1818 2 : if( nLayers == 0 )
1819 : return;
1820 :
1821 : ExploreContentsNonStructuredInternal(poContents,
1822 : poResources,
1823 2 : oMapPropertyToLayer);
1824 :
1825 : /* Remove empty layers */
1826 2 : int i = 0;
1827 8 : while(i < nLayers)
1828 : {
1829 4 : if (papoLayers[i]->GetFeatureCount() == 0)
1830 : {
1831 2 : delete papoLayers[i];
1832 2 : if (i < nLayers - 1)
1833 : {
1834 : memmove(papoLayers + i, papoLayers + i + 1,
1835 0 : (nLayers - 1 - i) * sizeof(OGRPDFLayer*));
1836 : }
1837 2 : nLayers --;
1838 : }
1839 : else
1840 2 : i ++;
1841 0 : }
1842 : }
1843 :
1844 : /************************************************************************/
1845 : /* Open() */
1846 : /************************************************************************/
1847 :
1848 6 : int OGRPDFDataSource::Open( const char * pszName)
1849 : {
1850 6 : this->pszName = CPLStrdup(pszName);
1851 :
1852 6 : poGDAL_DS = GDALPDFOpen(pszName, GA_ReadOnly);
1853 6 : if (poGDAL_DS == NULL)
1854 0 : return FALSE;
1855 :
1856 6 : const char* pszPageObj = poGDAL_DS->GetMetadataItem("PDF_PAGE_OBJECT");
1857 6 : if (pszPageObj)
1858 6 : sscanf(pszPageObj, "%p", &poPageObj);
1859 6 : if (poPageObj == NULL || poPageObj->GetType() != PDFObjectType_Dictionary)
1860 0 : return FALSE;
1861 :
1862 6 : GDALPDFObject* poMediaBox = poPageObj->GetDictionary()->Get("MediaBox");
1863 18 : if (poMediaBox == NULL || poMediaBox->GetType() != PDFObjectType_Array ||
1864 12 : poMediaBox->GetArray()->GetLength() != 4)
1865 0 : return FALSE;
1866 :
1867 6 : if (poMediaBox->GetArray()->Get(2)->GetType() == PDFObjectType_Real)
1868 1 : dfPageWidth = poMediaBox->GetArray()->Get(2)->GetReal();
1869 5 : else if (poMediaBox->GetArray()->Get(2)->GetType() == PDFObjectType_Int)
1870 5 : dfPageWidth = poMediaBox->GetArray()->Get(2)->GetInt();
1871 : else
1872 0 : return FALSE;
1873 :
1874 6 : if (poMediaBox->GetArray()->Get(3)->GetType() == PDFObjectType_Real)
1875 1 : dfPageHeight = poMediaBox->GetArray()->Get(3)->GetReal();
1876 5 : else if (poMediaBox->GetArray()->Get(3)->GetType() == PDFObjectType_Int)
1877 5 : dfPageHeight = poMediaBox->GetArray()->Get(3)->GetInt();
1878 : else
1879 0 : return FALSE;
1880 :
1881 6 : GDALPDFObject* poContents = poPageObj->GetDictionary()->Get("Contents");
1882 6 : if (poContents == NULL)
1883 0 : return FALSE;
1884 :
1885 7 : if (poContents->GetType() != PDFObjectType_Dictionary &&
1886 1 : poContents->GetType() != PDFObjectType_Array)
1887 0 : return FALSE;
1888 :
1889 6 : GDALPDFObject* poResources = poPageObj->GetDictionary()->Get("Resources");
1890 6 : if (poResources == NULL || poResources->GetType() != PDFObjectType_Dictionary)
1891 0 : return FALSE;
1892 :
1893 6 : const char* pszCatalog = poGDAL_DS->GetMetadataItem("PDF_CATALOG_OBJECT");
1894 6 : if (pszCatalog)
1895 6 : sscanf(pszCatalog, "%p", &poCatalogObj);
1896 6 : if (poCatalogObj == NULL || poCatalogObj->GetType() != PDFObjectType_Dictionary)
1897 0 : return FALSE;
1898 :
1899 6 : nXSize = poGDAL_DS->GetRasterXSize();
1900 6 : nYSize = poGDAL_DS->GetRasterYSize();
1901 6 : poGDAL_DS->GetGeoTransform(adfGeoTransform);
1902 :
1903 :
1904 6 : GDALPDFObject* poStructTreeRoot = poCatalogObj->GetDictionary()->Get("StructTreeRoot");
1905 10 : if (CSLTestBoolean(CPLGetConfigOption("OGR_PDF_READ_NON_STRUCTURED", "NO")) ||
1906 : poStructTreeRoot == NULL ||
1907 4 : poStructTreeRoot->GetType() != PDFObjectType_Dictionary)
1908 : {
1909 2 : ExploreContentsNonStructured(poContents, poResources);
1910 : }
1911 : else
1912 : {
1913 4 : ExploreContents(poContents, poResources);
1914 4 : ExploreTree(poStructTreeRoot, 0);
1915 : }
1916 :
1917 6 : CleanupIntermediateResources();
1918 :
1919 6 : int bEmptyDS = TRUE;
1920 6 : for(int i=0;i<nLayers;i++)
1921 : {
1922 6 : if (papoLayers[i]->GetFeatureCount() != 0)
1923 : {
1924 6 : bEmptyDS = FALSE;
1925 6 : break;
1926 : }
1927 : }
1928 6 : if (bEmptyDS)
1929 0 : return FALSE;
1930 :
1931 6 : return TRUE;
1932 : }
1933 :
1934 : /************************************************************************/
1935 : /* Create() */
1936 : /************************************************************************/
1937 :
1938 2 : int OGRPDFDataSource::Create( const char * pszName, char **papszOptions )
1939 : {
1940 2 : this->pszName = CPLStrdup(pszName);
1941 2 : this->papszOptions = CSLDuplicate(papszOptions);
1942 2 : bWritable = TRUE;
1943 :
1944 2 : return TRUE;
1945 : }
1946 :
1947 : /************************************************************************/
1948 : /* CreateLayer() */
1949 : /************************************************************************/
1950 :
1951 : OGRLayer *
1952 2 : OGRPDFDataSource::CreateLayer( const char * pszLayerName,
1953 : OGRSpatialReference *poSRS,
1954 : OGRwkbGeometryType eType,
1955 : char ** papszOptions )
1956 :
1957 : {
1958 : /* -------------------------------------------------------------------- */
1959 : /* Create the layer object. */
1960 : /* -------------------------------------------------------------------- */
1961 2 : OGRLayer* poLayer = new OGRPDFLayer(this, pszLayerName, poSRS, eType);
1962 :
1963 2 : papoLayers = (OGRLayer**)CPLRealloc(papoLayers, (nLayers + 1) * sizeof(OGRLayer*));
1964 2 : papoLayers[nLayers] = poLayer;
1965 2 : nLayers ++;
1966 :
1967 2 : return poLayer;
1968 : }
1969 :
1970 : /************************************************************************/
1971 : /* SyncToDisk() */
1972 : /************************************************************************/
1973 :
1974 8 : OGRErr OGRPDFDataSource::SyncToDisk()
1975 : {
1976 8 : if (nLayers == 0 || !bModified || !bWritable)
1977 6 : return OGRERR_NONE;
1978 :
1979 2 : bModified = FALSE;
1980 :
1981 2 : OGREnvelope sGlobalExtent;
1982 2 : int bHasExtent = FALSE;
1983 4 : for(int i=0;i<nLayers;i++)
1984 : {
1985 2 : OGREnvelope sExtent;
1986 2 : if (papoLayers[i]->GetExtent(&sExtent) == OGRERR_NONE)
1987 : {
1988 2 : bHasExtent = TRUE;
1989 2 : sGlobalExtent.Merge(sExtent);
1990 : }
1991 : }
1992 2 : if (!bHasExtent ||
1993 : sGlobalExtent.MinX == sGlobalExtent.MaxX ||
1994 : sGlobalExtent.MinY == sGlobalExtent.MaxY)
1995 : {
1996 : CPLError(CE_Failure, CPLE_AppDefined,
1997 0 : "Cannot compute spatial extent of features");
1998 0 : return OGRERR_FAILURE;
1999 : }
2000 :
2001 2 : PDFCompressMethod eStreamCompressMethod = COMPRESS_DEFLATE;
2002 2 : const char* pszStreamCompressMethod = CSLFetchNameValue(papszOptions, "STREAM_COMPRESS");
2003 2 : if (pszStreamCompressMethod)
2004 : {
2005 0 : if( EQUAL(pszStreamCompressMethod, "NONE") )
2006 0 : eStreamCompressMethod = COMPRESS_NONE;
2007 0 : else if( EQUAL(pszStreamCompressMethod, "DEFLATE") )
2008 0 : eStreamCompressMethod = COMPRESS_DEFLATE;
2009 : else
2010 : {
2011 : CPLError( CE_Warning, CPLE_NotSupported,
2012 0 : "Unsupported value for STREAM_COMPRESS.");
2013 : }
2014 : }
2015 :
2016 : const char* pszGEO_ENCODING =
2017 2 : CSLFetchNameValueDef(papszOptions, "GEO_ENCODING", "ISO32000");
2018 :
2019 2 : double dfDPI = atof(CSLFetchNameValueDef(papszOptions, "DPI", "72"));
2020 2 : if (dfDPI < 72.0)
2021 0 : dfDPI = 72.0;
2022 :
2023 2 : const char* pszNEATLINE = CSLFetchNameValue(papszOptions, "NEATLINE");
2024 :
2025 2 : int nMargin = atoi(CSLFetchNameValueDef(papszOptions, "MARGIN", "0"));
2026 :
2027 : PDFMargins sMargins;
2028 2 : sMargins.nLeft = nMargin;
2029 2 : sMargins.nRight = nMargin;
2030 2 : sMargins.nTop = nMargin;
2031 2 : sMargins.nBottom = nMargin;
2032 :
2033 2 : const char* pszLeftMargin = CSLFetchNameValue(papszOptions, "LEFT_MARGIN");
2034 2 : if (pszLeftMargin) sMargins.nLeft = atoi(pszLeftMargin);
2035 :
2036 2 : const char* pszRightMargin = CSLFetchNameValue(papszOptions, "RIGHT_MARGIN");
2037 2 : if (pszRightMargin) sMargins.nRight = atoi(pszRightMargin);
2038 :
2039 2 : const char* pszTopMargin = CSLFetchNameValue(papszOptions, "TOP_MARGIN");
2040 2 : if (pszTopMargin) sMargins.nTop = atoi(pszTopMargin);
2041 :
2042 2 : const char* pszBottomMargin = CSLFetchNameValue(papszOptions, "BOTTOM_MARGIN");
2043 2 : if (pszBottomMargin) sMargins.nBottom = atoi(pszBottomMargin);
2044 :
2045 2 : const char* pszExtraImages = CSLFetchNameValue(papszOptions, "EXTRA_IMAGES");
2046 2 : const char* pszExtraStream = CSLFetchNameValue(papszOptions, "EXTRA_STREAM");
2047 2 : const char* pszExtraLayerName = CSLFetchNameValue(papszOptions, "EXTRA_LAYER_NAME");
2048 :
2049 2 : const char* pszOGRDisplayField = CSLFetchNameValue(papszOptions, "OGR_DISPLAY_FIELD");
2050 2 : const char* pszOGRDisplayLayerNames = CSLFetchNameValue(papszOptions, "OGR_DISPLAY_LAYER_NAMES");
2051 2 : int bWriteOGRAttributes = CSLFetchBoolean(papszOptions, "OGR_WRITE_ATTRIBUTES", TRUE);
2052 2 : const char* pszOGRLinkField = CSLFetchNameValue(papszOptions, "OGR_LINK_FIELD");
2053 :
2054 2 : const char* pszOffLayers = CSLFetchNameValue(papszOptions, "OFF_LAYERS");
2055 2 : const char* pszExclusiveLayers = CSLFetchNameValue(papszOptions, "EXCLUSIVE_LAYERS");
2056 :
2057 2 : const char* pszJavascript = CSLFetchNameValue(papszOptions, "JAVASCRIPT");
2058 2 : const char* pszJavascriptFile = CSLFetchNameValue(papszOptions, "JAVASCRIPT_FILE");
2059 :
2060 : /* -------------------------------------------------------------------- */
2061 : /* Create file. */
2062 : /* -------------------------------------------------------------------- */
2063 2 : VSILFILE* fp = VSIFOpenL(pszName, "wb");
2064 2 : if( fp == NULL )
2065 : {
2066 : CPLError( CE_Failure, CPLE_OpenFailed,
2067 : "Unable to create PDF file %s.\n",
2068 0 : pszName );
2069 0 : return OGRERR_FAILURE;
2070 : }
2071 :
2072 2 : GDALPDFWriter oWriter(fp);
2073 :
2074 2 : double dfRatio = (sGlobalExtent.MaxY - sGlobalExtent.MinY) / (sGlobalExtent.MaxX - sGlobalExtent.MinX);
2075 :
2076 : int nWidth, nHeight;
2077 :
2078 2 : if (dfRatio < 1)
2079 : {
2080 0 : nWidth = 1024;
2081 0 : nHeight = nWidth * dfRatio;
2082 : }
2083 : else
2084 : {
2085 2 : nHeight = 1024;
2086 2 : nWidth = nHeight / dfRatio;
2087 : }
2088 :
2089 2 : GDALDataset* poSrcDS = MEMDataset::Create( "MEM:::", nWidth, nHeight, 0, GDT_Byte, NULL );
2090 :
2091 : double adfGeoTransform[6];
2092 2 : adfGeoTransform[0] = sGlobalExtent.MinX;
2093 2 : adfGeoTransform[1] = (sGlobalExtent.MaxX - sGlobalExtent.MinX) / nWidth;
2094 2 : adfGeoTransform[2] = 0;
2095 2 : adfGeoTransform[3] = sGlobalExtent.MaxY;
2096 2 : adfGeoTransform[4] = 0;
2097 2 : adfGeoTransform[5] = - (sGlobalExtent.MaxY - sGlobalExtent.MinY) / nHeight;
2098 :
2099 2 : poSrcDS->SetGeoTransform(adfGeoTransform);
2100 :
2101 2 : OGRSpatialReference* poSRS = papoLayers[0]->GetSpatialRef();
2102 2 : if (poSRS)
2103 : {
2104 2 : char* pszWKT = NULL;
2105 2 : poSRS->exportToWkt(&pszWKT);
2106 2 : poSrcDS->SetProjection(pszWKT);
2107 2 : CPLFree(pszWKT);
2108 : }
2109 :
2110 2 : oWriter.SetInfo(poSrcDS, papszOptions);
2111 :
2112 : oWriter.StartPage(poSrcDS,
2113 : dfDPI,
2114 : pszGEO_ENCODING,
2115 : pszNEATLINE,
2116 : &sMargins,
2117 : eStreamCompressMethod,
2118 2 : bWriteOGRAttributes);
2119 :
2120 2 : int iObj = 0;
2121 :
2122 2 : char** papszLayerNames = CSLTokenizeString2(pszOGRDisplayLayerNames,",",0);
2123 :
2124 4 : for(int i=0;i<nLayers;i++)
2125 : {
2126 2 : CPLString osLayerName;
2127 2 : if (CSLCount(papszLayerNames) < nLayers)
2128 2 : osLayerName = papoLayers[i]->GetName();
2129 : else
2130 0 : osLayerName = papszLayerNames[i];
2131 :
2132 : oWriter.WriteOGRLayer((OGRDataSourceH)this,
2133 : i,
2134 : pszOGRDisplayField,
2135 : pszOGRLinkField,
2136 : osLayerName,
2137 : bWriteOGRAttributes,
2138 2 : iObj);
2139 : }
2140 :
2141 2 : CSLDestroy(papszLayerNames);
2142 :
2143 : oWriter.EndPage(pszExtraImages,
2144 : pszExtraStream,
2145 : pszExtraLayerName,
2146 : pszOffLayers,
2147 2 : pszExclusiveLayers);
2148 :
2149 2 : if (pszJavascript)
2150 0 : oWriter.WriteJavascript(pszJavascript);
2151 2 : else if (pszJavascriptFile)
2152 0 : oWriter.WriteJavascriptFile(pszJavascriptFile);
2153 :
2154 2 : oWriter.Close();
2155 :
2156 2 : delete poSrcDS;
2157 :
2158 2 : return OGRERR_NONE;
2159 : }
|