LCOV - code coverage report
Current view: directory - frmts/pdf - pdfdataset.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 928 457 49.2 %
Date: 2011-12-18 Functions: 31 19 61.3 %

       1                 : /******************************************************************************
       2                 :  * $Id: pdfdataset.cpp 23033 2011-09-03 18:46:11Z rouault $
       3                 :  *
       4                 :  * Project:  PDF driver
       5                 :  * Purpose:  GDALDataset driver for PDF dataset.
       6                 :  * Author:   Even Rouault, <even dot rouault at mines dash paris dot org>
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 2010, Even Rouault
      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                 : /* hack for PDF driver and poppler >= 0.15.0 that defines incompatible "typedef bool GBool" */
      31                 : /* in include/poppler/goo/gtypes.h with the one defined in cpl_port.h */
      32                 : #define CPL_GBOOL_DEFINED
      33                 : 
      34                 : #include "cpl_vsi_virtual.h"
      35                 : #include "cpl_string.h"
      36                 : #include "gdal_pam.h"
      37                 : #include "ogr_spatialref.h"
      38                 : #include "ogr_geometry.h"
      39                 : 
      40                 : #ifdef USE_POPPLER
      41                 : #include "pdfio.h"
      42                 : #endif
      43                 : 
      44                 : #include "pdfobject.h"
      45                 : 
      46                 : /* g++ -fPIC -g -Wall frmts/pdf/pdfdataset.cpp -shared -o gdal_PDF.so -Iport -Igcore -Iogr -L. -lgdal -lpoppler -I/usr/include/poppler */
      47                 : 
      48                 : CPL_CVSID("$Id: pdfdataset.cpp 23033 2011-09-03 18:46:11Z rouault $");
      49                 : 
      50                 : CPL_C_START
      51                 : void    GDALRegister_PDF(void);
      52                 : CPL_C_END
      53                 : 
      54                 : #ifdef USE_POPPLER
      55                 : 
      56                 : /************************************************************************/
      57                 : /*                          ObjectAutoFree                              */
      58                 : /************************************************************************/
      59                 : 
      60                 : class ObjectAutoFree : public Object
      61                 : {
      62                 : public:
      63               4 :     ObjectAutoFree() {}
      64               4 :     ~ObjectAutoFree() { free(); }
      65                 : };
      66                 : 
      67                 : #endif
      68                 : 
      69                 : /************************************************************************/
      70                 : /*                         Dump routines                                */
      71                 : /************************************************************************/
      72                 : 
      73                 : static void DumpObject(FILE* f, GDALPDFObject* poObj, int nDepth = 0, int nDepthLimit = -1);
      74                 : static void DumpDict(FILE* f, GDALPDFDictionary* poDict, int nDepth = 0, int nDepthLimit = -1);
      75                 : static void DumpArray(FILE* f, GDALPDFArray* poArray, int nDepth = 0, int nDepthLimit = -1);
      76                 : static void DumpObjectSimplified(FILE* f, GDALPDFObject* poObj);
      77                 : 
      78               0 : static void DumpArray(FILE* f, GDALPDFArray* poArray, int nDepth, int nDepthLimit)
      79                 : {
      80               0 :     if (nDepthLimit >= 0 && nDepth > nDepthLimit)
      81               0 :         return;
      82                 : 
      83               0 :     int nLength = poArray->GetLength();
      84                 :     int i;
      85               0 :     CPLString osIndent;
      86               0 :     for(i=0;i<nDepth;i++)
      87               0 :         osIndent += " ";
      88               0 :     for(i=0;i<nLength;i++)
      89                 :     {
      90               0 :         fprintf(f, "%sItem[%d]:", osIndent.c_str(), i);
      91               0 :         GDALPDFObject* poObj = NULL;
      92               0 :         if ((poObj = poArray->Get(i)) != NULL)
      93                 :         {
      94               0 :             if (poObj->GetType() == PDFObjectType_String ||
      95               0 :                 poObj->GetType() == PDFObjectType_Int ||
      96               0 :                 poObj->GetType() == PDFObjectType_Real ||
      97               0 :                 poObj->GetType() == PDFObjectType_Name)
      98                 :             {
      99               0 :                 fprintf(f, " ");
     100               0 :                 DumpObjectSimplified(f, poObj);
     101               0 :                 fprintf(f, "\n");
     102                 :             }
     103                 :             else
     104                 :             {
     105               0 :                 fprintf(f, "\n");
     106               0 :                 DumpObject(f, poObj, nDepth+1, nDepthLimit);
     107                 :             }
     108                 :         }
     109               0 :     }
     110                 : }
     111                 : 
     112               0 : static void DumpObjectSimplified(FILE* f, GDALPDFObject* poObj)
     113                 : {
     114               0 :     switch(poObj->GetType())
     115                 :     {
     116                 :         case PDFObjectType_String:
     117               0 :             fprintf(f, "%s (string)", poObj->GetString().c_str());
     118               0 :             break;
     119                 : 
     120                 :         case PDFObjectType_Int:
     121               0 :             fprintf(f, "%d (int)", poObj->GetInt());
     122               0 :             break;
     123                 : 
     124                 :         case PDFObjectType_Real:
     125               0 :             fprintf(f, "%f (real)", poObj->GetReal());
     126               0 :             break;
     127                 : 
     128                 :         case PDFObjectType_Name:
     129               0 :             fprintf(f, "%s (name)", poObj->GetName().c_str());
     130                 :             break;
     131                 : 
     132                 :         default:
     133                 :             break;
     134                 :     }
     135               0 : }
     136                 : 
     137               0 : static void DumpObject(FILE* f, GDALPDFObject* poObj, int nDepth, int nDepthLimit)
     138                 : {
     139               0 :     if (nDepthLimit >= 0 && nDepth > nDepthLimit)
     140               0 :         return;
     141                 : 
     142                 :     int i;
     143               0 :     CPLString osIndent;
     144               0 :     for(i=0;i<nDepth;i++)
     145               0 :         osIndent += " ";
     146               0 :     fprintf(f, "%sType = %s\n", osIndent.c_str(), poObj->GetTypeName());
     147               0 :     switch(poObj->GetType())
     148                 :     {
     149                 :         case PDFObjectType_Array:
     150               0 :             DumpArray(f, poObj->GetArray(), nDepth+1, nDepthLimit);
     151               0 :             break;
     152                 : 
     153                 :         case PDFObjectType_Dictionary:
     154               0 :             DumpDict(f, poObj->GetDictionary(), nDepth+1, nDepthLimit);
     155               0 :             break;
     156                 : 
     157                 :         case PDFObjectType_String:
     158                 :         case PDFObjectType_Int:
     159                 :         case PDFObjectType_Real:
     160                 :         case PDFObjectType_Name:
     161               0 :             fprintf(f, "%s", osIndent.c_str());
     162               0 :             DumpObjectSimplified(f, poObj);
     163               0 :             fprintf(f, "\n");
     164                 :             break;
     165                 : 
     166                 :         default:
     167                 :             break;
     168               0 :     }
     169                 : }
     170                 : 
     171               0 : static void DumpDict(FILE* f, GDALPDFDictionary* poDict, int nDepth, int nDepthLimit)
     172                 : {
     173               0 :     if (nDepthLimit >= 0 && nDepth > nDepthLimit)
     174               0 :         return;
     175                 : 
     176               0 :     std::map<CPLString, GDALPDFObject*>& oMap = poDict->GetValues();
     177               0 :     std::map<CPLString, GDALPDFObject*>::iterator oIter = oMap.begin();
     178               0 :     std::map<CPLString, GDALPDFObject*>::iterator oEnd = oMap.end();
     179                 :     int i;
     180               0 :     CPLString osIndent;
     181               0 :     for(i=0;i<nDepth;i++)
     182               0 :         osIndent += " ";
     183               0 :     for(i=0;oIter != oEnd;++oIter, i++)
     184                 :     {
     185               0 :         const char* pszKey = oIter->first.c_str();
     186               0 :         fprintf(f, "%sItem[%d] : %s", osIndent.c_str(), i, pszKey);
     187               0 :         if (strcmp(pszKey, "Parent") == 0)
     188                 :         {
     189               0 :             fprintf(f, "\n");
     190               0 :             continue;
     191                 :         }
     192               0 :         GDALPDFObject* poObj = oIter->second;
     193               0 :         if (poObj != NULL)
     194                 :         {
     195               0 :             if (poObj->GetType() == PDFObjectType_String ||
     196               0 :                 poObj->GetType() == PDFObjectType_Int ||
     197               0 :                 poObj->GetType() == PDFObjectType_Real ||
     198               0 :                 poObj->GetType() == PDFObjectType_Name)
     199                 :             {
     200               0 :                 fprintf(f, " = ");
     201               0 :                 DumpObjectSimplified(f, poObj);
     202               0 :                 fprintf(f, "\n");
     203                 :             }
     204                 :             else
     205                 :             {
     206               0 :                 fprintf(f, "\n");
     207               0 :                 DumpObject(f, poObj, nDepth+1, nDepthLimit);
     208                 :             }
     209                 :         }
     210               0 :     }
     211                 : }
     212                 : 
     213                 : 
     214                 : /************************************************************************/
     215                 : /* ==================================================================== */
     216                 : /*                              PDFDataset                              */
     217                 : /* ==================================================================== */
     218                 : /************************************************************************/
     219                 : 
     220                 : class PDFRasterBand;
     221                 : 
     222                 : class PDFDataset : public GDALPamDataset
     223                 : {
     224                 :     friend class PDFRasterBand;
     225                 :     CPLString    osFilename;
     226                 :     CPLString    osUserPwd;
     227                 :     char        *pszWKT;
     228                 :     double       dfDPI;
     229                 :     double       adfCTM[6];
     230                 :     double       adfGeoTransform[6];
     231                 :     int          bGeoTransformValid;
     232                 : #ifdef USE_POPPLER
     233                 :     PDFDoc*      poDoc;
     234                 : #endif
     235                 :     int          iPage;
     236                 : 
     237                 :     double       dfMaxArea;
     238                 :     int          ParseLGIDictObject(GDALPDFObject* poLGIDict);
     239                 :     int          ParseLGIDictDictFirstPass(GDALPDFDictionary* poLGIDict, int* pbIsLargestArea = NULL);
     240                 :     int          ParseLGIDictDictSecondPass(GDALPDFDictionary* poLGIDict);
     241                 :     int          ParseProjDict(GDALPDFDictionary* poProjDict);
     242                 :     int          ParseVP(GDALPDFObject* poVP, double dfMediaBoxWidth, double dfMediaBoxHeight);
     243                 : 
     244                 :     int          bTried;
     245                 :     GByte       *pabyData;
     246                 : 
     247                 :     OGRPolygon*  poNeatLine;
     248                 : 
     249                 :   public:
     250                 :                  PDFDataset();
     251                 :     virtual     ~PDFDataset();
     252                 : 
     253                 :     virtual const char* GetProjectionRef();
     254                 :     virtual CPLErr GetGeoTransform( double * );
     255                 : 
     256                 :     static GDALDataset *Open( GDALOpenInfo * );
     257                 :     static int          Identify( GDALOpenInfo * );
     258                 : };
     259                 : 
     260                 : /************************************************************************/
     261                 : /* ==================================================================== */
     262                 : /*                         PDFRasterBand                                */
     263                 : /* ==================================================================== */
     264                 : /************************************************************************/
     265                 : 
     266                 : class PDFRasterBand : public GDALPamRasterBand
     267              12 : {
     268                 :     friend class PDFDataset;
     269                 : 
     270                 :   public:
     271                 : 
     272                 :                 PDFRasterBand( PDFDataset *, int );
     273                 : 
     274                 :     virtual CPLErr IReadBlock( int, int, void * );
     275                 :     virtual GDALColorInterp GetColorInterpretation();
     276                 : };
     277                 : 
     278                 : 
     279                 : /************************************************************************/
     280                 : /*                         PDFRasterBand()                             */
     281                 : /************************************************************************/
     282                 : 
     283              12 : PDFRasterBand::PDFRasterBand( PDFDataset *poDS, int nBand )
     284                 : 
     285                 : {
     286              12 :     this->poDS = poDS;
     287              12 :     this->nBand = nBand;
     288                 : 
     289              12 :     eDataType = GDT_Byte;
     290                 : 
     291              12 :     nBlockXSize = poDS->GetRasterXSize();
     292              12 :     nBlockYSize = 1;
     293              12 : }
     294                 : 
     295                 : /************************************************************************/
     296                 : /*                        GetColorInterpretation()                      */
     297                 : /************************************************************************/
     298                 : 
     299               0 : GDALColorInterp PDFRasterBand::GetColorInterpretation()
     300                 : {
     301               0 :     return (GDALColorInterp)(GCI_RedBand + (nBand - 1));
     302                 : }
     303                 : 
     304                 : /************************************************************************/
     305                 : /*                             IReadBlock()                             */
     306                 : /************************************************************************/
     307                 : 
     308            2743 : CPLErr PDFRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
     309                 :                                   void * pImage )
     310                 : 
     311                 : {
     312            2743 :     PDFDataset *poGDS = (PDFDataset *) poDS;
     313            2743 :     if (poGDS->bTried == FALSE)
     314                 :     {
     315               2 :         poGDS->bTried = TRUE;
     316               2 :         poGDS->pabyData = (GByte*)VSIMalloc3(3, nRasterXSize, nRasterYSize);
     317               2 :         if (poGDS->pabyData == NULL)
     318               0 :             return CE_Failure;
     319                 : 
     320                 : #ifdef USE_POPPLER
     321                 : 
     322                 :         /* poppler global variable */
     323               2 :         if (globalParams == NULL)
     324               1 :             globalParams = new GlobalParams();
     325                 : 
     326                 :         SplashColor sColor;
     327               2 :         sColor[0] = 255;
     328               2 :         sColor[1] = 255;
     329               2 :         sColor[2] = 255;
     330                 :         SplashOutputDev *poSplashOut;
     331               2 :         poSplashOut = new SplashOutputDev(splashModeRGB8, 4, gFalse, sColor);
     332               2 :         PDFDoc* poDoc = poGDS->poDoc;
     333               2 :         poSplashOut->startDoc(poDoc->getXRef());
     334               2 :         double dfDPI = poGDS->dfDPI;
     335                 : 
     336                 :         /* EVIL: we modify a private member... */
     337                 :         /* poppler (at least 0.12 and 0.14 versions) don't render correctly */
     338                 :         /* some PDFs and display an error message 'Could not find a OCG with Ref' */
     339                 :         /* in those cases. This processing of optional content is an addition of */
     340                 :         /* poppler in comparison to original xpdf, which hasn't the issue. All in */
     341                 :         /* all, nullifying optContent removes the error message and improves the rendering */
     342                 : #ifdef POPPLER_HAS_OPTCONTENT
     343               2 :         Catalog* poCatalog = poDoc->getCatalog();
     344               2 :         OCGs* poOldOCGs = poCatalog->optContent;
     345               2 :         poCatalog->optContent = NULL;
     346                 : #endif
     347                 : 
     348                 :         poGDS->poDoc->displayPageSlice(poSplashOut,
     349                 :                                        poGDS->iPage,
     350                 :                                        dfDPI, dfDPI,
     351                 :                                        0,
     352                 :                                        TRUE, gFalse, gFalse,
     353                 :                                        0, 0,
     354                 :                                        nRasterXSize,
     355               2 :                                        nRasterYSize);
     356                 : 
     357                 :         /* Restore back */
     358                 : #ifdef POPPLER_HAS_OPTCONTENT
     359               2 :         poCatalog->optContent = poOldOCGs;
     360                 : #endif
     361                 : 
     362               2 :         SplashBitmap* poBitmap = poSplashOut->getBitmap();
     363               4 :         if (poBitmap->getWidth() != nRasterXSize || poBitmap->getHeight() != nRasterYSize)
     364                 :         {
     365                 :             CPLError(CE_Failure, CPLE_AppDefined,
     366                 :                      "Bitmap decoded size (%dx%d) doesn't match raster size (%dx%d)" ,
     367                 :                      poBitmap->getWidth(), poBitmap->getHeight(),
     368               0 :                      nRasterXSize, nRasterYSize);
     369               0 :             VSIFree(poGDS->pabyData);
     370               0 :             poGDS->pabyData = NULL;
     371               0 :             delete poSplashOut;
     372               0 :             return CE_Failure;
     373                 :         }
     374                 : 
     375               2 :         int nRowSize = poBitmap->getRowSize();
     376               2 :         GByte* pabyBitmap = poBitmap->getDataPtr();
     377                 :         int i, j;
     378               2 :         GByte* pabyDataR = poGDS->pabyData;
     379               2 :         GByte* pabyDataG = poGDS->pabyData + nRasterXSize * nRasterYSize;
     380               2 :         GByte* pabyDataB = poGDS->pabyData + 2 * nRasterXSize * nRasterYSize;
     381            2745 :         for(j=0;j<nRasterYSize;j++)
     382                 :         {
     383         4079403 :             for(i=0;i<nRasterXSize;i++)
     384                 :             {
     385         4076660 :                 pabyDataR[j * nRasterXSize + i] = pabyBitmap[j * nRowSize + i * 3];
     386         4076660 :                 pabyDataG[j * nRasterXSize + i] = pabyBitmap[j * nRowSize + i * 3 + 1];
     387         4076660 :                 pabyDataB[j * nRasterXSize + i] = pabyBitmap[j * nRowSize + i * 3 + 2];
     388                 :             }
     389                 :         }
     390               2 :         delete poSplashOut;
     391                 : 
     392                 : #else
     393                 :         memset(poGDS->pabyData, 0, ((size_t)3) * nRasterXSize * nRasterYSize);
     394                 : 
     395                 :         CPLString osTmpFilenamePrefix = CPLGenerateTempFilename("pdf");
     396                 :         CPLString osTmpFilename(CPLSPrintf("%s-%d.ppm",
     397                 :                                            osTmpFilenamePrefix.c_str(),
     398                 :                                            poGDS->iPage));
     399                 : 
     400                 :         CPLString osCmd = CPLSPrintf("pdftoppm -r %f -f %d -l %d \"%s\" \"%s\"",
     401                 :                    poGDS->dfDPI, poGDS->iPage, poGDS->iPage,
     402                 :                    poGDS->osFilename.c_str(), osTmpFilenamePrefix.c_str());
     403                 :         if (poGDS->osUserPwd.size() != 0)
     404                 :         {
     405                 :             osCmd += " -upw \"";
     406                 :             osCmd += poGDS->osUserPwd;
     407                 :             osCmd += "\"";
     408                 :         }
     409                 : 
     410                 :         CPLDebug("PDF", "Running '%s'", osCmd.c_str());
     411                 :         int nRet = system(osCmd.c_str());
     412                 :         if (nRet == 0)
     413                 :         {
     414                 :             GDALDataset* poDS = (GDALDataset*) GDALOpen(osTmpFilename, GA_ReadOnly);
     415                 :             if (poDS)
     416                 :             {
     417                 :                 if (poDS->GetRasterCount() == 3)
     418                 :                 {
     419                 :                     poDS->RasterIO(GF_Read, 0, 0,
     420                 :                                    poDS->GetRasterXSize(),
     421                 :                                    poDS->GetRasterYSize(),
     422                 :                                    poGDS->pabyData, nRasterXSize, nRasterYSize,
     423                 :                                    GDT_Byte, 3, NULL, 0, 0, 0);
     424                 :                 }
     425                 :                 delete poDS;
     426                 :             }
     427                 :         }
     428                 :         else
     429                 :         {
     430                 :             CPLDebug("PDF", "Ret code = %d", nRet);
     431                 :         }
     432                 :         VSIUnlink(osTmpFilename);
     433                 : #endif
     434                 :     }
     435            2743 :     if (poGDS->pabyData == NULL)
     436               0 :         return CE_Failure;
     437                 : 
     438                 :     memcpy(pImage,
     439                 :            poGDS->pabyData + (nBand - 1) * nRasterXSize * nRasterYSize + nBlockYOff * nRasterXSize,
     440            2743 :            nRasterXSize);
     441                 : 
     442            2743 :     return CE_None;
     443                 : }
     444                 : 
     445                 : /************************************************************************/
     446                 : /*                            ~PDFDataset()                            */
     447                 : /************************************************************************/
     448                 : 
     449               4 : PDFDataset::PDFDataset()
     450                 : {
     451                 : #ifdef USE_POPPLER
     452               4 :     poDoc = NULL;
     453                 : #endif
     454               4 :     pszWKT = NULL;
     455               4 :     dfMaxArea = 0;
     456               4 :     adfGeoTransform[0] = 0;
     457               4 :     adfGeoTransform[1] = 1;
     458               4 :     adfGeoTransform[2] = 0;
     459               4 :     adfGeoTransform[3] = 0;
     460               4 :     adfGeoTransform[4] = 0;
     461               4 :     adfGeoTransform[5] = 1;
     462               4 :     bGeoTransformValid = FALSE;
     463               4 :     bTried = FALSE;
     464               4 :     pabyData = NULL;
     465               4 :     iPage = -1;
     466               4 :     poNeatLine = NULL;
     467               4 : }
     468                 : 
     469                 : /************************************************************************/
     470                 : /*                           PDFFreeDoc()                               */
     471                 : /************************************************************************/
     472                 : 
     473                 : #ifdef USE_POPPLER
     474               4 : static void PDFFreeDoc(PDFDoc* poDoc)
     475                 : {
     476               4 :     if (poDoc)
     477                 :     {
     478                 :         /* hack to avoid potential cross heap issues on Win32 */
     479                 :         /* str is the VSIPDFFileStream object passed in the constructor of PDFDoc */
     480               4 :         delete poDoc->str;
     481               4 :         poDoc->str = NULL;
     482                 : 
     483               4 :         delete poDoc;
     484                 :     }
     485               4 : }
     486                 : #endif
     487                 : 
     488                 : /************************************************************************/
     489                 : /*                            ~PDFDataset()                            */
     490                 : /************************************************************************/
     491                 : 
     492               4 : PDFDataset::~PDFDataset()
     493                 : {
     494               4 :     CPLFree(pszWKT);
     495               4 :     CPLFree(pabyData);
     496                 : 
     497               4 :     delete poNeatLine;
     498                 : 
     499                 : #ifdef USE_POPPLER
     500               4 :     PDFFreeDoc(poDoc);
     501                 : #endif
     502               4 : }
     503                 : 
     504                 : /************************************************************************/
     505                 : /*                             Identify()                               */
     506                 : /************************************************************************/
     507                 : 
     508           10505 : int PDFDataset::Identify( GDALOpenInfo * poOpenInfo )
     509                 : {
     510           10505 :     if (strncmp(poOpenInfo->pszFilename, "PDF:", 4) == 0)
     511               1 :         return TRUE;
     512                 : 
     513           10504 :     if (poOpenInfo->nHeaderBytes < 128)
     514           10359 :         return FALSE;
     515                 : 
     516             145 :     return strncmp((const char*)poOpenInfo->pabyHeader, "%PDF", 4) == 0;
     517                 : }
     518                 : 
     519                 : /************************************************************************/
     520                 : /*                    PDFDatasetErrorFunction()                         */
     521                 : /************************************************************************/
     522                 : 
     523                 : #ifdef USE_POPPLER
     524               0 : static void PDFDatasetErrorFunction(int nPos, char *pszMsg, va_list args)
     525                 : {
     526               0 :     CPLString osError;
     527                 : 
     528               0 :     if (nPos >= 0)
     529               0 :         osError.Printf("Pos = %d, ", nPos);
     530               0 :     osError += CPLString().vPrintf(pszMsg, args);
     531                 : 
     532               0 :     if (strcmp(osError.c_str(), "Incorrect password") == 0)
     533                 :         return;
     534                 : 
     535               0 :     CPLError(CE_Failure, CPLE_AppDefined, "%s", osError.c_str());
     536                 : }
     537                 : #endif
     538                 : 
     539                 : /************************************************************************/
     540                 : /*                                Open()                                */
     541                 : /************************************************************************/
     542                 : 
     543            1267 : GDALDataset *PDFDataset::Open( GDALOpenInfo * poOpenInfo )
     544                 : 
     545                 : {
     546            1267 :     if (!Identify(poOpenInfo))
     547            1263 :         return NULL;
     548                 : 
     549               4 :     const char* pszUserPwd = CPLGetConfigOption("PDF_USER_PWD", NULL);
     550                 : 
     551               4 :     int bOpenSubdataset = strncmp(poOpenInfo->pszFilename, "PDF:", 4) == 0;
     552               4 :     int iPage = -1;
     553               4 :     const char* pszFilename = poOpenInfo->pszFilename;
     554                 :     char szPassword[81];
     555                 : 
     556               4 :     if (bOpenSubdataset)
     557                 :     {
     558               1 :         iPage = atoi(pszFilename + 4);
     559               1 :         if (iPage <= 0)
     560               0 :             return NULL;
     561               1 :          pszFilename = strchr(pszFilename + 4, ':');
     562               1 :         if (pszFilename == NULL)
     563               0 :             return NULL;
     564               1 :         pszFilename ++;
     565                 :     }
     566                 :     else
     567               3 :         iPage = 1;
     568                 : 
     569                 : #ifdef USE_POPPLER
     570               4 :     GooString* poUserPwd = NULL;
     571                 : 
     572                 :     /* Set custom error handler for poppler errors */
     573               4 :     setErrorFunction(PDFDatasetErrorFunction);
     574                 : 
     575               4 :     PDFDoc* poDoc = NULL;
     576               4 :     ObjectAutoFree oObj;
     577               0 :     while(TRUE)
     578                 :     {
     579               4 :         VSILFILE* fp = VSIFOpenL(pszFilename, "rb");
     580               4 :         if (fp == NULL)
     581               0 :             return NULL;
     582                 : 
     583               4 :         fp = (VSILFILE*)VSICreateBufferedReaderHandle((VSIVirtualHandle*)fp);
     584                 : 
     585               4 :         if (pszUserPwd)
     586               0 :             poUserPwd = new GooString(pszUserPwd);
     587                 : 
     588               4 :         oObj.initNull();
     589               4 :         poDoc = new PDFDoc(new VSIPDFFileStream(fp, pszFilename, 0, gFalse, 0, &oObj), NULL, poUserPwd);
     590               4 :         delete poUserPwd;
     591                 : 
     592               4 :         if ( !poDoc->isOk() || poDoc->getNumPages() == 0 )
     593                 :         {
     594               0 :             if (poDoc->getErrorCode() == errEncrypted)
     595                 :             {
     596               0 :                 if (pszUserPwd && EQUAL(pszUserPwd, "ASK_INTERACTIVE"))
     597                 :                 {
     598               0 :                     printf( "Enter password (will be echo'ed in the console): " );
     599               0 :                     fgets( szPassword, sizeof(szPassword), stdin );
     600               0 :                     szPassword[sizeof(szPassword)-1] = 0;
     601               0 :                     char* sz10 = strchr(szPassword, '\n');
     602               0 :                     if (sz10)
     603               0 :                         *sz10 = 0;
     604               0 :                     pszUserPwd = szPassword;
     605               0 :                     PDFFreeDoc(poDoc);
     606               0 :                     continue;
     607                 :                 }
     608               0 :                 else if (pszUserPwd == NULL)
     609                 :                 {
     610                 :                     CPLError(CE_Failure, CPLE_AppDefined,
     611                 :                              "A password is needed. You can specify it through the PDF_USER_PWD "
     612               0 :                              "configuration option (that can be set to ASK_INTERACTIVE)");
     613                 :                 }
     614                 :                 else
     615                 :                 {
     616               0 :                     CPLError(CE_Failure, CPLE_AppDefined, "Invalid password");
     617                 :                 }
     618                 :             }
     619                 :             else
     620                 :             {
     621               0 :                 CPLError(CE_Failure, CPLE_AppDefined, "Invalid PDF");
     622                 :             }
     623                 : 
     624               0 :             PDFFreeDoc(poDoc);
     625                 : 
     626               0 :             return NULL;
     627                 :         }
     628                 :         else
     629                 :             break;
     630                 :     }
     631                 : 
     632               4 :     Catalog* poCatalog = poDoc->getCatalog();
     633               4 :     if ( poCatalog == NULL || !poCatalog->isOk() )
     634                 :     {
     635               0 :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid PDF : invalid catalog");
     636               0 :         PDFFreeDoc(poDoc);
     637               0 :         return NULL;
     638                 :     }
     639                 : 
     640               4 :     int nPages = poDoc->getNumPages();
     641               4 :     if (iPage < 1 || iPage > nPages)
     642                 :     {
     643                 :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid page number (%d/%d)",
     644               0 :                  iPage, nPages);
     645               0 :         PDFFreeDoc(poDoc);
     646               0 :         return NULL;
     647                 :     }
     648                 : 
     649               4 :     Page* poPage = poCatalog->getPage(iPage);
     650               4 :     if ( poPage == NULL || !poPage->isOk() )
     651                 :     {
     652               0 :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid PDF : invalid page");
     653               0 :         PDFFreeDoc(poDoc);
     654               0 :         return NULL;
     655                 :     }
     656                 : 
     657                 :     /* Here's the dirty part: this is a private member */
     658                 :     /* so we had to #define private public to get it ! */
     659               4 :     Object& oPageObj = poPage->pageObj;
     660               4 :     if ( !oPageObj.isDict() )
     661                 :     {
     662               0 :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid PDF : !oPageObj.isDict()");
     663               0 :         PDFFreeDoc(poDoc);
     664               0 :         return NULL;
     665                 :     }
     666                 : 
     667               4 :     GDALPDFObjectPoppler oPageObjPoppler(&oPageObj, FALSE);
     668               4 :     GDALPDFObject* poPageObj = &oPageObjPoppler;
     669                 : #else
     670                 :     PoDoFo::PdfError::EnableDebug( false );
     671                 :     PoDoFo::PdfError::EnableLogging( false );
     672                 : 
     673                 :     PoDoFo::PdfMemDocument* poDoc = new PoDoFo::PdfMemDocument();
     674                 :     try
     675                 :     {
     676                 :         poDoc->Load(pszFilename);
     677                 :     }
     678                 :     catch(PoDoFo::PdfError& oError)
     679                 :     {
     680                 :         if (oError.GetError() == PoDoFo::ePdfError_InvalidPassword)
     681                 :         {
     682                 :             if (pszUserPwd)
     683                 :             {
     684                 :                 if (EQUAL(pszUserPwd, "ASK_INTERACTIVE"))
     685                 :                 {
     686                 :                     printf( "Enter password (will be echo'ed in the console): " );
     687                 :                     fgets( szPassword, sizeof(szPassword), stdin );
     688                 :                     szPassword[sizeof(szPassword)-1] = 0;
     689                 :                     char* sz10 = strchr(szPassword, '\n');
     690                 :                     if (sz10)
     691                 :                         *sz10 = 0;
     692                 :                     pszUserPwd = szPassword;
     693                 :                 }
     694                 : 
     695                 :                 try
     696                 :                 {
     697                 :                     poDoc->SetPassword(pszUserPwd);
     698                 :                 }
     699                 :                 catch(PoDoFo::PdfError& oError)
     700                 :                 {
     701                 :                     if (oError.GetError() == PoDoFo::ePdfError_InvalidPassword)
     702                 :                     {
     703                 :                         CPLError(CE_Failure, CPLE_AppDefined, "Invalid password");
     704                 :                     }
     705                 :                     else
     706                 :                     {
     707                 :                         CPLError(CE_Failure, CPLE_AppDefined, "Invalid PDF : %s", oError.what());
     708                 :                     }
     709                 :                     delete poDoc;
     710                 :                     return NULL;
     711                 :                 }
     712                 :                 catch(...)
     713                 :                 {
     714                 :                     CPLError(CE_Failure, CPLE_AppDefined, "Invalid PDF");
     715                 :                     delete poDoc;
     716                 :                     return NULL;
     717                 :                 }
     718                 :             }
     719                 :             else
     720                 :             {
     721                 :                 CPLError(CE_Failure, CPLE_AppDefined,
     722                 :                             "A password is needed. You can specify it through the PDF_USER_PWD "
     723                 :                             "configuration option (that can be set to ASK_INTERACTIVE)");
     724                 :                 delete poDoc;
     725                 :                 return NULL;
     726                 :             }
     727                 :         }
     728                 :         else
     729                 :         {
     730                 :             CPLError(CE_Failure, CPLE_AppDefined, "Invalid PDF : %s", oError.what());
     731                 :             delete poDoc;
     732                 :             return NULL;
     733                 :         }
     734                 :     }
     735                 :     catch(...)
     736                 :     {
     737                 :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid PDF");
     738                 :         delete poDoc;
     739                 :         return NULL;
     740                 :     }
     741                 : 
     742                 :     int nPages = poDoc->GetPageCount();
     743                 :     if (iPage < 1 || iPage > nPages)
     744                 :     {
     745                 :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid page number (%d/%d)",
     746                 :                  iPage, nPages);
     747                 :         delete poDoc;
     748                 :         return NULL;
     749                 :     }
     750                 : 
     751                 :     PoDoFo::PdfPage* poPage = poDoc->GetPage(iPage - 1);
     752                 :     if ( poPage == NULL )
     753                 :     {
     754                 :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid PDF : invalid page");
     755                 :         delete poDoc;
     756                 :         return NULL;
     757                 :     }
     758                 : 
     759                 :     PoDoFo::PdfObject* pObj = poPage->GetObject();
     760                 :     GDALPDFObjectPodofo oPageObjPodofo(pObj, poDoc->GetObjects());
     761                 :     GDALPDFObject* poPageObj = &oPageObjPodofo;
     762                 : #endif
     763                 : 
     764               4 :     GDALPDFDictionary* poPageDict = poPageObj->GetDictionary();
     765               4 :     if ( poPageDict == NULL )
     766                 :     {
     767               0 :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid PDF : poPageDict == NULL");
     768                 : #ifdef USE_POPPLER
     769               0 :         PDFFreeDoc(poDoc);
     770                 : #else
     771                 :         delete poDoc;
     772                 : #endif
     773               0 :         return NULL;
     774                 :     }
     775                 : 
     776               4 :     const char* pszDumpObject = CPLGetConfigOption("PDF_DUMP_OBJECT", NULL);
     777               4 :     if (pszDumpObject != NULL)
     778                 :     {
     779                 :         FILE* f;
     780               0 :         if (strcmp(pszDumpObject, "stderr") == 0)
     781               0 :             f = stderr;
     782               0 :         else if (EQUAL(pszDumpObject, "YES"))
     783               0 :             f = fopen(CPLSPrintf("dump_%s.txt", CPLGetFilename(pszFilename)), "wt");
     784                 :         else
     785               0 :             f = fopen(pszDumpObject, "wt");
     786               0 :         if (f == NULL)
     787               0 :             f = stderr;
     788               0 :         DumpObject(f, poPageObj, 0 ,20);
     789               0 :         if (f != stderr)
     790               0 :             fclose(f);
     791                 :     }
     792                 : 
     793               4 :     PDFDataset* poDS = new PDFDataset();
     794               8 :     poDS->osFilename = pszFilename;
     795                 : 
     796               4 :     if ( nPages > 1 && !bOpenSubdataset )
     797                 :     {
     798                 :         int i;
     799               0 :         char** papszSubDatasets = NULL;
     800               0 :         for(i=0;i<nPages;i++)
     801                 :         {
     802                 :             char szKey[32];
     803               0 :             sprintf( szKey, "SUBDATASET_%d_NAME", i+1 );
     804                 :             papszSubDatasets =
     805                 :                 CSLSetNameValue( papszSubDatasets, szKey,
     806               0 :                                  CPLSPrintf("PDF:%d:%s", i+1, poOpenInfo->pszFilename));
     807               0 :             sprintf( szKey, "SUBDATASET_%d_DESC", i+1 );
     808                 :             papszSubDatasets =
     809                 :                 CSLSetNameValue( papszSubDatasets, szKey,
     810               0 :                                  CPLSPrintf("Page %d of %s", i+1, poOpenInfo->pszFilename));
     811                 :         }
     812               0 :         poDS->SetMetadata( papszSubDatasets, "SUBDATASETS" );
     813               0 :         CSLDestroy(papszSubDatasets);
     814                 :     }
     815                 : 
     816                 : #ifdef USE_POPPLER
     817               4 :     poDS->poDoc = poDoc;
     818                 : #endif
     819               4 :     poDS->osUserPwd = pszUserPwd ? pszUserPwd : "";
     820               4 :     poDS->iPage = iPage;
     821               4 :     poDS->dfDPI = atof(CPLGetConfigOption("GDAL_PDF_DPI", "150"));
     822               4 :     if (poDS->dfDPI < 1 || poDS->dfDPI > 7200)
     823                 :     {
     824                 :         CPLError(CE_Warning, CPLE_AppDefined,
     825               0 :                  "Invalid value for GDAL_PDF_DPI. Using default value instead");
     826               0 :         poDS->dfDPI = 150;
     827                 :     }
     828                 : 
     829                 : #ifdef USE_POPPLER
     830               4 :     PDFRectangle* psMediaBox = poPage->getMediaBox();
     831               4 :     double dfX1 = psMediaBox->x1;
     832               4 :     double dfY1 = psMediaBox->y1;
     833               4 :     double dfX2 = psMediaBox->x2;
     834               4 :     double dfY2 = psMediaBox->y2;
     835                 : #else
     836                 :     PoDoFo::PdfRect oMediaBox = poPage->GetMediaBox();
     837                 :     double dfX1 = oMediaBox.GetLeft();
     838                 :     double dfY1 = oMediaBox.GetBottom();
     839                 :     double dfX2 = dfX1 + oMediaBox.GetWidth();
     840                 :     double dfY2 = dfY1 + oMediaBox.GetHeight();
     841                 : #endif
     842                 : 
     843               4 :     double dfPixelPerPt = poDS->dfDPI / 72;
     844               4 :     poDS->nRasterXSize = (int) ((dfX2 - dfX1) * dfPixelPerPt);
     845               4 :     poDS->nRasterYSize = (int) ((dfY2 - dfY1) * dfPixelPerPt);
     846                 : 
     847                 : #ifdef USE_POPPLER
     848               4 :     double dfRotation = poDoc->getPageRotate(iPage);
     849                 : #else
     850                 :     double dfRotation = poPage->GetRotation();
     851                 : #endif
     852               4 :     if ( dfRotation == 90 ||
     853                 :          dfRotation == 270 )
     854                 :     {
     855                 : /* FIXME: the non poppler case should be implemented. This needs to rotate */
     856                 : /* the output of pdftoppm */
     857                 : #ifdef USE_POPPLER
     858                 :         /* Wondering how it would work with a georeferenced image */
     859                 :         /* Has only been tested with ungeoreferenced image */
     860               0 :         int nTmp = poDS->nRasterXSize;
     861               0 :         poDS->nRasterXSize = poDS->nRasterYSize;
     862               0 :         poDS->nRasterYSize = nTmp;
     863                 : #endif
     864                 :     }
     865                 : 
     866               4 :     GDALPDFObject* poLGIDict = NULL;
     867               4 :     GDALPDFObject* poVP = NULL;
     868               4 :     int bIsOGCBP = FALSE;
     869               4 :     if ( (poLGIDict = poPageDict->Get("LGIDict")) != NULL )
     870                 :     {
     871                 :         /* Cf 08-139r2_GeoPDF_Encoding_Best_Practice_Version_2.2.pdf */
     872               2 :         CPLDebug("PDF", "OGC Encoding Best Practice style detected");
     873               2 :         if (poDS->ParseLGIDictObject(poLGIDict))
     874                 :         {
     875               2 :             poDS->adfGeoTransform[0] = poDS->adfCTM[4] + poDS->adfCTM[0] * dfX1 + poDS->adfCTM[2] * dfY2;
     876               2 :             poDS->adfGeoTransform[1] = poDS->adfCTM[0] / dfPixelPerPt;
     877               2 :             poDS->adfGeoTransform[2] = poDS->adfCTM[1] / dfPixelPerPt;
     878               2 :             poDS->adfGeoTransform[3] = poDS->adfCTM[5] + poDS->adfCTM[1] * dfX1 + poDS->adfCTM[3] * dfY2;
     879               2 :             poDS->adfGeoTransform[4] = - poDS->adfCTM[2] / dfPixelPerPt;
     880               2 :             poDS->adfGeoTransform[5] = - poDS->adfCTM[3] / dfPixelPerPt;
     881               2 :             poDS->bGeoTransformValid = TRUE;
     882               2 :             bIsOGCBP = TRUE;
     883                 :         }
     884                 :     }
     885               2 :     else if ( (poVP = poPageDict->Get("VP")) != NULL )
     886                 :     {
     887                 :         /* Cf adobe_supplement_iso32000.pdf */
     888               2 :         CPLDebug("PDF", "Adobe ISO32000 style Geospatial PDF perhaps ?");
     889               2 :         if (dfX1 != 0 || dfY1 != 0)
     890                 :         {
     891               0 :             CPLDebug("PDF", "non null dfX1 or dfY1 values. untested case...");
     892                 :         }
     893               2 :         poDS->ParseVP(poVP, dfX2 - dfX1, dfY2 - dfY1);
     894                 :     }
     895                 :     else
     896                 :     {
     897                 :         /* Not a geospatial PDF doc */
     898                 :     }
     899                 : 
     900               4 :     if (poDS->poNeatLine)
     901                 :     {
     902               4 :         char* pszNeatLineWkt = NULL;
     903               4 :         OGRLinearRing* poRing = poDS->poNeatLine->getExteriorRing();
     904                 :         /* Adobe style is already in target SRS units */
     905               4 :         if (bIsOGCBP)
     906                 :         {
     907               2 :             int nPoints = poRing->getNumPoints();
     908                 :             int i;
     909                 : 
     910              10 :             for(i=0;i<nPoints;i++)
     911                 :             {
     912               8 :                 double x = poRing->getX(i) * dfPixelPerPt;
     913               8 :                 double y = poDS->nRasterYSize - poRing->getY(i) * dfPixelPerPt;
     914               8 :                 double X = poDS->adfGeoTransform[0] + x * poDS->adfGeoTransform[1] +
     915               8 :                                                     y * poDS->adfGeoTransform[2];
     916               8 :                 double Y = poDS->adfGeoTransform[3] + x * poDS->adfGeoTransform[4] +
     917               8 :                                                     y * poDS->adfGeoTransform[5];
     918               8 :                 poRing->setPoint(i, X, Y);
     919                 :             }
     920                 :         }
     921               4 :         poRing->closeRings();
     922                 : 
     923               4 :         poDS->poNeatLine->exportToWkt(&pszNeatLineWkt);
     924               4 :         poDS->SetMetadataItem("NEATLINE", pszNeatLineWkt);
     925               4 :         CPLFree(pszNeatLineWkt);
     926                 :     }
     927                 : 
     928                 : 
     929                 : #ifdef USE_POPPLER
     930               4 :     int nXRefSize = poDoc->getXRef()->getNumObjects();
     931              93 :     for(int i=0;i<nXRefSize;i++)
     932                 :     {
     933              89 :         Object o;
     934              89 :         poDoc->getXRef()->fetch(i, 0, &o);
     935              89 :         if (o.isStream())
     936                 :         {
     937              21 :             Dict* dict = o.getStream()->getDict();
     938              21 :             if (dict)
     939                 :             {
     940              21 :                 Object oSubType, oType;
     941              21 :                 dict->lookup((char*)"Subtype", &oSubType);
     942              21 :                 dict->lookup((char*)"Type", &oType);
     943              21 :                 if (oType.getType() == objName &&
     944                 :                     strcmp(oType.getName(), "Metadata") == 0 &&
     945                 :                     oSubType.getType() == objName &&
     946                 :                     strcmp(oSubType.getName(), "XML") == 0)
     947                 :                 {
     948               3 :                     int nBufferAlloc = 4096;
     949               3 :                     char* pszXMP = (char*) CPLMalloc(nBufferAlloc);
     950               3 :                     Stream* poStream = o.getStream();
     951               3 :                     poStream->reset();
     952                 :                     int j;
     953           10297 :                     for(j=0; ; j++)
     954                 :                     {
     955           10297 :                         const int ch = poStream->getChar();
     956           10297 :                         if (ch == EOF)
     957                 :                             break;
     958           10294 :                         if (j == nBufferAlloc - 2)
     959                 :                         {
     960               0 :                             nBufferAlloc *= 2;
     961               0 :                             pszXMP = (char*) CPLRealloc(pszXMP, nBufferAlloc);
     962                 :                         }
     963           10294 :                         pszXMP[j] = (char)ch;
     964                 :                     }
     965               3 :                     pszXMP[j] = '\0';
     966               3 :                     if (strncmp(pszXMP, "<?xpacket begin=", strlen("<?xpacket begin=")) == 0)
     967                 :                     {
     968                 :                         char *apszMDList[2];
     969               3 :                         apszMDList[0] = pszXMP;
     970               3 :                         apszMDList[1] = NULL;
     971               3 :                         poDS->SetMetadata(apszMDList, "xml:XMP");
     972                 :                     }
     973               3 :                     CPLFree(pszXMP);
     974                 :                 }
     975              21 :                 oSubType.free();
     976              21 :                 oType.free();
     977                 :             }
     978                 :         }
     979              89 :         o.free();
     980                 :     }
     981                 : #else
     982                 :     PoDoFo::TIVecObjects it = poDoc->GetObjects().begin();
     983                 :     for( ; it != poDoc->GetObjects().end(); ++it )
     984                 :     {
     985                 :         if( (*it)->HasStream() && (*it)->GetDataType() == PoDoFo::ePdfDataType_Dictionary)
     986                 :         {
     987                 :             PoDoFo::PdfDictionary& dict = (*it)->GetDictionary();
     988                 :             const PoDoFo::PdfObject* poType = dict.GetKey(PoDoFo::PdfName("Type"));
     989                 :             const PoDoFo::PdfObject* poSubType = dict.GetKey(PoDoFo::PdfName("Subtype"));
     990                 :             if (poType == NULL ||
     991                 :                 poType->GetDataType() != PoDoFo::ePdfDataType_Name ||
     992                 :                 poType->GetName().GetName().compare("Metadata") != 0 ||
     993                 :                 poSubType == NULL || 
     994                 :                 poSubType->GetDataType() != PoDoFo::ePdfDataType_Name ||
     995                 :                 poSubType->GetName().GetName().compare("XML") != 0)
     996                 :                 continue;
     997                 : 
     998                 :             try
     999                 :             {
    1000                 :                 PoDoFo::PdfMemStream* pStream = dynamic_cast<PoDoFo::PdfMemStream*>((*it)->GetStream());
    1001                 :                 pStream->Uncompress();
    1002                 : 
    1003                 :                 const char* pszContent = pStream->Get();
    1004                 :                 int nLength = (int)pStream->GetLength();
    1005                 :                 if (pszContent != NULL && nLength > 15 &&
    1006                 :                     strncmp(pszContent, "<?xpacket begin=", strlen("<?xpacket begin=")) == 0)
    1007                 :                 {
    1008                 :                     char *apszMDList[2];
    1009                 :                     apszMDList[0] = (char*) CPLMalloc(nLength + 1);
    1010                 :                     memcpy(apszMDList[0], pszContent, nLength);
    1011                 :                     apszMDList[0][nLength] = 0;
    1012                 :                     apszMDList[1] = NULL;
    1013                 :                     poDS->SetMetadata(apszMDList, "xml:XMP");
    1014                 :                     CPLFree(apszMDList[0]);
    1015                 : 
    1016                 :                     break;
    1017                 :                 }
    1018                 :             }
    1019                 :             catch( const PoDoFo::PdfError & e )
    1020                 :             {
    1021                 :                 e.PrintErrorMsg();
    1022                 :             }
    1023                 :         }
    1024                 :     }
    1025                 : #endif
    1026                 : 
    1027                 : 
    1028                 : #ifndef USE_POPPLER
    1029                 :     delete poDoc;
    1030                 : #endif
    1031                 : 
    1032                 :     int iBand;
    1033              16 :     for(iBand = 1; iBand <= 3; iBand ++)
    1034              12 :         poDS->SetBand(iBand, new PDFRasterBand(poDS, iBand));
    1035                 : 
    1036                 : /* -------------------------------------------------------------------- */
    1037                 : /*      Initialize any PAM information.                                 */
    1038                 : /* -------------------------------------------------------------------- */
    1039               4 :     poDS->SetDescription( poOpenInfo->pszFilename );
    1040               4 :     poDS->TryLoadXML();
    1041                 : 
    1042                 : /* -------------------------------------------------------------------- */
    1043                 : /*      Support overviews.                                              */
    1044                 : /* -------------------------------------------------------------------- */
    1045               4 :     poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
    1046               4 :     return( poDS );
    1047                 : }
    1048                 : 
    1049                 : /************************************************************************/
    1050                 : /*                       ParseLGIDictObject()                           */
    1051                 : /************************************************************************/
    1052                 : 
    1053               2 : int PDFDataset::ParseLGIDictObject(GDALPDFObject* poLGIDict)
    1054                 : {
    1055                 :     int i;
    1056               2 :     int bOK = FALSE;
    1057               2 :     if (poLGIDict->GetType() == PDFObjectType_Array)
    1058                 :     {
    1059               2 :         GDALPDFArray* poArray = poLGIDict->GetArray();
    1060               2 :         int nArrayLength = poArray->GetLength();
    1061               2 :         int iMax = -1;
    1062                 :         GDALPDFObject* poArrayElt;
    1063               4 :         for (i=0; i<nArrayLength; i++)
    1064                 :         {
    1065               4 :             if ( (poArrayElt = poArray->Get(i)) == NULL ||
    1066               2 :                  poArrayElt->GetType() != PDFObjectType_Dictionary )
    1067                 :             {
    1068                 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1069               0 :                          "LGIDict[%d] is not a dictionary", i);
    1070               0 :                 return FALSE;
    1071                 :             }
    1072                 : 
    1073               2 :             int bIsLargestArea = FALSE;
    1074               2 :             ParseLGIDictDictFirstPass(poArrayElt->GetDictionary(), &bIsLargestArea);
    1075               2 :             if (bIsLargestArea)
    1076               2 :                 iMax = i;
    1077                 :         }
    1078                 : 
    1079               2 :         if (iMax < 0)
    1080               0 :             return FALSE;
    1081                 : 
    1082               2 :         poArrayElt = poArray->Get(iMax);
    1083               2 :         bOK = ParseLGIDictDictSecondPass(poArrayElt->GetDictionary());
    1084                 :     }
    1085               0 :     else if (poLGIDict->GetType() == PDFObjectType_Dictionary)
    1086                 :     {
    1087               0 :         bOK = ParseLGIDictDictFirstPass(poLGIDict->GetDictionary()) &&
    1088               0 :               ParseLGIDictDictSecondPass(poLGIDict->GetDictionary());
    1089                 :     }
    1090                 :     else
    1091                 :     {
    1092                 :         CPLError(CE_Failure, CPLE_AppDefined,
    1093               0 :                  "LGIDict is of type %s", poLGIDict->GetTypeName());
    1094                 :     }
    1095                 : 
    1096               2 :     return bOK;
    1097                 : }
    1098                 : 
    1099                 : /************************************************************************/
    1100                 : /*                            Get()                                */
    1101                 : /************************************************************************/
    1102                 : 
    1103             232 : static double Get(GDALPDFObject* poObj, int nIndice = -1)
    1104                 : {
    1105             232 :     if (poObj->GetType() == PDFObjectType_Array && nIndice >= 0)
    1106                 :     {
    1107             116 :         poObj = poObj->GetArray()->Get(nIndice);
    1108             116 :         if (poObj == NULL)
    1109               0 :             return 0;
    1110             116 :         return Get(poObj);
    1111                 :     }
    1112             116 :     else if (poObj->GetType() == PDFObjectType_Int)
    1113              56 :         return poObj->GetInt();
    1114              60 :     else if (poObj->GetType() == PDFObjectType_Real)
    1115              16 :         return poObj->GetReal();
    1116              44 :     else if (poObj->GetType() == PDFObjectType_String)
    1117                 :     {
    1118              44 :         const char* pszStr = poObj->GetString().c_str();
    1119              44 :         int nLen = strlen(pszStr);
    1120                 :         /* cf Military_Installations_2008.pdf that has values like "96 0 0.0W" */
    1121              44 :         char chLast = pszStr[nLen-1];
    1122              44 :         if (chLast == 'W' || chLast == 'E' || chLast == 'N' || chLast == 'S')
    1123                 :         {
    1124               0 :             double dfDeg = atof(pszStr);
    1125               0 :             double dfMin = 0, dfSec = 0;
    1126               0 :             const char* pszNext = strchr(pszStr, ' ');
    1127               0 :             if (pszNext)
    1128               0 :                 pszNext ++;
    1129               0 :             if (pszNext)
    1130               0 :                 dfMin = atof(pszNext);
    1131               0 :             if (pszNext)
    1132               0 :                 pszNext = strchr(pszNext, ' ');
    1133               0 :             if (pszNext)
    1134               0 :                 pszNext ++;
    1135               0 :             if (pszNext)
    1136               0 :                 dfSec = atof(pszNext);
    1137               0 :             double dfVal = dfDeg + dfMin / 60 + dfSec / 3600;
    1138               0 :             if (chLast == 'W' || chLast == 'S')
    1139               0 :                 return -dfVal;
    1140                 :             else
    1141               0 :                 return dfVal;
    1142                 :         }
    1143              44 :         return atof(pszStr);
    1144                 :     }
    1145                 :     else
    1146                 :     {
    1147                 :         CPLError(CE_Warning, CPLE_AppDefined, "Unexpected type : %s",
    1148               0 :                  poObj->GetTypeName());
    1149               0 :         return 0;
    1150                 :     }
    1151                 : }
    1152                 : 
    1153                 : /************************************************************************/
    1154                 : /*                            Get()                                */
    1155                 : /************************************************************************/
    1156                 : 
    1157               0 : static double Get(GDALPDFDictionary* poDict, const char* pszName)
    1158                 : {
    1159                 :     GDALPDFObject* poObj;
    1160               0 :     if ( (poObj = poDict->Get(pszName)) != NULL )
    1161               0 :         return Get(poObj);
    1162                 :     CPLError(CE_Failure, CPLE_AppDefined,
    1163               0 :              "Cannot find parameter %s", pszName);
    1164               0 :     return 0;
    1165                 : }
    1166                 : 
    1167                 : /************************************************************************/
    1168                 : /*                   ParseLGIDictDictFirstPass()                        */
    1169                 : /************************************************************************/
    1170                 : 
    1171               2 : int PDFDataset::ParseLGIDictDictFirstPass(GDALPDFDictionary* poLGIDict,
    1172                 :                                           int* pbIsLargestArea)
    1173                 : {
    1174                 :     int i;
    1175                 : 
    1176               2 :     if (pbIsLargestArea)
    1177               2 :         *pbIsLargestArea = FALSE;
    1178                 : 
    1179               2 :     if (poLGIDict == NULL)
    1180               0 :         return FALSE;
    1181                 : 
    1182                 : /* -------------------------------------------------------------------- */
    1183                 : /*      Extract Type attribute                                          */
    1184                 : /* -------------------------------------------------------------------- */
    1185                 :     GDALPDFObject* poType;
    1186               2 :     if ((poType = poLGIDict->Get("Type")) == NULL)
    1187                 :     {
    1188                 :         CPLError(CE_Failure, CPLE_AppDefined,
    1189               0 :                  "Cannot find Type of LGIDict object");
    1190               0 :         return FALSE;
    1191                 :     }
    1192                 : 
    1193               2 :     if ( poType->GetType() != PDFObjectType_Name )
    1194                 :     {
    1195                 :         CPLError(CE_Failure, CPLE_AppDefined,
    1196               0 :                  "Invalid type for Type of LGIDict object");
    1197               0 :         return FALSE;
    1198                 :     }
    1199                 : 
    1200               2 :     if ( strcmp(poType->GetName().c_str(), "LGIDict") != 0 )
    1201                 :     {
    1202                 :         CPLError(CE_Failure, CPLE_AppDefined,
    1203                 :                  "Invalid value for Type of LGIDict object : %s",
    1204               0 :                  poType->GetName().c_str());
    1205               0 :         return FALSE;
    1206                 :     }
    1207                 : 
    1208                 : /* -------------------------------------------------------------------- */
    1209                 : /*      Extract Version attribute                                       */
    1210                 : /* -------------------------------------------------------------------- */
    1211                 :     GDALPDFObject* poVersion;
    1212               2 :     if ((poVersion = poLGIDict->Get("Version")) == NULL)
    1213                 :     {
    1214                 :         CPLError(CE_Failure, CPLE_AppDefined,
    1215               0 :                  "Cannot find Version of LGIDict object");
    1216               0 :         return FALSE;
    1217                 :     }
    1218                 : 
    1219               2 :     if ( poVersion->GetType() != PDFObjectType_String )
    1220                 :     {
    1221                 :         /* OGC best practice is 2.1 */
    1222                 :         CPLDebug("PDF", "LGIDict Version : %s",
    1223               2 :                  poVersion->GetString().c_str());
    1224                 :     }
    1225               0 :     else if (poVersion->GetType() != PDFObjectType_Int)
    1226                 :     {
    1227                 :         /* Old TerraGo is 2 */
    1228                 :         CPLDebug("PDF", "LGIDict Version : %d",
    1229               0 :                  poVersion->GetInt());
    1230                 :     }
    1231                 : 
    1232                 : /* -------------------------------------------------------------------- */
    1233                 : /*      Extract Neatline attribute                                      */
    1234                 : /* -------------------------------------------------------------------- */
    1235                 :     GDALPDFObject* poNeatline;
    1236               4 :     if ((poNeatline = poLGIDict->Get("Neatline")) != NULL &&
    1237               2 :         poNeatline->GetType() == PDFObjectType_Array)
    1238                 :     {
    1239               2 :         int nLength = poNeatline->GetArray()->GetLength();
    1240               2 :         if ( (nLength % 2) != 0 || nLength < 4 )
    1241                 :         {
    1242                 :             CPLError(CE_Failure, CPLE_AppDefined,
    1243               0 :                      "Invalid length for Neatline");
    1244               0 :             return FALSE;
    1245                 :         }
    1246                 : 
    1247               2 :         double dfMinX = 0, dfMinY = 0, dfMaxX = 0, dfMaxY = 0;
    1248              10 :         for(i=0;i<nLength;i+=2)
    1249                 :         {
    1250               8 :             double dfX = Get(poNeatline, i);
    1251               8 :             double dfY = Get(poNeatline, i + 1);
    1252               8 :             if (i == 0 || dfX < dfMinX) dfMinX = dfX;
    1253               8 :             if (i == 0 || dfY < dfMinY) dfMinY = dfY;
    1254               8 :             if (i == 0 || dfX > dfMaxX) dfMaxX = dfX;
    1255               8 :             if (i == 0 || dfY > dfMaxY) dfMaxY = dfY;
    1256                 :         }
    1257               2 :         double dfArea = (dfMaxX - dfMinX) * (dfMaxY - dfMinY);
    1258               2 :         if (dfArea < dfMaxArea)
    1259                 :         {
    1260               0 :             CPLDebug("PDF", "Not the largest neatline. Skipping it");
    1261               0 :             return TRUE;
    1262                 :         }
    1263                 : 
    1264               2 :         CPLDebug("PDF", "This is a the largest neatline for now");
    1265               2 :         dfMaxArea = dfArea;
    1266               2 :         if (pbIsLargestArea)
    1267               2 :             *pbIsLargestArea = TRUE;
    1268                 : 
    1269               2 :         delete poNeatLine;
    1270               2 :         poNeatLine = new OGRPolygon();
    1271               4 :         OGRLinearRing* poRing = new OGRLinearRing();
    1272              10 :         for(i=0;i<nLength;i+=2)
    1273                 :         {
    1274               8 :             double dfX = Get(poNeatline, i);
    1275               8 :             double dfY = Get(poNeatline, i + 1);
    1276               8 :             poRing->addPoint(dfX, dfY);
    1277                 :         }
    1278               2 :         poNeatLine->addRingDirectly(poRing);
    1279                 :     }
    1280                 : 
    1281               2 :     return TRUE;
    1282                 : }
    1283                 : 
    1284                 : /************************************************************************/
    1285                 : /*                  ParseLGIDictDictSecondPass()                        */
    1286                 : /************************************************************************/
    1287                 : 
    1288               2 : int PDFDataset::ParseLGIDictDictSecondPass(GDALPDFDictionary* poLGIDict)
    1289                 : {
    1290                 :     int i;
    1291                 : 
    1292                 : /* -------------------------------------------------------------------- */
    1293                 : /*      Extract CTM attribute                                           */
    1294                 : /* -------------------------------------------------------------------- */
    1295                 :     GDALPDFObject* poCTM;
    1296               2 :     int bHasCTM = FALSE;
    1297               4 :     if ((poCTM = poLGIDict->Get("CTM")) != NULL &&
    1298               2 :         poCTM->GetType() == PDFObjectType_Array)
    1299                 :     {
    1300               2 :         int nLength = poCTM->GetArray()->GetLength();
    1301               2 :         if ( nLength != 6 )
    1302                 :         {
    1303                 :             CPLError(CE_Failure, CPLE_AppDefined,
    1304               0 :                      "Invalid length for CTM");
    1305               0 :             return FALSE;
    1306                 :         }
    1307                 : 
    1308               2 :         bHasCTM = TRUE;
    1309              14 :         for(i=0;i<nLength;i++)
    1310                 :         {
    1311              12 :             adfCTM[i] = Get(poCTM, i);
    1312                 :             /* Nullify rotation terms that are significantly smaller than */
    1313                 :             /* scaling termes */
    1314              12 :             if ((i == 1 || i == 2) && fabs(adfCTM[i]) < fabs(adfCTM[0]) * 1e-10)
    1315               4 :                 adfCTM[i] = 0;
    1316              12 :             CPLDebug("PDF", "CTM[%d] = %.16g", i, adfCTM[i]);
    1317                 :         }
    1318                 :     }
    1319                 : 
    1320                 : /* -------------------------------------------------------------------- */
    1321                 : /*      Extract Registration attribute                                  */
    1322                 : /* -------------------------------------------------------------------- */
    1323               2 :     if (!bHasCTM)
    1324                 :     {
    1325                 :         GDALPDFObject* poRegistration;
    1326               0 :         if ((poRegistration = poLGIDict->Get("Registration")) != NULL)
    1327                 :         {
    1328                 :             /* TODO */
    1329               0 :             CPLDebug("PDF", "Registration unhandled for now");
    1330               0 :             return FALSE;
    1331                 :         }
    1332                 :         else
    1333                 :         {
    1334               0 :             CPLDebug("PDF", "Neither CTM nor Registration found");
    1335               0 :             return FALSE;
    1336                 :         }
    1337                 :     }
    1338                 : 
    1339                 : /* -------------------------------------------------------------------- */
    1340                 : /*      Extract Projection attribute                                    */
    1341                 : /* -------------------------------------------------------------------- */
    1342                 :     GDALPDFObject* poProjection;
    1343               4 :     if ((poProjection = poLGIDict->Get("Projection")) == NULL ||
    1344               2 :         poProjection->GetType() != PDFObjectType_Dictionary)
    1345                 :     {
    1346               0 :         CPLError(CE_Failure, CPLE_AppDefined, "Could not find Projection");
    1347               0 :         return FALSE;
    1348                 :     }
    1349                 : 
    1350               2 :     return ParseProjDict(poProjection->GetDictionary());
    1351                 : }
    1352                 : 
    1353                 : /************************************************************************/
    1354                 : /*                         ParseProjDict()                               */
    1355                 : /************************************************************************/
    1356                 : 
    1357               2 : int PDFDataset::ParseProjDict(GDALPDFDictionary* poProjDict)
    1358                 : {
    1359               2 :     if (poProjDict == NULL)
    1360               0 :         return FALSE;
    1361               2 :     OGRSpatialReference oSRS;
    1362                 : 
    1363                 : /* -------------------------------------------------------------------- */
    1364                 : /*      Extract Type attribute                                          */
    1365                 : /* -------------------------------------------------------------------- */
    1366                 :     GDALPDFObject* poType;
    1367               2 :     if ((poType = poProjDict->Get("Type")) == NULL)
    1368                 :     {
    1369                 :         CPLError(CE_Failure, CPLE_AppDefined,
    1370               0 :                  "Cannot find Type of Projection object");
    1371               0 :         return FALSE;
    1372                 :     }
    1373                 : 
    1374               2 :     if ( poType->GetType() != PDFObjectType_Name )
    1375                 :     {
    1376                 :         CPLError(CE_Failure, CPLE_AppDefined,
    1377               0 :                  "Invalid type for Type of Projection object");
    1378               0 :         return FALSE;
    1379                 :     }
    1380                 : 
    1381               2 :     if ( strcmp(poType->GetName().c_str(), "Projection") != 0 )
    1382                 :     {
    1383                 :         CPLError(CE_Failure, CPLE_AppDefined,
    1384                 :                  "Invalid value for Type of Projection object : %s",
    1385               0 :                  poType->GetName().c_str());
    1386               0 :         return FALSE;
    1387                 :     }
    1388                 : 
    1389                 : /* -------------------------------------------------------------------- */
    1390                 : /*      Extract Datum attribute                                         */
    1391                 : /* -------------------------------------------------------------------- */
    1392               2 :     int bIsWGS84 = FALSE;
    1393               2 :     int bIsNAD83 = FALSE;
    1394               2 :     int bIsNAD27 = FALSE;
    1395                 : 
    1396                 :     GDALPDFObject* poDatum;
    1397               2 :     if ((poDatum = poProjDict->Get("Datum")) != NULL)
    1398                 :     {
    1399               2 :         if (poDatum->GetType() == PDFObjectType_String)
    1400                 :         {
    1401               2 :             const char* pszDatum = poDatum->GetString().c_str();
    1402               2 :             CPLDebug("PDF", "Datum = %s", pszDatum);
    1403               4 :             if (EQUAL(pszDatum, "WE") || EQUAL(pszDatum, "WGE"))
    1404                 :             {
    1405               2 :                 bIsWGS84 = TRUE;
    1406               2 :                 oSRS.SetWellKnownGeogCS("WGS84");
    1407                 :             }
    1408               0 :             else if (EQUAL(pszDatum, "NAR") || EQUALN(pszDatum, "NAR-", 4))
    1409                 :             {
    1410               0 :                 bIsNAD83 = TRUE;
    1411               0 :                 oSRS.SetWellKnownGeogCS("NAD83");
    1412                 :             }
    1413               0 :             else if (EQUAL(pszDatum, "NAS") || EQUALN(pszDatum, "NAS-", 4))
    1414                 :             {
    1415               0 :                 bIsNAD27 = TRUE;
    1416               0 :                 oSRS.SetWellKnownGeogCS("NAD27");
    1417                 :             }
    1418               0 :             else if (EQUAL(pszDatum, "HEN")) /* HERAT North, Afghanistan */
    1419                 :             {
    1420                 :                 oSRS.SetGeogCS( "unknown" /*const char * pszGeogName*/,
    1421                 :                                 "unknown" /*const char * pszDatumName */,
    1422                 :                                 "International 1924",
    1423               0 :                                 6378388,297);
    1424               0 :                 oSRS.SetTOWGS84(-333,-222,114);
    1425                 :             }
    1426               0 :             else if (EQUAL(pszDatum, "ING-A")) /* INDIAN 1960, Vietnam 16N */
    1427                 :             {
    1428               0 :                 oSRS.importFromEPSG(4131);
    1429                 :             }
    1430               0 :             else if (EQUAL(pszDatum, "GDS")) /* Geocentric Datum of Australia */
    1431                 :             {
    1432               0 :                 oSRS.importFromEPSG(4283);
    1433                 :             }
    1434                 :             else
    1435                 :             {
    1436                 :                 CPLError(CE_Warning, CPLE_AppDefined,
    1437                 :                         "Unhandled (yet) value for Datum : %s. Defaulting to WGS84...",
    1438               0 :                         pszDatum);
    1439                 :                 oSRS.SetGeogCS( "unknown" /*const char * pszGeogName*/,
    1440                 :                                 "unknown" /*const char * pszDatumName */,
    1441                 :                                 "unknown",
    1442               0 :                                 6378137,298.257223563);
    1443                 :             }
    1444                 :         }
    1445               0 :         else if (poDatum->GetType() == PDFObjectType_Dictionary)
    1446                 :         {
    1447                 :             /* TODO */
    1448                 :             CPLError(CE_Warning, CPLE_AppDefined,
    1449               0 :                      "Datum as dictionary unhandled yet. Defaulting to WGS84...");
    1450                 :             oSRS.SetGeogCS( "unknown" /*const char * pszGeogName*/,
    1451                 :                                 "unknown" /*const char * pszDatumName */,
    1452                 :                                 "unknown",
    1453               0 :                                 6378137,298.257223563);
    1454                 :         }
    1455                 :     }
    1456                 : 
    1457                 : /* -------------------------------------------------------------------- */
    1458                 : /*      Extract Hemisphere attribute                                    */
    1459                 : /* -------------------------------------------------------------------- */
    1460               2 :     CPLString osHemisphere;
    1461                 :     GDALPDFObject* poHemisphere;
    1462               2 :     if ((poHemisphere = poProjDict->Get("Hemisphere")) != NULL &&
    1463               0 :         poHemisphere->GetType() == PDFObjectType_String)
    1464                 :     {
    1465               0 :         osHemisphere = poHemisphere->GetString();
    1466                 :     }
    1467                 : 
    1468                 : /* -------------------------------------------------------------------- */
    1469                 : /*      Extract ProjectionType attribute                                */
    1470                 : /* -------------------------------------------------------------------- */
    1471                 :     GDALPDFObject* poProjectionType;
    1472               4 :     if ((poProjectionType = poProjDict->Get("ProjectionType")) == NULL ||
    1473               2 :         poProjectionType->GetType() != PDFObjectType_String)
    1474                 :     {
    1475                 :         CPLError(CE_Failure, CPLE_AppDefined,
    1476               0 :                  "Cannot find ProjectionType of Projection object");
    1477               0 :         return FALSE;
    1478                 :     }
    1479               2 :     CPLString osProjectionType(poProjectionType->GetString());
    1480               2 :     CPLDebug("PDF", "Projection.ProjectionType = %s", osProjectionType.c_str());
    1481                 : 
    1482                 :     /* Unhandled: NONE, GEODETIC */
    1483                 : 
    1484               2 :     if (EQUAL(osProjectionType, "GEOGRAPHIC"))
    1485                 :     {
    1486                 :         /* Nothing to do */
    1487                 :     }
    1488                 : 
    1489                 :     /* Unhandled: LOCAL CARTESIAN, MG (MGRS) */
    1490                 : 
    1491               0 :     else if (EQUAL(osProjectionType, "UT")) /* UTM */
    1492                 :     {
    1493               0 :         int nZone = (int)Get(poProjDict, "Zone");
    1494               0 :         int bNorth = EQUAL(osHemisphere, "N");
    1495               0 :         if (bIsWGS84)
    1496               0 :             oSRS.importFromEPSG( ((bNorth) ? 32600 : 32700) + nZone );
    1497                 :         else
    1498               0 :             oSRS.SetUTM( nZone, bNorth );
    1499                 :     }
    1500                 : 
    1501               0 :     else if (EQUAL(osProjectionType, "UP")) /* Universal Polar Stereographic (UPS) */
    1502                 :     {
    1503               0 :         int bNorth = EQUAL(osHemisphere, "N");
    1504               0 :         if (bIsWGS84)
    1505               0 :             oSRS.importFromEPSG( (bNorth) ? 32661 : 32761 );
    1506                 :         else
    1507                 :             oSRS.SetPS( (bNorth) ? 90 : -90, 0,
    1508               0 :                         0.994, 200000, 200000 );
    1509                 :     }
    1510                 : 
    1511               0 :     else if (EQUAL(osProjectionType, "SPCS")) /* State Plane */
    1512                 :     {
    1513               0 :         int nZone = (int)Get(poProjDict, "Zone");
    1514               0 :         oSRS.SetStatePlane( nZone, bIsNAD83 );
    1515                 :     }
    1516                 : 
    1517               0 :     else if (EQUAL(osProjectionType, "AC")) /* Albers Equal Area Conic */
    1518                 :     {
    1519               0 :         double dfStdP1 = Get(poProjDict, "StandardParallelOne");
    1520               0 :         double dfStdP2 = Get(poProjDict, "StandardParallelTwo");
    1521               0 :         double dfCenterLat = Get(poProjDict, "OriginLatitude");
    1522               0 :         double dfCenterLong = Get(poProjDict, "CentralMeridian");
    1523               0 :         double dfFalseEasting = Get(poProjDict, "FalseEasting");
    1524               0 :         double dfFalseNorthing = Get(poProjDict, "FalseNorthing");
    1525                 :         oSRS.SetACEA( dfStdP1, dfStdP2,
    1526                 :                      dfCenterLat, dfCenterLong,
    1527               0 :                      dfFalseEasting, dfFalseNorthing );
    1528                 :     }
    1529                 :  
    1530               0 :     else if (EQUAL(osProjectionType, "AL")) /* Azimuthal Equidistant */
    1531                 :     {
    1532               0 :         double dfCenterLat = Get(poProjDict, "OriginLatitude");
    1533               0 :         double dfCenterLong = Get(poProjDict, "CentralMeridian");
    1534               0 :         double dfFalseEasting = Get(poProjDict, "FalseEasting");
    1535               0 :         double dfFalseNorthing = Get(poProjDict, "FalseNorthing");
    1536                 :         oSRS.SetAE(  dfCenterLat, dfCenterLong,
    1537               0 :                      dfFalseEasting, dfFalseNorthing );
    1538                 :     }
    1539                 : 
    1540               0 :     else if (EQUAL(osProjectionType, "BF")) /* Bonne */
    1541                 :     {
    1542               0 :         double dfStdP1 = Get(poProjDict, "OriginLatitude");
    1543               0 :         double dfCentralMeridian = Get(poProjDict, "CentralMeridian");
    1544               0 :         double dfFalseEasting = Get(poProjDict, "FalseEasting");
    1545               0 :         double dfFalseNorthing = Get(poProjDict, "FalseNorthing");
    1546                 :         oSRS.SetBonne( dfStdP1, dfCentralMeridian,
    1547               0 :                        dfFalseEasting, dfFalseNorthing );
    1548                 :     }
    1549                 : 
    1550               0 :     else if (EQUAL(osProjectionType, "CS")) /* Cassini */
    1551                 :     {
    1552               0 :         double dfCenterLat = Get(poProjDict, "OriginLatitude");
    1553               0 :         double dfCenterLong = Get(poProjDict, "CentralMeridian");
    1554               0 :         double dfFalseEasting = Get(poProjDict, "FalseEasting");
    1555               0 :         double dfFalseNorthing = Get(poProjDict, "FalseNorthing");
    1556                 :         oSRS.SetCS(  dfCenterLat, dfCenterLong,
    1557               0 :                      dfFalseEasting, dfFalseNorthing );
    1558                 :     }
    1559                 : 
    1560               0 :     else if (EQUAL(osProjectionType, "LI")) /* Cylindrical Equal Area */
    1561                 :     {
    1562               0 :         double dfStdP1 = Get(poProjDict, "OriginLatitude");
    1563               0 :         double dfCentralMeridian = Get(poProjDict, "CentralMeridian");
    1564               0 :         double dfFalseEasting = Get(poProjDict, "FalseEasting");
    1565               0 :         double dfFalseNorthing = Get(poProjDict, "FalseNorthing");
    1566                 :         oSRS.SetCEA( dfStdP1, dfCentralMeridian,
    1567               0 :                      dfFalseEasting, dfFalseNorthing );
    1568                 :     }
    1569                 : 
    1570               0 :     else if (EQUAL(osProjectionType, "EF")) /* Eckert IV */
    1571                 :     {
    1572               0 :         double dfCentralMeridian = Get(poProjDict, "CentralMeridian");
    1573               0 :         double dfFalseEasting = Get(poProjDict, "FalseEasting");
    1574               0 :         double dfFalseNorthing = Get(poProjDict, "FalseNorthing");
    1575                 :         oSRS.SetEckertIV( dfCentralMeridian,
    1576               0 :                           dfFalseEasting, dfFalseNorthing );
    1577                 :     }
    1578                 : 
    1579               0 :     else if (EQUAL(osProjectionType, "ED")) /* Eckert VI */
    1580                 :     {
    1581               0 :         double dfCentralMeridian = Get(poProjDict, "CentralMeridian");
    1582               0 :         double dfFalseEasting = Get(poProjDict, "FalseEasting");
    1583               0 :         double dfFalseNorthing = Get(poProjDict, "FalseNorthing");
    1584                 :         oSRS.SetEckertVI( dfCentralMeridian,
    1585               0 :                           dfFalseEasting, dfFalseNorthing );
    1586                 :     }
    1587                 : 
    1588               0 :     else if (EQUAL(osProjectionType, "CP")) /* Equidistant Cylindrical */
    1589                 :     {
    1590               0 :         double dfCenterLat = Get(poProjDict, "StandardParallel");
    1591               0 :         double dfCenterLong = Get(poProjDict, "CentralMeridian");
    1592               0 :         double dfFalseEasting = Get(poProjDict, "FalseEasting");
    1593               0 :         double dfFalseNorthing = Get(poProjDict, "FalseNorthing");
    1594                 :         oSRS.SetEquirectangular( dfCenterLat, dfCenterLong,
    1595               0 :                                  dfFalseEasting, dfFalseNorthing );
    1596                 :     }
    1597                 : 
    1598               0 :     else if (EQUAL(osProjectionType, "GN")) /* Gnomonic */
    1599                 :     {
    1600               0 :         double dfCenterLat = Get(poProjDict, "OriginLatitude");
    1601               0 :         double dfCenterLong = Get(poProjDict, "CentralMeridian");
    1602               0 :         double dfFalseEasting = Get(poProjDict, "FalseEasting");
    1603               0 :         double dfFalseNorthing = Get(poProjDict, "FalseNorthing");
    1604                 :         oSRS.SetGnomonic(dfCenterLat, dfCenterLong,
    1605               0 :                          dfFalseEasting, dfFalseNorthing );
    1606                 :     }
    1607                 : 
    1608               0 :     else if (EQUAL(osProjectionType, "LE")) /* Lambert Conformal Conic */
    1609                 :     {
    1610               0 :         double dfStdP1 = Get(poProjDict, "StandardParallelOne");
    1611               0 :         double dfStdP2 = Get(poProjDict, "StandardParallelTwo");
    1612               0 :         double dfCenterLat = Get(poProjDict, "OriginLatitude");
    1613               0 :         double dfCenterLong = Get(poProjDict, "CentralMeridian");
    1614               0 :         double dfFalseEasting = Get(poProjDict, "FalseEasting");
    1615               0 :         double dfFalseNorthing = Get(poProjDict, "FalseNorthing");
    1616                 :         oSRS.SetLCC( dfStdP1, dfStdP2,
    1617                 :                      dfCenterLat, dfCenterLong,
    1618               0 :                      dfFalseEasting, dfFalseNorthing );
    1619                 :     }
    1620                 : 
    1621               0 :     else if (EQUAL(osProjectionType, "MC")) /* Mercator */
    1622                 :     {
    1623               0 :         double dfCenterLat = Get(poProjDict, "OriginLatitude");
    1624               0 :         double dfCenterLong = Get(poProjDict, "CentralMeridian");
    1625               0 :         double dfScale = Get(poProjDict, "ScaleFactor");
    1626               0 :         double dfFalseEasting = Get(poProjDict, "FalseEasting");
    1627               0 :         double dfFalseNorthing = Get(poProjDict, "FalseNorthing");
    1628                 :         oSRS.SetMercator( dfCenterLat, dfCenterLong,
    1629                 :                           dfScale,
    1630               0 :                           dfFalseEasting, dfFalseNorthing );
    1631                 :     }
    1632                 : 
    1633               0 :     else if (EQUAL(osProjectionType, "MH")) /* Miller Cylindrical */
    1634                 :     {
    1635               0 :         double dfCenterLat = 0 /* ? */;
    1636               0 :         double dfCenterLong = Get(poProjDict, "CentralMeridian");
    1637               0 :         double dfFalseEasting = Get(poProjDict, "FalseEasting");
    1638               0 :         double dfFalseNorthing = Get(poProjDict, "FalseNorthing");
    1639                 :         oSRS.SetMC( dfCenterLat, dfCenterLong,
    1640               0 :                     dfFalseEasting, dfFalseNorthing );
    1641                 :     }
    1642                 : 
    1643               0 :     else if (EQUAL(osProjectionType, "MP")) /* Mollweide */
    1644                 :     {
    1645               0 :         double dfCentralMeridian = Get(poProjDict, "CentralMeridian");
    1646               0 :         double dfFalseEasting = Get(poProjDict, "FalseEasting");
    1647               0 :         double dfFalseNorthing = Get(poProjDict, "FalseNorthing");
    1648                 :         oSRS.SetMollweide( dfCentralMeridian,
    1649               0 :                            dfFalseEasting, dfFalseNorthing );
    1650                 :     }
    1651                 : 
    1652                 :     /* Unhandled:  "NY" : Ney's (Modified Lambert Conformal Conic) */
    1653                 : 
    1654               0 :     else if (EQUAL(osProjectionType, "NT")) /* New Zealand Map Grid */
    1655                 :     {
    1656                 :         /* No parameter specified in the PDF, so let's take the ones of EPSG:27200 */
    1657               0 :         double dfCenterLat = -41;
    1658               0 :         double dfCenterLong = 173;
    1659               0 :         double dfFalseEasting = 2510000;
    1660               0 :         double dfFalseNorthing = 6023150;
    1661                 :         oSRS.SetNZMG( dfCenterLat, dfCenterLong,
    1662               0 :                       dfFalseEasting, dfFalseNorthing );
    1663                 :     }
    1664                 : 
    1665               0 :     else if (EQUAL(osProjectionType, "OC")) /* Oblique Mercator */
    1666                 :     {
    1667               0 :         double dfCenterLat = Get(poProjDict, "OriginLatitude");
    1668               0 :         double dfLat1 = Get(poProjDict, "LatitudeOne");
    1669               0 :         double dfLong1 = Get(poProjDict, "LongitudeOne");
    1670               0 :         double dfLat2 = Get(poProjDict, "LatitudeTwo");
    1671               0 :         double dfLong2 = Get(poProjDict, "LongitudeTwo");
    1672               0 :         double dfScale = Get(poProjDict, "ScaleFactor");
    1673               0 :         double dfFalseEasting = Get(poProjDict, "FalseEasting");
    1674               0 :         double dfFalseNorthing = Get(poProjDict, "FalseNorthing");
    1675                 :         oSRS.SetHOM2PNO( dfCenterLat,
    1676                 :                          dfLat1, dfLong1,
    1677                 :                          dfLat2, dfLong2,
    1678                 :                          dfScale,
    1679                 :                          dfFalseEasting,
    1680               0 :                          dfFalseNorthing );
    1681                 :     }
    1682                 : 
    1683               0 :     else if (EQUAL(osProjectionType, "OD")) /* Orthographic */
    1684                 :     {
    1685               0 :         double dfCenterLat = Get(poProjDict, "OriginLatitude");
    1686               0 :         double dfCenterLong = Get(poProjDict, "CentralMeridian");
    1687               0 :         double dfFalseEasting = Get(poProjDict, "FalseEasting");
    1688               0 :         double dfFalseNorthing = Get(poProjDict, "FalseNorthing");
    1689                 :         oSRS.SetOrthographic( dfCenterLat, dfCenterLong,
    1690               0 :                            dfFalseEasting, dfFalseNorthing );
    1691                 :     }
    1692                 : 
    1693               0 :     else if (EQUAL(osProjectionType, "PG")) /* Polar Stereographic */
    1694                 :     {
    1695               0 :         double dfCenterLat = Get(poProjDict, "LatitudeTrueScale");
    1696               0 :         double dfCenterLong = Get(poProjDict, "LongitudeDownFromPole");
    1697               0 :         double dfScale = 1.0;
    1698               0 :         double dfFalseEasting = Get(poProjDict, "FalseEasting");
    1699               0 :         double dfFalseNorthing = Get(poProjDict, "FalseNorthing");
    1700                 :         oSRS.SetPS( dfCenterLat, dfCenterLong,
    1701                 :                     dfScale,
    1702               0 :                     dfFalseEasting, dfFalseNorthing);
    1703                 :     }
    1704                 : 
    1705               0 :     else if (EQUAL(osProjectionType, "PH")) /* Polyconic */
    1706                 :     {
    1707               0 :         double dfCenterLat = Get(poProjDict, "OriginLatitude");
    1708               0 :         double dfCenterLong = Get(poProjDict, "CentralMeridian");
    1709               0 :         double dfFalseEasting = Get(poProjDict, "FalseEasting");
    1710               0 :         double dfFalseNorthing = Get(poProjDict, "FalseNorthing");
    1711                 :         oSRS.SetPolyconic( dfCenterLat, dfCenterLong,
    1712               0 :                            dfFalseEasting, dfFalseNorthing );
    1713                 :     }
    1714                 : 
    1715               0 :     else if (EQUAL(osProjectionType, "SA")) /* Sinusoidal */
    1716                 :     {
    1717               0 :         double dfCenterLong = Get(poProjDict, "CentralMeridian");
    1718               0 :         double dfFalseEasting = Get(poProjDict, "FalseEasting");
    1719               0 :         double dfFalseNorthing = Get(poProjDict, "FalseNorthing");
    1720                 :         oSRS.SetSinusoidal( dfCenterLong,
    1721               0 :                            dfFalseEasting, dfFalseNorthing );
    1722                 :     }
    1723                 : 
    1724               0 :     else if (EQUAL(osProjectionType, "SD")) /* Stereographic */
    1725                 :     {
    1726               0 :         double dfCenterLat = Get(poProjDict, "OriginLatitude");
    1727               0 :         double dfCenterLong = Get(poProjDict, "CentralMeridian");
    1728               0 :         double dfScale = 1.0;
    1729               0 :         double dfFalseEasting = Get(poProjDict, "FalseEasting");
    1730               0 :         double dfFalseNorthing = Get(poProjDict, "FalseNorthing");
    1731                 :         oSRS.SetStereographic( dfCenterLat, dfCenterLong,
    1732                 :                                dfScale,
    1733               0 :                                dfFalseEasting, dfFalseNorthing);
    1734                 :     }
    1735                 : 
    1736               0 :     else if (EQUAL(osProjectionType, "TC")) /* Transverse Mercator */
    1737                 :     {
    1738               0 :         double dfCenterLat = Get(poProjDict, "OriginLatitude");
    1739               0 :         double dfCenterLong = Get(poProjDict, "CentralMeridian");
    1740               0 :         double dfScale = Get(poProjDict, "ScaleFactor");
    1741               0 :         double dfFalseEasting = Get(poProjDict, "FalseEasting");
    1742               0 :         double dfFalseNorthing = Get(poProjDict, "FalseNorthing");
    1743               0 :         if (dfCenterLat == 0.0 && dfScale == 0.9996 && dfFalseEasting == 500000 &&
    1744                 :             (dfFalseNorthing == 0.0 || dfFalseNorthing == 10000000.0))
    1745                 :         {
    1746               0 :             int nZone = (int) floor( (dfCenterLong + 180.0) / 6.0 ) + 1;
    1747               0 :             int bNorth = dfFalseNorthing == 0;
    1748               0 :             if (bIsWGS84)
    1749               0 :                 oSRS.importFromEPSG( ((bNorth) ? 32600 : 32700) + nZone );
    1750               0 :             else if (bIsNAD83 && bNorth)
    1751               0 :                 oSRS.importFromEPSG( 26900 + nZone );
    1752                 :             else
    1753               0 :                 oSRS.SetUTM( nZone, bNorth );
    1754                 :         }
    1755                 :         else
    1756                 :         {
    1757                 :             oSRS.SetTM( dfCenterLat, dfCenterLong,
    1758                 :                         dfScale,
    1759               0 :                         dfFalseEasting, dfFalseNorthing );
    1760                 :         }
    1761                 :     }
    1762                 : 
    1763                 :     /* Unhandled TX : Transverse Cylindrical Equal Area */
    1764                 : 
    1765               0 :     else if (EQUAL(osProjectionType, "VA")) /* Van der Grinten */
    1766                 :     {
    1767               0 :         double dfCenterLong = Get(poProjDict, "CentralMeridian");
    1768               0 :         double dfFalseEasting = Get(poProjDict, "FalseEasting");
    1769               0 :         double dfFalseNorthing = Get(poProjDict, "FalseNorthing");
    1770                 :         oSRS.SetVDG( dfCenterLong,
    1771               0 :                      dfFalseEasting, dfFalseNorthing );
    1772                 :     }
    1773                 : 
    1774                 :     else
    1775                 :     {
    1776                 :         CPLError(CE_Failure, CPLE_AppDefined,
    1777                 :                  "Unhandled (yet) value for ProjectionType : %s",
    1778               0 :                  osProjectionType.c_str());
    1779               0 :         return FALSE;
    1780                 :     }
    1781                 : 
    1782                 : /* -------------------------------------------------------------------- */
    1783                 : /*      Extract Units attribute                                         */
    1784                 : /* -------------------------------------------------------------------- */
    1785               2 :     CPLString osUnits;
    1786                 :     GDALPDFObject* poUnits;
    1787               2 :     if ((poUnits = poProjDict->Get("Units")) != NULL &&
    1788               0 :         poUnits->GetType() == PDFObjectType_String)
    1789                 :     {
    1790               0 :         osUnits = poUnits->GetString();
    1791               0 :         CPLDebug("PDF", "Projection.Units = %s", osUnits.c_str());
    1792                 : 
    1793               0 :         if (EQUAL(osUnits, "FT"))
    1794               0 :             oSRS.SetLinearUnits( "Foot", 0.3048 );
    1795                 :     }
    1796                 : 
    1797                 : /* -------------------------------------------------------------------- */
    1798                 : /*      Export SpatialRef                                               */
    1799                 : /* -------------------------------------------------------------------- */
    1800               2 :     CPLFree(pszWKT);
    1801               2 :     pszWKT = NULL;
    1802               2 :     if (oSRS.exportToWkt(&pszWKT) != OGRERR_NONE)
    1803                 :     {
    1804               0 :         CPLFree(pszWKT);
    1805               0 :         pszWKT = NULL;
    1806                 :     }
    1807                 : 
    1808               2 :     return TRUE;
    1809                 : }
    1810                 : 
    1811                 : /************************************************************************/
    1812                 : /*                              ParseVP()                               */
    1813                 : /************************************************************************/
    1814                 : 
    1815               2 : int PDFDataset::ParseVP(GDALPDFObject* poVP, double dfMediaBoxWidth, double dfMediaBoxHeight)
    1816                 : {
    1817                 :     int i;
    1818                 : 
    1819               2 :     if (poVP->GetType() != PDFObjectType_Array)
    1820               0 :         return FALSE;
    1821                 : 
    1822               2 :     GDALPDFArray* poVPArray = poVP->GetArray();
    1823                 : 
    1824               2 :     int nLength = poVPArray->GetLength();
    1825               2 :     CPLDebug("PDF", "VP length = %d", nLength);
    1826               2 :     if (nLength < 1)
    1827               0 :         return FALSE;
    1828                 : 
    1829                 : /* -------------------------------------------------------------------- */
    1830                 : /*      Find the largest BBox                                           */
    1831                 : /* -------------------------------------------------------------------- */
    1832               2 :     int iLargest = 0;
    1833               2 :     double dfLargestArea = 0;
    1834                 : 
    1835               6 :     for(i=0;i<nLength;i++)
    1836                 :     {
    1837               4 :         GDALPDFObject* poVPElt = poVPArray->Get(i);
    1838               4 :         if (poVPElt == NULL || poVPElt->GetType() != PDFObjectType_Dictionary)
    1839                 :         {
    1840               0 :             return FALSE;
    1841                 :         }
    1842                 : 
    1843               4 :         GDALPDFDictionary* poVPEltDict = poVPElt->GetDictionary();
    1844                 : 
    1845                 :         GDALPDFObject* poBBox;
    1846               8 :         if( (poBBox = poVPEltDict->Get("BBox")) == NULL ||
    1847               4 :             poBBox->GetType() != PDFObjectType_Array )
    1848                 :         {
    1849                 :             CPLError(CE_Failure, CPLE_AppDefined,
    1850               0 :                     "Cannot find Bbox object");
    1851               0 :             return FALSE;
    1852                 :         }
    1853                 : 
    1854               4 :         int nBboxLength = poBBox->GetArray()->GetLength();
    1855               4 :         if (nBboxLength != 4)
    1856                 :         {
    1857                 :             CPLError(CE_Failure, CPLE_AppDefined,
    1858               0 :                     "Invalid length for Bbox object");
    1859               0 :             return FALSE;
    1860                 :         }
    1861                 : 
    1862                 :         double adfBBox[4];
    1863               4 :         adfBBox[0] = Get(poBBox, 0);
    1864               4 :         adfBBox[1] = Get(poBBox, 1);
    1865               4 :         adfBBox[2] = Get(poBBox, 2);
    1866               4 :         adfBBox[3] = Get(poBBox, 3);
    1867               4 :         double dfArea = fabs(adfBBox[2] - adfBBox[0]) * fabs(adfBBox[3] - adfBBox[1]);
    1868               4 :         if (dfArea > dfLargestArea)
    1869                 :         {
    1870               2 :             iLargest = i;
    1871               2 :             dfLargestArea = dfArea;
    1872                 :         }
    1873                 :     }
    1874                 : 
    1875               2 :     if (nLength > 1)
    1876                 :     {
    1877               2 :         CPLDebug("PDF", "Largest BBox in VP array is element %d", iLargest);
    1878                 :     }
    1879                 : 
    1880                 : 
    1881               2 :     GDALPDFObject* poVPElt = poVPArray->Get(iLargest);
    1882               2 :     if (poVPElt == NULL || poVPElt->GetType() != PDFObjectType_Dictionary)
    1883                 :     {
    1884               0 :         return FALSE;
    1885                 :     }
    1886                 : 
    1887               2 :     GDALPDFDictionary* poVPEltDict = poVPElt->GetDictionary();
    1888                 : 
    1889                 :     GDALPDFObject* poBBox;
    1890               4 :     if( (poBBox = poVPEltDict->Get("BBox")) == NULL ||
    1891               2 :         poBBox->GetType() != PDFObjectType_Array )
    1892                 :     {
    1893                 :         CPLError(CE_Failure, CPLE_AppDefined,
    1894               0 :                 "Cannot find Bbox object");
    1895               0 :         return FALSE;
    1896                 :     }
    1897                 : 
    1898               2 :     int nBboxLength = poBBox->GetArray()->GetLength();
    1899               2 :     if (nBboxLength != 4)
    1900                 :     {
    1901                 :         CPLError(CE_Failure, CPLE_AppDefined,
    1902               0 :                 "Invalid length for Bbox object");
    1903               0 :         return FALSE;
    1904                 :     }
    1905                 : 
    1906               2 :     double dfULX = Get(poBBox, 0);
    1907               2 :     double dfULY = dfMediaBoxHeight - Get(poBBox, 1);
    1908               2 :     double dfLRX = Get(poBBox, 2);
    1909               2 :     double dfLRY = dfMediaBoxHeight - Get(poBBox, 3);
    1910                 : 
    1911                 : /* -------------------------------------------------------------------- */
    1912                 : /*      Extract Measure attribute                                       */
    1913                 : /* -------------------------------------------------------------------- */
    1914                 :     GDALPDFObject* poMeasure;
    1915               4 :     if( (poMeasure = poVPEltDict->Get("Measure")) == NULL ||
    1916               2 :         poMeasure->GetType() != PDFObjectType_Dictionary )
    1917                 :     {
    1918                 :         CPLError(CE_Failure, CPLE_AppDefined,
    1919               0 :                  "Cannot find Measure object");
    1920               0 :         return FALSE;
    1921                 :     }
    1922                 : 
    1923               2 :     GDALPDFDictionary* poMeasureDict = poMeasure->GetDictionary();
    1924                 : 
    1925                 : /* -------------------------------------------------------------------- */
    1926                 : /*      Extract Subtype attribute                                       */
    1927                 : /* -------------------------------------------------------------------- */
    1928                 :     GDALPDFObject* poSubtype;
    1929               4 :     if( (poSubtype = poMeasureDict->Get("Subtype")) == NULL ||
    1930               2 :         poSubtype->GetType() != PDFObjectType_Name )
    1931                 :     {
    1932                 :         CPLError(CE_Failure, CPLE_AppDefined,
    1933               0 :                  "Cannot find Subtype object");
    1934               0 :         return FALSE;
    1935                 :     }
    1936                 : 
    1937               2 :     CPLDebug("PDF", "Subtype = %s", poSubtype->GetName().c_str());
    1938                 : 
    1939                 : /* -------------------------------------------------------------------- */
    1940                 : /*      Extract Bounds attribute                                       */
    1941                 : /* -------------------------------------------------------------------- */
    1942                 : 
    1943                 :     /* http://acrobatusers.com/sites/default/files/gallery_pictures/SEVERODVINSK.pdf */
    1944                 :     /* has lgit:LPTS, lgit:GPTS and lgit:Bounds that have more precision than */
    1945                 :     /* LPTS, GPTS and Bounds. Use those ones */
    1946                 : 
    1947                 :     GDALPDFObject* poBounds;
    1948               2 :     if( (poBounds = poMeasureDict->Get("lgit:Bounds")) != NULL &&
    1949               0 :         poBounds->GetType() == PDFObjectType_Array )
    1950                 :     {
    1951               0 :         CPLDebug("PDF", "Using lgit:Bounds");
    1952                 :     }
    1953               4 :     else if( (poBounds = poMeasureDict->Get("Bounds")) == NULL ||
    1954               2 :               poBounds->GetType() != PDFObjectType_Array )
    1955                 :     {
    1956                 :         CPLError(CE_Failure, CPLE_AppDefined,
    1957               0 :                  "Cannot find Bounds object");
    1958               0 :         return FALSE;
    1959                 :     }
    1960                 : 
    1961               2 :     int nBoundsLength = poBounds->GetArray()->GetLength();
    1962               2 :     if (nBoundsLength != 8)
    1963                 :     {
    1964                 :         CPLError(CE_Failure, CPLE_AppDefined,
    1965               0 :                  "Invalid length for Bounds object");
    1966               0 :         return FALSE;
    1967                 :     }
    1968                 : 
    1969                 :     double adfBounds[8];
    1970              18 :     for(i=0;i<8;i++)
    1971                 :     {
    1972              16 :         adfBounds[i] = Get(poBounds, i);
    1973              16 :         CPLDebug("PDF", "Bounds[%d] = %f", i, adfBounds[i]);
    1974                 :     }
    1975                 : 
    1976                 : /* -------------------------------------------------------------------- */
    1977                 : /*      Extract GPTS attribute                                          */
    1978                 : /* -------------------------------------------------------------------- */
    1979                 :     GDALPDFObject* poGPTS;
    1980               2 :     if( (poGPTS = poMeasureDict->Get("lgit:GPTS")) != NULL &&
    1981               0 :         poGPTS->GetType() == PDFObjectType_Array )
    1982                 :     {
    1983               0 :         CPLDebug("PDF", "Using lgit:GPTS");
    1984                 :     }
    1985               4 :     else if( (poGPTS = poMeasureDict->Get("GPTS")) == NULL ||
    1986               2 :               poGPTS->GetType() != PDFObjectType_Array )
    1987                 :     {
    1988                 :         CPLError(CE_Failure, CPLE_AppDefined,
    1989               0 :                  "Cannot find GPTS object");
    1990               0 :         return FALSE;
    1991                 :     }
    1992                 : 
    1993               2 :     int nGPTSLength = poGPTS->GetArray()->GetLength();
    1994               2 :     if (nGPTSLength != 8)
    1995                 :     {
    1996                 :         CPLError(CE_Failure, CPLE_AppDefined,
    1997               0 :                  "Invalid length for GPTS object");
    1998               0 :         return FALSE;
    1999                 :     }
    2000                 : 
    2001                 :     double adfGPTS[8];
    2002              18 :     for(i=0;i<8;i++)
    2003                 :     {
    2004              16 :         adfGPTS[i] = Get(poGPTS, i);
    2005              16 :         CPLDebug("PDF", "GPTS[%d] = %.18f", i, adfGPTS[i]);
    2006                 :     }
    2007                 : 
    2008                 : /* -------------------------------------------------------------------- */
    2009                 : /*      Extract LPTS attribute                                          */
    2010                 : /* -------------------------------------------------------------------- */
    2011                 :     GDALPDFObject* poLPTS;
    2012               2 :     if( (poLPTS = poMeasureDict->Get("lgit:LPTS")) != NULL &&
    2013               0 :         poLPTS->GetType() == PDFObjectType_Array )
    2014                 :     {
    2015               0 :         CPLDebug("PDF", "Using lgit:LPTS");
    2016                 :     }
    2017               4 :     else if( (poLPTS = poMeasureDict->Get("LPTS")) == NULL ||
    2018               2 :               poLPTS->GetType() != PDFObjectType_Array )
    2019                 :     {
    2020                 :         CPLError(CE_Failure, CPLE_AppDefined,
    2021               0 :                  "Cannot find LPTS object");
    2022               0 :         return FALSE;
    2023                 :     }
    2024                 : 
    2025               2 :     int nLPTSLength = poLPTS->GetArray()->GetLength();
    2026               2 :     if (nLPTSLength != 8)
    2027                 :     {
    2028                 :         CPLError(CE_Failure, CPLE_AppDefined,
    2029               0 :                  "Invalid length for LPTS object");
    2030               0 :         return FALSE;
    2031                 :     }
    2032                 : 
    2033                 :     double adfLPTS[8];
    2034              18 :     for(i=0;i<8;i++)
    2035                 :     {
    2036              16 :         adfLPTS[i] = Get(poLPTS, i);
    2037              16 :         CPLDebug("PDF", "LPTS[%d] = %f", i, adfLPTS[i]);
    2038                 :     }
    2039                 : 
    2040                 : /* -------------------------------------------------------------------- */
    2041                 : /*      Extract GCS attribute                                           */
    2042                 : /* -------------------------------------------------------------------- */
    2043                 :     GDALPDFObject* poGCS;
    2044               4 :     if( (poGCS = poMeasureDict->Get("GCS")) == NULL ||
    2045               2 :         poGCS->GetType() != PDFObjectType_Dictionary )
    2046                 :     {
    2047                 :         CPLError(CE_Failure, CPLE_AppDefined,
    2048               0 :                  "Cannot find GCS object");
    2049               0 :         return FALSE;
    2050                 :     }
    2051                 : 
    2052               2 :     GDALPDFDictionary* poGCSDict = poGCS->GetDictionary();
    2053                 : 
    2054                 : /* -------------------------------------------------------------------- */
    2055                 : /*      Extract GCS.Type attribute                                      */
    2056                 : /* -------------------------------------------------------------------- */
    2057                 :     GDALPDFObject* poGCSType;
    2058               4 :     if( (poGCSType = poGCSDict->Get("Type")) == NULL ||
    2059               2 :         poGCSType->GetType() != PDFObjectType_Name )
    2060                 :     {
    2061                 :         CPLError(CE_Failure, CPLE_AppDefined,
    2062               0 :                  "Cannot find GCS.Type object");
    2063               0 :         return FALSE;
    2064                 :     }
    2065                 : 
    2066               2 :     CPLDebug("PDF", "GCS.Type = %s", poGCSType->GetName().c_str());
    2067                 : 
    2068                 : /* -------------------------------------------------------------------- */
    2069                 : /*      Extract GCS.WKT attribute                                      */
    2070                 : /* -------------------------------------------------------------------- */
    2071                 :     GDALPDFObject* poGCSWKT;
    2072               4 :     if( (poGCSWKT = poGCSDict->Get("WKT")) == NULL ||
    2073               2 :         poGCSWKT->GetType() != PDFObjectType_String )
    2074                 :     {
    2075                 :         CPLError(CE_Failure, CPLE_AppDefined,
    2076               0 :                  "Cannot find GCS.WKT object");
    2077               0 :         return FALSE;
    2078                 :     }
    2079                 : 
    2080               2 :     CPLDebug("PDF", "GCS.WKT = %s", poGCSWKT->GetString().c_str());
    2081               2 :     CPLFree(pszWKT);
    2082               2 :     pszWKT = CPLStrdup(poGCSWKT->GetString().c_str());
    2083                 : 
    2084                 : /* -------------------------------------------------------------------- */
    2085                 : /*      Compute geotransform                                            */
    2086                 : /* -------------------------------------------------------------------- */
    2087               2 :     OGRSpatialReference oSRS;
    2088               2 :     char* pszWktTemp = pszWKT;
    2089               2 :     if (oSRS.importFromWkt(&pszWktTemp) != OGRERR_NONE)
    2090                 :     {
    2091               0 :         CPLFree(pszWKT);
    2092               0 :         pszWKT = NULL;
    2093               0 :         return FALSE;
    2094                 :     }
    2095                 : 
    2096                 :     /* For http://www.avenza.com/sites/default/files/spatialpdf/US_County_Populations.pdf */
    2097                 :     /* or http://www.agmkt.state.ny.us/soilwater/aem/gis_mapping_tools/HUC12_Albany.pdf */
    2098               2 :     const char* pszDatum = oSRS.GetAttrValue("Datum");
    2099               2 :     if (pszDatum && strncmp(pszDatum, "D_", 2) == 0)
    2100                 :     {
    2101               2 :         oSRS.morphFromESRI();
    2102                 : 
    2103               2 :         CPLFree(pszWKT);
    2104               2 :         pszWKT = NULL;
    2105               2 :         if (oSRS.exportToWkt(&pszWKT) != OGRERR_NONE)
    2106                 :         {
    2107               0 :             CPLFree(pszWKT);
    2108               0 :             pszWKT = NULL;
    2109                 :         }
    2110                 :         else
    2111                 :         {
    2112               2 :             CPLDebug("PDF", "WKT after morphFromESRI() = %s", pszWKT);
    2113                 :         }
    2114                 :     }
    2115                 : 
    2116               2 :     OGRSpatialReference* poSRSGeog = oSRS.CloneGeogCS();
    2117                 : 
    2118               2 :     OGRCoordinateTransformation* poCT = OGRCreateCoordinateTransformation( poSRSGeog, &oSRS);
    2119               2 :     if (poCT == NULL)
    2120                 :     {
    2121               0 :         delete poSRSGeog;
    2122               0 :         CPLFree(pszWKT);
    2123               0 :         pszWKT = NULL;
    2124               0 :         return FALSE;
    2125                 :     }
    2126                 : 
    2127                 :     GDAL_GCP asGCPS[4];
    2128                 : 
    2129                 :     /* Create NEATLINE */
    2130               2 :     poNeatLine = new OGRPolygon();
    2131               4 :     OGRLinearRing* poRing = new OGRLinearRing();
    2132               2 :     poNeatLine->addRingDirectly(poRing);
    2133                 : 
    2134              10 :     for(i=0;i<4;i++)
    2135                 :     {
    2136                 :         /* We probably assume LPTS is 0 or 1 */
    2137               8 :         asGCPS[i].dfGCPPixel = (dfULX * (1 - adfLPTS[2*i+0]) + dfLRX * adfLPTS[2*i+0]) / dfMediaBoxWidth * nRasterXSize;
    2138               8 :         asGCPS[i].dfGCPLine  = (dfULY * (1 - adfLPTS[2*i+1]) + dfLRY * adfLPTS[2*i+1]) / dfMediaBoxHeight * nRasterYSize;
    2139                 : 
    2140               8 :         double lat = adfGPTS[2*i], lon = adfGPTS[2*i+1];
    2141               8 :         double x = lon, y = lat;
    2142               8 :         if (!poCT->Transform(1, &x, &y, NULL))
    2143                 :         {
    2144                 :             CPLError(CE_Failure, CPLE_AppDefined,
    2145               0 :                      "Cannot reproject (%f, %f)", lon, lat);
    2146               0 :             delete poSRSGeog;
    2147               0 :             delete poCT;
    2148               0 :             CPLFree(pszWKT);
    2149               0 :             pszWKT = NULL;
    2150               0 :             return FALSE;
    2151                 :         }
    2152               8 :         asGCPS[i].dfGCPX     = x;
    2153               8 :         asGCPS[i].dfGCPY     = y;
    2154                 : 
    2155               8 :         poRing->addPoint(x, y);
    2156                 :     }
    2157                 : 
    2158               2 :     delete poSRSGeog;
    2159               2 :     delete poCT;
    2160                 : 
    2161               2 :     if (!GDALGCPsToGeoTransform( 4, asGCPS,
    2162                 :                                adfGeoTransform, FALSE))
    2163                 :     {
    2164               0 :         CPLDebug("PDF", "Could not compute GT with exact match. Try with approximate");
    2165               0 :         if (!GDALGCPsToGeoTransform( 4, asGCPS,
    2166                 :                                adfGeoTransform, TRUE))
    2167                 :         {
    2168                 :             CPLError(CE_Failure, CPLE_AppDefined,
    2169               0 :                      "Could not compute GT with approximate match.");
    2170               0 :             return FALSE;
    2171                 :         }
    2172                 :     }
    2173               2 :     bGeoTransformValid = TRUE;
    2174                 : 
    2175                 :     /* If the non scaling terms of the geotransform are significantly smaller than */
    2176                 :     /* the pixel size, then nullify them as being just artifacts of reprojection and */
    2177                 :     /* GDALGCPsToGeoTransform() numerical imprecisions */
    2178               2 :     double dfPixelSize = MIN(fabs(adfGeoTransform[1]), fabs(adfGeoTransform[5]));
    2179               2 :     double dfRotationShearTerm = MAX(fabs(adfGeoTransform[2]), fabs(adfGeoTransform[4]));
    2180               2 :     if (dfRotationShearTerm < 1e-5 * dfPixelSize)
    2181                 :     {
    2182               2 :         double dfLRX = adfGeoTransform[0] + nRasterXSize * adfGeoTransform[1] + nRasterYSize * adfGeoTransform[2];
    2183               2 :         double dfLRY = adfGeoTransform[3] + nRasterXSize * adfGeoTransform[4] + nRasterYSize * adfGeoTransform[5];
    2184               2 :         adfGeoTransform[1] = (dfLRX - adfGeoTransform[0]) / nRasterXSize;
    2185               2 :         adfGeoTransform[5] = (dfLRY - adfGeoTransform[3]) / nRasterYSize;
    2186               2 :         adfGeoTransform[2] = adfGeoTransform[4] = 0;
    2187                 :     }
    2188                 : 
    2189                 : /* -------------------------------------------------------------------- */
    2190                 : /*      Extract PointData attribute                                     */
    2191                 : /* -------------------------------------------------------------------- */
    2192                 :     GDALPDFObject* poPointData;
    2193               2 :     if( (poPointData = poVPEltDict->Get("PtData")) != NULL &&
    2194               0 :         poPointData->GetType() == PDFObjectType_Dictionary )
    2195                 :     {
    2196               0 :         CPLDebug("PDF", "Found PointData");
    2197                 :     }
    2198                 : 
    2199               2 :     return TRUE;
    2200                 : }
    2201                 : 
    2202                 : /************************************************************************/
    2203                 : /*                          GetProjectionRef()                          */
    2204                 : /************************************************************************/
    2205                 : 
    2206               3 : const char* PDFDataset::GetProjectionRef()
    2207                 : {
    2208               3 :     if (pszWKT)
    2209               3 :         return pszWKT;
    2210               0 :     return "";
    2211                 : }
    2212                 : 
    2213                 : /************************************************************************/
    2214                 : /*                          GetGeoTransform()                           */
    2215                 : /************************************************************************/
    2216                 : 
    2217               3 : CPLErr PDFDataset::GetGeoTransform( double * padfTransform )
    2218                 : 
    2219                 : {
    2220               3 :     memcpy(padfTransform, adfGeoTransform, 6 * sizeof(double));
    2221                 : 
    2222               3 :     return( (bGeoTransformValid) ? CE_None : CE_Failure );
    2223                 : }
    2224                 : 
    2225                 : /************************************************************************/
    2226                 : /*                         GDALRegister_PDF()                           */
    2227                 : /************************************************************************/
    2228                 : 
    2229             558 : void GDALRegister_PDF()
    2230                 : 
    2231                 : {
    2232                 :     GDALDriver  *poDriver;
    2233                 : 
    2234             558 :     if (! GDAL_CHECK_VERSION("PDF driver"))
    2235               0 :         return;
    2236                 : 
    2237             558 :     if( GDALGetDriverByName( "PDF" ) == NULL )
    2238                 :     {
    2239             537 :         poDriver = new GDALDriver();
    2240                 : 
    2241             537 :         poDriver->SetDescription( "PDF" );
    2242                 :         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
    2243             537 :                                    "Geospatial PDF" );
    2244                 :         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
    2245             537 :                                    "frmt_pdf.html" );
    2246             537 :         poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "pdf" );
    2247                 : 
    2248                 : #ifdef USE_POPPLER
    2249             537 :         poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
    2250                 : #endif
    2251                 : 
    2252             537 :         poDriver->pfnOpen = PDFDataset::Open;
    2253             537 :         poDriver->pfnIdentify = PDFDataset::Identify;
    2254                 : 
    2255             537 :         GetGDALDriverManager()->RegisterDriver( poDriver );
    2256                 :     }
    2257                 : }
    2258                 : 

Generated by: LCOV version 1.7