LCOV - code coverage report
Current view: directory - frmts/pdf - pdfdataset.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 2345 1562 66.6 %
Date: 2013-03-30 Functions: 93 70 75.3 %

       1                 : /******************************************************************************
       2                 :  * $Id: pdfdataset.cpp 25598 2013-02-05 22:24:35Z 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 "pdfdataset.h"
      35                 : #include "cpl_vsi_virtual.h"
      36                 : #include "cpl_string.h"
      37                 : #include "gdal_pam.h"
      38                 : #include "ogr_spatialref.h"
      39                 : #include "ogr_geometry.h"
      40                 : #include "cpl_spawn.h"
      41                 : 
      42                 : #ifdef HAVE_POPPLER
      43                 : #include "cpl_multiproc.h"
      44                 : #include "pdfio.h"
      45                 : #include <goo/GooList.h>
      46                 : #endif
      47                 : 
      48                 : #include "pdfobject.h"
      49                 : #include "pdfcreatecopy.h"
      50                 : 
      51                 : #include <set>
      52                 : #include <map>
      53                 : 
      54                 : #define DEFAULT_DPI 150.0
      55                 : 
      56                 : /* g++ -fPIC -g -Wall frmts/pdf/pdfdataset.cpp -shared -o gdal_PDF.so -Iport -Igcore -Iogr -L. -lgdal -lpoppler -I/usr/include/poppler */
      57                 : 
      58                 : CPL_CVSID("$Id: pdfdataset.cpp 25598 2013-02-05 22:24:35Z rouault $");
      59                 : 
      60                 : CPL_C_START
      61                 : void    GDALRegister_PDF(void);
      62                 : CPL_C_END
      63                 : 
      64                 : #if defined(HAVE_POPPLER) || defined(HAVE_PODOFO)
      65                 : 
      66                 : static double Get(GDALPDFObject* poObj, int nIndice = -1);
      67                 : 
      68                 : #ifdef HAVE_POPPLER
      69                 : 
      70                 : static void* hGlobalParamsMutex = NULL;
      71                 : 
      72                 : /************************************************************************/
      73                 : /*                          ObjectAutoFree                              */
      74                 : /************************************************************************/
      75                 : 
      76                 : class ObjectAutoFree : public Object
      77                 : {
      78                 : public:
      79             190 :     ObjectAutoFree() {}
      80             190 :     ~ObjectAutoFree() { free(); }
      81                 : };
      82                 : 
      83                 : 
      84                 : /************************************************************************/
      85                 : /*                         GDALPDFOutputDev                             */
      86                 : /************************************************************************/
      87                 : 
      88                 : class GDALPDFOutputDev : public SplashOutputDev
      89              48 : {
      90                 :     private:
      91                 :         int bEnableVector;
      92                 :         int bEnableText;
      93                 :         int bEnableBitmap;
      94                 : 
      95               0 :         void skipBytes(Stream *str,
      96                 :                        int width, int height,
      97                 :                        int nComps, int nBits)
      98                 :         {
      99               0 :             int nVals = width * nComps;
     100               0 :             int nLineSize = (nVals * nBits + 7) >> 3;
     101               0 :             int nBytes = nLineSize * height;
     102               0 :             for (int i = 0; i < nBytes; i++)
     103                 :             {
     104               0 :                 if( str->getChar() == EOF)
     105               0 :                     break;
     106                 :             }
     107               0 :         }
     108                 : 
     109                 :     public:
     110              48 :         GDALPDFOutputDev(SplashColorMode colorModeA, int bitmapRowPadA,
     111                 :                          GBool reverseVideoA, SplashColorPtr paperColorA,
     112                 :                          GBool bitmapTopDownA = gTrue,
     113                 :                          GBool allowAntialiasA = gTrue) :
     114                 :                 SplashOutputDev(colorModeA, bitmapRowPadA,
     115                 :                                 reverseVideoA, paperColorA,
     116                 :                                 bitmapTopDownA, allowAntialiasA),
     117                 :                 bEnableVector(TRUE),
     118                 :                 bEnableText(TRUE),
     119              48 :                 bEnableBitmap(TRUE) {}
     120                 : 
     121               5 :         void SetEnableVector(int bFlag) { bEnableVector = bFlag; }
     122               4 :         void SetEnableText(int bFlag) { bEnableText = bFlag; }
     123               5 :         void SetEnableBitmap(int bFlag) { bEnableBitmap = bFlag; }
     124                 : 
     125              48 :         virtual void startPage(int pageNum, GfxState *state
     126                 : #ifdef POPPLER_0_23_OR_LATER
     127                 :                                ,XRef* xref
     128                 : #endif
     129                 :         )
     130                 :         {
     131                 :             SplashOutputDev::startPage(pageNum, state
     132                 : #ifdef POPPLER_0_23_OR_LATER
     133                 :                                        ,xref
     134                 : #endif
     135              48 :             );
     136              48 :             SplashBitmap* poBitmap = getBitmap();
     137              48 :             memset(poBitmap->getDataPtr(), 255, poBitmap->getRowSize() * poBitmap->getHeight());
     138              48 :         }
     139                 : 
     140            1631 :         virtual void stroke(GfxState * state)
     141                 :         {
     142            1631 :             if (bEnableVector)
     143            1628 :                 SplashOutputDev::stroke(state);
     144            1631 :         }
     145                 : 
     146               0 :         virtual void fill(GfxState * state)
     147                 :         {
     148               0 :             if (bEnableVector)
     149               0 :                 SplashOutputDev::fill(state);
     150               0 :         }
     151                 : 
     152               8 :         virtual void eoFill(GfxState * state)
     153                 :         {
     154               8 :             if (bEnableVector)
     155               6 :                 SplashOutputDev::eoFill(state);
     156               8 :         }
     157                 : 
     158            4247 :         virtual void drawChar(GfxState *state, double x, double y,
     159                 :                               double dx, double dy,
     160                 :                               double originX, double originY,
     161                 :                               CharCode code, int nBytes, Unicode *u, int uLen)
     162                 :         {
     163            4247 :             if (bEnableText)
     164                 :                 SplashOutputDev::drawChar(state, x, y, dx, dy,
     165                 :                                           originX, originY,
     166            4223 :                                           code, nBytes, u, uLen);
     167            4247 :         }
     168                 : 
     169             677 :         virtual void beginTextObject(GfxState *state)
     170                 :         {
     171             677 :             if (bEnableText)
     172             675 :                 SplashOutputDev::beginTextObject(state);
     173             677 :         }
     174                 : 
     175                 : #ifndef POPPLER_0_23_OR_LATER
     176                 :         virtual GBool deviceHasTextClip(GfxState *state)
     177                 :         {
     178                 :             if (bEnableText)
     179                 :                 return SplashOutputDev::deviceHasTextClip(state);
     180                 :             return gFalse;
     181                 :         }
     182                 : #endif
     183                 : 
     184             677 :         virtual void endTextObject(GfxState *state)
     185                 :         {
     186             677 :             if (bEnableText)
     187             675 :                 SplashOutputDev::endTextObject(state);
     188             677 :         }
     189                 : 
     190               0 :         virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
     191                 :                                    int width, int height, GBool invert,
     192                 :                                    GBool interpolate, GBool inlineImg)
     193                 :         {
     194               0 :             if (bEnableBitmap)
     195                 :                 SplashOutputDev::drawImageMask(state, ref, str,
     196                 :                                                width, height, invert,
     197               0 :                                                interpolate, inlineImg);
     198                 :             else
     199                 :             {
     200               0 :                 str->reset();
     201               0 :                 if (inlineImg)
     202                 :                 {
     203               0 :                     skipBytes(str, width, height, 1, 1);
     204                 :                 }
     205               0 :                 str->close();
     206                 :             }
     207               0 :         }
     208                 : 
     209                 : #ifdef POPPLER_0_20_OR_LATER
     210               0 :         virtual void setSoftMaskFromImageMask(GfxState *state,
     211                 :                             Object *ref, Stream *str,
     212                 :                             int width, int height, GBool invert,
     213                 :                             GBool inlineImg, double *baseMatrix)
     214                 :         {
     215               0 :             if (bEnableBitmap)
     216                 :                 SplashOutputDev::setSoftMaskFromImageMask(state, ref, str,
     217                 :                                                width, height, invert,
     218               0 :                                                inlineImg, baseMatrix);
     219                 :             else
     220               0 :                 str->close();
     221               0 :         }
     222                 : 
     223               0 :         virtual void unsetSoftMaskFromImageMask(GfxState *state, double *baseMatrix)
     224                 :         {
     225               0 :             if (bEnableBitmap)
     226               0 :                 SplashOutputDev::unsetSoftMaskFromImageMask(state, baseMatrix);
     227               0 :         }
     228                 : #endif
     229                 : 
     230              42 :         virtual void drawImage(GfxState *state, Object *ref, Stream *str,
     231                 :                                int width, int height, GfxImageColorMap *colorMap,
     232                 :                                GBool interpolate, int *maskColors, GBool inlineImg)
     233                 :         {
     234              42 :             if (bEnableBitmap)
     235                 :                 SplashOutputDev::drawImage(state, ref, str,
     236                 :                                            width, height, colorMap,
     237              41 :                                            interpolate, maskColors, inlineImg);
     238                 :             else
     239                 :             {
     240               1 :                 str->reset();
     241               1 :                 if (inlineImg)
     242                 :                 {
     243                 :                     skipBytes(str, width, height,
     244                 :                               colorMap->getNumPixelComps(),
     245               0 :                               colorMap->getBits());
     246                 :                 }
     247               1 :                 str->close();
     248                 :             }
     249              42 :         }
     250                 : 
     251               0 :         virtual void drawMaskedImage(GfxState *state, Object *ref, Stream *str,
     252                 :                                      int width, int height,
     253                 :                                      GfxImageColorMap *colorMap,
     254                 :                                      GBool interpolate,
     255                 :                                      Stream *maskStr, int maskWidth, int maskHeight,
     256                 :                                      GBool maskInvert, GBool maskInterpolate)
     257                 :         {
     258               0 :             if (bEnableBitmap)
     259                 :                 SplashOutputDev::drawMaskedImage(state, ref, str,
     260                 :                                                  width, height, colorMap,
     261                 :                                                  interpolate,
     262                 :                                                  maskStr, maskWidth, maskHeight,
     263               0 :                                                  maskInvert, maskInterpolate);
     264                 :             else
     265               0 :                 str->close();
     266               0 :         }
     267                 : 
     268               3 :         virtual void drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str,
     269                 :                                          int width, int height,
     270                 :                                          GfxImageColorMap *colorMap,
     271                 :                                          GBool interpolate,
     272                 :                                          Stream *maskStr,
     273                 :                                          int maskWidth, int maskHeight,
     274                 :                                          GfxImageColorMap *maskColorMap,
     275                 :                                          GBool maskInterpolate)
     276                 :         {
     277               3 :             if (bEnableBitmap)
     278                 :             {
     279               3 :                 if( maskColorMap->getBits() <= 0 ) /* workaround poppler bug (robustness) */
     280                 :                 {
     281               0 :                     str->close();
     282               0 :                     return;
     283                 :                 }
     284                 :                 SplashOutputDev::drawSoftMaskedImage(state, ref, str,
     285                 :                                                      width, height, colorMap,
     286                 :                                                      interpolate,
     287                 :                                                      maskStr, maskWidth, maskHeight,
     288               3 :                                                      maskColorMap, maskInterpolate);
     289                 :             }
     290                 :             else
     291               0 :                 str->close();
     292                 :         }
     293                 : };
     294                 : 
     295                 : #endif
     296                 : 
     297                 : /************************************************************************/
     298                 : /*                         Dump routines                                */
     299                 : /************************************************************************/
     300                 : 
     301                 : class GDALPDFDumper
     302               0 : {
     303                 :     private:
     304                 :         FILE* f;
     305                 :         int   nDepthLimit;
     306                 :         std::set< int > aoSetObjectExplored;
     307                 :         int   bDumpParent;
     308                 : 
     309                 :         void DumpSimplified(GDALPDFObject* poObj);
     310                 : 
     311                 :     public:
     312               0 :         GDALPDFDumper(FILE* fIn, int nDepthLimitIn = -1) : f(fIn), nDepthLimit(nDepthLimitIn)
     313                 :         {
     314               0 :             bDumpParent = CSLTestBoolean(CPLGetConfigOption("PDF_DUMP_PARENT", "FALSE"));
     315               0 :         }
     316                 : 
     317                 :         void Dump(GDALPDFObject* poObj, int nDepth = 0);
     318                 :         void Dump(GDALPDFDictionary* poDict, int nDepth = 0);
     319                 :         void Dump(GDALPDFArray* poArray, int nDepth = 0);
     320                 : };
     321                 : 
     322               0 : void GDALPDFDumper::Dump(GDALPDFArray* poArray, int nDepth)
     323                 : {
     324               0 :     if (nDepthLimit >= 0 && nDepth > nDepthLimit)
     325               0 :         return;
     326                 : 
     327               0 :     int nLength = poArray->GetLength();
     328                 :     int i;
     329               0 :     CPLString osIndent;
     330               0 :     for(i=0;i<nDepth;i++)
     331               0 :         osIndent += " ";
     332               0 :     for(i=0;i<nLength;i++)
     333                 :     {
     334               0 :         fprintf(f, "%sItem[%d]:", osIndent.c_str(), i);
     335               0 :         GDALPDFObject* poObj = NULL;
     336               0 :         if ((poObj = poArray->Get(i)) != NULL)
     337                 :         {
     338               0 :             if (poObj->GetType() == PDFObjectType_String ||
     339               0 :                 poObj->GetType() == PDFObjectType_Null ||
     340               0 :                 poObj->GetType() == PDFObjectType_Bool ||
     341               0 :                 poObj->GetType() == PDFObjectType_Int ||
     342               0 :                 poObj->GetType() == PDFObjectType_Real ||
     343               0 :                 poObj->GetType() == PDFObjectType_Name)
     344                 :             {
     345               0 :                 fprintf(f, " ");
     346               0 :                 DumpSimplified(poObj);
     347               0 :                 fprintf(f, "\n");
     348                 :             }
     349                 :             else
     350                 :             {
     351               0 :                 fprintf(f, "\n");
     352               0 :                 Dump( poObj, nDepth+1);
     353                 :             }
     354                 :         }
     355               0 :     }
     356                 : }
     357                 : 
     358               0 : void GDALPDFDumper::DumpSimplified(GDALPDFObject* poObj)
     359                 : {
     360               0 :     switch(poObj->GetType())
     361                 :     {
     362                 :         case PDFObjectType_String:
     363               0 :             fprintf(f, "%s (string)", poObj->GetString().c_str());
     364               0 :             break;
     365                 : 
     366                 :         case PDFObjectType_Null:
     367               0 :             fprintf(f, "null");
     368               0 :             break;
     369                 : 
     370                 :         case PDFObjectType_Bool:
     371               0 :             fprintf(f, "%s (bool)", poObj->GetBool() ? "true" : "false");
     372               0 :             break;
     373                 : 
     374                 :         case PDFObjectType_Int:
     375               0 :             fprintf(f, "%d (int)", poObj->GetInt());
     376               0 :             break;
     377                 : 
     378                 :         case PDFObjectType_Real:
     379               0 :             fprintf(f, "%f (real)", poObj->GetReal());
     380               0 :             break;
     381                 : 
     382                 :         case PDFObjectType_Name:
     383               0 :             fprintf(f, "%s (name)", poObj->GetName().c_str());
     384               0 :             break;
     385                 : 
     386                 :         default:
     387               0 :             fprintf(f, "unknown !");
     388                 :             break;
     389                 :     }
     390               0 : }
     391                 : 
     392               0 : void GDALPDFDumper::Dump(GDALPDFObject* poObj, int nDepth)
     393                 : {
     394               0 :     if (nDepthLimit >= 0 && nDepth > nDepthLimit)
     395               0 :         return;
     396                 : 
     397                 :     int i;
     398               0 :     CPLString osIndent;
     399               0 :     for(i=0;i<nDepth;i++)
     400               0 :         osIndent += " ";
     401                 :     fprintf(f, "%sType = %s",
     402               0 :             osIndent.c_str(), poObj->GetTypeName());
     403               0 :     int nRefNum = poObj->GetRefNum();
     404               0 :     if (nRefNum != 0)
     405                 :         fprintf(f, ", Num = %d, Gen = %d",
     406               0 :                 nRefNum, poObj->GetRefGen());
     407               0 :     fprintf(f, "\n");
     408                 : 
     409               0 :     if (nRefNum != 0)
     410                 :     {
     411               0 :         if (aoSetObjectExplored.find(nRefNum) != aoSetObjectExplored.end())
     412                 :             return;
     413               0 :         aoSetObjectExplored.insert(nRefNum);
     414                 :     }
     415                 : 
     416               0 :     switch(poObj->GetType())
     417                 :     {
     418                 :         case PDFObjectType_Array:
     419               0 :             Dump(poObj->GetArray(), nDepth+1);
     420               0 :             break;
     421                 : 
     422                 :         case PDFObjectType_Dictionary:
     423               0 :             Dump(poObj->GetDictionary(), nDepth+1);
     424               0 :             break;
     425                 : 
     426                 :         case PDFObjectType_String:
     427                 :         case PDFObjectType_Null:
     428                 :         case PDFObjectType_Bool:
     429                 :         case PDFObjectType_Int:
     430                 :         case PDFObjectType_Real:
     431                 :         case PDFObjectType_Name:
     432               0 :             fprintf(f, "%s", osIndent.c_str());
     433               0 :             DumpSimplified(poObj);
     434               0 :             fprintf(f, "\n");
     435               0 :             break;
     436                 : 
     437                 :         default:
     438               0 :             fprintf(f, "%s", osIndent.c_str());
     439               0 :             fprintf(f, "unknown !\n");
     440                 :             break;
     441                 :     }
     442                 : 
     443               0 :     GDALPDFStream* poStream = poObj->GetStream();
     444               0 :     if (poStream != NULL)
     445                 :     {
     446               0 :         fprintf(f, "%sHas stream (%d bytes)\n", osIndent.c_str(), poStream->GetLength());
     447               0 :     }
     448                 : }
     449                 : 
     450               0 : void GDALPDFDumper::Dump(GDALPDFDictionary* poDict, int nDepth)
     451                 : {
     452               0 :     if (nDepthLimit >= 0 && nDepth > nDepthLimit)
     453               0 :         return;
     454                 : 
     455               0 :     std::map<CPLString, GDALPDFObject*>& oMap = poDict->GetValues();
     456               0 :     std::map<CPLString, GDALPDFObject*>::iterator oIter = oMap.begin();
     457               0 :     std::map<CPLString, GDALPDFObject*>::iterator oEnd = oMap.end();
     458                 :     int i;
     459               0 :     CPLString osIndent;
     460               0 :     for(i=0;i<nDepth;i++)
     461               0 :         osIndent += " ";
     462               0 :     for(i=0;oIter != oEnd;++oIter, i++)
     463                 :     {
     464               0 :         const char* pszKey = oIter->first.c_str();
     465               0 :         fprintf(f, "%sItem[%d] : %s", osIndent.c_str(), i, pszKey);
     466               0 :         GDALPDFObject* poObj = oIter->second;
     467               0 :         if (strcmp(pszKey, "Parent") == 0 && !bDumpParent)
     468                 :         {
     469               0 :             if (poObj->GetRefNum())
     470                 :                 fprintf(f, ", Num = %d, Gen = %d",
     471               0 :                         poObj->GetRefNum(), poObj->GetRefGen());
     472               0 :             fprintf(f, "\n");
     473               0 :             continue;
     474                 :         }
     475               0 :         if (poObj != NULL)
     476                 :         {
     477               0 :             if (poObj->GetType() == PDFObjectType_String ||
     478               0 :                 poObj->GetType() == PDFObjectType_Null ||
     479               0 :                 poObj->GetType() == PDFObjectType_Bool ||
     480               0 :                 poObj->GetType() == PDFObjectType_Int ||
     481               0 :                 poObj->GetType() == PDFObjectType_Real ||
     482               0 :                 poObj->GetType() == PDFObjectType_Name)
     483                 :             {
     484               0 :                 fprintf(f, " = ");
     485               0 :                 DumpSimplified(poObj);
     486               0 :                 fprintf(f, "\n");
     487                 :             }
     488                 :             else
     489                 :             {
     490               0 :                 fprintf(f, "\n");
     491               0 :                 Dump(poObj, nDepth+1);
     492                 :             }
     493                 :         }
     494               0 :     }
     495                 : }
     496                 : 
     497                 : /************************************************************************/
     498                 : /*                            GDALPDFTileDesc                           */
     499                 : /************************************************************************/
     500                 : 
     501                 : typedef struct
     502                 : {
     503                 :     GDALPDFObject* poImage;
     504                 :     double         adfCM[6];
     505                 :     double         dfWidth;
     506                 :     double         dfHeight;
     507                 :     int            nBands;
     508               0 : } GDALPDFTileDesc;
     509                 : 
     510                 : /************************************************************************/
     511                 : /* ==================================================================== */
     512                 : /*                              PDFDataset                              */
     513                 : /* ==================================================================== */
     514                 : /************************************************************************/
     515                 : 
     516                 : class PDFRasterBand;
     517                 : class PDFImageRasterBand;
     518                 : 
     519                 : class PDFDataset : public GDALPamDataset
     520                 : {
     521                 :     friend class PDFRasterBand;
     522                 :     friend class PDFImageRasterBand;
     523                 : 
     524                 :     CPLString    osFilename;
     525                 :     CPLString    osUserPwd;
     526                 :     char        *pszWKT;
     527                 :     double       dfDPI;
     528                 :     int          bHasCTM;
     529                 :     double       adfCTM[6];
     530                 :     double       adfGeoTransform[6];
     531                 :     int          bGeoTransformValid;
     532                 :     int          nGCPCount;
     533                 :     GDAL_GCP    *pasGCPList;
     534                 :     int          bProjDirty;
     535                 :     int          bNeatLineDirty;
     536                 : 
     537                 :     GDALMultiDomainMetadata oMDMD;
     538                 :     int          bInfoDirty;
     539                 :     int          bXMPDirty;
     540                 : 
     541                 :     int          bUsePoppler;
     542                 : #ifdef HAVE_POPPLER
     543                 :     PDFDoc*      poDocPoppler;
     544                 : #endif
     545                 : #ifdef HAVE_PODOFO
     546                 :     PoDoFo::PdfMemDocument* poDocPodofo;
     547                 :     int          bPdfToPpmFailed;
     548                 : #endif
     549                 :     GDALPDFObject* poPageObj;
     550                 : 
     551                 :     int          iPage;
     552                 : 
     553                 :     GDALPDFObject *poImageObj;
     554                 : 
     555                 :     double       dfMaxArea;
     556                 :     int          ParseLGIDictObject(GDALPDFObject* poLGIDict);
     557                 :     int          ParseLGIDictDictFirstPass(GDALPDFDictionary* poLGIDict, int* pbIsBestCandidate = NULL);
     558                 :     int          ParseLGIDictDictSecondPass(GDALPDFDictionary* poLGIDict);
     559                 :     int          ParseProjDict(GDALPDFDictionary* poProjDict);
     560                 :     int          ParseVP(GDALPDFObject* poVP, double dfMediaBoxWidth, double dfMediaBoxHeight);
     561                 :     int          ParseMeasure(GDALPDFObject* poMeasure,
     562                 :                               double dfMediaBoxWidth, double dfMediaBoxHeight,
     563                 :                               double dfULX, double dfULY, double dfLRX, double dfLRY);
     564                 : 
     565                 :     int          bTried;
     566                 :     GByte       *pabyCachedData;
     567                 :     int          nLastBlockXOff, nLastBlockYOff;
     568                 : 
     569                 :     OGRPolygon*  poNeatLine;
     570                 : 
     571                 :     std::vector<GDALPDFTileDesc> asTiles; /* in the order of the PDF file */
     572                 :     std::vector<int> aiTiles; /* in the order of blocks */
     573                 :     int          nBlockXSize;
     574                 :     int          nBlockYSize;
     575                 :     int          CheckTiledRaster();
     576                 : 
     577                 :     void         GuessDPI(GDALPDFDictionary* poPageDict, int* pnBands);
     578                 :     void         FindXMP(GDALPDFObject* poObj);
     579                 :     void         ParseInfo(GDALPDFObject* poObj);
     580                 : 
     581                 : #ifdef HAVE_POPPLER
     582                 :     ObjectAutoFree* poCatalogObjectPoppler;
     583                 : #endif
     584                 :     GDALPDFObject* poCatalogObject;
     585                 :     GDALPDFObject* GetCatalog();
     586                 : 
     587                 : #ifdef HAVE_POPPLER
     588                 :     void         AddLayer(const char* pszLayerName, OptionalContentGroup* ocg);
     589                 :     void         ExploreLayers(GDALPDFArray* poArray, int nRecLevel, CPLString osTopLayer = "");
     590                 :     void         FindLayers();
     591                 :     void         TurnLayersOnOff();
     592                 :     CPLStringList osLayerList;
     593                 :     std::map<CPLString, OptionalContentGroup*> oLayerOCGMap;
     594                 : #endif
     595                 : 
     596                 :     CPLStringList osLayerWithRefList;
     597                 :     CPLString     FindLayerOCG(GDALPDFDictionary* poPageDict,
     598                 :                                const char* pszLayerName);
     599                 :     void          FindLayersGeneric(GDALPDFDictionary* poPageDict);
     600                 : 
     601                 :     int          bUseOCG;
     602                 : 
     603                 :   public:
     604                 :                  PDFDataset();
     605                 :     virtual     ~PDFDataset();
     606                 : 
     607                 :     virtual const char* GetProjectionRef();
     608                 :     virtual CPLErr GetGeoTransform( double * );
     609                 : 
     610                 :     virtual CPLErr      SetProjection(const char* pszWKTIn);
     611                 :     virtual CPLErr      SetGeoTransform(double* padfGeoTransform);
     612                 : 
     613                 :     virtual char      **GetMetadata( const char * pszDomain = "" );
     614                 :     virtual CPLErr      SetMetadata( char ** papszMetadata,
     615                 :                                      const char * pszDomain = "" );
     616                 :     virtual const char *GetMetadataItem( const char * pszName,
     617                 :                                          const char * pszDomain = "" );
     618                 :     virtual CPLErr      SetMetadataItem( const char * pszName,
     619                 :                                          const char * pszValue,
     620                 :                                          const char * pszDomain = "" );
     621                 : 
     622                 :     virtual CPLErr IRasterIO( GDALRWFlag, int, int, int, int,
     623                 :                               void *, int, int, GDALDataType,
     624                 :                               int, int *, int, int, int );
     625                 : 
     626                 :     virtual int    GetGCPCount();
     627                 :     virtual const char *GetGCPProjection();
     628                 :     virtual const GDAL_GCP *GetGCPs();
     629                 :     virtual CPLErr SetGCPs( int nGCPCount, const GDAL_GCP *pasGCPList,
     630                 :                             const char *pszGCPProjection );
     631                 : 
     632                 :     CPLErr ReadPixels( int nReqXOff, int nReqYOff,
     633                 :                        int nReqXSize, int nReqYSize,
     634                 :                        int nPixelSpace,
     635                 :                        int nLineSpace,
     636                 :                        int nBandSpace,
     637                 :                        GByte* pabyData );
     638                 : 
     639                 :     static GDALDataset *Open( GDALOpenInfo * );
     640                 :     static int          Identify( GDALOpenInfo * );
     641                 : };
     642                 : 
     643                 : /************************************************************************/
     644                 : /* ==================================================================== */
     645                 : /*                         PDFRasterBand                                */
     646                 : /* ==================================================================== */
     647                 : /************************************************************************/
     648                 : 
     649                 : class PDFRasterBand : public GDALPamRasterBand
     650             554 : {
     651                 :     friend class PDFDataset;
     652                 : 
     653                 :     CPLErr IReadBlockFromTile( int, int, void * );
     654                 : 
     655                 :   public:
     656                 : 
     657                 :                 PDFRasterBand( PDFDataset *, int );
     658                 : 
     659                 :     virtual CPLErr IReadBlock( int, int, void * );
     660                 :     virtual GDALColorInterp GetColorInterpretation();
     661                 : };
     662                 : 
     663                 : 
     664                 : /************************************************************************/
     665                 : /*                         PDFRasterBand()                              */
     666                 : /************************************************************************/
     667                 : 
     668             554 : PDFRasterBand::PDFRasterBand( PDFDataset *poDS, int nBand )
     669                 : 
     670                 : {
     671             554 :     this->poDS = poDS;
     672             554 :     this->nBand = nBand;
     673                 : 
     674             554 :     eDataType = GDT_Byte;
     675                 : 
     676             554 :     if( poDS->nBlockXSize )
     677                 :     {
     678              40 :         nBlockXSize = poDS->nBlockXSize;
     679              40 :         nBlockYSize = poDS->nBlockYSize;
     680                 :     }
     681             514 :     else if( poDS->GetRasterXSize() < 64 * 1024 * 1024 / poDS->GetRasterYSize() )
     682                 :     {
     683             514 :         nBlockXSize = poDS->GetRasterXSize();
     684             514 :         nBlockYSize = 1;
     685                 :     }
     686                 :     else
     687                 :     {
     688               0 :         nBlockXSize = MIN(1024, poDS->GetRasterXSize());
     689               0 :         nBlockYSize = MIN(1024, poDS->GetRasterYSize());
     690               0 :         poDS->SetMetadataItem( "INTERLEAVE", "PIXEL", "IMAGE_STRUCTURE" );
     691                 :     }
     692             554 : }
     693                 : 
     694                 : /************************************************************************/
     695                 : /*                        GetColorInterpretation()                      */
     696                 : /************************************************************************/
     697                 : 
     698               0 : GDALColorInterp PDFRasterBand::GetColorInterpretation()
     699                 : {
     700               0 :     PDFDataset *poGDS = (PDFDataset *) poDS;
     701               0 :     if (poGDS->nBands == 1)
     702               0 :         return GCI_GrayIndex;
     703                 :     else
     704               0 :         return (GDALColorInterp)(GCI_RedBand + (nBand - 1));
     705                 : }
     706                 : 
     707                 : /************************************************************************/
     708                 : /*                         IReadBlockFromTile()                         */
     709                 : /************************************************************************/
     710                 : 
     711             284 : CPLErr PDFRasterBand::IReadBlockFromTile( int nBlockXOff, int nBlockYOff,
     712                 :                                           void * pImage )
     713                 : 
     714                 : {
     715             284 :     PDFDataset *poGDS = (PDFDataset *) poDS;
     716                 : 
     717             284 :     int nReqXSize = nBlockXSize;
     718             284 :     int nReqYSize = nBlockYSize;
     719             284 :     if( (nBlockXOff + 1) * nBlockXSize > nRasterXSize )
     720              42 :         nReqXSize = nRasterXSize - nBlockXOff * nBlockXSize;
     721             284 :     if( (nBlockYOff + 1) * nBlockYSize > nRasterYSize )
     722              50 :         nReqYSize = nRasterYSize - nBlockYOff * nBlockYSize;
     723                 : 
     724             284 :     int nXBlocks = DIV_ROUND_UP(nRasterXSize, nBlockXSize);
     725             284 :     int iTile = poGDS->aiTiles[nBlockYOff * nXBlocks + nBlockXOff];
     726             284 :     GDALPDFTileDesc& sTile = poGDS->asTiles[iTile];
     727             284 :     GDALPDFObject* poImage = sTile.poImage;
     728                 : 
     729             284 :     if( iTile < 0 )
     730                 :     {
     731               0 :         memset(pImage, 0, nBlockXSize * nBlockYSize);
     732               0 :         return CE_None;
     733                 :     }
     734                 : 
     735             284 :     if( nBand == 4 )
     736                 :     {
     737              60 :         GDALPDFDictionary* poImageDict = poImage->GetDictionary();
     738              60 :         GDALPDFObject* poSMask = poImageDict->Get("SMask");
     739              60 :         if( poSMask != NULL && poSMask->GetType() == PDFObjectType_Dictionary )
     740                 :         {
     741              60 :             GDALPDFDictionary* poSMaskDict = poSMask->GetDictionary();
     742              60 :             GDALPDFObject* poWidth = poSMaskDict->Get("Width");
     743              60 :             GDALPDFObject* poHeight = poSMaskDict->Get("Height");
     744              60 :             GDALPDFObject* poColorSpace = poSMaskDict->Get("ColorSpace");
     745              60 :             GDALPDFObject* poBitsPerComponent = poSMaskDict->Get("BitsPerComponent");
     746              60 :             int nBits = 0;
     747              60 :             if( poBitsPerComponent )
     748              60 :                 nBits = (int)Get(poBitsPerComponent);
     749             180 :             if (poWidth && Get(poWidth) == nReqXSize &&
     750                 :                 poHeight && Get(poHeight) == nReqYSize &&
     751              60 :                 poColorSpace && poColorSpace->GetType() == PDFObjectType_Name &&
     752              60 :                 poColorSpace->GetName() == "DeviceGray" &&
     753                 :                 (nBits == 1 || nBits == 8) )
     754                 :             {
     755              60 :                 GDALPDFStream* poStream = poSMask->GetStream();
     756              60 :                 GByte* pabyStream = NULL;
     757                 : 
     758              60 :                 if( poStream == NULL )
     759               0 :                     return CE_Failure;
     760                 : 
     761              60 :                 pabyStream = (GByte*) poStream->GetBytes();
     762              60 :                 if( pabyStream == NULL )
     763               0 :                     return CE_Failure;
     764                 : 
     765              60 :                 int nReqXSize1 = (nReqXSize + 7) / 8;
     766              76 :                 if( (nBits == 8 && poStream->GetLength() != nReqXSize * nReqYSize) ||
     767              16 :                     (nBits == 1 && poStream->GetLength() != nReqXSize1 * nReqYSize) )
     768                 :                 {
     769               0 :                     VSIFree(pabyStream);
     770               0 :                     return CE_Failure;
     771                 :                 }
     772                 : 
     773              60 :                 GByte* pabyData = (GByte*) pImage;
     774              60 :                 if( nReqXSize != nBlockXSize || nReqYSize != nBlockYSize )
     775                 :                 {
     776              20 :                     memset(pabyData, 0, nBlockXSize * nBlockYSize);
     777                 :                 }
     778                 : 
     779              60 :                 if( nBits == 8 )
     780                 :                 {
     781            1372 :                     for(int j = 0; j < nReqYSize; j++)
     782                 :                     {
     783           43824 :                         for(int i = 0; i < nReqXSize; i++)
     784                 :                         {
     785           42496 :                             pabyData[j * nBlockXSize + i] = pabyStream[j * nReqXSize + i];
     786                 :                         }
     787                 :                     }
     788                 :                 }
     789                 :                 else
     790                 :                 {
     791             488 :                     for(int j = 0; j < nReqYSize; j++)
     792                 :                     {
     793            6576 :                         for(int i = 0; i < nReqXSize; i++)
     794                 :                         {
     795            6104 :                             if( pabyStream[j * nReqXSize1 + i / 8] & (1 << (7 - (i % 8))) )
     796            1792 :                                 pabyData[j * nBlockXSize + i] = 255;
     797                 :                             else
     798            4312 :                                 pabyData[j * nBlockXSize + i] = 0;
     799                 :                         }
     800                 :                     }
     801                 :                 }
     802                 : 
     803              60 :                 VSIFree(pabyStream);
     804              60 :                 return CE_None;
     805                 :             }
     806                 :         }
     807                 : 
     808               0 :         memset(pImage, 255, nBlockXSize * nBlockYSize);
     809               0 :         return CE_None;
     810                 :     }
     811                 : 
     812             224 :     if( poGDS->nLastBlockXOff == nBlockXOff &&
     813                 :         poGDS->nLastBlockYOff == nBlockYOff &&
     814                 :         poGDS->pabyCachedData != NULL )
     815                 :     {
     816                 :         CPLDebug("PDF", "Using cached block (%d, %d)",
     817               0 :                  nBlockXOff, nBlockYOff);
     818                 :         // do nothing
     819                 :     }
     820                 :     else
     821                 :     {
     822             224 :         if (poGDS->bTried == FALSE)
     823                 :         {
     824               7 :             poGDS->bTried = TRUE;
     825               7 :             poGDS->pabyCachedData = (GByte*)VSIMalloc3(3, nBlockXSize, nBlockYSize);
     826                 :         }
     827             224 :         if (poGDS->pabyCachedData == NULL)
     828               0 :             return CE_Failure;
     829                 : 
     830             224 :         GDALPDFStream* poStream = poImage->GetStream();
     831             224 :         GByte* pabyStream = NULL;
     832                 : 
     833             224 :         if( poStream == NULL )
     834               0 :             return CE_Failure;
     835                 : 
     836             224 :         pabyStream = (GByte*) poStream->GetBytes();
     837             224 :         if( pabyStream == NULL )
     838               0 :             return CE_Failure;
     839                 : 
     840             224 :         if( poStream->GetLength() != sTile.nBands * nReqXSize * nReqYSize)
     841                 :         {
     842               0 :             VSIFree(pabyStream);
     843               0 :             return CE_Failure;
     844                 :         }
     845                 : 
     846             224 :         memcpy(poGDS->pabyCachedData, pabyStream, poStream->GetLength());
     847             224 :         VSIFree(pabyStream);
     848             224 :         poGDS->nLastBlockXOff = nBlockXOff;
     849             224 :         poGDS->nLastBlockYOff = nBlockYOff;
     850                 :     }
     851                 : 
     852             224 :     GByte* pabyData = (GByte*) pImage;
     853             224 :     if( nBand != 4 && (nReqXSize != nBlockXSize || nReqYSize != nBlockYSize) )
     854                 :     {
     855              63 :         memset(pabyData, 0, nBlockXSize * nBlockYSize);
     856                 :     }
     857                 : 
     858             404 :     if( poGDS->nBands >= 3 && sTile.nBands == 3 )
     859                 :     {
     860            5580 :         for(int j = 0; j < nReqYSize; j++)
     861                 :         {
     862          151200 :             for(int i = 0; i < nReqXSize; i++)
     863                 :             {
     864          145800 :                 pabyData[j * nBlockXSize + i] = poGDS->pabyCachedData[3 * (j * nReqXSize + i) + nBand - 1];
     865                 :             }
     866                 :         }
     867                 :     }
     868              44 :     else if( sTile.nBands == 1 )
     869                 :     {
     870            8362 :         for(int j = 0; j < nReqYSize; j++)
     871                 :         {
     872         2405861 :             for(int i = 0; i < nReqXSize; i++)
     873                 :             {
     874         2397543 :                 pabyData[j * nBlockXSize + i] = poGDS->pabyCachedData[j * nReqXSize + i];
     875                 :             }
     876                 :         }
     877                 :     }
     878                 : 
     879             224 :     return CE_None;
     880                 : }
     881                 : 
     882                 : /************************************************************************/
     883                 : /*                             IReadBlock()                             */
     884                 : /************************************************************************/
     885                 : 
     886           21725 : CPLErr PDFRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
     887                 :                                   void * pImage )
     888                 : 
     889                 : {
     890           21725 :     PDFDataset *poGDS = (PDFDataset *) poDS;
     891                 : 
     892           21725 :     if (poGDS->aiTiles.size() )
     893                 :     {
     894             284 :         if ( IReadBlockFromTile(nBlockXOff, nBlockYOff,
     895                 :                                 pImage) == CE_None )
     896                 :         {
     897             284 :             return CE_None;
     898                 :         }
     899                 :         else
     900                 :         {
     901               0 :             poGDS->aiTiles.resize(0);
     902               0 :             poGDS->bTried = FALSE;
     903               0 :             CPLFree(poGDS->pabyCachedData);
     904               0 :             poGDS->pabyCachedData = NULL;
     905               0 :             poGDS->nLastBlockXOff = -1;
     906               0 :             poGDS->nLastBlockYOff = -1;
     907                 :         }
     908                 :     }
     909                 : 
     910           21441 :     int nReqXSize = nBlockXSize;
     911           21441 :     int nReqYSize = nBlockYSize;
     912           21441 :     if( (nBlockXOff + 1) * nBlockXSize > nRasterXSize )
     913               0 :         nReqXSize = nRasterXSize - nBlockXOff * nBlockXSize;
     914           21441 :     if( nBlockYSize == 1 )
     915           21441 :         nReqYSize = nRasterYSize;
     916               0 :     else if( (nBlockYOff + 1) * nBlockYSize > nRasterYSize )
     917               0 :         nReqYSize = nRasterYSize - nBlockYOff * nBlockYSize;
     918                 : 
     919           21441 :     if (poGDS->bTried == FALSE)
     920                 :     {
     921              52 :         poGDS->bTried = TRUE;
     922              52 :         if( nBlockYSize == 1 )
     923              52 :             poGDS->pabyCachedData = (GByte*)VSIMalloc3(MAX(3, poGDS->nBands), nRasterXSize, nRasterYSize);
     924                 :         else
     925               0 :             poGDS->pabyCachedData = (GByte*)VSIMalloc3(MAX(3, poGDS->nBands), nBlockXSize, nBlockYSize);
     926                 :     }
     927           21441 :     if (poGDS->pabyCachedData == NULL)
     928               0 :         return CE_Failure;
     929                 : 
     930           21441 :     if( poGDS->nLastBlockXOff == nBlockXOff &&
     931                 :         (nBlockYSize == 1 || poGDS->nLastBlockYOff == nBlockYOff) &&
     932                 :         poGDS->pabyCachedData != NULL )
     933                 :     {
     934                 :         /*CPLDebug("PDF", "Using cached block (%d, %d)",
     935                 :                  nBlockXOff, nBlockYOff);*/
     936                 :         // do nothing
     937                 :     }
     938                 :     else
     939                 :     {
     940                 : #ifdef HAVE_PODOFO
     941              52 :         if (!poGDS->bUsePoppler && nBand == 4)
     942                 :         {
     943               0 :             memset(pImage, 255, nBlockXSize * nBlockYSize);
     944               0 :             return CE_None;
     945                 :         }
     946                 : #endif
     947                 : 
     948                 :         CPLErr eErr = poGDS->ReadPixels( nBlockXOff * nBlockXSize,
     949                 :                                          (nBlockYSize == 1) ? 0 : nBlockYOff * nBlockYSize,
     950                 :                                          nReqXSize,
     951                 :                                          nReqYSize,
     952                 :                                          1,
     953                 :                                          nBlockXSize,
     954                 :                                          nBlockXSize * ((nBlockYSize == 1) ? nRasterYSize : nBlockYSize),
     955              52 :                                          poGDS->pabyCachedData);
     956              52 :         if( eErr == CE_None )
     957                 :         {
     958              52 :             poGDS->nLastBlockXOff = nBlockXOff;
     959              52 :             poGDS->nLastBlockYOff = nBlockYOff;
     960                 :         }
     961                 :         else
     962                 :         {
     963               0 :             CPLFree(poGDS->pabyCachedData);
     964               0 :             poGDS->pabyCachedData = NULL;
     965                 :         }
     966                 : 
     967                 :     }
     968           21441 :     if (poGDS->pabyCachedData == NULL)
     969               0 :         return CE_Failure;
     970                 : 
     971           21441 :     if( nBlockYSize == 1 )
     972                 :         memcpy(pImage,
     973                 :                poGDS->pabyCachedData + (nBand - 1) * nBlockXSize * nRasterYSize + nBlockYOff * nBlockXSize,
     974           21441 :                nBlockXSize);
     975                 :     else
     976                 :         memcpy(pImage,
     977                 :                poGDS->pabyCachedData + (nBand - 1) * nBlockXSize * nBlockYSize,
     978               0 :                nBlockXSize * nBlockYSize);
     979                 : 
     980           21441 :     return CE_None;
     981                 : }
     982                 : 
     983                 : /************************************************************************/
     984                 : /*                             ReadPixels()                             */
     985                 : /************************************************************************/
     986                 : 
     987              52 : CPLErr PDFDataset::ReadPixels( int nReqXOff, int nReqYOff,
     988                 :                                int nReqXSize, int nReqYSize,
     989                 :                                int nPixelSpace, int nLineSpace, int nBandSpace,
     990                 :                                GByte* pabyData )
     991                 : {
     992              52 :     CPLErr eErr = CE_None;
     993              52 :     const char* pszRenderingOptions = CPLGetConfigOption("GDAL_PDF_RENDERING_OPTIONS", NULL);
     994                 : 
     995                 : #ifdef HAVE_POPPLER
     996              52 :     if(bUsePoppler)
     997                 :     {
     998                 :         SplashColor sColor;
     999              48 :         sColor[0] = 255;
    1000              48 :         sColor[1] = 255;
    1001              48 :         sColor[2] = 255;
    1002                 :         GDALPDFOutputDev *poSplashOut;
    1003                 :         poSplashOut = new GDALPDFOutputDev((nBands < 4) ? splashModeRGB8 : splashModeXBGR8,
    1004                 :                                             4, gFalse,
    1005              48 :                                             (nBands < 4) ? sColor : NULL);
    1006                 : 
    1007              48 :         if (pszRenderingOptions != NULL)
    1008                 :         {
    1009               3 :             poSplashOut->SetEnableVector(FALSE);
    1010               3 :             poSplashOut->SetEnableText(FALSE);
    1011               3 :             poSplashOut->SetEnableBitmap(FALSE);
    1012                 : 
    1013               3 :             char** papszTokens = CSLTokenizeString2( pszRenderingOptions, " ,", 0 );
    1014               8 :             for(int i=0;papszTokens[i] != NULL;i++)
    1015                 :             {
    1016               5 :                 if (EQUAL(papszTokens[i], "VECTOR"))
    1017               2 :                     poSplashOut->SetEnableVector(TRUE);
    1018               3 :                 else if (EQUAL(papszTokens[i], "TEXT"))
    1019               1 :                     poSplashOut->SetEnableText(TRUE);
    1020               4 :                 else if (EQUAL(papszTokens[i], "RASTER") ||
    1021               0 :                             EQUAL(papszTokens[i], "BITMAP"))
    1022               2 :                     poSplashOut->SetEnableBitmap(TRUE);
    1023                 :                 else
    1024                 :                 {
    1025                 :                     CPLError(CE_Warning, CPLE_NotSupported,
    1026                 :                                 "Value %s is not a valid value for GDAL_PDF_RENDERING_OPTIONS",
    1027               0 :                                 papszTokens[i]);
    1028                 :                 }
    1029                 :             }
    1030               3 :             CSLDestroy(papszTokens);
    1031                 :         }
    1032                 : 
    1033              48 :         PDFDoc* poDoc = poDocPoppler;
    1034                 : #ifdef POPPLER_0_20_OR_LATER
    1035              48 :         poSplashOut->startDoc(poDoc);
    1036                 : #else
    1037                 :         poSplashOut->startDoc(poDoc->getXRef());
    1038                 : #endif
    1039                 : 
    1040                 :         /* EVIL: we modify a private member... */
    1041                 :         /* poppler (at least 0.12 and 0.14 versions) don't render correctly */
    1042                 :         /* some PDFs and display an error message 'Could not find a OCG with Ref' */
    1043                 :         /* in those cases. This processing of optional content is an addition of */
    1044                 :         /* poppler in comparison to original xpdf, which hasn't the issue. All in */
    1045                 :         /* all, nullifying optContent removes the error message and improves the rendering */
    1046                 : #ifdef POPPLER_HAS_OPTCONTENT
    1047              48 :         Catalog* poCatalog = poDoc->getCatalog();
    1048              48 :         OCGs* poOldOCGs = poCatalog->optContent;
    1049              48 :         if (!bUseOCG)
    1050              45 :             poCatalog->optContent = NULL;
    1051                 : #endif
    1052                 :         poDoc->displayPageSlice(poSplashOut,
    1053                 :                                 iPage,
    1054                 :                                 dfDPI, dfDPI,
    1055                 :                                 0,
    1056                 :                                 TRUE, gFalse, gFalse,
    1057                 :                                 nReqXOff, nReqYOff,
    1058              48 :                                 nReqXSize, nReqYSize);
    1059                 : 
    1060                 :     /* Restore back */
    1061                 : #ifdef POPPLER_HAS_OPTCONTENT
    1062              48 :         poCatalog->optContent = poOldOCGs;
    1063                 : #endif
    1064                 : 
    1065              48 :         SplashBitmap* poBitmap = poSplashOut->getBitmap();
    1066              48 :         if (poBitmap->getWidth() != nReqXSize || poBitmap->getHeight() != nReqYSize)
    1067                 :         {
    1068                 :             CPLError(CE_Failure, CPLE_AppDefined,
    1069                 :                         "Bitmap decoded size (%dx%d) doesn't match raster size (%dx%d)" ,
    1070                 :                         poBitmap->getWidth(), poBitmap->getHeight(),
    1071               0 :                         nReqXSize, nReqYSize);
    1072               0 :             delete poSplashOut;
    1073               0 :             return CE_Failure;
    1074                 :         }
    1075                 : 
    1076              48 :         GByte* pabyDataR = pabyData;
    1077              48 :         GByte* pabyDataG = pabyData + nBandSpace;
    1078              48 :         GByte* pabyDataB = pabyData + 2 * nBandSpace;
    1079              48 :         GByte* pabyDataA = pabyData + 3 * nBandSpace;
    1080              48 :         GByte* pabySrc   = poBitmap->getDataPtr();
    1081              48 :         GByte* pabyAlphaSrc  = (GByte*)poBitmap->getAlphaPtr();
    1082                 :         int i, j;
    1083           17619 :         for(j=0;j<nReqYSize;j++)
    1084                 :         {
    1085        17315602 :             for(i=0;i<nReqXSize;i++)
    1086                 :             {
    1087        17298031 :                 if (nBands < 4)
    1088                 :                 {
    1089        17225131 :                     pabyDataR[i * nPixelSpace] = pabySrc[i * 3 + 0];
    1090        17225131 :                     pabyDataG[i * nPixelSpace] = pabySrc[i * 3 + 1];
    1091        17225131 :                     pabyDataB[i * nPixelSpace] = pabySrc[i * 3 + 2];
    1092                 :                 }
    1093                 :                 else
    1094                 :                 {
    1095           72900 :                     pabyDataR[i * nPixelSpace] = pabySrc[i * 4 + 2];
    1096           72900 :                     pabyDataG[i * nPixelSpace] = pabySrc[i * 4 + 1];
    1097           72900 :                     pabyDataB[i * nPixelSpace] = pabySrc[i * 4 + 0];
    1098           72900 :                     pabyDataA[i * nPixelSpace] = pabyAlphaSrc[i];
    1099                 :                 }
    1100                 :             }
    1101           17571 :             pabyDataR += nLineSpace;
    1102           17571 :             pabyDataG += nLineSpace;
    1103           17571 :             pabyDataB += nLineSpace;
    1104           17571 :             pabyDataA += nLineSpace;
    1105           17571 :             pabyAlphaSrc += poBitmap->getAlphaRowSize();
    1106           17571 :             pabySrc += poBitmap->getRowSize();
    1107                 :         }
    1108              48 :         delete poSplashOut;
    1109                 :     }
    1110                 : #endif // HAVE_POPPLER
    1111                 : 
    1112                 : #ifdef HAVE_PODOFO
    1113              52 :     if (!bUsePoppler)
    1114                 :     {
    1115               4 :         if( bPdfToPpmFailed )
    1116               0 :             return CE_Failure;
    1117                 : 
    1118               4 :         if (pszRenderingOptions != NULL)
    1119                 :         {
    1120                 :             CPLError(CE_Warning, CPLE_NotSupported,
    1121                 :                         "GDAL_PDF_RENDERING_OPTIONS only supported "
    1122               0 :                         "when PDF driver is compiled against Poppler.");
    1123                 :         }
    1124                 : 
    1125               4 :         CPLString osTmpFilename;
    1126                 :         int nRet;
    1127                 : 
    1128                 : #ifdef notdef
    1129                 :         int bUseSpawn = CSLTestBoolean(CPLGetConfigOption("GDAL_PDF_USE_SPAWN", "YES"));
    1130                 :         if( !bUseSpawn )
    1131                 :         {
    1132                 :             CPLString osCmd = CPLSPrintf("pdftoppm -r %f -x %d -y %d -W %d -H %d -f %d -l %d \"%s\"",
    1133                 :                     dfDPI,
    1134                 :                     nReqXOff,
    1135                 :                     nReqYOff,
    1136                 :                     nReqXSize,
    1137                 :                     nReqYSize,
    1138                 :                     iPage, iPage,
    1139                 :                     osFilename.c_str());
    1140                 : 
    1141                 :             if (osUserPwd.size() != 0)
    1142                 :             {
    1143                 :                 osCmd += " -upw \"";
    1144                 :                 osCmd += osUserPwd;
    1145                 :                 osCmd += "\"";
    1146                 :             }
    1147                 : 
    1148                 :             CPLString osTmpFilenamePrefix = CPLGenerateTempFilename("pdf");
    1149                 :             osTmpFilename = CPLSPrintf("%s-%d.ppm",
    1150                 :                                            osTmpFilenamePrefix.c_str(),
    1151                 :                                            iPage);
    1152                 :             osCmd += CPLSPrintf(" \"%s\"", osTmpFilenamePrefix.c_str());
    1153                 : 
    1154                 :             CPLDebug("PDF", "Running '%s'", osCmd.c_str());
    1155                 :             nRet = CPLSystem(NULL, osCmd.c_str());
    1156                 :         }
    1157                 :         else
    1158                 : #endif
    1159                 :         {
    1160               4 :             char** papszArgs = NULL;
    1161               4 :             papszArgs = CSLAddString(papszArgs, "pdftoppm");
    1162               4 :             papszArgs = CSLAddString(papszArgs, "-r");
    1163               4 :             papszArgs = CSLAddString(papszArgs, CPLSPrintf("%f", dfDPI));
    1164               4 :             papszArgs = CSLAddString(papszArgs, "-x");
    1165               4 :             papszArgs = CSLAddString(papszArgs, CPLSPrintf("%d", nReqXOff));
    1166               4 :             papszArgs = CSLAddString(papszArgs, "-y");
    1167               4 :             papszArgs = CSLAddString(papszArgs, CPLSPrintf("%d", nReqYOff));
    1168               4 :             papszArgs = CSLAddString(papszArgs, "-W");
    1169               4 :             papszArgs = CSLAddString(papszArgs, CPLSPrintf("%d", nReqXSize));
    1170               4 :             papszArgs = CSLAddString(papszArgs, "-H");
    1171               4 :             papszArgs = CSLAddString(papszArgs, CPLSPrintf("%d", nReqYSize));
    1172               4 :             papszArgs = CSLAddString(papszArgs, "-f");
    1173               4 :             papszArgs = CSLAddString(papszArgs, CPLSPrintf("%d", iPage));
    1174               4 :             papszArgs = CSLAddString(papszArgs, "-l");
    1175               4 :             papszArgs = CSLAddString(papszArgs, CPLSPrintf("%d", iPage));
    1176               4 :             if (osUserPwd.size() != 0)
    1177                 :             {
    1178               0 :                 papszArgs = CSLAddString(papszArgs, "-upw");
    1179               0 :                 papszArgs = CSLAddString(papszArgs, osUserPwd.c_str());
    1180                 :             }
    1181               4 :             papszArgs = CSLAddString(papszArgs, osFilename.c_str());
    1182                 : 
    1183               4 :             osTmpFilename = CPLSPrintf("/vsimem/pdf/temp_%p.ppm", this);
    1184               4 :             VSILFILE* fpOut = VSIFOpenL(osTmpFilename, "wb");
    1185               4 :             if( fpOut != NULL )
    1186                 :             {
    1187               4 :                 nRet = CPLSpawn(papszArgs, NULL, fpOut, FALSE);
    1188               4 :                 VSIFCloseL(fpOut);
    1189                 :             }
    1190                 :             else
    1191               0 :                 nRet = -1;
    1192                 : 
    1193               4 :             CSLDestroy(papszArgs);
    1194                 :         }
    1195                 : 
    1196               4 :         if (nRet == 0)
    1197                 :         {
    1198               4 :             GDALDataset* poDS = (GDALDataset*) GDALOpen(osTmpFilename, GA_ReadOnly);
    1199               4 :             if (poDS)
    1200                 :             {
    1201               4 :                 if (poDS->GetRasterCount() == 3)
    1202                 :                 {
    1203                 :                     eErr = poDS->RasterIO(GF_Read, 0, 0,
    1204                 :                                           nReqXSize,
    1205                 :                                           nReqYSize,
    1206                 :                                           pabyData,
    1207                 :                                           nReqXSize, nReqYSize,
    1208                 :                                           GDT_Byte, 3, NULL,
    1209               4 :                                           nPixelSpace, nLineSpace, nBandSpace);
    1210                 :                 }
    1211               4 :                 delete poDS;
    1212                 :             }
    1213                 :         }
    1214                 :         else
    1215                 :         {
    1216               0 :             CPLDebug("PDF", "Ret code = %d", nRet);
    1217               0 :             bPdfToPpmFailed = TRUE;
    1218               0 :             eErr = CE_Failure;
    1219                 :         }
    1220               4 :         VSIUnlink(osTmpFilename);
    1221                 :     }
    1222                 : #endif
    1223                 : 
    1224              52 :     return eErr;
    1225                 : }
    1226                 : 
    1227                 : /************************************************************************/
    1228                 : /* ==================================================================== */
    1229                 : /*                        PDFImageRasterBand                            */
    1230                 : /* ==================================================================== */
    1231                 : /************************************************************************/
    1232                 : 
    1233                 : class PDFImageRasterBand : public PDFRasterBand
    1234               4 : {
    1235                 :     friend class PDFDataset;
    1236                 : 
    1237                 :   public:
    1238                 : 
    1239                 :                 PDFImageRasterBand( PDFDataset *, int );
    1240                 : 
    1241                 :     virtual CPLErr IReadBlock( int, int, void * );
    1242                 : };
    1243                 : 
    1244                 : 
    1245                 : /************************************************************************/
    1246                 : /*                        PDFImageRasterBand()                          */
    1247                 : /************************************************************************/
    1248                 : 
    1249               4 : PDFImageRasterBand::PDFImageRasterBand( PDFDataset *poDS, int nBand ) : PDFRasterBand(poDS, nBand)
    1250                 : 
    1251                 : {
    1252               4 : }
    1253                 : 
    1254                 : /************************************************************************/
    1255                 : /*                             IReadBlock()                             */
    1256                 : /************************************************************************/
    1257                 : 
    1258              70 : CPLErr PDFImageRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
    1259                 :                                   void * pImage )
    1260                 : 
    1261                 : {
    1262              70 :     PDFDataset *poGDS = (PDFDataset *) poDS;
    1263              70 :     CPLAssert(poGDS->poImageObj != NULL);
    1264                 : 
    1265              70 :     if (poGDS->bTried == FALSE)
    1266                 :     {
    1267               2 :         int nBands = (poGDS->nBands == 1) ? 1 : 3;
    1268               2 :         poGDS->bTried = TRUE;
    1269               2 :         if (nBands == 3)
    1270                 :         {
    1271               1 :             poGDS->pabyCachedData = (GByte*)VSIMalloc3(nBands, nRasterXSize, nRasterYSize);
    1272               1 :             if (poGDS->pabyCachedData == NULL)
    1273               0 :                 return CE_Failure;
    1274                 :         }
    1275                 : 
    1276               2 :         GDALPDFStream* poStream = poGDS->poImageObj->GetStream();
    1277               2 :         GByte* pabyStream = NULL;
    1278                 : 
    1279               6 :         if (poStream == NULL ||
    1280               2 :             poStream->GetLength() != nBands * nRasterXSize * nRasterYSize ||
    1281               2 :             (pabyStream = (GByte*) poStream->GetBytes()) == NULL)
    1282                 :         {
    1283               0 :             VSIFree(poGDS->pabyCachedData);
    1284               0 :             poGDS->pabyCachedData = NULL;
    1285               0 :             return CE_Failure;
    1286                 :         }
    1287                 : 
    1288               2 :         if (nBands == 3)
    1289                 :         {
    1290                 :             /* pixel interleaved to band interleaved */
    1291            2501 :             for(int i = 0; i < nRasterXSize * nRasterYSize; i++)
    1292                 :             {
    1293            2500 :                 poGDS->pabyCachedData[0 * nRasterXSize * nRasterYSize + i] = pabyStream[3 * i + 0];
    1294            2500 :                 poGDS->pabyCachedData[1 * nRasterXSize * nRasterYSize + i] = pabyStream[3 * i + 1];
    1295            2500 :                 poGDS->pabyCachedData[2 * nRasterXSize * nRasterYSize + i] = pabyStream[3 * i + 2];
    1296                 :             }
    1297               1 :             VSIFree(pabyStream);
    1298                 :         }
    1299                 :         else
    1300               1 :             poGDS->pabyCachedData = pabyStream;
    1301                 :     }
    1302                 : 
    1303              70 :     if (poGDS->pabyCachedData == NULL)
    1304               0 :         return CE_Failure;
    1305                 : 
    1306              70 :     if (nBand == 4)
    1307               0 :         memset(pImage, 255, nRasterXSize);
    1308                 :     else
    1309                 :         memcpy(pImage,
    1310                 :             poGDS->pabyCachedData + (nBand - 1) * nRasterXSize * nRasterYSize + nBlockYOff * nRasterXSize,
    1311              70 :             nRasterXSize);
    1312                 : 
    1313              70 :     return CE_None;
    1314                 : }
    1315                 : 
    1316                 : /************************************************************************/
    1317                 : /*                            ~PDFDataset()                            */
    1318                 : /************************************************************************/
    1319                 : 
    1320             182 : PDFDataset::PDFDataset()
    1321                 : {
    1322             182 :     bUsePoppler = FALSE;
    1323                 : #ifdef HAVE_POPPLER
    1324             182 :     poDocPoppler = NULL;
    1325                 : #endif
    1326                 : #ifdef HAVE_PODOFO
    1327             182 :     poDocPodofo = NULL;
    1328             182 :     bPdfToPpmFailed = FALSE;
    1329                 : #endif
    1330             182 :     poImageObj = NULL;
    1331             182 :     pszWKT = NULL;
    1332             182 :     dfDPI = DEFAULT_DPI;
    1333             182 :     dfMaxArea = 0;
    1334             182 :     adfGeoTransform[0] = 0;
    1335             182 :     adfGeoTransform[1] = 1;
    1336             182 :     adfGeoTransform[2] = 0;
    1337             182 :     adfGeoTransform[3] = 0;
    1338             182 :     adfGeoTransform[4] = 0;
    1339             182 :     adfGeoTransform[5] = 1;
    1340             182 :     bHasCTM = FALSE;
    1341             182 :     bGeoTransformValid = FALSE;
    1342             182 :     nGCPCount = 0;
    1343             182 :     pasGCPList = NULL;
    1344             182 :     bProjDirty = FALSE;
    1345             182 :     bNeatLineDirty = FALSE;
    1346             182 :     bInfoDirty = FALSE;
    1347             182 :     bXMPDirty = FALSE;
    1348             182 :     bTried = FALSE;
    1349             182 :     pabyCachedData = NULL;
    1350             182 :     nLastBlockXOff = -1;
    1351             182 :     nLastBlockYOff = -1;
    1352             182 :     iPage = -1;
    1353             182 :     poNeatLine = NULL;
    1354             182 :     bUseOCG = FALSE;
    1355             182 :     poCatalogObject = NULL;
    1356                 : #ifdef HAVE_POPPLER
    1357             182 :     poCatalogObjectPoppler = NULL;
    1358                 : #endif
    1359             182 :     nBlockXSize = 0;
    1360             182 :     nBlockYSize = 0;
    1361             182 : }
    1362                 : 
    1363                 : /************************************************************************/
    1364                 : /*                           PDFFreeDoc()                               */
    1365                 : /************************************************************************/
    1366                 : 
    1367                 : #ifdef HAVE_POPPLER
    1368             182 : static void PDFFreeDoc(PDFDoc* poDoc)
    1369                 : {
    1370             182 :     if (poDoc)
    1371                 :     {
    1372                 :         /* hack to avoid potential cross heap issues on Win32 */
    1373                 :         /* str is the VSIPDFFileStream object passed in the constructor of PDFDoc */
    1374             149 :         delete poDoc->str;
    1375             149 :         poDoc->str = NULL;
    1376                 : 
    1377             149 :         delete poDoc;
    1378                 :     }
    1379             182 : }
    1380                 : #endif
    1381                 : 
    1382                 : /************************************************************************/
    1383                 : /*                            GetCatalog()                              */
    1384                 : /************************************************************************/
    1385                 : 
    1386              12 : GDALPDFObject* PDFDataset::GetCatalog()
    1387                 : {
    1388              12 :     if (poCatalogObject)
    1389               0 :         return poCatalogObject;
    1390                 : 
    1391                 : #ifdef HAVE_POPPLER
    1392              12 :     if (bUsePoppler)
    1393                 :     {
    1394               8 :         poCatalogObjectPoppler = new ObjectAutoFree;
    1395               8 :         poDocPoppler->getXRef()->getCatalog(poCatalogObjectPoppler);
    1396               8 :         if (!poCatalogObjectPoppler->isNull())
    1397               8 :             poCatalogObject = new GDALPDFObjectPoppler(poCatalogObjectPoppler, FALSE);
    1398                 :     }
    1399                 : #endif
    1400                 : 
    1401                 : #ifdef HAVE_PODOFO
    1402              12 :     if (!bUsePoppler)
    1403                 :     {
    1404               4 :         int nCatalogNum = 0, nCatalogGen = 0;
    1405               4 :         VSILFILE* fp = VSIFOpenL(osFilename.c_str(), "rb");
    1406               4 :         if (fp != NULL)
    1407                 :         {
    1408               4 :             GDALPDFWriter oWriter(fp, TRUE);
    1409               4 :             if (oWriter.ParseTrailerAndXRef())
    1410                 :             {
    1411               4 :                 nCatalogNum = oWriter.GetCatalogNum();
    1412               4 :                 nCatalogGen = oWriter.GetCatalogGen();
    1413                 :             }
    1414               4 :             oWriter.Close();
    1415                 :         }
    1416                 : 
    1417                 :         PoDoFo::PdfObject* poCatalogPodofo =
    1418               4 :             poDocPodofo->GetObjects().GetObject(PoDoFo::PdfReference(nCatalogNum, nCatalogGen));
    1419               4 :         if (poCatalogPodofo)
    1420               4 :             poCatalogObject = new GDALPDFObjectPodofo(poCatalogPodofo, poDocPodofo->GetObjects());
    1421                 :     }
    1422                 : #endif
    1423                 : 
    1424              12 :     return poCatalogObject;
    1425                 : }
    1426                 : 
    1427                 : /************************************************************************/
    1428                 : /*                            ~PDFDataset()                            */
    1429                 : /************************************************************************/
    1430                 : 
    1431             182 : PDFDataset::~PDFDataset()
    1432                 : {
    1433             182 :     CPLFree(pabyCachedData);
    1434             182 :     pabyCachedData = NULL;
    1435                 : 
    1436             182 :     delete poNeatLine;
    1437             182 :     poNeatLine = NULL;
    1438                 : 
    1439                 :     /* Collect data necessary to update */
    1440             182 :     int nNum = poPageObj->GetRefNum();
    1441             182 :     int nGen = poPageObj->GetRefGen();
    1442             182 :     GDALPDFDictionaryRW* poPageDictCopy = NULL;
    1443             182 :     GDALPDFDictionaryRW* poCatalogDictCopy = NULL;
    1444             204 :     if (eAccess == GA_Update &&
    1445                 :         (bProjDirty || bNeatLineDirty || bInfoDirty || bXMPDirty) &&
    1446                 :         nNum != 0 &&
    1447                 :         poPageObj != NULL &&
    1448              22 :         poPageObj->GetType() == PDFObjectType_Dictionary)
    1449                 :     {
    1450              22 :         poPageDictCopy = poPageObj->GetDictionary()->Clone();
    1451                 : 
    1452              22 :         if (bXMPDirty)
    1453                 :         {
    1454                 :             /* We need the catalog because it points to the XMP Metadata object */
    1455               6 :             GetCatalog();
    1456               6 :             if (poCatalogObject && poCatalogObject->GetType() == PDFObjectType_Dictionary)
    1457               6 :                 poCatalogDictCopy = poCatalogObject->GetDictionary()->Clone();
    1458                 :         }
    1459                 :     }
    1460                 : 
    1461                 :     /* Close document (and file descriptor) to be able to open it */
    1462                 :     /* in read-write mode afterwards */
    1463             182 :     delete poPageObj;
    1464             182 :     poPageObj = NULL;
    1465             182 :     delete poCatalogObject;
    1466             182 :     poCatalogObject = NULL;
    1467                 : #ifdef HAVE_POPPLER
    1468             182 :     delete poCatalogObjectPoppler;
    1469             182 :     PDFFreeDoc(poDocPoppler);
    1470             182 :     poDocPoppler = NULL;
    1471                 : #endif
    1472                 : #ifdef HAVE_PODOFO
    1473             182 :     delete poDocPodofo;
    1474             182 :     poDocPodofo = NULL;
    1475                 : #endif
    1476                 : 
    1477                 :     /* Now do the update */
    1478             182 :     if (poPageDictCopy)
    1479                 :     {
    1480              22 :         VSILFILE* fp = VSIFOpenL(osFilename, "rb+");
    1481              22 :         if (fp != NULL)
    1482                 :         {
    1483              22 :             GDALPDFWriter oWriter(fp, TRUE);
    1484              22 :             if (oWriter.ParseTrailerAndXRef())
    1485                 :             {
    1486              22 :                 if ((bProjDirty || bNeatLineDirty) && poPageDictCopy != NULL)
    1487                 :                     oWriter.UpdateProj(this, dfDPI,
    1488              10 :                                         poPageDictCopy, nNum, nGen);
    1489                 : 
    1490              22 :                 if (bInfoDirty)
    1491               6 :                     oWriter.UpdateInfo(this);
    1492                 : 
    1493              22 :                 if (bXMPDirty && poCatalogDictCopy != NULL)
    1494               6 :                     oWriter.UpdateXMP(this, poCatalogDictCopy);
    1495                 :             }
    1496              22 :             oWriter.Close();
    1497                 :         }
    1498                 :         else
    1499                 :         {
    1500                 :             CPLError(CE_Failure, CPLE_AppDefined,
    1501               0 :                      "Cannot open %s in update mode", osFilename.c_str());
    1502                 :         }
    1503                 :     }
    1504             182 :     delete poPageDictCopy;
    1505             182 :     poPageDictCopy = NULL;
    1506             182 :     delete poCatalogDictCopy;
    1507             182 :     poCatalogDictCopy = NULL;
    1508                 : 
    1509             182 :     if( nGCPCount > 0 )
    1510                 :     {
    1511               5 :         GDALDeinitGCPs( nGCPCount, pasGCPList );
    1512               5 :         CPLFree( pasGCPList );
    1513               5 :         pasGCPList = NULL;
    1514               5 :         nGCPCount = 0;
    1515                 :     }
    1516             182 :     CPLFree(pszWKT);
    1517             182 :     pszWKT = NULL;
    1518             182 : }
    1519                 : 
    1520                 : 
    1521                 : /************************************************************************/
    1522                 : /*                            IRasterIO()                               */
    1523                 : /************************************************************************/
    1524                 : 
    1525            1670 : CPLErr PDFDataset::IRasterIO( GDALRWFlag eRWFlag,
    1526                 :                               int nXOff, int nYOff, int nXSize, int nYSize,
    1527                 :                               void * pData, int nBufXSize, int nBufYSize,
    1528                 :                               GDALDataType eBufType, 
    1529                 :                               int nBandCount, int *panBandMap,
    1530                 :                               int nPixelSpace, int nLineSpace, int nBandSpace )
    1531                 : {
    1532                 :     int nBandBlockXSize, nBandBlockYSize;
    1533            1670 :     GetRasterBand(1)->GetBlockSize(&nBandBlockXSize, &nBandBlockYSize);
    1534            1670 :     if( aiTiles.size() == 0 &&
    1535                 :         eRWFlag == GF_Read && nXSize == nBufXSize && nYSize == nBufYSize &&
    1536                 :         (nBufXSize > nBandBlockXSize || nBufYSize > nBandBlockYSize) &&
    1537                 :         eBufType == GDT_Byte && nBandCount == nBands &&
    1538               0 :         (nBands >= 3 && panBandMap[0] == 1 && panBandMap[1] == 2 &&
    1539               0 :          panBandMap[2] == 3 && ( nBands == 3 || panBandMap[3] == 4)) )
    1540                 :     {
    1541               0 :         int bReadPixels = TRUE;
    1542                 : #ifdef HAVE_PODOFO
    1543               0 :         if (!bUsePoppler && nBands == 4)
    1544                 :         {
    1545               0 :             bReadPixels = FALSE;
    1546                 :         }
    1547                 : #endif
    1548               0 :         if( bReadPixels )
    1549                 :             return ReadPixels(nXOff, nYOff, nXSize, nYSize,
    1550               0 :                               nPixelSpace, nLineSpace, nBandSpace, (GByte*)pData);
    1551                 :     }
    1552                 : 
    1553                 :     return GDALPamDataset::IRasterIO( eRWFlag,
    1554                 :                                         nXOff, nYOff, nXSize, nYSize,
    1555                 :                                         pData, nBufXSize, nBufYSize,
    1556                 :                                         eBufType, 
    1557                 :                                         nBandCount, panBandMap,
    1558            1670 :                                         nPixelSpace, nLineSpace, nBandSpace );
    1559                 : }
    1560                 : 
    1561                 : /************************************************************************/
    1562                 : /*                             Identify()                               */
    1563                 : /************************************************************************/
    1564                 : 
    1565           11628 : int PDFDataset::Identify( GDALOpenInfo * poOpenInfo )
    1566                 : {
    1567           11628 :     if (strncmp(poOpenInfo->pszFilename, "PDF:", 4) == 0)
    1568               1 :         return TRUE;
    1569           11627 :     if (strncmp(poOpenInfo->pszFilename, "PDF_IMAGE:", 10) == 0)
    1570               2 :         return TRUE;
    1571                 : 
    1572           11625 :     if (poOpenInfo->nHeaderBytes < 128)
    1573           11284 :         return FALSE;
    1574                 : 
    1575             341 :     return strncmp((const char*)poOpenInfo->pabyHeader, "%PDF", 4) == 0;
    1576                 : }
    1577                 : 
    1578                 : /************************************************************************/
    1579                 : /*                    PDFDatasetErrorFunction()                         */
    1580                 : /************************************************************************/
    1581                 : 
    1582                 : #ifdef HAVE_POPPLER
    1583                 : #ifdef POPPLER_0_20_OR_LATER
    1584               0 : static void PDFDatasetErrorFunction(void* userData, ErrorCategory eErrCatagory,
    1585                 : #ifdef POPPLER_0_23_OR_LATER
    1586                 :                                     Goffset nPos,
    1587                 : #else
    1588                 :                                     int nPos,
    1589                 : #endif
    1590                 :                                     char *pszMsg)
    1591                 : {
    1592               0 :     CPLString osError;
    1593                 : 
    1594               0 :     if (nPos >= 0)
    1595               0 :         osError.Printf("Pos = %d, ", (int)nPos);
    1596               0 :     osError += pszMsg;
    1597                 : 
    1598               0 :     if (strcmp(osError.c_str(), "Incorrect password") == 0)
    1599                 :         return;
    1600                 : 
    1601               0 :     CPLError(CE_Failure, CPLE_AppDefined, "%s", osError.c_str());
    1602                 : }
    1603                 : #else
    1604                 : static void PDFDatasetErrorFunction(int nPos, char *pszMsg, va_list args)
    1605                 : {
    1606                 :     CPLString osError;
    1607                 : 
    1608                 :     if (nPos >= 0)
    1609                 :         osError.Printf("Pos = %d, ", nPos);
    1610                 :     osError += CPLString().vPrintf(pszMsg, args);
    1611                 : 
    1612                 :     if (strcmp(osError.c_str(), "Incorrect password") == 0)
    1613                 :         return;
    1614                 : 
    1615                 :     CPLError(CE_Failure, CPLE_AppDefined, "%s", osError.c_str());
    1616                 : }
    1617                 : #endif
    1618                 : #endif
    1619                 : 
    1620                 : /************************************************************************/
    1621                 : /*                GDALPDFParseStreamContentOnlyDrawForm()               */
    1622                 : /************************************************************************/
    1623                 : 
    1624                 : static
    1625             171 : CPLString GDALPDFParseStreamContentOnlyDrawForm(const char* pszContent)
    1626                 : {
    1627             171 :     CPLString osToken;
    1628                 :     char ch;
    1629             171 :     int nCurIdx = 0;
    1630             171 :     CPLString osCurrentForm;
    1631                 : 
    1632                 :     //CPLDebug("PDF", "content = %s", pszContent);
    1633                 : 
    1634             608 :     while((ch = *pszContent) != '\0')
    1635                 :     {
    1636             435 :         if (ch == '%')
    1637                 :         {
    1638                 :             /* Skip comments until end-of-line */
    1639               0 :             while((ch = *pszContent) != '\0')
    1640                 :             {
    1641               0 :                 if (ch == '\r' || ch == '\n')
    1642               0 :                     break;
    1643               0 :                 pszContent ++;
    1644                 :             }
    1645               0 :             if (ch == 0)
    1646               0 :                 break;
    1647                 :         }
    1648             446 :         else if (ch == ' ' || ch == '\r' || ch == '\n')
    1649                 :         {
    1650             180 :             if (osToken.size())
    1651                 :             {
    1652             180 :                 if (nCurIdx == 0 && osToken[0] == '/')
    1653                 :                 {
    1654               9 :                     osCurrentForm = osToken.substr(1);
    1655               9 :                     nCurIdx ++;
    1656                 :                 }
    1657             171 :                 else if (nCurIdx == 1 && osToken == "Do")
    1658                 :                 {
    1659               2 :                     nCurIdx ++;
    1660                 :                 }
    1661                 :                 else
    1662                 :                 {
    1663             169 :                     return "";
    1664                 :                 }
    1665                 :             }
    1666              11 :             osToken = "";
    1667                 :         }
    1668                 :         else
    1669             255 :             osToken += ch;
    1670             266 :         pszContent ++;
    1671                 :     }
    1672                 : 
    1673               2 :     return osCurrentForm;
    1674                 : }
    1675                 : 
    1676                 : /************************************************************************/
    1677                 : /*                    GDALPDFParseStreamContent()                       */
    1678                 : /************************************************************************/
    1679                 : 
    1680                 : typedef enum
    1681                 : {
    1682                 :     STATE_INIT,
    1683                 :     STATE_AFTER_q,
    1684                 :     STATE_AFTER_cm,
    1685                 :     STATE_AFTER_Do
    1686                 : } PDFStreamState;
    1687                 : 
    1688                 : /* This parser is reduced to understanding sequences that draw rasters, such as :
    1689                 :    q
    1690                 :    scaleX 0 0 scaleY translateX translateY cm
    1691                 :    /ImXXX Do
    1692                 :    Q
    1693                 : 
    1694                 :    All other sequences will abort the parsing.
    1695                 : 
    1696                 :    Returns TRUE if the stream only contains images.
    1697                 : */
    1698                 : 
    1699                 : static
    1700             171 : int GDALPDFParseStreamContent(const char* pszContent,
    1701                 :                               GDALPDFDictionary* poXObjectDict,
    1702                 :                               double* pdfDPI,
    1703                 :                               int* pbDPISet,
    1704                 :                               int* pnBands,
    1705                 :                               std::vector<GDALPDFTileDesc>& asTiles,
    1706                 :                               int bAcceptRotationTerms)
    1707                 : {
    1708             171 :     CPLString osToken;
    1709                 :     char ch;
    1710             171 :     PDFStreamState nState = STATE_INIT;
    1711             171 :     int nCurIdx = 0;
    1712                 :     double adfVals[6];
    1713             171 :     CPLString osCurrentImage;
    1714                 : 
    1715             171 :     double dfDPI = 72.0;
    1716             171 :     *pbDPISet = FALSE;
    1717                 : 
    1718           13186 :     while((ch = *pszContent) != '\0')
    1719                 :     {
    1720           12859 :         if (ch == '%')
    1721                 :         {
    1722                 :             /* Skip comments until end-of-line */
    1723               0 :             while((ch = *pszContent) != '\0')
    1724                 :             {
    1725               0 :                 if (ch == '\r' || ch == '\n')
    1726               0 :                     break;
    1727               0 :                 pszContent ++;
    1728                 :             }
    1729               0 :             if (ch == 0)
    1730               0 :                 break;
    1731                 :         }
    1732           16599 :         else if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n')
    1733                 :         {
    1734            3755 :             if (osToken.size())
    1735                 :             {
    1736            3755 :                 if (nState == STATE_INIT)
    1737                 :                 {
    1738             355 :                     if (osToken == "q")
    1739                 :                     {
    1740             340 :                         nState = STATE_AFTER_q;
    1741             340 :                         nCurIdx = 0;
    1742                 :                     }
    1743              15 :                     else if (osToken != "Q")
    1744              15 :                         return FALSE;
    1745                 :                 }
    1746            3400 :                 else if (nState == STATE_AFTER_q)
    1747                 :                 {
    1748            2380 :                     if (osToken == "q")
    1749                 :                     {
    1750                 :                         // ignore
    1751                 :                     }
    1752            2380 :                     else if (nCurIdx < 6)
    1753                 :                     {
    1754            2040 :                         adfVals[nCurIdx ++] = CPLAtof(osToken);
    1755                 :                     }
    1756             340 :                     else if (nCurIdx == 6 && osToken == "cm")
    1757                 :                     {
    1758             340 :                         nState = STATE_AFTER_cm;
    1759             340 :                         nCurIdx = 0;
    1760                 :                     }
    1761                 :                     else
    1762               0 :                         return FALSE;
    1763                 :                 }
    1764            1020 :                 else if (nState == STATE_AFTER_cm)
    1765                 :                 {
    1766             680 :                     if (nCurIdx == 0 && osToken[0] == '/')
    1767                 :                     {
    1768             340 :                         osCurrentImage = osToken.substr(1);
    1769                 :                     }
    1770             340 :                     else if (osToken == "Do")
    1771                 :                     {
    1772             340 :                         nState = STATE_AFTER_Do;
    1773                 :                     }
    1774                 :                     else
    1775               0 :                         return FALSE;
    1776                 :                 }
    1777             340 :                 else if (nState == STATE_AFTER_Do)
    1778                 :                 {
    1779             340 :                     if (osToken == "Q")
    1780                 :                     {
    1781             340 :                         GDALPDFObject* poImage = poXObjectDict->Get(osCurrentImage);
    1782             340 :                         if (poImage != NULL && poImage->GetType() == PDFObjectType_Dictionary)
    1783                 :                         {
    1784                 :                             GDALPDFTileDesc sTile;
    1785             340 :                             GDALPDFDictionary* poImageDict = poImage->GetDictionary();
    1786             340 :                             GDALPDFObject* poWidth = poImageDict->Get("Width");
    1787             340 :                             GDALPDFObject* poHeight = poImageDict->Get("Height");
    1788             340 :                             GDALPDFObject* poColorSpace = poImageDict->Get("ColorSpace");
    1789             340 :                             GDALPDFObject* poSMask = poImageDict->Get("SMask");
    1790             340 :                             if (poColorSpace && poColorSpace->GetType() == PDFObjectType_Name)
    1791                 :                             {
    1792             337 :                                 if (poColorSpace->GetName() == "DeviceRGB")
    1793                 :                                 {
    1794             140 :                                     sTile.nBands = 3;
    1795             140 :                                     if ( *pnBands < 3)
    1796              24 :                                         *pnBands = 3;
    1797                 :                                 }
    1798             197 :                                 else if (poColorSpace->GetName() == "DeviceGray")
    1799                 :                                 {
    1800             197 :                                     sTile.nBands = 1;
    1801             197 :                                     if ( *pnBands < 1)
    1802             137 :                                         *pnBands = 1;
    1803                 :                                 }
    1804                 :                                 else
    1805               0 :                                     sTile.nBands = 0;
    1806                 :                             }
    1807             340 :                             if ( poSMask != NULL )
    1808             126 :                                 *pnBands = 4;
    1809                 : 
    1810            1020 :                             if (poWidth && poHeight && ((bAcceptRotationTerms && adfVals[1] == -adfVals[2]) ||
    1811             680 :                                                         (!bAcceptRotationTerms && adfVals[1] == 0.0 && adfVals[2] == 0.0)))
    1812                 :                             {
    1813             340 :                                 double dfWidth = Get(poWidth);
    1814             340 :                                 double dfHeight = Get(poHeight);
    1815             340 :                                 double dfScaleX = adfVals[0];
    1816             340 :                                 double dfScaleY = adfVals[3];
    1817             340 :                                 double dfDPI_X = ROUND_TO_INT_IF_CLOSE(dfWidth / dfScaleX * 72, 1e-3);
    1818             340 :                                 double dfDPI_Y = ROUND_TO_INT_IF_CLOSE(dfHeight / dfScaleY * 72, 1e-3);
    1819                 :                                 //CPLDebug("PDF", "Image %s, width = %.16g, height = %.16g, scaleX = %.16g, scaleY = %.16g --> DPI_X = %.16g, DPI_Y = %.16g",
    1820                 :                                 //                osCurrentImage.c_str(), dfWidth, dfHeight, dfScaleX, dfScaleY, dfDPI_X, dfDPI_Y);
    1821             340 :                                 if (dfDPI_X > dfDPI) dfDPI = dfDPI_X;
    1822             340 :                                 if (dfDPI_Y > dfDPI) dfDPI = dfDPI_Y;
    1823                 : 
    1824             340 :                                 memcpy(&(sTile.adfCM), adfVals, 6 * sizeof(double));
    1825             340 :                                 sTile.poImage = poImage;
    1826             340 :                                 sTile.dfWidth = dfWidth;
    1827             340 :                                 sTile.dfHeight = dfHeight;
    1828             340 :                                 asTiles.push_back(sTile);
    1829                 : 
    1830             340 :                                 *pbDPISet = TRUE;
    1831             340 :                                 *pdfDPI = dfDPI;
    1832                 :                             }
    1833                 :                         }
    1834             340 :                         nState = STATE_INIT;
    1835                 :                     }
    1836                 :                     else
    1837               0 :                         return FALSE;
    1838                 :                 }
    1839                 :             }
    1840            3740 :             osToken = "";
    1841                 :         }
    1842                 :         else
    1843            9104 :             osToken += ch;
    1844           12844 :         pszContent ++;
    1845                 :     }
    1846                 : 
    1847             156 :     return TRUE;
    1848                 : }
    1849                 : 
    1850                 : /************************************************************************/
    1851                 : /*                         CheckTiledRaster()                           */
    1852                 : /************************************************************************/
    1853                 : 
    1854             164 : int PDFDataset::CheckTiledRaster()
    1855                 : {
    1856                 :     size_t i;
    1857             164 :     int nBlockXSize = 0, nBlockYSize = 0;
    1858                 : 
    1859                 :     /* First pass : check that all tiles have same DPI, */
    1860                 :     /* are contained entirely in the raster size, */
    1861                 :     /* and determine the block size */
    1862             501 :     for(i=0; i<asTiles.size(); i++)
    1863                 :     {
    1864             340 :         double dfDrawWidth = asTiles[i].adfCM[0] * dfDPI / 72.0;
    1865             340 :         double dfDrawHeight = asTiles[i].adfCM[3] * dfDPI / 72.0;
    1866             340 :         double dfX = asTiles[i].adfCM[4] * dfDPI / 72.0;
    1867             340 :         double dfY = asTiles[i].adfCM[5] * dfDPI / 72.0;
    1868             340 :         int nX = (int)(dfX+0.1);
    1869             340 :         int nY = (int)(dfY+0.1);
    1870             340 :         int nWidth = (int)(asTiles[i].dfWidth + 1e-8);
    1871             340 :         int nHeight = (int)(asTiles[i].dfHeight + 1e-8);
    1872                 : 
    1873             340 :         GDALPDFDictionary* poImageDict = asTiles[i].poImage->GetDictionary();
    1874             340 :         GDALPDFObject* poBitsPerComponent = poImageDict->Get("BitsPerComponent");
    1875             340 :         GDALPDFObject* poColorSpace = poImageDict->Get("ColorSpace");
    1876             340 :         GDALPDFObject* poFilter = poImageDict->Get("Filter");
    1877                 : 
    1878                 :         /* Podofo cannot uncompress JPEG2000 streams */
    1879             520 :         if( !bUsePoppler && poFilter != NULL &&
    1880              90 :             poFilter->GetType() == PDFObjectType_Name &&
    1881              90 :             poFilter->GetName() == "JPXDecode" )
    1882                 :         {
    1883                 :             CPLDebug("PDF", "Tile %d : Incompatible image for tiled reading",
    1884               0 :                      (int)i);
    1885               0 :             return FALSE;
    1886                 :         }
    1887                 : 
    1888            1214 :         if( poBitsPerComponent == NULL ||
    1889                 :             Get(poBitsPerComponent) != 8 ||
    1890                 :             poColorSpace == NULL ||
    1891             340 :             poColorSpace->GetType() != PDFObjectType_Name ||
    1892             337 :             (poColorSpace->GetName() != "DeviceRGB" &&
    1893             197 :              poColorSpace->GetName() != "DeviceGray") )
    1894                 :         {
    1895                 :             CPLDebug("PDF", "Tile %d : Incompatible image for tiled reading",
    1896               3 :                      (int)i);
    1897               3 :             return FALSE;
    1898                 :         }
    1899                 : 
    1900             337 :         if( fabs(dfDrawWidth - asTiles[i].dfWidth) > 1e-2 ||
    1901                 :             fabs(dfDrawHeight - asTiles[i].dfHeight) > 1e-2 ||
    1902                 :             fabs(nWidth - asTiles[i].dfWidth) > 1e-8 ||
    1903                 :             fabs(nHeight - asTiles[i].dfHeight) > 1e-8 ||
    1904                 :             fabs(nX - dfX) > 1e-1 ||
    1905                 :             fabs(nY - dfY) > 1e-1 ||
    1906                 :             nX < 0 || nY < 0 || nX + nWidth > nRasterXSize ||
    1907                 :             nY >= nRasterYSize )
    1908                 :         {
    1909                 :             CPLDebug("PDF", "Tile %d : %f %f %f %f %f %f",
    1910                 :                      (int)i, dfX, dfY, dfDrawWidth, dfDrawHeight,
    1911               0 :                      asTiles[i].dfWidth, asTiles[i].dfHeight);
    1912               0 :             return FALSE;
    1913                 :         }
    1914             337 :         if( nBlockXSize == 0 && nBlockYSize == 0 &&
    1915                 :             nX == 0 && nY != 0 )
    1916                 :         {
    1917              12 :             nBlockXSize = nWidth;
    1918              12 :             nBlockYSize = nHeight;
    1919                 :         }
    1920                 :     }
    1921             161 :     if( nBlockXSize <= 0 || nBlockYSize <= 0 || nBlockXSize > 2048 || nBlockYSize > 2048 )
    1922             149 :         return FALSE;
    1923                 : 
    1924              12 :     int nXBlocks = DIV_ROUND_UP(nRasterXSize, nBlockXSize);
    1925              12 :     int nYBlocks = DIV_ROUND_UP(nRasterYSize, nBlockYSize);
    1926                 : 
    1927                 :     /* Second pass to determine that all tiles are properly aligned on block size */
    1928             200 :     for(i=0; i<asTiles.size(); i++)
    1929                 :     {
    1930             188 :         double dfX = asTiles[i].adfCM[4] * dfDPI / 72.0;
    1931             188 :         double dfY = asTiles[i].adfCM[5] * dfDPI / 72.0;
    1932             188 :         int nX = (int)(dfX+0.1);
    1933             188 :         int nY = (int)(dfY+0.1);
    1934             188 :         int nWidth = (int)(asTiles[i].dfWidth + 1e-8);
    1935             188 :         int nHeight = (int)(asTiles[i].dfHeight + 1e-8);
    1936             188 :         int bOK = TRUE;
    1937             188 :         int nBlockXOff = nX / nBlockXSize;
    1938             188 :         if( (nX % nBlockXSize) != 0 )
    1939               0 :             bOK = FALSE;
    1940             188 :         if( nBlockXOff < nXBlocks - 1 && nWidth != nBlockXSize )
    1941               0 :             bOK = FALSE;
    1942             188 :         if( nBlockXOff == nXBlocks - 1 && nX + nWidth != nRasterXSize )
    1943               0 :             bOK = FALSE;
    1944                 : 
    1945             188 :         if( nY > 0 && nHeight != nBlockYSize )
    1946               0 :             bOK = FALSE;
    1947             188 :         if( nY == 0 && nHeight != nRasterYSize - (nYBlocks - 1) * nBlockYSize)
    1948               0 :             bOK = FALSE;
    1949                 : 
    1950             188 :         if( !bOK )
    1951                 :         {
    1952                 :             CPLDebug("PDF", "Tile %d : %d %d %d %d",
    1953               0 :                      (int)i, nX, nY, nWidth, nHeight);
    1954               0 :             return FALSE;
    1955                 :         }
    1956                 :     }
    1957                 : 
    1958                 :     /* Third pass to set the aiTiles array */
    1959              12 :     aiTiles.resize(nXBlocks * nYBlocks, -1);
    1960             200 :     for(i=0; i<asTiles.size(); i++)
    1961                 :     {
    1962             188 :         double dfX = asTiles[i].adfCM[4] * dfDPI / 72.0;
    1963             188 :         double dfY = asTiles[i].adfCM[5] * dfDPI / 72.0;
    1964             188 :         int nHeight = (int)(asTiles[i].dfHeight + 1e-8);
    1965             188 :         int nX = (int)(dfX+0.1);
    1966             188 :         int nY = nRasterYSize - ((int)(dfY+0.1) + nHeight);
    1967             188 :         int nBlockXOff = nX / nBlockXSize;
    1968             188 :         int nBlockYOff = nY / nBlockYSize;
    1969             188 :         aiTiles[ nBlockYOff * nXBlocks + nBlockXOff ] = (int) i;
    1970                 :     }
    1971                 : 
    1972              12 :     this->nBlockXSize = nBlockXSize;
    1973              12 :     this->nBlockYSize = nBlockYSize;
    1974                 : 
    1975              12 :     return TRUE;
    1976                 : }
    1977                 : 
    1978                 : /************************************************************************/
    1979                 : /*                              GuessDPI()                              */
    1980                 : /************************************************************************/
    1981                 : 
    1982             180 : void PDFDataset::GuessDPI(GDALPDFDictionary* poPageDict, int* pnBands)
    1983                 : {
    1984             180 :     const char* pszDPI = CPLGetConfigOption("GDAL_PDF_DPI", NULL);
    1985             180 :     if (pszDPI != NULL)
    1986                 :     {
    1987               1 :         dfDPI = atof(pszDPI);
    1988                 :     }
    1989                 :     else
    1990                 :     {
    1991                 :         /* Try to get a better value from the images that are drawn */
    1992                 :         /* Very simplistic logic. Will only work for raster only PDF */
    1993                 : 
    1994             179 :         GDALPDFObject* poContents = poPageDict->Get("Contents");
    1995             179 :         if (poContents != NULL && poContents->GetType() == PDFObjectType_Array)
    1996                 :         {
    1997               3 :             GDALPDFArray* poContentsArray = poContents->GetArray();
    1998               3 :             if (poContentsArray->GetLength() == 1)
    1999                 :             {
    2000               2 :                 poContents = poContentsArray->Get(0);
    2001                 :             }
    2002                 :         }
    2003                 : 
    2004             179 :         GDALPDFObject* poXObject = poPageDict->LookupObject("Resources.XObject");
    2005             529 :         if (poContents != NULL &&
    2006             179 :             poContents->GetType() == PDFObjectType_Dictionary &&
    2007                 :             poXObject != NULL &&
    2008             171 :             poXObject->GetType() == PDFObjectType_Dictionary)
    2009                 :         {
    2010             171 :             GDALPDFDictionary* poXObjectDict = poXObject->GetDictionary();
    2011             171 :             GDALPDFDictionary* poContentDict = poXObjectDict;
    2012             171 :             GDALPDFStream* poPageStream = poContents->GetStream();
    2013             171 :             if (poPageStream != NULL)
    2014                 :             {
    2015             171 :                 char* pszContent = NULL;
    2016             171 :                 int nLength = poPageStream->GetLength();
    2017             171 :                 int bResetTiles = FALSE;
    2018             171 :                 double dfScaleDPI = 1.0;
    2019                 : 
    2020             171 :                 if( nLength < 100000 )
    2021                 :                 {
    2022             171 :                     CPLString osForm;
    2023             171 :                     pszContent = poPageStream->GetBytes();
    2024             171 :                     if( pszContent != NULL )
    2025                 :                     {
    2026                 : #ifdef DEBUG
    2027             171 :                         const char* pszDumpStream = CPLGetConfigOption("PDF_DUMP_STREAM", NULL);
    2028             171 :                         if( pszDumpStream != NULL )
    2029                 :                         {
    2030               0 :                             VSILFILE* fpDump = VSIFOpenL(pszDumpStream, "wb");
    2031               0 :                             if( fpDump )
    2032                 :                             {
    2033               0 :                                 VSIFWriteL(pszContent, 1, nLength, fpDump);
    2034               0 :                                 VSIFCloseL(fpDump);
    2035                 :                             }
    2036                 :                         }
    2037                 : #endif
    2038             171 :                         osForm = GDALPDFParseStreamContentOnlyDrawForm(pszContent);
    2039             171 :                         if (osForm.size() == 0)
    2040                 :                         {
    2041                 :                             /* Special case for USGS Topo PDF, like CA_Hollywood_20090811_OM_geo.pdf */
    2042             169 :                             const char* pszOGCDo = strstr(pszContent, " /XO1 Do");
    2043             169 :                             if( pszOGCDo )
    2044                 :                             {
    2045               0 :                                 const char* pszcm = strstr(pszContent, " cm ");
    2046               0 :                                 if( pszcm != NULL && pszcm < pszOGCDo )
    2047                 :                                 {
    2048               0 :                                     const char* pszNextcm = strstr(pszcm + 2, "cm");
    2049               0 :                                     if( pszNextcm == NULL || pszNextcm > pszOGCDo )
    2050                 :                                     {
    2051               0 :                                         const char* pszIter = pszcm;
    2052               0 :                                         while( pszIter > pszContent )
    2053                 :                                         {
    2054               0 :                                             if( (*pszIter >= '0' && *pszIter <= '9') ||
    2055                 :                                                 *pszIter == '-' ||
    2056                 :                                                 *pszIter == '.' ||
    2057                 :                                                 *pszIter == ' ' )
    2058               0 :                                                 pszIter --;
    2059                 :                                             else
    2060                 :                                             {
    2061               0 :                                                 pszIter ++;
    2062               0 :                                                 break;
    2063                 :                                             }
    2064                 :                                         }
    2065               0 :                                         CPLString oscm(pszIter);
    2066               0 :                                         oscm.resize(pszcm - pszIter);
    2067               0 :                                         char** papszTokens = CSLTokenizeString(oscm);
    2068               0 :                                         double dfScaleX = -1, dfScaleY = -2;
    2069               0 :                                         if( CSLCount(papszTokens) == 6 )
    2070                 :                                         {
    2071               0 :                                             dfScaleX = CPLAtof(papszTokens[0]);
    2072               0 :                                             dfScaleY = CPLAtof(papszTokens[3]);
    2073                 :                                         }
    2074               0 :                                         CSLDestroy(papszTokens);
    2075               0 :                                         if( dfScaleX == dfScaleY && dfScaleX > 0.0 )
    2076                 :                                         {
    2077               0 :                                             osForm = "XO1";
    2078               0 :                                             bResetTiles = TRUE;
    2079               0 :                                             dfScaleDPI = 1.0 / dfScaleX;
    2080               0 :                                         }
    2081                 :                                     }
    2082                 :                                 }
    2083                 :                                 else
    2084                 :                                 {
    2085               0 :                                     osForm = "XO1";
    2086               0 :                                     bResetTiles = TRUE;
    2087                 :                                 }
    2088                 :                             }
    2089                 :                             /* Special case for USGS Topo PDF, like CA_Sacramento_East_20120308_TM_geo.pdf */
    2090                 :                             else
    2091                 :                             {
    2092             169 :                                 CPLString osOCG = FindLayerOCG(poPageDict, "Orthoimage");
    2093             169 :                                 if( osOCG.size() )
    2094                 :                                 {
    2095               0 :                                     const char* pszBDCLookup = CPLSPrintf("/OC /%s BDC", osOCG.c_str());
    2096               0 :                                     const char* pszBDC = strstr(pszContent, pszBDCLookup);
    2097               0 :                                     if( pszBDC != NULL )
    2098                 :                                     {
    2099               0 :                                         const char* pszIter = pszBDC + strlen(pszBDCLookup);
    2100               0 :                                         while( *pszIter != '\0' )
    2101                 :                                         {
    2102               0 :                                             if( *pszIter == 13 || *pszIter == 10 ||
    2103                 :                                                 *pszIter == ' '|| *pszIter == 'q' )
    2104               0 :                                                 pszIter ++;
    2105                 :                                             else
    2106               0 :                                                 break;
    2107                 :                                         }
    2108               0 :                                         if( strncmp(pszIter, "1 0 0 1 0 0 cm\n",
    2109                 :                                                     strlen( "1 0 0 1 0 0 cm\n" )) == 0 )
    2110               0 :                                             pszIter += strlen("1 0 0 1 0 0 cm\n");
    2111               0 :                                         if( *pszIter == '/' )
    2112                 :                                         {
    2113               0 :                                             pszIter ++;
    2114               0 :                                             const char* pszDo = strstr(pszIter, " Do");
    2115               0 :                                             if( pszDo != NULL )
    2116                 :                                             {
    2117               0 :                                                 osForm = pszIter;
    2118               0 :                                                 osForm.resize(pszDo - pszIter);
    2119               0 :                                                 bResetTiles = TRUE;
    2120                 :                                             }
    2121                 :                                         }
    2122                 :                                     }
    2123             169 :                                 }
    2124                 :                             }
    2125                 :                         }
    2126                 :                     }
    2127                 : 
    2128             171 :                     if (osForm.size())
    2129                 :                     {
    2130               2 :                         CPLFree(pszContent);
    2131               2 :                         pszContent = NULL;
    2132                 : 
    2133               2 :                         GDALPDFObject* poObjForm = poXObjectDict->Get(osForm);
    2134               6 :                         if (poObjForm != NULL &&
    2135               2 :                             poObjForm->GetType() == PDFObjectType_Dictionary &&
    2136               2 :                             (poPageStream = poObjForm->GetStream()) != NULL)
    2137                 :                         {
    2138               2 :                             GDALPDFDictionary* poObjFormDict = poObjForm->GetDictionary();
    2139                 :                             GDALPDFObject* poSubtype;
    2140               6 :                             if ((poSubtype = poObjFormDict->Get("Subtype")) != NULL &&
    2141               2 :                                 poSubtype->GetType() == PDFObjectType_Name &&
    2142               2 :                                 poSubtype->GetName() == "Form")
    2143                 :                             {
    2144               2 :                                 int nLength = poPageStream->GetLength();
    2145               2 :                                 if( nLength < 100000 )
    2146                 :                                 {
    2147               2 :                                     pszContent = poPageStream->GetBytes();
    2148                 : 
    2149               2 :                                     GDALPDFObject* poXObject2 = poObjFormDict->LookupObject("Resources.XObject");
    2150               2 :                                     if( poXObject2 != NULL &&
    2151               0 :                                         poXObject2->GetType() == PDFObjectType_Dictionary )
    2152               0 :                                         poContentDict = poXObject2->GetDictionary();
    2153                 :                                 }
    2154                 :                             }
    2155                 :                         }
    2156             171 :                     }
    2157                 :                 }
    2158                 : 
    2159             171 :                 if (pszContent != NULL)
    2160                 :                 {
    2161             171 :                     int bDPISet = FALSE;
    2162                 : 
    2163             171 :                     const char* pszContentToParse = pszContent;
    2164             171 :                     if( bResetTiles )
    2165                 :                     {
    2166               0 :                         while( *pszContentToParse != '\0' )
    2167                 :                         {
    2168               0 :                             if( *pszContentToParse == 13 || *pszContentToParse == 10 ||
    2169                 :                                 *pszContentToParse == ' ' ||
    2170                 :                                 (*pszContentToParse >= '0' && *pszContentToParse <= '9') ||
    2171                 :                                 *pszContentToParse == '.' || 
    2172                 :                                 *pszContentToParse == '-' || 
    2173                 :                                 *pszContentToParse == 'l' ||
    2174                 :                                 *pszContentToParse == 'm' ||
    2175                 :                                 *pszContentToParse == 'n' ||
    2176                 :                                 *pszContentToParse == 'W' )
    2177               0 :                                 pszContentToParse ++;
    2178                 :                             else
    2179               0 :                                 break;
    2180                 :                         }
    2181                 :                     }
    2182                 : 
    2183                 :                     GDALPDFParseStreamContent(pszContentToParse,
    2184                 :                                               poContentDict,
    2185                 :                                               &(dfDPI),
    2186                 :                                               &bDPISet,
    2187                 :                                               pnBands,
    2188                 :                                               asTiles,
    2189             171 :                                               bResetTiles);
    2190             171 :                     CPLFree(pszContent);
    2191             171 :                     if (bDPISet)
    2192                 :                     {
    2193             164 :                         dfDPI *= dfScaleDPI;
    2194                 : 
    2195             164 :                         CPLDebug("PDF", "DPI guessed from contents stream = %.16g", dfDPI);
    2196             164 :                         SetMetadataItem("DPI", CPLSPrintf("%.16g", dfDPI));
    2197             164 :                         if( bResetTiles )
    2198               0 :                             asTiles.resize(0);
    2199                 :                     }
    2200                 :                     else
    2201               7 :                         asTiles.resize(0);
    2202                 :                 }
    2203                 :             }
    2204                 :         }
    2205                 : 
    2206             179 :         GDALPDFObject* poUserUnit = NULL;
    2207             379 :         if ( (poUserUnit = poPageDict->Get("UserUnit")) != NULL &&
    2208             169 :               (poUserUnit->GetType() == PDFObjectType_Int ||
    2209              31 :                poUserUnit->GetType() == PDFObjectType_Real) )
    2210                 :         {
    2211             169 :             dfDPI = ROUND_TO_INT_IF_CLOSE(Get(poUserUnit) * 72.0);
    2212             169 :             CPLDebug("PDF", "Found UserUnit in Page --> DPI = %.16g", dfDPI);
    2213             169 :             SetMetadataItem("DPI", CPLSPrintf("%.16g", dfDPI));
    2214                 :         }
    2215                 :     }
    2216                 : 
    2217             180 :     if (dfDPI < 1 || dfDPI > 7200)
    2218                 :     {
    2219                 :         CPLError(CE_Warning, CPLE_AppDefined,
    2220               0 :                  "Invalid value for GDAL_PDF_DPI. Using default value instead");
    2221               0 :         dfDPI = DEFAULT_DPI;
    2222                 :     }
    2223             180 : }
    2224                 : 
    2225                 : /************************************************************************/
    2226                 : /*                              FindXMP()                               */
    2227                 : /************************************************************************/
    2228                 : 
    2229             719 : void PDFDataset::FindXMP(GDALPDFObject* poObj)
    2230                 : {
    2231             719 :     if (poObj->GetType() != PDFObjectType_Dictionary)
    2232             233 :         return;
    2233                 : 
    2234             486 :     GDALPDFDictionary* poDict = poObj->GetDictionary();
    2235             486 :     GDALPDFObject* poType = poDict->Get("Type");
    2236             486 :     GDALPDFObject* poSubtype = poDict->Get("Subtype");
    2237            1264 :     if (poType == NULL ||
    2238             385 :         poType->GetType() != PDFObjectType_Name ||
    2239             385 :         poType->GetName() != "Metadata" ||
    2240                 :         poSubtype == NULL ||
    2241               4 :         poSubtype->GetType() != PDFObjectType_Name ||
    2242               4 :         poSubtype->GetName() != "XML")
    2243                 :     {
    2244             482 :         return;
    2245                 :     }
    2246                 : 
    2247               4 :     GDALPDFStream* poStream = poObj->GetStream();
    2248               4 :     if (poStream == NULL)
    2249               0 :         return;
    2250                 : 
    2251               4 :     char* pszContent = poStream->GetBytes();
    2252               4 :     int nLength = (int)poStream->GetLength();
    2253               4 :     if (pszContent != NULL && nLength > 15 &&
    2254                 :         strncmp(pszContent, "<?xpacket begin=", strlen("<?xpacket begin=")) == 0)
    2255                 :     {
    2256                 :         char *apszMDList[2];
    2257               4 :         apszMDList[0] = pszContent;
    2258               4 :         apszMDList[1] = NULL;
    2259               4 :         SetMetadata(apszMDList, "xml:XMP");
    2260                 :     }
    2261               4 :     CPLFree(pszContent);
    2262                 : }
    2263                 : 
    2264                 : /************************************************************************/
    2265                 : /*                             ParseInfo()                              */
    2266                 : /************************************************************************/
    2267                 : 
    2268             182 : void PDFDataset::ParseInfo(GDALPDFObject* poInfoObj)
    2269                 : {
    2270             182 :     if (poInfoObj->GetType() != PDFObjectType_Dictionary)
    2271             130 :         return;
    2272                 : 
    2273              52 :     GDALPDFDictionary* poInfoObjDict = poInfoObj->GetDictionary();
    2274              52 :     GDALPDFObject* poItem = NULL;
    2275              52 :     int bOneMDISet = FALSE;
    2276              62 :     if ((poItem = poInfoObjDict->Get("Author")) != NULL &&
    2277              10 :             poItem->GetType() == PDFObjectType_String)
    2278                 :     {
    2279              10 :         SetMetadataItem("AUTHOR", poItem->GetString().c_str());
    2280              10 :         bOneMDISet = TRUE;
    2281                 :     }
    2282              65 :     if ((poItem = poInfoObjDict->Get("Creator")) != NULL &&
    2283              13 :             poItem->GetType() == PDFObjectType_String)
    2284                 :     {
    2285              13 :         SetMetadataItem("CREATOR", poItem->GetString().c_str());
    2286              13 :         bOneMDISet = TRUE;
    2287                 :     }
    2288              54 :     if ((poItem = poInfoObjDict->Get("Keywords")) != NULL &&
    2289               2 :             poItem->GetType() == PDFObjectType_String)
    2290                 :     {
    2291               2 :         SetMetadataItem("KEYWORDS", poItem->GetString().c_str());
    2292               2 :         bOneMDISet = TRUE;
    2293                 :     }
    2294              56 :     if ((poItem = poInfoObjDict->Get("Subject")) != NULL &&
    2295               4 :             poItem->GetType() == PDFObjectType_String)
    2296                 :     {
    2297               4 :         SetMetadataItem("SUBJECT", poItem->GetString().c_str());
    2298               4 :         bOneMDISet = TRUE;
    2299                 :     }
    2300              56 :     if ((poItem = poInfoObjDict->Get("Title")) != NULL &&
    2301               4 :             poItem->GetType() == PDFObjectType_String)
    2302                 :     {
    2303               4 :         SetMetadataItem("TITLE", poItem->GetString().c_str());
    2304               4 :         bOneMDISet = TRUE;
    2305                 :     }
    2306              83 :     if ((poItem = poInfoObjDict->Get("Producer")) != NULL &&
    2307              31 :             poItem->GetType() == PDFObjectType_String)
    2308                 :     {
    2309              31 :         if (bOneMDISet || poItem->GetString() != "PoDoFo - http://podofo.sf.net")
    2310                 :         {
    2311               4 :             SetMetadataItem("PRODUCER", poItem->GetString().c_str());
    2312               4 :             bOneMDISet = TRUE;
    2313                 :         }
    2314                 :     }
    2315              90 :     if ((poItem = poInfoObjDict->Get("CreationDate")) != NULL &&
    2316              38 :         poItem->GetType() == PDFObjectType_String)
    2317                 :     {
    2318              38 :         if (bOneMDISet)
    2319              11 :             SetMetadataItem("CREATION_DATE", poItem->GetString().c_str());
    2320                 :     }
    2321                 : }
    2322                 : 
    2323                 : /************************************************************************/
    2324                 : /*                           PDFSanitizeLayerName()                     */
    2325                 : /************************************************************************/
    2326                 : 
    2327                 : static
    2328              81 : CPLString PDFSanitizeLayerName(const char* pszName)
    2329                 : {
    2330              81 :     CPLString osName;
    2331             882 :     for(int i=0; pszName[i] != '\0'; i++)
    2332                 :     {
    2333             842 :         if (pszName[i] == ' ' || pszName[i] == '.' || pszName[i] == ',')
    2334              41 :             osName += "_";
    2335             760 :         else if (pszName[i] != '"')
    2336             760 :             osName += pszName[i];
    2337                 :     }
    2338               0 :     return osName;
    2339                 : }
    2340                 : 
    2341                 : #ifdef HAVE_POPPLER
    2342                 : 
    2343                 : /************************************************************************/
    2344                 : /*                               AddLayer()                             */
    2345                 : /************************************************************************/
    2346                 : 
    2347              79 : void PDFDataset::AddLayer(const char* pszLayerName, OptionalContentGroup* ocg)
    2348                 : {
    2349              79 :     int nNewIndex = osLayerList.size() /*/ 2*/;
    2350                 : 
    2351              79 :     if (nNewIndex == 100)
    2352                 :     {
    2353               0 :         CPLStringList osNewLayerList;
    2354               0 :         for(int i=0;i<100;i++)
    2355                 :         {
    2356                 :             osNewLayerList.AddNameValue(CPLSPrintf("LAYER_%03d_NAME", i),
    2357               0 :                                         osLayerList[/*2 * */ i] + strlen("LAYER_00_NAME="));
    2358                 :             /*osNewLayerList.AddNameValue(CPLSPrintf("LAYER_%03d_INIT_STATE", i),
    2359                 :                                         osLayerList[i * 2 + 1] + strlen("LAYER_00_INIT_STATE="));*/
    2360                 :         }
    2361               0 :         osLayerList = osNewLayerList;
    2362                 :     }
    2363                 : 
    2364                 :     char szFormatName[64];
    2365                 :     /* char szFormatInitState[64]; */
    2366              79 :     sprintf(szFormatName, "LAYER_%%0%dd_NAME",  nNewIndex >= 100 ? 3 : 2);
    2367                 :     /* sprintf(szFormatInitState, "LAYER_%%0%dd_INIT_STATE", nNewIndex >= 100 ? 3 : 2); */
    2368                 : 
    2369                 :     osLayerList.AddNameValue(CPLSPrintf(szFormatName, nNewIndex),
    2370              79 :                              pszLayerName);
    2371                 :     /*osLayerList.AddNameValue(CPLSPrintf(szFormatInitState, nNewIndex),
    2372                 :                              (ocg == NULL || ocg->getState() == OptionalContentGroup::On) ? "ON" : "OFF");*/
    2373              79 :     oLayerOCGMap[pszLayerName] = ocg;
    2374                 : 
    2375                 :     //if (ocg != NULL && ocg->getState() == OptionalContentGroup::Off)
    2376                 :     //    bUseOCG = TRUE;
    2377              79 : }
    2378                 : 
    2379                 : /************************************************************************/
    2380                 : /*                             ExploreLayers()                          */
    2381                 : /************************************************************************/
    2382                 : 
    2383              47 : void PDFDataset::ExploreLayers(GDALPDFArray* poArray,
    2384                 :                                int nRecLevel,
    2385                 :                                CPLString osTopLayer)
    2386                 : {
    2387              47 :     if( nRecLevel == 16 )
    2388               0 :         return;
    2389                 : 
    2390              47 :     int nLength = poArray->GetLength();
    2391              47 :     CPLString osCurLayer;
    2392             150 :     for(int i=0;i<nLength;i++)
    2393                 :     {
    2394             103 :         GDALPDFObject* poObj = poArray->Get(i);
    2395             103 :         if (i == 0 && poObj->GetType() == PDFObjectType_String)
    2396                 :         {
    2397               1 :             CPLString osName = PDFSanitizeLayerName(poObj->GetString().c_str());
    2398               1 :             if (osTopLayer.size())
    2399               0 :                 osTopLayer = osTopLayer + "." + osName;
    2400                 :             else
    2401               1 :                 osTopLayer = osName;
    2402               1 :             AddLayer(osTopLayer.c_str(), NULL);
    2403                 :         }
    2404             102 :         else if (poObj->GetType() == PDFObjectType_Array)
    2405                 :         {
    2406              24 :             ExploreLayers(poObj->GetArray(), nRecLevel + 1, osCurLayer);
    2407              24 :             osCurLayer = "";
    2408                 :         }
    2409              78 :         else if (poObj->GetType() == PDFObjectType_Dictionary)
    2410                 :         {
    2411              78 :             GDALPDFDictionary* poDict = poObj->GetDictionary();
    2412              78 :             GDALPDFObject* poName = poDict->Get("Name");
    2413              78 :             if (poName != NULL && poName->GetType() == PDFObjectType_String)
    2414                 :             {
    2415              78 :                 CPLString osName = PDFSanitizeLayerName(poName->GetString().c_str());
    2416              78 :                 if (osTopLayer.size())
    2417              44 :                     osCurLayer = osTopLayer + "." + osName;
    2418                 :                 else
    2419              34 :                     osCurLayer = osName;
    2420                 :                 //CPLDebug("PDF", "Layer %s", osCurLayer.c_str());
    2421                 : 
    2422              78 :                 OCGs* optContentConfig = poDocPoppler->getOptContentConfig();
    2423                 :                 struct Ref r;
    2424              78 :                 r.num = poObj->GetRefNum();
    2425              78 :                 r.gen = poObj->GetRefGen();
    2426              78 :                 OptionalContentGroup* ocg = optContentConfig->findOcgByRef(r);
    2427              78 :                 if (ocg)
    2428                 :                 {
    2429              78 :                     AddLayer(osCurLayer.c_str(), ocg);
    2430                 :                     osLayerWithRefList.AddString(
    2431              78 :                         CPLSPrintf("%s %d %d", osCurLayer.c_str(), r.num, r.gen));
    2432              78 :                 }
    2433                 :             }
    2434                 :         }
    2435              47 :     }
    2436                 : }
    2437                 : 
    2438                 : /************************************************************************/
    2439                 : /*                              FindLayers()                            */
    2440                 : /************************************************************************/
    2441                 : 
    2442             149 : void PDFDataset::FindLayers()
    2443                 : {
    2444             149 :     OCGs* optContentConfig = poDocPoppler->getOptContentConfig();
    2445             149 :     if (optContentConfig == NULL || !optContentConfig->isOk() )
    2446             126 :         return;
    2447                 : 
    2448              23 :     Array* array = optContentConfig->getOrderArray();
    2449              23 :     if (array)
    2450                 :     {
    2451              23 :         GDALPDFArray* poArray = GDALPDFCreateArray(array);
    2452              23 :         ExploreLayers(poArray, 0);
    2453              46 :         delete poArray;
    2454                 :     }
    2455                 :     else
    2456                 :     {
    2457               0 :         GooList* ocgList = optContentConfig->getOCGs();
    2458               0 :         for(int i=0;i<ocgList->getLength();i++)
    2459                 :         {
    2460               0 :             OptionalContentGroup* ocg = (OptionalContentGroup*) ocgList->get(i);
    2461               0 :             if( ocg != NULL && ocg->getName() != NULL )
    2462               0 :                 AddLayer((const char*)ocg->getName()->getCString(), ocg);
    2463                 :         }
    2464                 :     }
    2465                 : 
    2466              23 :     oMDMD.SetMetadata(osLayerList.List(), "LAYERS");
    2467                 : }
    2468                 : 
    2469                 : /************************************************************************/
    2470                 : /*                            TurnLayersOnOff()                         */
    2471                 : /************************************************************************/
    2472                 : 
    2473             149 : void PDFDataset::TurnLayersOnOff()
    2474                 : {
    2475             149 :     OCGs* optContentConfig = poDocPoppler->getOptContentConfig();
    2476             149 :     if (optContentConfig == NULL || !optContentConfig->isOk() )
    2477             126 :         return;
    2478                 : 
    2479                 :     // Which layers to turn ON ?
    2480              23 :     const char* pszLayers = CPLGetConfigOption("GDAL_PDF_LAYERS", NULL);
    2481              23 :     if (pszLayers)
    2482                 :     {
    2483                 :         int i;
    2484               2 :         int bAll = EQUAL(pszLayers, "ALL");
    2485               2 :         GooList* ocgList = optContentConfig->getOCGs();
    2486              12 :         for(i=0;i<ocgList->getLength();i++)
    2487                 :         {
    2488              10 :             OptionalContentGroup* ocg = (OptionalContentGroup*) ocgList->get(i);
    2489              10 :             ocg->setState( (bAll) ? OptionalContentGroup::On : OptionalContentGroup::Off );
    2490                 :         }
    2491                 : 
    2492               2 :         char** papszLayers = CSLTokenizeString2(pszLayers, ",", 0);
    2493               4 :         for(i=0;!bAll && papszLayers[i] != NULL;i++)
    2494                 :         {
    2495                 :             std::map<CPLString, OptionalContentGroup*>::iterator oIter =
    2496               2 :                 oLayerOCGMap.find(papszLayers[i]);
    2497               2 :             if (oIter != oLayerOCGMap.end())
    2498                 :             {
    2499               2 :                 if (oIter->second)
    2500                 :                 {
    2501                 :                     //CPLDebug("PDF", "Turn '%s' on", papszLayers[i]);
    2502               2 :                     oIter->second->setState(OptionalContentGroup::On);
    2503                 :                 }
    2504                 : 
    2505                 :                 // Turn child layers on, unless there's one of them explicitely listed
    2506                 :                 // in the list.
    2507               2 :                 size_t nLen = strlen(papszLayers[i]);
    2508               2 :                 int bFoundChildLayer = FALSE;
    2509               2 :                 oIter = oLayerOCGMap.begin();
    2510              12 :                 for( ; oIter != oLayerOCGMap.end() && !bFoundChildLayer; oIter ++)
    2511                 :                 {
    2512              15 :                     if (oIter->first.size() > nLen &&
    2513               5 :                         strncmp(oIter->first.c_str(), papszLayers[i], nLen) == 0 &&
    2514                 :                         oIter->first[nLen] == '.')
    2515                 :                     {
    2516               4 :                         for(int j=0;papszLayers[j] != NULL;j++)
    2517                 :                         {
    2518               2 :                             if (strcmp(papszLayers[j], oIter->first.c_str()) == 0)
    2519               0 :                                 bFoundChildLayer = TRUE;
    2520                 :                         }
    2521                 :                     }
    2522                 :                 }
    2523                 : 
    2524               2 :                 if( !bFoundChildLayer )
    2525                 :                 {
    2526               2 :                     oIter = oLayerOCGMap.begin();
    2527              12 :                     for( ; oIter != oLayerOCGMap.end() && !bFoundChildLayer; oIter ++)
    2528                 :                     {
    2529              15 :                         if (oIter->first.size() > nLen &&
    2530               5 :                             strncmp(oIter->first.c_str(), papszLayers[i], nLen) == 0 &&
    2531                 :                             oIter->first[nLen] == '.')
    2532                 :                         {
    2533               2 :                             if (oIter->second)
    2534                 :                             {
    2535                 :                                 //CPLDebug("PDF", "Turn '%s' on too", oIter->first.c_str());
    2536               2 :                                 oIter->second->setState(OptionalContentGroup::On);
    2537                 :                             }
    2538                 :                         }
    2539                 :                     }
    2540                 :                 }
    2541                 : 
    2542                 :                 // Turn parent layers on too
    2543                 :                 char* pszLastDot;
    2544               5 :                 while( (pszLastDot = strrchr(papszLayers[i], '.')) != NULL)
    2545                 :                 {
    2546               1 :                     *pszLastDot = '\0';
    2547               1 :                     oIter = oLayerOCGMap.find(papszLayers[i]);
    2548               1 :                     if (oIter != oLayerOCGMap.end())
    2549                 :                     {
    2550               1 :                         if (oIter->second)
    2551                 :                         {
    2552                 :                             //CPLDebug("PDF", "Turn '%s' on too", papszLayers[i]);
    2553               1 :                             oIter->second->setState(OptionalContentGroup::On);
    2554                 :                         }
    2555                 :                     }
    2556                 :                 }
    2557                 :             }
    2558                 :             else
    2559                 :             {
    2560                 :                 CPLError(CE_Warning, CPLE_AppDefined, "Unknown layer '%s'",
    2561               0 :                             papszLayers[i]);
    2562                 :             }
    2563                 :         }
    2564               2 :         CSLDestroy(papszLayers);
    2565                 : 
    2566               2 :         bUseOCG = TRUE;
    2567                 :     }
    2568                 : 
    2569                 :     // Which layers to turn OFF ?
    2570              23 :     const char* pszLayersOFF = CPLGetConfigOption("GDAL_PDF_LAYERS_OFF", NULL);
    2571              23 :     if (pszLayersOFF)
    2572                 :     {
    2573               1 :         char** papszLayersOFF = CSLTokenizeString2(pszLayersOFF, ",", 0);
    2574               2 :         for(int i=0;papszLayersOFF[i] != NULL;i++)
    2575                 :         {
    2576                 :             std::map<CPLString, OptionalContentGroup*>::iterator oIter =
    2577               1 :                 oLayerOCGMap.find(papszLayersOFF[i]);
    2578               1 :             if (oIter != oLayerOCGMap.end())
    2579                 :             {
    2580               1 :                 if (oIter->second)
    2581                 :                 {
    2582                 :                     //CPLDebug("PDF", "Turn '%s' off", papszLayersOFF[i]);
    2583               1 :                     oIter->second->setState(OptionalContentGroup::Off);
    2584                 :                 }
    2585                 : 
    2586                 :                 // Turn child layers off too
    2587               1 :                 size_t nLen = strlen(papszLayersOFF[i]);
    2588               1 :                 oIter = oLayerOCGMap.begin();
    2589               6 :                 for( ; oIter != oLayerOCGMap.end(); oIter ++)
    2590                 :                 {
    2591               8 :                     if (oIter->first.size() > nLen &&
    2592               3 :                         strncmp(oIter->first.c_str(), papszLayersOFF[i], nLen) == 0 &&
    2593                 :                         oIter->first[nLen] == '.')
    2594                 :                     {
    2595               1 :                         if (oIter->second)
    2596                 :                         {
    2597                 :                             //CPLDebug("PDF", "Turn '%s' off too", oIter->first.c_str());
    2598               1 :                             oIter->second->setState(OptionalContentGroup::Off);
    2599                 :                         }
    2600                 :                     }
    2601                 :                 }
    2602                 :             }
    2603                 :             else
    2604                 :             {
    2605                 :                 CPLError(CE_Warning, CPLE_AppDefined, "Unknown layer '%s'",
    2606               0 :                             papszLayersOFF[i]);
    2607                 :             }
    2608                 :         }
    2609               1 :         CSLDestroy(papszLayersOFF);
    2610                 : 
    2611               1 :         bUseOCG = TRUE;
    2612                 :     }
    2613                 : }
    2614                 : 
    2615                 : #endif
    2616                 : 
    2617                 : /************************************************************************/
    2618                 : /*                           FindLayerOCG()                             */
    2619                 : /************************************************************************/
    2620                 : 
    2621             169 : CPLString PDFDataset::FindLayerOCG(GDALPDFDictionary* poPageDict,
    2622                 :                                    const char* pszLayerName)
    2623                 : {
    2624                 :     GDALPDFObject* poProperties =
    2625             169 :         poPageDict->LookupObject("Resources.Properties");
    2626             184 :     if (poProperties != NULL &&
    2627              15 :         poProperties->GetType() == PDFObjectType_Dictionary)
    2628                 :     {
    2629                 :         std::map<CPLString, GDALPDFObject*>& oMap =
    2630              15 :                                 poProperties->GetDictionary()->GetValues();
    2631              15 :         std::map<CPLString, GDALPDFObject*>::iterator oIter = oMap.begin();
    2632              15 :         std::map<CPLString, GDALPDFObject*>::iterator oEnd = oMap.end();
    2633                 : 
    2634              43 :         for(; oIter != oEnd; ++oIter)
    2635                 :         {
    2636              28 :             GDALPDFObject* poObj = oIter->second;
    2637              28 :             if( poObj->GetRefNum() != 0 && poObj->GetType() == PDFObjectType_Dictionary )
    2638                 :             {
    2639              28 :                 GDALPDFObject* poType = poObj->GetDictionary()->Get("Type");
    2640              28 :                 GDALPDFObject* poName = poObj->GetDictionary()->Get("Name");
    2641             112 :                 if( poType != NULL &&
    2642              28 :                     poType->GetType() == PDFObjectType_Name &&
    2643              28 :                     poType->GetName() == "OCG" &&
    2644                 :                     poName != NULL &&
    2645              28 :                     poName->GetType() == PDFObjectType_String )
    2646                 :                 {
    2647              28 :                     if( strcmp(poName->GetString().c_str(), pszLayerName) ==  0)
    2648               0 :                         return oIter->first;
    2649                 :                 }
    2650                 :             }
    2651                 :         }
    2652                 :     }
    2653             169 :     return "";
    2654                 : }
    2655                 : 
    2656                 : /************************************************************************/
    2657                 : /*                         FindLayersGeneric()                          */
    2658                 : /************************************************************************/
    2659                 : 
    2660              33 : void PDFDataset::FindLayersGeneric(GDALPDFDictionary* poPageDict)
    2661                 : {
    2662                 :     GDALPDFObject* poProperties =
    2663              33 :         poPageDict->LookupObject("Resources.Properties");
    2664              34 :     if (poProperties != NULL &&
    2665               1 :         poProperties->GetType() == PDFObjectType_Dictionary)
    2666                 :     {
    2667                 :         std::map<CPLString, GDALPDFObject*>& oMap =
    2668               1 :                                 poProperties->GetDictionary()->GetValues();
    2669               1 :         std::map<CPLString, GDALPDFObject*>::iterator oIter = oMap.begin();
    2670               1 :         std::map<CPLString, GDALPDFObject*>::iterator oEnd = oMap.end();
    2671                 : 
    2672               3 :         for(; oIter != oEnd; ++oIter)
    2673                 :         {
    2674               2 :             GDALPDFObject* poObj = oIter->second;
    2675               2 :             if( poObj->GetRefNum() != 0 && poObj->GetType() == PDFObjectType_Dictionary )
    2676                 :             {
    2677               2 :                 GDALPDFObject* poType = poObj->GetDictionary()->Get("Type");
    2678               2 :                 GDALPDFObject* poName = poObj->GetDictionary()->Get("Name");
    2679               8 :                 if( poType != NULL &&
    2680               2 :                     poType->GetType() == PDFObjectType_Name &&
    2681               2 :                     poType->GetName() == "OCG" &&
    2682                 :                     poName != NULL &&
    2683               2 :                     poName->GetType() == PDFObjectType_String )
    2684                 :                 {
    2685                 :                     osLayerWithRefList.AddString(
    2686                 :                         CPLSPrintf("%s %d %d",
    2687               2 :                                     PDFSanitizeLayerName(poName->GetString()).c_str(),
    2688               2 :                                     poObj->GetRefNum(),
    2689               6 :                                     poObj->GetRefGen()));
    2690                 :                 }
    2691                 :             }
    2692                 :         }
    2693                 :     }
    2694              33 : }
    2695                 : 
    2696                 : /************************************************************************/
    2697                 : /*                                Open()                                */
    2698                 : /************************************************************************/
    2699                 : 
    2700            1526 : GDALDataset *PDFDataset::Open( GDALOpenInfo * poOpenInfo )
    2701                 : 
    2702                 : {
    2703            1526 :     if (!Identify(poOpenInfo))
    2704            1344 :         return NULL;
    2705                 : 
    2706             182 :     const char* pszUserPwd = CPLGetConfigOption("PDF_USER_PWD", NULL);
    2707                 : 
    2708             182 :     int bOpenSubdataset = strncmp(poOpenInfo->pszFilename, "PDF:", 4) == 0;
    2709             182 :     int bOpenSubdatasetImage = strncmp(poOpenInfo->pszFilename, "PDF_IMAGE:", 10) == 0;
    2710             182 :     int iPage = -1;
    2711             182 :     int nImageNum = -1;
    2712             182 :     const char* pszFilename = poOpenInfo->pszFilename;
    2713                 :     char szPassword[81];
    2714                 : 
    2715             182 :     if (bOpenSubdataset)
    2716                 :     {
    2717               1 :         iPage = atoi(pszFilename + 4);
    2718               1 :         if (iPage <= 0)
    2719               0 :             return NULL;
    2720               1 :          pszFilename = strchr(pszFilename + 4, ':');
    2721               1 :         if (pszFilename == NULL)
    2722               0 :             return NULL;
    2723               1 :         pszFilename ++;
    2724                 :     }
    2725             181 :     else if (bOpenSubdatasetImage)
    2726                 :     {
    2727               2 :         iPage = atoi(pszFilename + 10);
    2728               2 :         if (iPage <= 0)
    2729               0 :             return NULL;
    2730               2 :         const char* pszNext = strchr(pszFilename + 10, ':');
    2731               2 :         if (pszNext == NULL)
    2732               0 :             return NULL;
    2733               2 :         nImageNum = atoi(pszNext + 1);
    2734               2 :         if (nImageNum <= 0)
    2735               0 :             return NULL;
    2736               2 :         pszFilename = strchr(pszNext + 1, ':');
    2737               2 :         if (pszFilename == NULL)
    2738               0 :             return NULL;
    2739               2 :         pszFilename ++;
    2740                 :     }
    2741                 :     else
    2742             179 :         iPage = 1;
    2743                 : 
    2744                 :     int bUsePoppler;
    2745                 : #if defined(HAVE_POPPLER) && !defined(HAVE_PODOFO)
    2746                 :     bUsePoppler = TRUE;
    2747                 : #elif !defined(HAVE_POPPLER) && defined(HAVE_PODOFO)
    2748                 :     bUsePoppler = FALSE;
    2749                 : #elif defined(HAVE_POPPLER) && defined(HAVE_PODOFO)
    2750             182 :     const char* pszPDFLib = CPLGetConfigOption("GDAL_PDF_LIB", "POPPLER");
    2751             182 :     if (EQUAL(pszPDFLib, "POPPLER"))
    2752             149 :         bUsePoppler = TRUE;
    2753              33 :     else if (EQUAL(pszPDFLib, "PODOFO"))
    2754              33 :         bUsePoppler = FALSE;
    2755                 :     else
    2756                 :     {
    2757               0 :         CPLDebug("PDF", "Invalid value for GDAL_PDF_LIB config option");
    2758               0 :         bUsePoppler = TRUE;
    2759                 :     }
    2760                 : #else
    2761                 :     return NULL;
    2762                 : #endif
    2763                 : 
    2764             182 :     GDALPDFObject* poPageObj = NULL;
    2765                 : #ifdef HAVE_POPPLER
    2766             182 :     PDFDoc* poDocPoppler = NULL;
    2767             182 :     ObjectAutoFree oObj;
    2768             182 :     Page* poPagePoppler = NULL;
    2769             182 :     Catalog* poCatalogPoppler = NULL;
    2770                 : #endif
    2771                 : #ifdef HAVE_PODOFO
    2772             182 :     PoDoFo::PdfMemDocument* poDocPodofo = NULL;
    2773             182 :     PoDoFo::PdfPage* poPagePodofo = NULL;
    2774                 : #endif
    2775             182 :     int nPages = 0;
    2776                 : 
    2777                 : #ifdef HAVE_POPPLER
    2778             182 :   if(bUsePoppler)
    2779                 :   {
    2780             149 :     GooString* poUserPwd = NULL;
    2781                 : 
    2782                 :     /* Set custom error handler for poppler errors */
    2783                 : #ifdef POPPLER_0_20_OR_LATER
    2784             149 :     setErrorCallback(PDFDatasetErrorFunction, NULL);
    2785                 : #else
    2786                 :     setErrorFunction(PDFDatasetErrorFunction);
    2787                 : #endif
    2788                 : 
    2789                 :     {
    2790             149 :         CPLMutexHolderD(&hGlobalParamsMutex);
    2791                 :         /* poppler global variable */
    2792             149 :         if (globalParams == NULL)
    2793               1 :             globalParams = new GlobalParams();
    2794                 : 
    2795                 :         globalParams->setPrintCommands(CSLTestBoolean(
    2796             149 :             CPLGetConfigOption("GDAL_PDF_PRINT_COMMANDS", "FALSE")));
    2797                 :     }
    2798                 : 
    2799               0 :     while(TRUE)
    2800                 :     {
    2801             149 :         VSILFILE* fp = VSIFOpenL(pszFilename, "rb");
    2802             149 :         if (fp == NULL)
    2803               0 :             return NULL;
    2804                 : 
    2805             149 :         fp = (VSILFILE*)VSICreateBufferedReaderHandle((VSIVirtualHandle*)fp);
    2806                 : 
    2807             149 :         if (pszUserPwd)
    2808               0 :             poUserPwd = new GooString(pszUserPwd);
    2809                 : 
    2810             149 :         oObj.initNull();
    2811             149 :         poDocPoppler = new PDFDoc(new VSIPDFFileStream(fp, pszFilename, &oObj), NULL, poUserPwd);
    2812             149 :         delete poUserPwd;
    2813                 : 
    2814             149 :         if ( !poDocPoppler->isOk() || poDocPoppler->getNumPages() == 0 )
    2815                 :         {
    2816               0 :             if (poDocPoppler->getErrorCode() == errEncrypted)
    2817                 :             {
    2818               0 :                 if (pszUserPwd && EQUAL(pszUserPwd, "ASK_INTERACTIVE"))
    2819                 :                 {
    2820               0 :                     printf( "Enter password (will be echo'ed in the console): " );
    2821               0 :                     fgets( szPassword, sizeof(szPassword), stdin );
    2822               0 :                     szPassword[sizeof(szPassword)-1] = 0;
    2823               0 :                     char* sz10 = strchr(szPassword, '\n');
    2824               0 :                     if (sz10)
    2825               0 :                         *sz10 = 0;
    2826               0 :                     pszUserPwd = szPassword;
    2827               0 :                     PDFFreeDoc(poDocPoppler);
    2828               0 :                     continue;
    2829                 :                 }
    2830               0 :                 else if (pszUserPwd == NULL)
    2831                 :                 {
    2832                 :                     CPLError(CE_Failure, CPLE_AppDefined,
    2833                 :                              "A password is needed. You can specify it through the PDF_USER_PWD "
    2834               0 :                              "configuration option (that can be set to ASK_INTERACTIVE)");
    2835                 :                 }
    2836                 :                 else
    2837                 :                 {
    2838               0 :                     CPLError(CE_Failure, CPLE_AppDefined, "Invalid password");
    2839                 :                 }
    2840                 :             }
    2841                 :             else
    2842                 :             {
    2843               0 :                 CPLError(CE_Failure, CPLE_AppDefined, "Invalid PDF");
    2844                 :             }
    2845                 : 
    2846               0 :             PDFFreeDoc(poDocPoppler);
    2847                 : 
    2848               0 :             return NULL;
    2849                 :         }
    2850                 :         else
    2851                 :             break;
    2852                 :     }
    2853                 : 
    2854             149 :     poCatalogPoppler = poDocPoppler->getCatalog();
    2855             149 :     if ( poCatalogPoppler == NULL || !poCatalogPoppler->isOk() )
    2856                 :     {
    2857               0 :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid PDF : invalid catalog");
    2858               0 :         PDFFreeDoc(poDocPoppler);
    2859               0 :         return NULL;
    2860                 :     }
    2861                 : 
    2862                 : #ifdef dump_catalog
    2863                 :     {
    2864                 :         ObjectAutoFree oCatalog;
    2865                 :         poDocPoppler->getXRef()->getCatalog(&oCatalog);
    2866                 :         GDALPDFObjectPoppler oCatalogGDAL(&oCatalog, FALSE);
    2867                 :         GDALPDFDumper oDumper(stderr);
    2868                 :         oDumper.Dump(&oCatalogGDAL);
    2869                 :     }
    2870                 : #endif
    2871                 : 
    2872             149 :     nPages = poDocPoppler->getNumPages();
    2873             149 :     if (iPage < 1 || iPage > nPages)
    2874                 :     {
    2875                 :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid page number (%d/%d)",
    2876               0 :                  iPage, nPages);
    2877               0 :         PDFFreeDoc(poDocPoppler);
    2878               0 :         return NULL;
    2879                 :     }
    2880                 : 
    2881             149 :     poPagePoppler = poCatalogPoppler->getPage(iPage);
    2882             149 :     if ( poPagePoppler == NULL || !poPagePoppler->isOk() )
    2883                 :     {
    2884               0 :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid PDF : invalid page");
    2885               0 :         PDFFreeDoc(poDocPoppler);
    2886               0 :         return NULL;
    2887                 :     }
    2888                 : 
    2889                 :     /* Here's the dirty part: this is a private member */
    2890                 :     /* so we had to #define private public to get it ! */
    2891             149 :     Object& oPageObj = poPagePoppler->pageObj;
    2892             149 :     if ( !oPageObj.isDict() )
    2893                 :     {
    2894               0 :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid PDF : !oPageObj.isDict()");
    2895               0 :         PDFFreeDoc(poDocPoppler);
    2896               0 :         return NULL;
    2897                 :     }
    2898                 : 
    2899             149 :     poPageObj = new GDALPDFObjectPoppler(&oPageObj, FALSE);
    2900             298 :     Ref* poPageRef = poCatalogPoppler->getPageRef(iPage);
    2901             149 :     if (poPageRef != NULL)
    2902                 :     {
    2903             149 :         ((GDALPDFObjectPoppler*)poPageObj)->SetRefNumAndGen(poPageRef->num, poPageRef->gen);
    2904                 :     }
    2905                 :   }
    2906                 : #endif
    2907                 : 
    2908                 : #ifdef HAVE_PODOFO
    2909             182 :   if (!bUsePoppler)
    2910                 :   {
    2911              33 :     PoDoFo::PdfError::EnableDebug( false );
    2912              33 :     PoDoFo::PdfError::EnableLogging( false );
    2913                 : 
    2914              33 :     poDocPodofo = new PoDoFo::PdfMemDocument();
    2915                 :     try
    2916                 :     {
    2917              33 :         poDocPodofo->Load(pszFilename);
    2918                 :     }
    2919               0 :     catch(PoDoFo::PdfError& oError)
    2920                 :     {
    2921               0 :         if (oError.GetError() == PoDoFo::ePdfError_InvalidPassword)
    2922                 :         {
    2923               0 :             if (pszUserPwd)
    2924                 :             {
    2925               0 :                 if (EQUAL(pszUserPwd, "ASK_INTERACTIVE"))
    2926                 :                 {
    2927               0 :                     printf( "Enter password (will be echo'ed in the console): " );
    2928               0 :                     fgets( szPassword, sizeof(szPassword), stdin );
    2929               0 :                     szPassword[sizeof(szPassword)-1] = 0;
    2930               0 :                     char* sz10 = strchr(szPassword, '\n');
    2931               0 :                     if (sz10)
    2932               0 :                         *sz10 = 0;
    2933               0 :                     pszUserPwd = szPassword;
    2934                 :                 }
    2935                 : 
    2936                 :                 try
    2937                 :                 {
    2938               0 :                     poDocPodofo->SetPassword(pszUserPwd);
    2939                 :                 }
    2940               0 :                 catch(PoDoFo::PdfError& oError)
    2941                 :                 {
    2942               0 :                     if (oError.GetError() == PoDoFo::ePdfError_InvalidPassword)
    2943                 :                     {
    2944               0 :                         CPLError(CE_Failure, CPLE_AppDefined, "Invalid password");
    2945                 :                     }
    2946                 :                     else
    2947                 :                     {
    2948               0 :                         CPLError(CE_Failure, CPLE_AppDefined, "Invalid PDF : %s", oError.what());
    2949                 :                     }
    2950               0 :                     delete poDocPodofo;
    2951               0 :                     return NULL;
    2952                 :                 }
    2953               0 :                 catch(...)
    2954                 :                 {
    2955               0 :                     CPLError(CE_Failure, CPLE_AppDefined, "Invalid PDF");
    2956               0 :                     delete poDocPodofo;
    2957               0 :                     return NULL;
    2958                 :                 }
    2959                 :             }
    2960                 :             else
    2961                 :             {
    2962                 :                 CPLError(CE_Failure, CPLE_AppDefined,
    2963                 :                             "A password is needed. You can specify it through the PDF_USER_PWD "
    2964               0 :                             "configuration option (that can be set to ASK_INTERACTIVE)");
    2965               0 :                 delete poDocPodofo;
    2966               0 :                 return NULL;
    2967                 :             }
    2968                 :         }
    2969                 :         else
    2970                 :         {
    2971               0 :             CPLError(CE_Failure, CPLE_AppDefined, "Invalid PDF : %s", oError.what());
    2972               0 :             delete poDocPodofo;
    2973               0 :             return NULL;
    2974                 :         }
    2975                 :     }
    2976               0 :     catch(...)
    2977                 :     {
    2978               0 :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid PDF");
    2979               0 :         delete poDocPodofo;
    2980               0 :         return NULL;
    2981                 :     }
    2982                 : 
    2983              33 :     nPages = poDocPodofo->GetPageCount();
    2984              33 :     if (iPage < 1 || iPage > nPages)
    2985                 :     {
    2986                 :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid page number (%d/%d)",
    2987               0 :                  iPage, nPages);
    2988               0 :         delete poDocPodofo;
    2989               0 :         return NULL;
    2990                 :     }
    2991                 : 
    2992                 :     try
    2993                 :     {
    2994              33 :         poPagePodofo = poDocPodofo->GetPage(iPage - 1);
    2995                 :     }
    2996               0 :     catch(PoDoFo::PdfError& oError)
    2997                 :     {
    2998               0 :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid PDF : %s", oError.what());
    2999               0 :         delete poDocPodofo;
    3000               0 :         return NULL;
    3001                 :     }
    3002               0 :     catch(...)
    3003                 :     {
    3004               0 :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid PDF");
    3005               0 :         delete poDocPodofo;
    3006               0 :         return NULL;
    3007                 :     }
    3008                 : 
    3009              33 :     if ( poPagePodofo == NULL )
    3010                 :     {
    3011               0 :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid PDF : invalid page");
    3012               0 :         delete poDocPodofo;
    3013               0 :         return NULL;
    3014                 :     }
    3015                 : 
    3016              33 :     PoDoFo::PdfObject* pObj = poPagePodofo->GetObject();
    3017              33 :     poPageObj = new GDALPDFObjectPodofo(pObj, poDocPodofo->GetObjects());
    3018                 :   }
    3019                 : #endif
    3020                 : 
    3021             182 :     GDALPDFDictionary* poPageDict = poPageObj->GetDictionary();
    3022             182 :     if ( poPageDict == NULL )
    3023                 :     {
    3024               0 :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid PDF : poPageDict == NULL");
    3025                 : #ifdef HAVE_POPPLER
    3026               0 :         PDFFreeDoc(poDocPoppler);
    3027                 : #endif
    3028                 : #ifdef HAVE_PODOFO
    3029               0 :         delete poDocPodofo;
    3030                 : #endif
    3031               0 :         return NULL;
    3032                 :     }
    3033                 : 
    3034             182 :     const char* pszDumpObject = CPLGetConfigOption("PDF_DUMP_OBJECT", NULL);
    3035             182 :     if (pszDumpObject != NULL)
    3036                 :     {
    3037                 :         FILE* f;
    3038               0 :         if (strcmp(pszDumpObject, "stderr") == 0)
    3039               0 :             f = stderr;
    3040               0 :         else if (EQUAL(pszDumpObject, "YES"))
    3041               0 :             f = fopen(CPLSPrintf("dump_%s.txt", CPLGetFilename(pszFilename)), "wt");
    3042                 :         else
    3043               0 :             f = fopen(pszDumpObject, "wt");
    3044               0 :         if (f == NULL)
    3045               0 :             f = stderr;
    3046                 : 
    3047               0 :         GDALPDFDumper oDumper(f);
    3048               0 :         oDumper.Dump(poPageObj);
    3049               0 :         if (f != stderr)
    3050               0 :             fclose(f);
    3051                 :     }
    3052                 : 
    3053             182 :     PDFDataset* poDS = new PDFDataset();
    3054             182 :     poDS->bUsePoppler = bUsePoppler;
    3055             364 :     poDS->osFilename = pszFilename;
    3056             182 :     poDS->eAccess = poOpenInfo->eAccess;
    3057                 : 
    3058             182 :     if ( nPages > 1 && !bOpenSubdataset )
    3059                 :     {
    3060                 :         int i;
    3061               1 :         CPLStringList aosList;
    3062               5 :         for(i=0;i<nPages;i++)
    3063                 :         {
    3064                 :             char szKey[32];
    3065               4 :             sprintf( szKey, "SUBDATASET_%d_NAME", i+1 );
    3066               4 :             aosList.AddNameValue(szKey, CPLSPrintf("PDF:%d:%s", i+1, poOpenInfo->pszFilename));
    3067               4 :             sprintf( szKey, "SUBDATASET_%d_DESC", i+1 );
    3068               4 :             aosList.AddNameValue(szKey, CPLSPrintf("Page %d of %s", i+1, poOpenInfo->pszFilename));
    3069                 :         }
    3070               1 :         poDS->SetMetadata( aosList.List(), "SUBDATASETS" );
    3071                 :     }
    3072                 : 
    3073                 : #ifdef HAVE_POPPLER
    3074             182 :     poDS->poDocPoppler = poDocPoppler;
    3075                 : #endif
    3076                 : #ifdef HAVE_PODOFO
    3077             182 :     poDS->poDocPodofo = poDocPodofo;
    3078                 : #endif
    3079             182 :     poDS->poPageObj = poPageObj;
    3080             182 :     poDS->osUserPwd = pszUserPwd ? pszUserPwd : "";
    3081             182 :     poDS->iPage = iPage;
    3082                 : 
    3083             182 :     int nBandsGuessed = 0;
    3084             182 :     if (nImageNum < 0)
    3085                 :     {
    3086             180 :         poDS->GuessDPI(poPageDict, &nBandsGuessed);
    3087             180 :         if( nBandsGuessed < 4 )
    3088             170 :             nBandsGuessed = 0;
    3089                 :     }
    3090                 :     else
    3091                 :     {
    3092               2 :         const char* pszDPI = CPLGetConfigOption("GDAL_PDF_DPI", NULL);
    3093               2 :         if (pszDPI != NULL)
    3094                 :         {
    3095               0 :             poDS->dfDPI = atof(pszDPI);
    3096                 :         }
    3097                 :     }
    3098                 : 
    3099             182 :     double dfX1 = 0.0, dfY1 = 0.0, dfX2 = 0.0, dfY2 = 0.0;
    3100                 : 
    3101                 : #ifdef HAVE_POPPLER
    3102             182 :     if (bUsePoppler)
    3103                 :     {
    3104             149 :         PDFRectangle* psMediaBox = poPagePoppler->getMediaBox();
    3105             149 :         dfX1 = psMediaBox->x1;
    3106             149 :         dfY1 = psMediaBox->y1;
    3107             149 :         dfX2 = psMediaBox->x2;
    3108             149 :         dfY2 = psMediaBox->y2;
    3109                 :     }
    3110                 : #endif
    3111                 : 
    3112                 : #ifdef HAVE_PODOFO
    3113             182 :     if (!bUsePoppler)
    3114                 :     {
    3115              33 :         PoDoFo::PdfRect oMediaBox = poPagePodofo->GetMediaBox();
    3116              33 :         dfX1 = oMediaBox.GetLeft();
    3117              33 :         dfY1 = oMediaBox.GetBottom();
    3118              33 :         dfX2 = dfX1 + oMediaBox.GetWidth();
    3119              33 :         dfY2 = dfY1 + oMediaBox.GetHeight();
    3120                 :     }
    3121                 : #endif
    3122                 : 
    3123             182 :     double dfUserUnit = poDS->dfDPI / 72.0;
    3124             182 :     poDS->nRasterXSize = (int) floor((dfX2 - dfX1) * dfUserUnit+0.5);
    3125             182 :     poDS->nRasterYSize = (int) floor((dfY2 - dfY1) * dfUserUnit+0.5);
    3126                 : 
    3127             182 :     if( !GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize) )
    3128                 :     {
    3129               0 :         delete poDS;
    3130               0 :         return NULL;
    3131                 :     }
    3132                 : 
    3133             182 :     double dfRotation = 0;
    3134                 : #ifdef HAVE_POPPLER
    3135             182 :     if (bUsePoppler)
    3136             149 :         dfRotation = poDocPoppler->getPageRotate(iPage);
    3137                 : #endif
    3138                 : 
    3139                 : #ifdef HAVE_PODOFO
    3140             182 :     if (!bUsePoppler)
    3141              33 :         dfRotation = poPagePodofo->GetRotation();
    3142                 : #endif
    3143             182 :     if ( dfRotation == 90 ||
    3144                 :          dfRotation == 270 )
    3145                 :     {
    3146                 : /* FIXME: the non poppler case should be implemented. This needs to rotate */
    3147                 : /* the output of pdftoppm */
    3148                 : #ifdef HAVE_POPPLER
    3149               0 :       if (bUsePoppler)
    3150                 :       {
    3151                 :         /* Wondering how it would work with a georeferenced image */
    3152                 :         /* Has only been tested with ungeoreferenced image */
    3153               0 :         int nTmp = poDS->nRasterXSize;
    3154               0 :         poDS->nRasterXSize = poDS->nRasterYSize;
    3155               0 :         poDS->nRasterYSize = nTmp;
    3156                 :       }
    3157                 : #endif
    3158                 :     }
    3159                 : 
    3160                 :     /* Check if the PDF is only made of regularly tiled images */
    3161                 :     /* (like some USGS GeoPDF production) */
    3162             182 :     if( dfRotation == 0.0 && poDS->asTiles.size() &&
    3163                 :         EQUAL(CPLGetConfigOption("GDAL_PDF_LAYERS", "ALL"), "ALL") )
    3164                 :     {
    3165             164 :         poDS->CheckTiledRaster();
    3166             164 :         if (poDS->aiTiles.size() )
    3167              12 :             poDS->SetMetadataItem( "INTERLEAVE", "PIXEL", "IMAGE_STRUCTURE" );
    3168                 :     }
    3169                 : 
    3170             182 :     GDALPDFObject* poLGIDict = NULL;
    3171             182 :     GDALPDFObject* poVP = NULL;
    3172             182 :     int bIsOGCBP = FALSE;
    3173             182 :     if ( (poLGIDict = poPageDict->Get("LGIDict")) != NULL && nImageNum < 0 )
    3174                 :     {
    3175                 :         /* Cf 08-139r3_GeoPDF_Encoding_Best_Practice_Version_2.2.pdf */
    3176              22 :         CPLDebug("PDF", "OGC Encoding Best Practice style detected");
    3177              22 :         if (poDS->ParseLGIDictObject(poLGIDict))
    3178                 :         {
    3179              22 :             if (poDS->bHasCTM)
    3180                 :             {
    3181              19 :                 poDS->adfGeoTransform[0] = poDS->adfCTM[4] + poDS->adfCTM[0] * dfX1 + poDS->adfCTM[2] * dfY2;
    3182              19 :                 poDS->adfGeoTransform[1] = poDS->adfCTM[0] / dfUserUnit;
    3183              19 :                 poDS->adfGeoTransform[2] = poDS->adfCTM[1] / dfUserUnit;
    3184              19 :                 poDS->adfGeoTransform[3] = poDS->adfCTM[5] + poDS->adfCTM[1] * dfX1 + poDS->adfCTM[3] * dfY2;
    3185              19 :                 poDS->adfGeoTransform[4] = - poDS->adfCTM[2] / dfUserUnit;
    3186              19 :                 poDS->adfGeoTransform[5] = - poDS->adfCTM[3] / dfUserUnit;
    3187              19 :                 poDS->bGeoTransformValid = TRUE;
    3188                 :             }
    3189                 : 
    3190              22 :             bIsOGCBP = TRUE;
    3191                 : 
    3192                 :             int i;
    3193              37 :             for(i=0;i<poDS->nGCPCount;i++)
    3194                 :             {
    3195              15 :                 poDS->pasGCPList[i].dfGCPPixel = poDS->pasGCPList[i].dfGCPPixel * dfUserUnit;
    3196              15 :                 poDS->pasGCPList[i].dfGCPLine = poDS->nRasterYSize - poDS->pasGCPList[i].dfGCPLine * dfUserUnit;
    3197                 :             }
    3198                 :         }
    3199                 :     }
    3200             160 :     else if ( (poVP = poPageDict->Get("VP")) != NULL && nImageNum < 0 )
    3201                 :     {
    3202                 :         /* Cf adobe_supplement_iso32000.pdf */
    3203             132 :         CPLDebug("PDF", "Adobe ISO32000 style Geospatial PDF perhaps ?");
    3204             132 :         if (dfX1 != 0 || dfY1 != 0)
    3205                 :         {
    3206               0 :             CPLDebug("PDF", "non null dfX1 or dfY1 values. untested case...");
    3207                 :         }
    3208             132 :         poDS->ParseVP(poVP, dfX2 - dfX1, dfY2 - dfY1);
    3209                 :     }
    3210                 :     else
    3211                 :     {
    3212              28 :         GDALPDFObject* poXObject = poPageDict->LookupObject("Resources.XObject");
    3213                 : 
    3214              56 :         if (poXObject != NULL &&
    3215              28 :             poXObject->GetType() == PDFObjectType_Dictionary)
    3216                 :         {
    3217              28 :             GDALPDFDictionary* poXObjectDict = poXObject->GetDictionary();
    3218              28 :             std::map<CPLString, GDALPDFObject*>& oMap = poXObjectDict->GetValues();
    3219              28 :             std::map<CPLString, GDALPDFObject*>::iterator oMapIter = oMap.begin();
    3220              28 :             int nSubDataset = 0;
    3221             198 :             while(oMapIter != oMap.end())
    3222                 :             {
    3223             144 :                 GDALPDFObject* poObj = oMapIter->second;
    3224             144 :                 if (poObj->GetType() == PDFObjectType_Dictionary)
    3225                 :                 {
    3226             144 :                     GDALPDFDictionary* poDict = poObj->GetDictionary();
    3227             144 :                     GDALPDFObject* poSubtype = NULL;
    3228             144 :                     GDALPDFObject* poMeasure = NULL;
    3229             144 :                     GDALPDFObject* poWidth = NULL;
    3230             144 :                     GDALPDFObject* poHeight = NULL;
    3231             144 :                     int nW = 0;
    3232             144 :                     int nH = 0;
    3233             618 :                     if ((poSubtype = poDict->Get("Subtype")) != NULL &&
    3234             144 :                         poSubtype->GetType() == PDFObjectType_Name &&
    3235             144 :                         poSubtype->GetName() == "Image" &&
    3236             144 :                         (poMeasure = poDict->Get("Measure")) != NULL &&
    3237               6 :                         poMeasure->GetType() == PDFObjectType_Dictionary &&
    3238               6 :                         (poWidth = poDict->Get("Width")) != NULL &&
    3239               6 :                         poWidth->GetType() == PDFObjectType_Int &&
    3240               6 :                         (nW = poWidth->GetInt()) > 0 &&
    3241               6 :                         (poHeight = poDict->Get("Height")) != NULL &&
    3242               6 :                         poHeight->GetType() == PDFObjectType_Int &&
    3243               6 :                         (nH = poHeight->GetInt()) > 0 )
    3244                 :                     {
    3245               6 :                         if (nImageNum < 0)
    3246                 :                             CPLDebug("PDF", "Measure found on Image object (%d)",
    3247               4 :                                      poObj->GetRefNum());
    3248                 : 
    3249               6 :                         GDALPDFObject* poColorSpace = poDict->Get("ColorSpace");
    3250               6 :                         GDALPDFObject* poBitsPerComponent = poDict->Get("BitsPerComponent");
    3251              39 :                         if (poObj->GetRefNum() != 0 &&
    3252               6 :                             poObj->GetRefGen() == 0 &&
    3253                 :                             poColorSpace != NULL &&
    3254               6 :                             poColorSpace->GetType() == PDFObjectType_Name &&
    3255               6 :                             (poColorSpace->GetName() == "DeviceGray" ||
    3256               3 :                              poColorSpace->GetName() == "DeviceRGB") &&
    3257                 :                             (poBitsPerComponent == NULL ||
    3258               6 :                              (poBitsPerComponent->GetType() == PDFObjectType_Int &&
    3259               6 :                               poBitsPerComponent->GetInt() == 8)))
    3260                 :                         {
    3261               6 :                             if (nImageNum < 0)
    3262                 :                             {
    3263               4 :                                 nSubDataset ++;
    3264                 :                                 poDS->SetMetadataItem(CPLSPrintf("SUBDATASET_%d_NAME",
    3265                 :                                                                  nSubDataset),
    3266                 :                                                       CPLSPrintf("PDF_IMAGE:%d:%d:%s",
    3267               4 :                                                                  iPage, poObj->GetRefNum(), pszFilename),
    3268               8 :                                                       "SUBDATASETS");
    3269                 :                                 poDS->SetMetadataItem(CPLSPrintf("SUBDATASET_%d_DESC",
    3270                 :                                                                  nSubDataset),
    3271                 :                                                       CPLSPrintf("Georeferenced image of size %dx%d of page %d of %s",
    3272                 :                                                                  nW, nH, iPage, pszFilename),
    3273               4 :                                                       "SUBDATASETS");
    3274                 :                             }
    3275               2 :                             else if (poObj->GetRefNum() == nImageNum)
    3276                 :                             {
    3277               2 :                                 poDS->nRasterXSize = nW;
    3278               2 :                                 poDS->nRasterYSize = nH;
    3279               2 :                                 poDS->ParseMeasure(poMeasure, nW, nH, 0, nH, nW, 0);
    3280               2 :                                 poDS->poImageObj = poObj;
    3281               2 :                                 if (poColorSpace->GetName() == "DeviceGray")
    3282               1 :                                     nBandsGuessed = 1;
    3283               2 :                                 break;
    3284                 :                             }
    3285                 :                         }
    3286                 :                     }
    3287                 :                 }
    3288             142 :                 ++ oMapIter;
    3289                 :             }
    3290                 :         }
    3291                 : 
    3292              28 :         if (nImageNum >= 0 && poDS->poImageObj == NULL)
    3293                 :         {
    3294               0 :             CPLError(CE_Failure, CPLE_AppDefined, "Cannot find image %d", nImageNum);
    3295               0 :             delete poDS;
    3296               0 :             return NULL;
    3297                 :         }
    3298                 : 
    3299                 :         /* Not a geospatial PDF doc */
    3300                 :     }
    3301                 : 
    3302                 :     /* If pixel size or top left coordinates are very close to an int, round them to the int */
    3303             182 :     double dfEps = ( fabs(poDS->adfGeoTransform[0]) > 1e5 &&
    3304             182 :                      fabs(poDS->adfGeoTransform[3]) > 1e5 ) ? 1e-5 : 1e-8;
    3305             182 :     poDS->adfGeoTransform[0] = ROUND_TO_INT_IF_CLOSE(poDS->adfGeoTransform[0], dfEps);
    3306             182 :     poDS->adfGeoTransform[1] = ROUND_TO_INT_IF_CLOSE(poDS->adfGeoTransform[1]);
    3307             182 :     poDS->adfGeoTransform[3] = ROUND_TO_INT_IF_CLOSE(poDS->adfGeoTransform[3], dfEps);
    3308             182 :     poDS->adfGeoTransform[5] = ROUND_TO_INT_IF_CLOSE(poDS->adfGeoTransform[5]);
    3309                 : 
    3310             182 :     if (poDS->poNeatLine)
    3311                 :     {
    3312             156 :         char* pszNeatLineWkt = NULL;
    3313             156 :         OGRLinearRing* poRing = poDS->poNeatLine->getExteriorRing();
    3314                 :         /* Adobe style is already in target SRS units */
    3315             156 :         if (bIsOGCBP)
    3316                 :         {
    3317              22 :             int nPoints = poRing->getNumPoints();
    3318                 :             int i;
    3319                 : 
    3320             116 :             for(i=0;i<nPoints;i++)
    3321                 :             {
    3322              94 :                 double x = poRing->getX(i) * dfUserUnit;
    3323              94 :                 double y = poDS->nRasterYSize - poRing->getY(i) * dfUserUnit;
    3324              94 :                 double X = poDS->adfGeoTransform[0] + x * poDS->adfGeoTransform[1] +
    3325              94 :                                                       y * poDS->adfGeoTransform[2];
    3326              94 :                 double Y = poDS->adfGeoTransform[3] + x * poDS->adfGeoTransform[4] +
    3327              94 :                                                       y * poDS->adfGeoTransform[5];
    3328              94 :                 poRing->setPoint(i, X, Y);
    3329                 :             }
    3330                 :         }
    3331             156 :         poRing->closeRings();
    3332                 : 
    3333             156 :         poDS->poNeatLine->exportToWkt(&pszNeatLineWkt);
    3334             156 :         if (nImageNum < 0)
    3335             154 :             poDS->SetMetadataItem("NEATLINE", pszNeatLineWkt);
    3336             156 :         CPLFree(pszNeatLineWkt);
    3337                 :     }
    3338                 : 
    3339                 : 
    3340                 : #ifdef HAVE_POPPLER
    3341             182 :   if (bUsePoppler)
    3342                 :   {
    3343             149 :     GooString* poMetadata = poCatalogPoppler->readMetadata();
    3344             149 :     if (poMetadata)
    3345                 :     {
    3346              10 :         char* pszContent = poMetadata->getCString();
    3347              10 :         if (pszContent != NULL &&
    3348                 :             strncmp(pszContent, "<?xpacket begin=", strlen("<?xpacket begin=")) == 0)
    3349                 :         {
    3350                 :             char *apszMDList[2];
    3351              10 :             apszMDList[0] = pszContent;
    3352              10 :             apszMDList[1] = NULL;
    3353              10 :             poDS->SetMetadata(apszMDList, "xml:XMP");
    3354                 :         }
    3355              10 :         delete poMetadata;
    3356                 :     }
    3357                 : 
    3358                 :     /* Read Info object */
    3359                 :     /* The test is necessary since with some corrupted PDFs poDocPoppler->getDocInfo() */
    3360                 :     /* might abort() */
    3361             149 :     if( poDocPoppler->getXRef()->isOk() )
    3362                 :     {
    3363             149 :         Object oInfo;
    3364             149 :         poDocPoppler->getDocInfo(&oInfo);
    3365             149 :         GDALPDFObjectPoppler oInfoObjPoppler(&oInfo, FALSE);
    3366             149 :         poDS->ParseInfo(&oInfoObjPoppler);
    3367             149 :         oInfo.free();
    3368                 :     }
    3369                 : 
    3370                 :     /* Find layers */
    3371             149 :     poDS->FindLayers();
    3372                 : 
    3373                 :     /* Turn user specified layers on or off */
    3374             149 :     poDS->TurnLayersOnOff();
    3375                 :   }
    3376                 : #endif
    3377                 : 
    3378                 : #ifdef HAVE_PODOFO
    3379             182 :   if (!bUsePoppler)
    3380                 :   {
    3381              33 :     PoDoFo::TIVecObjects it = poDocPodofo->GetObjects().begin();
    3382             752 :     for( ; it != poDocPodofo->GetObjects().end(); ++it )
    3383                 :     {
    3384             719 :         GDALPDFObjectPodofo oObjPodofo((*it), poDocPodofo->GetObjects());
    3385             719 :         poDS->FindXMP(&oObjPodofo);
    3386                 :     }
    3387                 : 
    3388                 :     /* Find layers */
    3389              33 :     poDS->FindLayersGeneric(poPageDict);
    3390                 : 
    3391                 :     /* Read Info object */
    3392              33 :     PoDoFo::PdfInfo* poInfo = poDocPodofo->GetInfo();
    3393              33 :     if (poInfo != NULL)
    3394                 :     {
    3395              33 :         GDALPDFObjectPodofo oInfoObjPodofo(poInfo->GetObject(), poDocPodofo->GetObjects());
    3396              33 :         poDS->ParseInfo(&oInfoObjPodofo);
    3397                 :     }
    3398                 :   }
    3399                 : #endif
    3400                 : 
    3401             182 :     int nBands = 3;
    3402             182 :     if( nBandsGuessed )
    3403              11 :         nBands = nBandsGuessed;
    3404             182 :     const char* pszPDFBands = CPLGetConfigOption("GDAL_PDF_BANDS", NULL);
    3405             182 :     if( pszPDFBands )
    3406                 :     {
    3407               0 :         nBands = atoi(pszPDFBands);
    3408               0 :         if (nBands != 3 && nBands != 4)
    3409                 :         {
    3410                 :             CPLError(CE_Warning, CPLE_NotSupported,
    3411               0 :                     "Invalid value for GDAL_PDF_BANDS. Using 3 as a fallback");
    3412               0 :             nBands = 3;
    3413                 :         }
    3414                 :     }
    3415                 : #ifdef HAVE_PODOFO
    3416             182 :     if (!bUsePoppler && nBands == 4 && poDS->aiTiles.size() == 0)
    3417                 :     {
    3418                 :         CPLError(CE_Warning, CPLE_NotSupported,
    3419                 :                  "GDAL_PDF_BANDS=4 only supported when PDF driver is compiled against Poppler. "
    3420               0 :                  "Using 3 as a fallback");
    3421               0 :         nBands = 3;
    3422                 :     }
    3423                 : #endif
    3424                 : 
    3425                 :     int iBand;
    3426             736 :     for(iBand = 1; iBand <= nBands; iBand ++)
    3427                 :     {
    3428             554 :         if (poDS->poImageObj != NULL)
    3429               4 :             poDS->SetBand(iBand, new PDFImageRasterBand(poDS, iBand));
    3430                 :         else
    3431             550 :             poDS->SetBand(iBand, new PDFRasterBand(poDS, iBand));
    3432                 :     }
    3433                 : 
    3434                 : /* -------------------------------------------------------------------- */
    3435                 : /*      Initialize any PAM information.                                 */
    3436                 : /* -------------------------------------------------------------------- */
    3437             182 :     poDS->SetDescription( poOpenInfo->pszFilename );
    3438             182 :     poDS->TryLoadXML();
    3439                 : 
    3440                 : /* -------------------------------------------------------------------- */
    3441                 : /*      Support overviews.                                              */
    3442                 : /* -------------------------------------------------------------------- */
    3443             182 :     poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
    3444                 : 
    3445                 :     /* Clear dirty flag */
    3446             182 :     poDS->bProjDirty = FALSE;
    3447             182 :     poDS->bNeatLineDirty = FALSE;
    3448             182 :     poDS->bInfoDirty = FALSE;
    3449             182 :     poDS->bXMPDirty = FALSE;
    3450                 : 
    3451             182 :     return( poDS );
    3452                 : }
    3453                 : 
    3454                 : /************************************************************************/
    3455                 : /*                       ParseLGIDictObject()                           */
    3456                 : /************************************************************************/
    3457                 : 
    3458              22 : int PDFDataset::ParseLGIDictObject(GDALPDFObject* poLGIDict)
    3459                 : {
    3460                 :     int i;
    3461              22 :     int bOK = FALSE;
    3462              22 :     if (poLGIDict->GetType() == PDFObjectType_Array)
    3463                 :     {
    3464               2 :         GDALPDFArray* poArray = poLGIDict->GetArray();
    3465               2 :         int nArrayLength = poArray->GetLength();
    3466               2 :         int iMax = -1;
    3467                 :         GDALPDFObject* poArrayElt;
    3468               4 :         for (i=0; i<nArrayLength; i++)
    3469                 :         {
    3470               4 :             if ( (poArrayElt = poArray->Get(i)) == NULL ||
    3471               2 :                  poArrayElt->GetType() != PDFObjectType_Dictionary )
    3472                 :             {
    3473                 :                 CPLError(CE_Failure, CPLE_AppDefined,
    3474               0 :                          "LGIDict[%d] is not a dictionary", i);
    3475               0 :                 return FALSE;
    3476                 :             }
    3477                 : 
    3478               2 :             int bIsBestCandidate = FALSE;
    3479               2 :             if (ParseLGIDictDictFirstPass(poArrayElt->GetDictionary(), &bIsBestCandidate))
    3480                 :             {
    3481               2 :                 if (bIsBestCandidate || iMax < 0)
    3482               2 :                     iMax = i;
    3483                 :             }
    3484                 :         }
    3485                 : 
    3486               2 :         if (iMax < 0)
    3487               0 :             return FALSE;
    3488                 : 
    3489               2 :         poArrayElt = poArray->Get(iMax);
    3490               2 :         bOK = ParseLGIDictDictSecondPass(poArrayElt->GetDictionary());
    3491                 :     }
    3492              20 :     else if (poLGIDict->GetType() == PDFObjectType_Dictionary)
    3493                 :     {
    3494              20 :         bOK = ParseLGIDictDictFirstPass(poLGIDict->GetDictionary()) &&
    3495              20 :               ParseLGIDictDictSecondPass(poLGIDict->GetDictionary());
    3496                 :     }
    3497                 :     else
    3498                 :     {
    3499                 :         CPLError(CE_Failure, CPLE_AppDefined,
    3500               0 :                  "LGIDict is of type %s", poLGIDict->GetTypeName());
    3501                 :     }
    3502                 : 
    3503              22 :     return bOK;
    3504                 : }
    3505                 : 
    3506                 : /************************************************************************/
    3507                 : /*                            Get()                                     */
    3508                 : /************************************************************************/
    3509                 : 
    3510           11091 : static double Get(GDALPDFObject* poObj, int nIndice)
    3511                 : {
    3512           11091 :     if (poObj->GetType() == PDFObjectType_Array && nIndice >= 0)
    3513                 :     {
    3514            4854 :         poObj = poObj->GetArray()->Get(nIndice);
    3515            4854 :         if (poObj == NULL)
    3516               0 :             return 0;
    3517            4854 :         return Get(poObj);
    3518                 :     }
    3519            6237 :     else if (poObj->GetType() == PDFObjectType_Int)
    3520            4931 :         return poObj->GetInt();
    3521            1306 :     else if (poObj->GetType() == PDFObjectType_Real)
    3522            1055 :         return poObj->GetReal();
    3523             251 :     else if (poObj->GetType() == PDFObjectType_String)
    3524                 :     {
    3525             251 :         const char* pszStr = poObj->GetString().c_str();
    3526             251 :         size_t nLen = strlen(pszStr);
    3527                 :         /* cf Military_Installations_2008.pdf that has values like "96 0 0.0W" */
    3528             251 :         char chLast = pszStr[nLen-1];
    3529             251 :         if (chLast == 'W' || chLast == 'E' || chLast == 'N' || chLast == 'S')
    3530                 :         {
    3531               0 :             double dfDeg = atof(pszStr);
    3532               0 :             double dfMin = 0, dfSec = 0;
    3533               0 :             const char* pszNext = strchr(pszStr, ' ');
    3534               0 :             if (pszNext)
    3535               0 :                 pszNext ++;
    3536               0 :             if (pszNext)
    3537               0 :                 dfMin = atof(pszNext);
    3538               0 :             if (pszNext)
    3539               0 :                 pszNext = strchr(pszNext, ' ');
    3540               0 :             if (pszNext)
    3541               0 :                 pszNext ++;
    3542               0 :             if (pszNext)
    3543               0 :                 dfSec = atof(pszNext);
    3544               0 :             double dfVal = dfDeg + dfMin / 60 + dfSec / 3600;
    3545               0 :             if (chLast == 'W' || chLast == 'S')
    3546               0 :                 return -dfVal;
    3547                 :             else
    3548               0 :                 return dfVal;
    3549                 :         }
    3550             251 :         return atof(pszStr);
    3551                 :     }
    3552                 :     else
    3553                 :     {
    3554                 :         CPLError(CE_Warning, CPLE_AppDefined, "Unexpected type : %s",
    3555               0 :                  poObj->GetTypeName());
    3556               0 :         return 0;
    3557                 :     }
    3558                 : }
    3559                 : 
    3560                 : /************************************************************************/
    3561                 : /*                            Get()                                */
    3562                 : /************************************************************************/
    3563                 : 
    3564              14 : static double Get(GDALPDFDictionary* poDict, const char* pszName)
    3565                 : {
    3566                 :     GDALPDFObject* poObj;
    3567              14 :     if ( (poObj = poDict->Get(pszName)) != NULL )
    3568              14 :         return Get(poObj);
    3569                 :     CPLError(CE_Failure, CPLE_AppDefined,
    3570               0 :              "Cannot find parameter %s", pszName);
    3571               0 :     return 0;
    3572                 : }
    3573                 : 
    3574                 : /************************************************************************/
    3575                 : /*                   ParseLGIDictDictFirstPass()                        */
    3576                 : /************************************************************************/
    3577                 : 
    3578              22 : int PDFDataset::ParseLGIDictDictFirstPass(GDALPDFDictionary* poLGIDict,
    3579                 :                                           int* pbIsBestCandidate)
    3580                 : {
    3581                 :     int i;
    3582                 : 
    3583              22 :     if (pbIsBestCandidate)
    3584               2 :         *pbIsBestCandidate = FALSE;
    3585                 : 
    3586              22 :     if (poLGIDict == NULL)
    3587               0 :         return FALSE;
    3588                 : 
    3589                 : /* -------------------------------------------------------------------- */
    3590                 : /*      Extract Type attribute                                          */
    3591                 : /* -------------------------------------------------------------------- */
    3592                 :     GDALPDFObject* poType;
    3593              22 :     if ((poType = poLGIDict->Get("Type")) == NULL)
    3594                 :     {
    3595                 :         CPLError(CE_Failure, CPLE_AppDefined,
    3596               0 :                  "Cannot find Type of LGIDict object");
    3597               0 :         return FALSE;
    3598                 :     }
    3599                 : 
    3600              22 :     if ( poType->GetType() != PDFObjectType_Name )
    3601                 :     {
    3602                 :         CPLError(CE_Failure, CPLE_AppDefined,
    3603               0 :                  "Invalid type for Type of LGIDict object");
    3604               0 :         return FALSE;
    3605                 :     }
    3606                 : 
    3607              22 :     if ( strcmp(poType->GetName().c_str(), "LGIDict") != 0 )
    3608                 :     {
    3609                 :         CPLError(CE_Failure, CPLE_AppDefined,
    3610                 :                  "Invalid value for Type of LGIDict object : %s",
    3611               0 :                  poType->GetName().c_str());
    3612               0 :         return FALSE;
    3613                 :     }
    3614                 : 
    3615                 : /* -------------------------------------------------------------------- */
    3616                 : /*      Extract Version attribute                                       */
    3617                 : /* -------------------------------------------------------------------- */
    3618                 :     GDALPDFObject* poVersion;
    3619              22 :     if ((poVersion = poLGIDict->Get("Version")) == NULL)
    3620                 :     {
    3621                 :         CPLError(CE_Failure, CPLE_AppDefined,
    3622               0 :                  "Cannot find Version of LGIDict object");
    3623               0 :         return FALSE;
    3624                 :     }
    3625                 : 
    3626              22 :     if ( poVersion->GetType() == PDFObjectType_String )
    3627                 :     {
    3628                 :         /* OGC best practice is 2.1 */
    3629                 :         CPLDebug("PDF", "LGIDict Version : %s",
    3630              20 :                  poVersion->GetString().c_str());
    3631                 :     }
    3632               2 :     else if (poVersion->GetType() == PDFObjectType_Int)
    3633                 :     {
    3634                 :         /* Old TerraGo is 2 */
    3635                 :         CPLDebug("PDF", "LGIDict Version : %d",
    3636               2 :                  poVersion->GetInt());
    3637                 :     }
    3638                 : 
    3639                 :     /* USGS PDF maps have several LGIDict. Keep the one whose description */
    3640                 :     /* is "Map Layers" by default */
    3641                 :     const char* pszNeatlineToSelect =
    3642              22 :         CPLGetConfigOption("GDAL_PDF_NEATLINE", "Map Layers");
    3643                 : 
    3644                 : /* -------------------------------------------------------------------- */
    3645                 : /*      Extract Neatline attribute                                      */
    3646                 : /* -------------------------------------------------------------------- */
    3647                 :     GDALPDFObject* poNeatline;
    3648              44 :     if ((poNeatline = poLGIDict->Get("Neatline")) != NULL &&
    3649              22 :         poNeatline->GetType() == PDFObjectType_Array)
    3650                 :     {
    3651              22 :         int nLength = poNeatline->GetArray()->GetLength();
    3652              22 :         if ( (nLength % 2) != 0 || nLength < 4 )
    3653                 :         {
    3654                 :             CPLError(CE_Failure, CPLE_AppDefined,
    3655               0 :                      "Invalid length for Neatline");
    3656               0 :             return FALSE;
    3657                 :         }
    3658                 : 
    3659                 :         GDALPDFObject* poDescription;
    3660              22 :         int bIsAskedNeatline = FALSE;
    3661              44 :         if ( (poDescription = poLGIDict->Get("Description")) != NULL &&
    3662              22 :             poDescription->GetType() == PDFObjectType_String )
    3663                 :         {
    3664              22 :             CPLDebug("PDF", "Description = %s", poDescription->GetString().c_str());
    3665                 : 
    3666              22 :             if( EQUAL(poDescription->GetString().c_str(), pszNeatlineToSelect) )
    3667                 :             {
    3668               0 :                 dfMaxArea = 1e300;
    3669               0 :                 bIsAskedNeatline = TRUE;
    3670                 :             }
    3671                 :         }
    3672                 : 
    3673              22 :         if( !bIsAskedNeatline )
    3674                 :         {
    3675              22 :             double dfMinX = 0, dfMinY = 0, dfMaxX = 0, dfMaxY = 0;
    3676             116 :             for(i=0;i<nLength;i+=2)
    3677                 :             {
    3678              94 :                 double dfX = Get(poNeatline, i);
    3679              94 :                 double dfY = Get(poNeatline, i + 1);
    3680              94 :                 if (i == 0 || dfX < dfMinX) dfMinX = dfX;
    3681              94 :                 if (i == 0 || dfY < dfMinY) dfMinY = dfY;
    3682              94 :                 if (i == 0 || dfX > dfMaxX) dfMaxX = dfX;
    3683              94 :                 if (i == 0 || dfY > dfMaxY) dfMaxY = dfY;
    3684                 :             }
    3685              22 :             double dfArea = (dfMaxX - dfMinX) * (dfMaxY - dfMinY);
    3686              22 :             if (dfArea < dfMaxArea)
    3687                 :             {
    3688               0 :                 CPLDebug("PDF", "Not the largest neatline. Skipping it");
    3689               0 :                 return TRUE;
    3690                 :             }
    3691                 : 
    3692              22 :             CPLDebug("PDF", "This is the largest neatline for now");
    3693              22 :             dfMaxArea = dfArea;
    3694                 :         }
    3695                 :         else
    3696                 :             CPLDebug("PDF", "The \"%s\" registration will be selected",
    3697               0 :                      pszNeatlineToSelect);
    3698                 : 
    3699              22 :         if (pbIsBestCandidate)
    3700               2 :             *pbIsBestCandidate = TRUE;
    3701                 : 
    3702              22 :         delete poNeatLine;
    3703              22 :         poNeatLine = new OGRPolygon();
    3704              44 :         OGRLinearRing* poRing = new OGRLinearRing();
    3705              22 :         if (nLength == 4)
    3706                 :         {
    3707                 :             /* 2 points only ? They are the bounding box */
    3708               0 :             double dfX1 = Get(poNeatline, 0);
    3709               0 :             double dfY1 = Get(poNeatline, 1);
    3710               0 :             double dfX2 = Get(poNeatline, 2);
    3711               0 :             double dfY2 = Get(poNeatline, 3);
    3712               0 :             poRing->addPoint(dfX1, dfY1);
    3713               0 :             poRing->addPoint(dfX2, dfY1);
    3714               0 :             poRing->addPoint(dfX2, dfY2);
    3715               0 :             poRing->addPoint(dfX1, dfY2);
    3716                 :         }
    3717                 :         else
    3718                 :         {
    3719             116 :             for(i=0;i<nLength;i+=2)
    3720                 :             {
    3721              94 :                 double dfX = Get(poNeatline, i);
    3722              94 :                 double dfY = Get(poNeatline, i + 1);
    3723              94 :                 poRing->addPoint(dfX, dfY);
    3724                 :             }
    3725                 :         }
    3726              22 :         poNeatLine->addRingDirectly(poRing);
    3727                 :     }
    3728                 : 
    3729              22 :     return TRUE;
    3730                 : }
    3731                 : 
    3732                 : /************************************************************************/
    3733                 : /*                  ParseLGIDictDictSecondPass()                        */
    3734                 : /************************************************************************/
    3735                 : 
    3736              22 : int PDFDataset::ParseLGIDictDictSecondPass(GDALPDFDictionary* poLGIDict)
    3737                 : {
    3738                 :     int i;
    3739                 : 
    3740                 : /* -------------------------------------------------------------------- */
    3741                 : /*      Extract Description attribute                                   */
    3742                 : /* -------------------------------------------------------------------- */
    3743                 :     GDALPDFObject* poDescription;
    3744              44 :     if ( (poDescription = poLGIDict->Get("Description")) != NULL &&
    3745              22 :          poDescription->GetType() == PDFObjectType_String )
    3746                 :     {
    3747              22 :         CPLDebug("PDF", "Description = %s", poDescription->GetString().c_str());
    3748                 :     }
    3749                 : 
    3750                 : /* -------------------------------------------------------------------- */
    3751                 : /*      Extract CTM attribute                                           */
    3752                 : /* -------------------------------------------------------------------- */
    3753                 :     GDALPDFObject* poCTM;
    3754              22 :     bHasCTM = FALSE;
    3755              41 :     if ((poCTM = poLGIDict->Get("CTM")) != NULL &&
    3756              19 :         poCTM->GetType() == PDFObjectType_Array)
    3757                 :     {
    3758              19 :         int nLength = poCTM->GetArray()->GetLength();
    3759              19 :         if ( nLength != 6 )
    3760                 :         {
    3761                 :             CPLError(CE_Failure, CPLE_AppDefined,
    3762               0 :                      "Invalid length for CTM");
    3763               0 :             return FALSE;
    3764                 :         }
    3765                 : 
    3766              19 :         bHasCTM = TRUE;
    3767             133 :         for(i=0;i<nLength;i++)
    3768                 :         {
    3769             114 :             adfCTM[i] = Get(poCTM, i);
    3770                 :             /* Nullify rotation terms that are significantly smaller than */
    3771                 :             /* scaling termes */
    3772             114 :             if ((i == 1 || i == 2) && fabs(adfCTM[i]) < fabs(adfCTM[0]) * 1e-10)
    3773              38 :                 adfCTM[i] = 0;
    3774             114 :             CPLDebug("PDF", "CTM[%d] = %.16g", i, adfCTM[i]);
    3775                 :         }
    3776                 :     }
    3777                 : 
    3778                 : /* -------------------------------------------------------------------- */
    3779                 : /*      Extract Registration attribute                                  */
    3780                 : /* -------------------------------------------------------------------- */
    3781                 :     GDALPDFObject* poRegistration;
    3782              26 :     if ((poRegistration = poLGIDict->Get("Registration")) != NULL &&
    3783               4 :         poRegistration->GetType() == PDFObjectType_Array)
    3784                 :     {
    3785               4 :         GDALPDFArray* poRegistrationArray = poRegistration->GetArray();
    3786               4 :         int nLength = poRegistrationArray->GetLength();
    3787               4 :         if (nLength > 4 || (!bHasCTM && nLength >= 2) )
    3788                 :         {
    3789               3 :             nGCPCount = 0;
    3790               3 :             pasGCPList = (GDAL_GCP *) CPLCalloc(sizeof(GDAL_GCP),nLength);
    3791                 : 
    3792              18 :             for(i=0;i<nLength;i++)
    3793                 :             {
    3794              15 :                 GDALPDFObject* poGCP = poRegistrationArray->Get(i);
    3795              60 :                 if ( poGCP != NULL &&
    3796              15 :                     poGCP->GetType() == PDFObjectType_Array &&
    3797              30 :                     poGCP->GetArray()->GetLength() == 4 )
    3798                 :                 {
    3799              15 :                     double dfUserX = Get(poGCP, 0);
    3800              15 :                     double dfUserY = Get(poGCP, 1);
    3801              15 :                     double dfX = Get(poGCP, 2);
    3802              15 :                     double dfY = Get(poGCP, 3);
    3803              15 :                     CPLDebug("PDF", "GCP[%d].userX = %.16g", i, dfUserX);
    3804              15 :                     CPLDebug("PDF", "GCP[%d].userY = %.16g", i, dfUserY);
    3805              15 :                     CPLDebug("PDF", "GCP[%d].x = %.16g", i, dfX);
    3806              15 :                     CPLDebug("PDF", "GCP[%d].y = %.16g", i, dfY);
    3807                 : 
    3808                 :                     char    szID[32];
    3809              15 :                     sprintf( szID, "%d", nGCPCount+1 );
    3810              15 :                     pasGCPList[nGCPCount].pszId = CPLStrdup( szID );
    3811              15 :                     pasGCPList[nGCPCount].pszInfo = CPLStrdup("");
    3812              15 :                     pasGCPList[nGCPCount].dfGCPPixel = dfUserX;
    3813              15 :                     pasGCPList[nGCPCount].dfGCPLine = dfUserY;
    3814              15 :                     pasGCPList[nGCPCount].dfGCPX = dfX;
    3815              15 :                     pasGCPList[nGCPCount].dfGCPY = dfY;
    3816              15 :                     nGCPCount ++;
    3817                 :                 }
    3818                 :             }
    3819                 :         }
    3820                 :     }
    3821                 : 
    3822              22 :     if (!bHasCTM && nGCPCount == 0)
    3823                 :     {
    3824               0 :         CPLDebug("PDF", "Neither CTM nor Registration found");
    3825               0 :         return FALSE;
    3826                 :     }
    3827                 : 
    3828                 : /* -------------------------------------------------------------------- */
    3829                 : /*      Extract Projection attribute                                    */
    3830                 : /* -------------------------------------------------------------------- */
    3831                 :     GDALPDFObject* poProjection;
    3832              44 :     if ((poProjection = poLGIDict->Get("Projection")) == NULL ||
    3833              22 :         poProjection->GetType() != PDFObjectType_Dictionary)
    3834                 :     {
    3835               0 :         CPLError(CE_Failure, CPLE_AppDefined, "Could not find Projection");
    3836               0 :         return FALSE;
    3837                 :     }
    3838                 : 
    3839              22 :     return ParseProjDict(poProjection->GetDictionary());
    3840                 : }
    3841                 : 
    3842                 : /************************************************************************/
    3843                 : /*                         ParseProjDict()                               */
    3844                 : /************************************************************************/
    3845                 : 
    3846              22 : int PDFDataset::ParseProjDict(GDALPDFDictionary* poProjDict)
    3847                 : {
    3848              22 :     if (poProjDict == NULL)
    3849               0 :         return FALSE;
    3850              22 :     OGRSpatialReference oSRS;
    3851                 : 
    3852                 : /* -------------------------------------------------------------------- */
    3853                 : /*      Extract WKT attribute (GDAL extension)                          */
    3854                 : /* -------------------------------------------------------------------- */
    3855                 :     GDALPDFObject* poWKT;
    3856              30 :     if ( (poWKT = poProjDict->Get("WKT")) != NULL &&
    3857               8 :          poWKT->GetType() == PDFObjectType_String &&
    3858                 :          CSLTestBoolean( CPLGetConfigOption("GDAL_PDF_OGC_BP_READ_WKT", "TRUE") ) )
    3859                 :     {
    3860               8 :         CPLDebug("PDF", "Found WKT attribute (GDAL extension). Using it");
    3861               8 :         const char* pszWKTRead = poWKT->GetString().c_str();
    3862               8 :         CPLFree(pszWKT);
    3863               8 :         pszWKT = CPLStrdup(pszWKTRead);
    3864               8 :         return TRUE;
    3865                 :     }
    3866                 : 
    3867                 : /* -------------------------------------------------------------------- */
    3868                 : /*      Extract Type attribute                                          */
    3869                 : /* -------------------------------------------------------------------- */
    3870                 :     GDALPDFObject* poType;
    3871              14 :     if ((poType = poProjDict->Get("Type")) == NULL)
    3872                 :     {
    3873                 :         CPLError(CE_Failure, CPLE_AppDefined,
    3874               0 :                  "Cannot find Type of Projection object");
    3875               0 :         return FALSE;
    3876                 :     }
    3877                 : 
    3878              14 :     if ( poType->GetType() != PDFObjectType_Name )
    3879                 :     {
    3880                 :         CPLError(CE_Failure, CPLE_AppDefined,
    3881               0 :                  "Invalid type for Type of Projection object");
    3882               0 :         return FALSE;
    3883                 :     }
    3884                 : 
    3885              14 :     if ( strcmp(poType->GetName().c_str(), "Projection") != 0 )
    3886                 :     {
    3887                 :         CPLError(CE_Failure, CPLE_AppDefined,
    3888                 :                  "Invalid value for Type of Projection object : %s",
    3889               0 :                  poType->GetName().c_str());
    3890               0 :         return FALSE;
    3891                 :     }
    3892                 : 
    3893                 : /* -------------------------------------------------------------------- */
    3894                 : /*      Extract Datum attribute                                         */
    3895                 : /* -------------------------------------------------------------------- */
    3896              14 :     int bIsWGS84 = FALSE;
    3897              14 :     int bIsNAD83 = FALSE;
    3898              14 :     int bIsNAD27 = FALSE;
    3899                 : 
    3900                 :     GDALPDFObject* poDatum;
    3901              14 :     if ((poDatum = poProjDict->Get("Datum")) != NULL)
    3902                 :     {
    3903              14 :         if (poDatum->GetType() == PDFObjectType_String)
    3904                 :         {
    3905              14 :             const char* pszDatum = poDatum->GetString().c_str();
    3906              14 :             CPLDebug("PDF", "Datum = %s", pszDatum);
    3907              18 :             if (EQUAL(pszDatum, "WE") || EQUAL(pszDatum, "WGE"))
    3908                 :             {
    3909               4 :                 bIsWGS84 = TRUE;
    3910               4 :                 oSRS.SetWellKnownGeogCS("WGS84");
    3911                 :             }
    3912              10 :             else if (EQUAL(pszDatum, "NAR") || EQUALN(pszDatum, "NAR-", 4))
    3913                 :             {
    3914               0 :                 bIsNAD83 = TRUE;
    3915               0 :                 oSRS.SetWellKnownGeogCS("NAD83");
    3916                 :             }
    3917              19 :             else if (EQUAL(pszDatum, "NAS") || EQUALN(pszDatum, "NAS-", 4))
    3918                 :             {
    3919               9 :                 bIsNAD27 = TRUE;
    3920               9 :                 oSRS.SetWellKnownGeogCS("NAD27");
    3921                 :             }
    3922               1 :             else if (EQUAL(pszDatum, "HEN")) /* HERAT North, Afghanistan */
    3923                 :             {
    3924                 :                 oSRS.SetGeogCS( "unknown" /*const char * pszGeogName*/,
    3925                 :                                 "unknown" /*const char * pszDatumName */,
    3926                 :                                 "International 1924",
    3927               1 :                                 6378388,297);
    3928               1 :                 oSRS.SetTOWGS84(-333,-222,114);
    3929                 :             }
    3930               0 :             else if (EQUAL(pszDatum, "ING-A")) /* INDIAN 1960, Vietnam 16N */
    3931                 :             {
    3932               0 :                 oSRS.importFromEPSG(4131);
    3933                 :             }
    3934               0 :             else if (EQUAL(pszDatum, "GDS")) /* Geocentric Datum of Australia */
    3935                 :             {
    3936               0 :                 oSRS.importFromEPSG(4283);
    3937                 :             }
    3938                 :             else
    3939                 :             {
    3940                 :                 CPLError(CE_Warning, CPLE_AppDefined,
    3941                 :                         "Unhandled (yet) value for Datum : %s. Defaulting to WGS84...",
    3942               0 :                         pszDatum);
    3943                 :                 oSRS.SetGeogCS( "unknown" /*const char * pszGeogName*/,
    3944                 :                                 "unknown" /*const char * pszDatumName */,
    3945                 :                                 "unknown",
    3946               0 :                                 6378137,298.257223563);
    3947                 :             }
    3948                 :         }
    3949               0 :         else if (poDatum->GetType() == PDFObjectType_Dictionary)
    3950                 :         {
    3951               0 :             GDALPDFDictionary* poDatumDict = poDatum->GetDictionary();
    3952                 : 
    3953               0 :             GDALPDFObject* poDatumDescription = poDatumDict->Get("Description");
    3954               0 :             const char* pszDatumDescription = "unknown";
    3955               0 :             if (poDatumDescription != NULL &&
    3956               0 :                 poDatumDescription->GetType() == PDFObjectType_String)
    3957               0 :                 pszDatumDescription  = poDatumDescription->GetString().c_str();
    3958               0 :             CPLDebug("PDF", "Datum.Description = %s", pszDatumDescription);
    3959                 :                 
    3960               0 :             GDALPDFObject* poEllipsoid = poDatumDict->Get("Ellipsoid");
    3961               0 :             if (poEllipsoid == NULL ||
    3962               0 :                 !(poEllipsoid->GetType() == PDFObjectType_String ||
    3963               0 :                   poEllipsoid->GetType() == PDFObjectType_Dictionary))
    3964                 :             {
    3965                 :                 CPLError(CE_Warning, CPLE_AppDefined,
    3966               0 :                          "Cannot find Ellipsoid in Datum. Defaulting to WGS84...");
    3967                 :                 oSRS.SetGeogCS( "unknown",
    3968                 :                                 pszDatumDescription,
    3969                 :                                 "unknown",
    3970               0 :                                 6378137,298.257223563);
    3971                 :             }
    3972               0 :             else if (poEllipsoid->GetType() == PDFObjectType_String)
    3973                 :             {
    3974               0 :                 const char* pszEllipsoid = poEllipsoid->GetString().c_str();
    3975               0 :                 CPLDebug("PDF", "Datum.Ellipsoid = %s", pszEllipsoid);
    3976               0 :                 if( EQUAL(pszEllipsoid, "WE") )
    3977                 :                 {
    3978                 :                     oSRS.SetGeogCS( "unknown",
    3979                 :                                     pszDatumDescription,
    3980                 :                                     "WGS 84",
    3981               0 :                                     6378137,298.257223563);
    3982                 :                 }
    3983                 :                 else
    3984                 :                 {
    3985                 :                     CPLError(CE_Warning, CPLE_AppDefined,
    3986                 :                             "Unhandled (yet) value for Ellipsoid : %s. Defaulting to WGS84...",
    3987               0 :                             pszEllipsoid);
    3988                 :                     oSRS.SetGeogCS( "unknown",
    3989                 :                                     pszDatumDescription,
    3990                 :                                     pszEllipsoid,
    3991               0 :                                     6378137,298.257223563);
    3992                 :                 }
    3993                 :             }
    3994                 :             else// if (poEllipsoid->GetType() == PDFObjectType_Dictionary)
    3995                 :             {
    3996               0 :                 GDALPDFDictionary* poEllipsoidDict = poEllipsoid->GetDictionary();
    3997                 : 
    3998               0 :                 GDALPDFObject* poEllipsoidDescription = poEllipsoidDict->Get("Description");
    3999               0 :                 const char* pszEllipsoidDescription = "unknown";
    4000               0 :                 if (poEllipsoidDescription != NULL &&
    4001               0 :                     poEllipsoidDescription->GetType() == PDFObjectType_String)
    4002               0 :                     pszEllipsoidDescription = poEllipsoidDescription->GetString().c_str();
    4003               0 :                 CPLDebug("PDF", "Datum.Ellipsoid.Description = %s", pszEllipsoidDescription);
    4004                 :                     
    4005               0 :                 double dfSemiMajor = Get(poEllipsoidDict, "SemiMajorAxis");
    4006               0 :                 CPLDebug("PDF", "Datum.Ellipsoid.SemiMajorAxis = %.16g", dfSemiMajor);
    4007               0 :                 double dfInvFlattening = -1.0;
    4008                 :                 
    4009               0 :                 if( poEllipsoidDict->Get("InvFlattening") )
    4010                 :                 {
    4011               0 :                     dfInvFlattening = Get(poEllipsoidDict, "InvFlattening");
    4012               0 :                     CPLDebug("PDF", "Datum.Ellipsoid.InvFlattening = %.16g", dfInvFlattening);
    4013                 :                 }
    4014               0 :                 else if( poEllipsoidDict->Get("SemiMinorAxis") )
    4015                 :                 {
    4016               0 :                     double dfSemiMinor = Get(poEllipsoidDict, "SemiMinorAxis");
    4017               0 :                     CPLDebug("PDF", "Datum.Ellipsoid.SemiMinorAxis = %.16g", dfSemiMinor);
    4018               0 :                     if( ABS(dfSemiMajor/dfSemiMinor) - 1.0 < 0.0000000000001 )
    4019               0 :                         dfInvFlattening = 0.0;
    4020                 :                     else
    4021               0 :                         dfInvFlattening = -1.0 / (dfSemiMinor/dfSemiMajor - 1.0);
    4022                 :                 }
    4023                 :                 
    4024               0 :                 if( dfSemiMajor != 0.0 && dfInvFlattening != -1.0 )
    4025                 :                 {
    4026                 :                     oSRS.SetGeogCS( "unknown",
    4027                 :                                     pszDatumDescription,
    4028                 :                                     pszEllipsoidDescription,
    4029               0 :                                     dfSemiMajor, dfInvFlattening);
    4030                 :                 }
    4031                 :                 else
    4032                 :                 {
    4033                 :                     CPLError(CE_Warning, CPLE_AppDefined,
    4034               0 :                              "Invalid Ellipsoid object. Defaulting to WGS84...");
    4035                 :                     oSRS.SetGeogCS( "unknown",
    4036                 :                                     pszDatumDescription,
    4037                 :                                     pszEllipsoidDescription,
    4038               0 :                                     6378137,298.257223563);
    4039                 :                 }
    4040                 :                 
    4041                 :                 
    4042                 :             }
    4043                 :             
    4044               0 :             GDALPDFObject* poTOWGS84 = poDatumDict->Get("ToWGS84");
    4045               0 :             if( poTOWGS84 != NULL && poTOWGS84->GetType() == PDFObjectType_Dictionary )
    4046                 :             {
    4047               0 :                 GDALPDFDictionary* poTOWGS84Dict = poTOWGS84->GetDictionary();
    4048               0 :                 double dx = Get(poTOWGS84Dict, "dx");
    4049               0 :                 double dy = Get(poTOWGS84Dict, "dy");
    4050               0 :                 double dz = Get(poTOWGS84Dict, "dz");
    4051               0 :                 if (poTOWGS84Dict->Get("rx") && poTOWGS84Dict->Get("ry") &&
    4052               0 :                     poTOWGS84Dict->Get("rz") && poTOWGS84Dict->Get("sf"))
    4053                 :                 {
    4054               0 :                     double rx = Get(poTOWGS84Dict, "rx");
    4055               0 :                     double ry = Get(poTOWGS84Dict, "ry");
    4056               0 :                     double rz = Get(poTOWGS84Dict, "rz");
    4057               0 :                     double sf = Get(poTOWGS84Dict, "sf");
    4058               0 :                     oSRS.SetTOWGS84(dx, dy, dz, rx, ry, rz, sf);
    4059                 :                 }
    4060                 :                 else
    4061                 :                 {
    4062               0 :                     oSRS.SetTOWGS84(dx, dy, dz);
    4063                 :                 }
    4064                 :             }
    4065                 :         }
    4066                 :     }
    4067                 : 
    4068                 : /* -------------------------------------------------------------------- */
    4069                 : /*      Extract Hemisphere attribute                                    */
    4070                 : /* -------------------------------------------------------------------- */
    4071              14 :     CPLString osHemisphere;
    4072                 :     GDALPDFObject* poHemisphere;
    4073              23 :     if ((poHemisphere = poProjDict->Get("Hemisphere")) != NULL &&
    4074               9 :         poHemisphere->GetType() == PDFObjectType_String)
    4075                 :     {
    4076               9 :         osHemisphere = poHemisphere->GetString();
    4077                 :     }
    4078                 : 
    4079                 : /* -------------------------------------------------------------------- */
    4080                 : /*      Extract ProjectionType attribute                                */
    4081                 : /* -------------------------------------------------------------------- */
    4082                 :     GDALPDFObject* poProjectionType;
    4083              28 :     if ((poProjectionType = poProjDict->Get("ProjectionType")) == NULL ||
    4084              14 :         poProjectionType->GetType() != PDFObjectType_String)
    4085                 :     {
    4086                 :         CPLError(CE_Failure, CPLE_AppDefined,
    4087               0 :                  "Cannot find ProjectionType of Projection object");
    4088               0 :         return FALSE;
    4089                 :     }
    4090              14 :     CPLString osProjectionType(poProjectionType->GetString());
    4091              14 :     CPLDebug("PDF", "Projection.ProjectionType = %s", osProjectionType.c_str());
    4092                 : 
    4093                 :     /* Unhandled: NONE, GEODETIC */
    4094                 : 
    4095              14 :     if (EQUAL(osProjectionType, "GEOGRAPHIC"))
    4096                 :     {
    4097                 :         /* Nothing to do */
    4098                 :     }
    4099                 : 
    4100                 :     /* Unhandled: LOCAL CARTESIAN, MG (MGRS) */
    4101                 : 
    4102              10 :     else if (EQUAL(osProjectionType, "UT")) /* UTM */
    4103                 :     {
    4104               9 :         int nZone = (int)Get(poProjDict, "Zone");
    4105               9 :         int bNorth = EQUAL(osHemisphere, "N");
    4106               9 :         if (bIsWGS84)
    4107               0 :             oSRS.importFromEPSG( ((bNorth) ? 32600 : 32700) + nZone );
    4108                 :         else
    4109               9 :             oSRS.SetUTM( nZone, bNorth );
    4110                 :     }
    4111                 : 
    4112               1 :     else if (EQUAL(osProjectionType, "UP")) /* Universal Polar Stereographic (UPS) */
    4113                 :     {
    4114               0 :         int bNorth = EQUAL(osHemisphere, "N");
    4115               0 :         if (bIsWGS84)
    4116               0 :             oSRS.importFromEPSG( (bNorth) ? 32661 : 32761 );
    4117                 :         else
    4118                 :             oSRS.SetPS( (bNorth) ? 90 : -90, 0,
    4119               0 :                         0.994, 200000, 200000 );
    4120                 :     }
    4121                 : 
    4122               1 :     else if (EQUAL(osProjectionType, "SPCS")) /* State Plane */
    4123                 :     {
    4124               0 :         int nZone = (int)Get(poProjDict, "Zone");
    4125               0 :         oSRS.SetStatePlane( nZone, bIsNAD83 );
    4126                 :     }
    4127                 : 
    4128               1 :     else if (EQUAL(osProjectionType, "AC")) /* Albers Equal Area Conic */
    4129                 :     {
    4130               0 :         double dfStdP1 = Get(poProjDict, "StandardParallelOne");
    4131               0 :         double dfStdP2 = Get(poProjDict, "StandardParallelTwo");
    4132               0 :         double dfCenterLat = Get(poProjDict, "OriginLatitude");
    4133               0 :         double dfCenterLong = Get(poProjDict, "CentralMeridian");
    4134               0 :         double dfFalseEasting = Get(poProjDict, "FalseEasting");
    4135               0 :         double dfFalseNorthing = Get(poProjDict, "FalseNorthing");
    4136                 :         oSRS.SetACEA( dfStdP1, dfStdP2,
    4137                 :                      dfCenterLat, dfCenterLong,
    4138               0 :                      dfFalseEasting, dfFalseNorthing );
    4139                 :     }
    4140                 :  
    4141               1 :     else if (EQUAL(osProjectionType, "AL")) /* Azimuthal Equidistant */
    4142                 :     {
    4143               0 :         double dfCenterLat = Get(poProjDict, "OriginLatitude");
    4144               0 :         double dfCenterLong = Get(poProjDict, "CentralMeridian");
    4145               0 :         double dfFalseEasting = Get(poProjDict, "FalseEasting");
    4146               0 :         double dfFalseNorthing = Get(poProjDict, "FalseNorthing");
    4147                 :         oSRS.SetAE(  dfCenterLat, dfCenterLong,
    4148               0 :                      dfFalseEasting, dfFalseNorthing );
    4149                 :     }
    4150                 : 
    4151               1 :     else if (EQUAL(osProjectionType, "BF")) /* Bonne */
    4152                 :     {
    4153               0 :         double dfStdP1 = Get(poProjDict, "OriginLatitude");
    4154               0 :         double dfCentralMeridian = Get(poProjDict, "CentralMeridian");
    4155               0 :         double dfFalseEasting = Get(poProjDict, "FalseEasting");
    4156               0 :         double dfFalseNorthing = Get(poProjDict, "FalseNorthing");
    4157                 :         oSRS.SetBonne( dfStdP1, dfCentralMeridian,
    4158               0 :                        dfFalseEasting, dfFalseNorthing );
    4159                 :     }
    4160                 : 
    4161               1 :     else if (EQUAL(osProjectionType, "CS")) /* Cassini */
    4162                 :     {
    4163               0 :         double dfCenterLat = Get(poProjDict, "OriginLatitude");
    4164               0 :         double dfCenterLong = Get(poProjDict, "CentralMeridian");
    4165               0 :         double dfFalseEasting = Get(poProjDict, "FalseEasting");
    4166               0 :         double dfFalseNorthing = Get(poProjDict, "FalseNorthing");
    4167                 :         oSRS.SetCS(  dfCenterLat, dfCenterLong,
    4168               0 :                      dfFalseEasting, dfFalseNorthing );
    4169                 :     }
    4170                 : 
    4171               1 :     else if (EQUAL(osProjectionType, "LI")) /* Cylindrical Equal Area */
    4172                 :     {
    4173               0 :         double dfStdP1 = Get(poProjDict, "OriginLatitude");
    4174               0 :         double dfCentralMeridian = Get(poProjDict, "CentralMeridian");
    4175               0 :         double dfFalseEasting = Get(poProjDict, "FalseEasting");
    4176               0 :         double dfFalseNorthing = Get(poProjDict, "FalseNorthing");
    4177                 :         oSRS.SetCEA( dfStdP1, dfCentralMeridian,
    4178               0 :                      dfFalseEasting, dfFalseNorthing );
    4179                 :     }
    4180                 : 
    4181               1 :     else if (EQUAL(osProjectionType, "EF")) /* Eckert IV */
    4182                 :     {
    4183               0 :         double dfCentralMeridian = Get(poProjDict, "CentralMeridian");
    4184               0 :         double dfFalseEasting = Get(poProjDict, "FalseEasting");
    4185               0 :         double dfFalseNorthing = Get(poProjDict, "FalseNorthing");
    4186                 :         oSRS.SetEckertIV( dfCentralMeridian,
    4187               0 :                           dfFalseEasting, dfFalseNorthing );
    4188                 :     }
    4189                 : 
    4190               1 :     else if (EQUAL(osProjectionType, "ED")) /* Eckert VI */
    4191                 :     {
    4192               0 :         double dfCentralMeridian = Get(poProjDict, "CentralMeridian");
    4193               0 :         double dfFalseEasting = Get(poProjDict, "FalseEasting");
    4194               0 :         double dfFalseNorthing = Get(poProjDict, "FalseNorthing");
    4195                 :         oSRS.SetEckertVI( dfCentralMeridian,
    4196               0 :                           dfFalseEasting, dfFalseNorthing );
    4197                 :     }
    4198                 : 
    4199               1 :     else if (EQUAL(osProjectionType, "CP")) /* Equidistant Cylindrical */
    4200                 :     {
    4201               0 :         double dfCenterLat = Get(poProjDict, "StandardParallel");
    4202               0 :         double dfCenterLong = Get(poProjDict, "CentralMeridian");
    4203               0 :         double dfFalseEasting = Get(poProjDict, "FalseEasting");
    4204               0 :         double dfFalseNorthing = Get(poProjDict, "FalseNorthing");
    4205                 :         oSRS.SetEquirectangular( dfCenterLat, dfCenterLong,
    4206               0 :                                  dfFalseEasting, dfFalseNorthing );
    4207                 :     }
    4208                 : 
    4209               1 :     else if (EQUAL(osProjectionType, "GN")) /* Gnomonic */
    4210                 :     {
    4211               0 :         double dfCenterLat = Get(poProjDict, "OriginLatitude");
    4212               0 :         double dfCenterLong = Get(poProjDict, "CentralMeridian");
    4213               0 :         double dfFalseEasting = Get(poProjDict, "FalseEasting");
    4214               0 :         double dfFalseNorthing = Get(poProjDict, "FalseNorthing");
    4215                 :         oSRS.SetGnomonic(dfCenterLat, dfCenterLong,
    4216               0 :                          dfFalseEasting, dfFalseNorthing );
    4217                 :     }
    4218                 : 
    4219               1 :     else if (EQUAL(osProjectionType, "LE")) /* Lambert Conformal Conic */
    4220                 :     {
    4221               0 :         double dfStdP1 = Get(poProjDict, "StandardParallelOne");
    4222               0 :         double dfStdP2 = Get(poProjDict, "StandardParallelTwo");
    4223               0 :         double dfCenterLat = Get(poProjDict, "OriginLatitude");
    4224               0 :         double dfCenterLong = Get(poProjDict, "CentralMeridian");
    4225               0 :         double dfFalseEasting = Get(poProjDict, "FalseEasting");
    4226               0 :         double dfFalseNorthing = Get(poProjDict, "FalseNorthing");
    4227                 :         oSRS.SetLCC( dfStdP1, dfStdP2,
    4228                 :                      dfCenterLat, dfCenterLong,
    4229               0 :                      dfFalseEasting, dfFalseNorthing );
    4230                 :     }
    4231                 : 
    4232               1 :     else if (EQUAL(osProjectionType, "MC")) /* Mercator */
    4233                 :     {
    4234                 : #ifdef not_supported
    4235                 :         if (poProjDict->Get("StandardParallelOne") == NULL)
    4236                 :         {
    4237                 : #endif
    4238               0 :         double dfCenterLat = Get(poProjDict, "OriginLatitude");
    4239               0 :         double dfCenterLong = Get(poProjDict, "CentralMeridian");
    4240               0 :         double dfScale = Get(poProjDict, "ScaleFactor");
    4241               0 :         double dfFalseEasting = Get(poProjDict, "FalseEasting");
    4242               0 :         double dfFalseNorthing = Get(poProjDict, "FalseNorthing");
    4243                 :         oSRS.SetMercator( dfCenterLat, dfCenterLong,
    4244                 :                           dfScale,
    4245               0 :                           dfFalseEasting, dfFalseNorthing );
    4246                 : #ifdef not_supported
    4247                 :         }
    4248                 :         else
    4249                 :         {
    4250                 :             double dfStdP1 = Get(poProjDict, "StandardParallelOne");
    4251                 :             double dfCenterLat = poProjDict->Get("OriginLatitude") ? Get(poProjDict, "OriginLatitude") : 0;
    4252                 :             double dfCenterLong = Get(poProjDict, "CentralMeridian");
    4253                 :             double dfFalseEasting = Get(poProjDict, "FalseEasting");
    4254                 :             double dfFalseNorthing = Get(poProjDict, "FalseNorthing");
    4255                 :             oSRS.SetMercator2SP( dfStdP1,
    4256                 :                                  dfCenterLat, dfCenterLong,
    4257                 :                                  dfFalseEasting, dfFalseNorthing );
    4258                 :         }
    4259                 : #endif
    4260                 :     }
    4261                 : 
    4262               1 :     else if (EQUAL(osProjectionType, "MH")) /* Miller Cylindrical */
    4263                 :     {
    4264               0 :         double dfCenterLat = 0 /* ? */;
    4265               0 :         double dfCenterLong = Get(poProjDict, "CentralMeridian");
    4266               0 :         double dfFalseEasting = Get(poProjDict, "FalseEasting");
    4267               0 :         double dfFalseNorthing = Get(poProjDict, "FalseNorthing");
    4268                 :         oSRS.SetMC( dfCenterLat, dfCenterLong,
    4269               0 :                     dfFalseEasting, dfFalseNorthing );
    4270                 :     }
    4271                 : 
    4272               1 :     else if (EQUAL(osProjectionType, "MP")) /* Mollweide */
    4273                 :     {
    4274               0 :         double dfCentralMeridian = Get(poProjDict, "CentralMeridian");
    4275               0 :         double dfFalseEasting = Get(poProjDict, "FalseEasting");
    4276               0 :         double dfFalseNorthing = Get(poProjDict, "FalseNorthing");
    4277                 :         oSRS.SetMollweide( dfCentralMeridian,
    4278               0 :                            dfFalseEasting, dfFalseNorthing );
    4279                 :     }
    4280                 : 
    4281                 :     /* Unhandled:  "NY" : Ney's (Modified Lambert Conformal Conic) */
    4282                 : 
    4283               1 :     else if (EQUAL(osProjectionType, "NT")) /* New Zealand Map Grid */
    4284                 :     {
    4285                 :         /* No parameter specified in the PDF, so let's take the ones of EPSG:27200 */
    4286               0 :         double dfCenterLat = -41;
    4287               0 :         double dfCenterLong = 173;
    4288               0 :         double dfFalseEasting = 2510000;
    4289               0 :         double dfFalseNorthing = 6023150;
    4290                 :         oSRS.SetNZMG( dfCenterLat, dfCenterLong,
    4291               0 :                       dfFalseEasting, dfFalseNorthing );
    4292                 :     }
    4293                 : 
    4294               1 :     else if (EQUAL(osProjectionType, "OC")) /* Oblique Mercator */
    4295                 :     {
    4296               0 :         double dfCenterLat = Get(poProjDict, "OriginLatitude");
    4297               0 :         double dfLat1 = Get(poProjDict, "LatitudeOne");
    4298               0 :         double dfLong1 = Get(poProjDict, "LongitudeOne");
    4299               0 :         double dfLat2 = Get(poProjDict, "LatitudeTwo");
    4300               0 :         double dfLong2 = Get(poProjDict, "LongitudeTwo");
    4301               0 :         double dfScale = Get(poProjDict, "ScaleFactor");
    4302               0 :         double dfFalseEasting = Get(poProjDict, "FalseEasting");
    4303               0 :         double dfFalseNorthing = Get(poProjDict, "FalseNorthing");
    4304                 :         oSRS.SetHOM2PNO( dfCenterLat,
    4305                 :                          dfLat1, dfLong1,
    4306                 :                          dfLat2, dfLong2,
    4307                 :                          dfScale,
    4308                 :                          dfFalseEasting,
    4309               0 :                          dfFalseNorthing );
    4310                 :     }
    4311                 : 
    4312               1 :     else if (EQUAL(osProjectionType, "OD")) /* Orthographic */
    4313                 :     {
    4314               0 :         double dfCenterLat = Get(poProjDict, "OriginLatitude");
    4315               0 :         double dfCenterLong = Get(poProjDict, "CentralMeridian");
    4316               0 :         double dfFalseEasting = Get(poProjDict, "FalseEasting");
    4317               0 :         double dfFalseNorthing = Get(poProjDict, "FalseNorthing");
    4318                 :         oSRS.SetOrthographic( dfCenterLat, dfCenterLong,
    4319               0 :                            dfFalseEasting, dfFalseNorthing );
    4320                 :     }
    4321                 : 
    4322               1 :     else if (EQUAL(osProjectionType, "PG")) /* Polar Stereographic */
    4323                 :     {
    4324               0 :         double dfCenterLat = Get(poProjDict, "LatitudeTrueScale");
    4325               0 :         double dfCenterLong = Get(poProjDict, "LongitudeDownFromPole");
    4326               0 :         double dfScale = 1.0;
    4327               0 :         double dfFalseEasting = Get(poProjDict, "FalseEasting");
    4328               0 :         double dfFalseNorthing = Get(poProjDict, "FalseNorthing");
    4329                 :         oSRS.SetPS( dfCenterLat, dfCenterLong,
    4330                 :                     dfScale,
    4331               0 :                     dfFalseEasting, dfFalseNorthing);
    4332                 :     }
    4333                 : 
    4334               1 :     else if (EQUAL(osProjectionType, "PH")) /* Polyconic */
    4335                 :     {
    4336               0 :         double dfCenterLat = Get(poProjDict, "OriginLatitude");
    4337               0 :         double dfCenterLong = Get(poProjDict, "CentralMeridian");
    4338               0 :         double dfFalseEasting = Get(poProjDict, "FalseEasting");
    4339               0 :         double dfFalseNorthing = Get(poProjDict, "FalseNorthing");
    4340                 :         oSRS.SetPolyconic( dfCenterLat, dfCenterLong,
    4341               0 :                            dfFalseEasting, dfFalseNorthing );
    4342                 :     }
    4343                 : 
    4344               1 :     else if (EQUAL(osProjectionType, "SA")) /* Sinusoidal */
    4345                 :     {
    4346               0 :         double dfCenterLong = Get(poProjDict, "CentralMeridian");
    4347               0 :         double dfFalseEasting = Get(poProjDict, "FalseEasting");
    4348               0 :         double dfFalseNorthing = Get(poProjDict, "FalseNorthing");
    4349                 :         oSRS.SetSinusoidal( dfCenterLong,
    4350               0 :                            dfFalseEasting, dfFalseNorthing );
    4351                 :     }
    4352                 : 
    4353               1 :     else if (EQUAL(osProjectionType, "SD")) /* Stereographic */
    4354                 :     {
    4355               0 :         double dfCenterLat = Get(poProjDict, "OriginLatitude");
    4356               0 :         double dfCenterLong = Get(poProjDict, "CentralMeridian");
    4357               0 :         double dfScale = 1.0;
    4358               0 :         double dfFalseEasting = Get(poProjDict, "FalseEasting");
    4359               0 :         double dfFalseNorthing = Get(poProjDict, "FalseNorthing");
    4360                 :         oSRS.SetStereographic( dfCenterLat, dfCenterLong,
    4361                 :                                dfScale,
    4362               0 :                                dfFalseEasting, dfFalseNorthing);
    4363                 :     }
    4364                 : 
    4365               1 :     else if (EQUAL(osProjectionType, "TC")) /* Transverse Mercator */
    4366                 :     {
    4367               1 :         double dfCenterLat = Get(poProjDict, "OriginLatitude");
    4368               1 :         double dfCenterLong = Get(poProjDict, "CentralMeridian");
    4369               1 :         double dfScale = Get(poProjDict, "ScaleFactor");
    4370               1 :         double dfFalseEasting = Get(poProjDict, "FalseEasting");
    4371               1 :         double dfFalseNorthing = Get(poProjDict, "FalseNorthing");
    4372               2 :         if (dfCenterLat == 0.0 && dfScale == 0.9996 && dfFalseEasting == 500000 &&
    4373                 :             (dfFalseNorthing == 0.0 || dfFalseNorthing == 10000000.0))
    4374                 :         {
    4375               1 :             int nZone = (int) floor( (dfCenterLong + 180.0) / 6.0 ) + 1;
    4376               1 :             int bNorth = dfFalseNorthing == 0;
    4377               1 :             if (bIsWGS84)
    4378               0 :                 oSRS.importFromEPSG( ((bNorth) ? 32600 : 32700) + nZone );
    4379               1 :             else if (bIsNAD83 && bNorth)
    4380               0 :                 oSRS.importFromEPSG( 26900 + nZone );
    4381                 :             else
    4382               1 :                 oSRS.SetUTM( nZone, bNorth );
    4383                 :         }
    4384                 :         else
    4385                 :         {
    4386                 :             oSRS.SetTM( dfCenterLat, dfCenterLong,
    4387                 :                         dfScale,
    4388               0 :                         dfFalseEasting, dfFalseNorthing );
    4389                 :         }
    4390                 :     }
    4391                 : 
    4392                 :     /* Unhandled TX : Transverse Cylindrical Equal Area */
    4393                 : 
    4394               0 :     else if (EQUAL(osProjectionType, "VA")) /* Van der Grinten */
    4395                 :     {
    4396               0 :         double dfCenterLong = Get(poProjDict, "CentralMeridian");
    4397               0 :         double dfFalseEasting = Get(poProjDict, "FalseEasting");
    4398               0 :         double dfFalseNorthing = Get(poProjDict, "FalseNorthing");
    4399                 :         oSRS.SetVDG( dfCenterLong,
    4400               0 :                      dfFalseEasting, dfFalseNorthing );
    4401                 :     }
    4402                 : 
    4403                 :     else
    4404                 :     {
    4405                 :         CPLError(CE_Failure, CPLE_AppDefined,
    4406                 :                  "Unhandled (yet) value for ProjectionType : %s",
    4407               0 :                  osProjectionType.c_str());
    4408               0 :         return FALSE;
    4409                 :     }
    4410                 : 
    4411                 : /* -------------------------------------------------------------------- */
    4412                 : /*      Extract Units attribute                                         */
    4413                 : /* -------------------------------------------------------------------- */
    4414              14 :     CPLString osUnits;
    4415                 :     GDALPDFObject* poUnits;
    4416              23 :     if ((poUnits = poProjDict->Get("Units")) != NULL &&
    4417               9 :         poUnits->GetType() == PDFObjectType_String)
    4418                 :     {
    4419               9 :         osUnits = poUnits->GetString();
    4420               9 :         CPLDebug("PDF", "Projection.Units = %s", osUnits.c_str());
    4421                 : 
    4422               9 :         if (EQUAL(osUnits, "M"))
    4423               9 :             oSRS.SetLinearUnits( "Meter", 1.0 );
    4424               0 :         else if (EQUAL(osUnits, "FT"))
    4425               0 :             oSRS.SetLinearUnits( "foot", 0.3048 );
    4426                 :     }
    4427                 : 
    4428                 : /* -------------------------------------------------------------------- */
    4429                 : /*      Export SpatialRef                                               */
    4430                 : /* -------------------------------------------------------------------- */
    4431              14 :     CPLFree(pszWKT);
    4432              14 :     pszWKT = NULL;
    4433              14 :     if (oSRS.exportToWkt(&pszWKT) != OGRERR_NONE)
    4434                 :     {
    4435               0 :         CPLFree(pszWKT);
    4436               0 :         pszWKT = NULL;
    4437                 :     }
    4438                 : 
    4439              14 :     return TRUE;
    4440                 : }
    4441                 : 
    4442                 : /************************************************************************/
    4443                 : /*                              ParseVP()                               */
    4444                 : /************************************************************************/
    4445                 : 
    4446             132 : int PDFDataset::ParseVP(GDALPDFObject* poVP, double dfMediaBoxWidth, double dfMediaBoxHeight)
    4447                 : {
    4448                 :     int i;
    4449                 : 
    4450             132 :     if (poVP->GetType() != PDFObjectType_Array)
    4451               0 :         return FALSE;
    4452                 : 
    4453             132 :     GDALPDFArray* poVPArray = poVP->GetArray();
    4454                 : 
    4455             132 :     int nLength = poVPArray->GetLength();
    4456             132 :     CPLDebug("PDF", "VP length = %d", nLength);
    4457             132 :     if (nLength < 1)
    4458               0 :         return FALSE;
    4459                 : 
    4460                 : /* -------------------------------------------------------------------- */
    4461                 : /*      Find the largest BBox                                           */
    4462                 : /* -------------------------------------------------------------------- */
    4463             132 :     int iLargest = 0;
    4464             132 :     double dfLargestArea = 0;
    4465                 : 
    4466             272 :     for(i=0;i<nLength;i++)
    4467                 :     {
    4468             140 :         GDALPDFObject* poVPElt = poVPArray->Get(i);
    4469             140 :         if (poVPElt == NULL || poVPElt->GetType() != PDFObjectType_Dictionary)
    4470                 :         {
    4471               0 :             return FALSE;
    4472                 :         }
    4473                 : 
    4474             140 :         GDALPDFDictionary* poVPEltDict = poVPElt->GetDictionary();
    4475                 : 
    4476                 :         GDALPDFObject* poBBox;
    4477             280 :         if( (poBBox = poVPEltDict->Get("BBox")) == NULL ||
    4478             140 :             poBBox->GetType() != PDFObjectType_Array )
    4479                 :         {
    4480                 :             CPLError(CE_Failure, CPLE_AppDefined,
    4481               0 :                     "Cannot find Bbox object");
    4482               0 :             return FALSE;
    4483                 :         }
    4484                 : 
    4485             140 :         int nBboxLength = poBBox->GetArray()->GetLength();
    4486             140 :         if (nBboxLength != 4)
    4487                 :         {
    4488                 :             CPLError(CE_Failure, CPLE_AppDefined,
    4489               0 :                     "Invalid length for Bbox object");
    4490               0 :             return FALSE;
    4491                 :         }
    4492                 : 
    4493                 :         double adfBBox[4];
    4494             140 :         adfBBox[0] = Get(poBBox, 0);
    4495             140 :         adfBBox[1] = Get(poBBox, 1);
    4496             140 :         adfBBox[2] = Get(poBBox, 2);
    4497             140 :         adfBBox[3] = Get(poBBox, 3);
    4498             140 :         double dfArea = fabs(adfBBox[2] - adfBBox[0]) * fabs(adfBBox[3] - adfBBox[1]);
    4499             140 :         if (dfArea > dfLargestArea)
    4500                 :         {
    4501             132 :             iLargest = i;
    4502             132 :             dfLargestArea = dfArea;
    4503                 :         }
    4504                 :     }
    4505                 : 
    4506             132 :     if (nLength > 1)
    4507                 :     {
    4508               8 :         CPLDebug("PDF", "Largest BBox in VP array is element %d", iLargest);
    4509                 :     }
    4510                 : 
    4511                 : 
    4512             132 :     GDALPDFObject* poVPElt = poVPArray->Get(iLargest);
    4513             132 :     if (poVPElt == NULL || poVPElt->GetType() != PDFObjectType_Dictionary)
    4514                 :     {
    4515               0 :         return FALSE;
    4516                 :     }
    4517                 : 
    4518             132 :     GDALPDFDictionary* poVPEltDict = poVPElt->GetDictionary();
    4519                 : 
    4520                 :     GDALPDFObject* poBBox;
    4521             264 :     if( (poBBox = poVPEltDict->Get("BBox")) == NULL ||
    4522             132 :         poBBox->GetType() != PDFObjectType_Array )
    4523                 :     {
    4524                 :         CPLError(CE_Failure, CPLE_AppDefined,
    4525               0 :                 "Cannot find Bbox object");
    4526               0 :         return FALSE;
    4527                 :     }
    4528                 : 
    4529             132 :     int nBboxLength = poBBox->GetArray()->GetLength();
    4530             132 :     if (nBboxLength != 4)
    4531                 :     {
    4532                 :         CPLError(CE_Failure, CPLE_AppDefined,
    4533               0 :                 "Invalid length for Bbox object");
    4534               0 :         return FALSE;
    4535                 :     }
    4536                 : 
    4537             132 :     double dfULX = Get(poBBox, 0);
    4538             132 :     double dfULY = dfMediaBoxHeight - Get(poBBox, 1);
    4539             132 :     double dfLRX = Get(poBBox, 2);
    4540             132 :     double dfLRY = dfMediaBoxHeight - Get(poBBox, 3);
    4541                 : 
    4542                 : /* -------------------------------------------------------------------- */
    4543                 : /*      Extract Measure attribute                                       */
    4544                 : /* -------------------------------------------------------------------- */
    4545                 :     GDALPDFObject* poMeasure;
    4546             264 :     if( (poMeasure = poVPEltDict->Get("Measure")) == NULL ||
    4547             132 :         poMeasure->GetType() != PDFObjectType_Dictionary )
    4548                 :     {
    4549                 :         CPLError(CE_Failure, CPLE_AppDefined,
    4550               0 :                  "Cannot find Measure object");
    4551               0 :         return FALSE;
    4552                 :     }
    4553                 : 
    4554                 :     int bRet = ParseMeasure(poMeasure, dfMediaBoxWidth, dfMediaBoxHeight,
    4555             132 :                             dfULX, dfULY, dfLRX, dfLRY);
    4556                 : 
    4557                 : /* -------------------------------------------------------------------- */
    4558                 : /*      Extract PointData attribute                                     */
    4559                 : /* -------------------------------------------------------------------- */
    4560                 :     GDALPDFObject* poPointData;
    4561             132 :     if( (poPointData = poVPEltDict->Get("PtData")) != NULL &&
    4562               0 :         poPointData->GetType() == PDFObjectType_Dictionary )
    4563                 :     {
    4564               0 :         CPLDebug("PDF", "Found PointData");
    4565                 :     }
    4566                 : 
    4567             132 :     return bRet;
    4568                 : }
    4569                 : 
    4570                 : /************************************************************************/
    4571                 : /*                           ParseMeasure()                             */
    4572                 : /************************************************************************/
    4573                 : 
    4574             134 : int PDFDataset::ParseMeasure(GDALPDFObject* poMeasure,
    4575                 :                              double dfMediaBoxWidth, double dfMediaBoxHeight,
    4576                 :                              double dfULX, double dfULY, double dfLRX, double dfLRY)
    4577                 : {
    4578                 :     int i;
    4579             134 :     GDALPDFDictionary* poMeasureDict = poMeasure->GetDictionary();
    4580                 : 
    4581                 : /* -------------------------------------------------------------------- */
    4582                 : /*      Extract Subtype attribute                                       */
    4583                 : /* -------------------------------------------------------------------- */
    4584                 :     GDALPDFObject* poSubtype;
    4585             268 :     if( (poSubtype = poMeasureDict->Get("Subtype")) == NULL ||
    4586             134 :         poSubtype->GetType() != PDFObjectType_Name )
    4587                 :     {
    4588                 :         CPLError(CE_Failure, CPLE_AppDefined,
    4589               0 :                  "Cannot find Subtype object");
    4590               0 :         return FALSE;
    4591                 :     }
    4592                 : 
    4593             134 :     CPLDebug("PDF", "Subtype = %s", poSubtype->GetName().c_str());
    4594                 : 
    4595                 : /* -------------------------------------------------------------------- */
    4596                 : /*      Extract Bounds attribute (optional)                             */
    4597                 : /* -------------------------------------------------------------------- */
    4598                 : 
    4599                 :     /* http://acrobatusers.com/sites/default/files/gallery_pictures/SEVERODVINSK.pdf */
    4600                 :     /* has lgit:LPTS, lgit:GPTS and lgit:Bounds that have more precision than */
    4601                 :     /* LPTS, GPTS and Bounds. Use those ones */
    4602                 : 
    4603                 :     GDALPDFObject* poBounds;
    4604             134 :     if( (poBounds = poMeasureDict->Get("lgit:Bounds")) != NULL &&
    4605               0 :         poBounds->GetType() == PDFObjectType_Array )
    4606                 :     {
    4607               0 :         CPLDebug("PDF", "Using lgit:Bounds");
    4608                 :     }
    4609             268 :     else if( (poBounds = poMeasureDict->Get("Bounds")) == NULL ||
    4610             134 :               poBounds->GetType() != PDFObjectType_Array )
    4611                 :     {
    4612               0 :         poBounds = NULL;
    4613                 :     }
    4614                 : 
    4615             134 :     if (poBounds != NULL)
    4616                 :     {
    4617             134 :         int nBoundsLength = poBounds->GetArray()->GetLength();
    4618             134 :         if (nBoundsLength == 8)
    4619                 :         {
    4620                 :             double adfBounds[8];
    4621            1206 :             for(i=0;i<8;i++)
    4622                 :             {
    4623            1072 :                 adfBounds[i] = Get(poBounds, i);
    4624            1072 :                 CPLDebug("PDF", "Bounds[%d] = %f", i, adfBounds[i]);
    4625                 :             }
    4626                 : 
    4627                 :             // TODO we should use it to restrict the neatline but
    4628                 :             // I have yet to set a sample where bounds are not the four
    4629                 :             // corners of the unit square.
    4630                 :         }
    4631                 :     }
    4632                 : 
    4633                 : /* -------------------------------------------------------------------- */
    4634                 : /*      Extract GPTS attribute                                          */
    4635                 : /* -------------------------------------------------------------------- */
    4636                 :     GDALPDFObject* poGPTS;
    4637             134 :     if( (poGPTS = poMeasureDict->Get("lgit:GPTS")) != NULL &&
    4638               0 :         poGPTS->GetType() == PDFObjectType_Array )
    4639                 :     {
    4640               0 :         CPLDebug("PDF", "Using lgit:GPTS");
    4641                 :     }
    4642             268 :     else if( (poGPTS = poMeasureDict->Get("GPTS")) == NULL ||
    4643             134 :               poGPTS->GetType() != PDFObjectType_Array )
    4644                 :     {
    4645                 :         CPLError(CE_Failure, CPLE_AppDefined,
    4646               0 :                  "Cannot find GPTS object");
    4647               0 :         return FALSE;
    4648                 :     }
    4649                 : 
    4650             134 :     int nGPTSLength = poGPTS->GetArray()->GetLength();
    4651             134 :     if (nGPTSLength != 8)
    4652                 :     {
    4653                 :         CPLError(CE_Failure, CPLE_AppDefined,
    4654               0 :                  "Invalid length for GPTS object");
    4655               0 :         return FALSE;
    4656                 :     }
    4657                 : 
    4658                 :     double adfGPTS[8];
    4659            1206 :     for(i=0;i<8;i++)
    4660                 :     {
    4661            1072 :         adfGPTS[i] = Get(poGPTS, i);
    4662            1072 :         CPLDebug("PDF", "GPTS[%d] = %.18f", i, adfGPTS[i]);
    4663                 :     }
    4664                 : 
    4665                 : /* -------------------------------------------------------------------- */
    4666                 : /*      Extract LPTS attribute                                          */
    4667                 : /* -------------------------------------------------------------------- */
    4668                 :     GDALPDFObject* poLPTS;
    4669             134 :     if( (poLPTS = poMeasureDict->Get("lgit:LPTS")) != NULL &&
    4670               0 :         poLPTS->GetType() == PDFObjectType_Array )
    4671                 :     {
    4672               0 :         CPLDebug("PDF", "Using lgit:LPTS");
    4673                 :     }
    4674             268 :     else if( (poLPTS = poMeasureDict->Get("LPTS")) == NULL ||
    4675             134 :               poLPTS->GetType() != PDFObjectType_Array )
    4676                 :     {
    4677                 :         CPLError(CE_Failure, CPLE_AppDefined,
    4678               0 :                  "Cannot find LPTS object");
    4679               0 :         return FALSE;
    4680                 :     }
    4681                 : 
    4682             134 :     int nLPTSLength = poLPTS->GetArray()->GetLength();
    4683             134 :     if (nLPTSLength != 8)
    4684                 :     {
    4685                 :         CPLError(CE_Failure, CPLE_AppDefined,
    4686               0 :                  "Invalid length for LPTS object");
    4687               0 :         return FALSE;
    4688                 :     }
    4689                 : 
    4690                 :     double adfLPTS[8];
    4691            1206 :     for(i=0;i<8;i++)
    4692                 :     {
    4693            1072 :         adfLPTS[i] = Get(poLPTS, i);
    4694            1072 :         CPLDebug("PDF", "LPTS[%d] = %f", i, adfLPTS[i]);
    4695                 :     }
    4696                 : 
    4697                 : /* -------------------------------------------------------------------- */
    4698                 : /*      Extract GCS attribute                                           */
    4699                 : /* -------------------------------------------------------------------- */
    4700                 :     GDALPDFObject* poGCS;
    4701             268 :     if( (poGCS = poMeasureDict->Get("GCS")) == NULL ||
    4702             134 :         poGCS->GetType() != PDFObjectType_Dictionary )
    4703                 :     {
    4704                 :         CPLError(CE_Failure, CPLE_AppDefined,
    4705               0 :                  "Cannot find GCS object");
    4706               0 :         return FALSE;
    4707                 :     }
    4708                 : 
    4709             134 :     GDALPDFDictionary* poGCSDict = poGCS->GetDictionary();
    4710                 : 
    4711                 : /* -------------------------------------------------------------------- */
    4712                 : /*      Extract GCS.Type attribute                                      */
    4713                 : /* -------------------------------------------------------------------- */
    4714                 :     GDALPDFObject* poGCSType;
    4715             268 :     if( (poGCSType = poGCSDict->Get("Type")) == NULL ||
    4716             134 :         poGCSType->GetType() != PDFObjectType_Name )
    4717                 :     {
    4718                 :         CPLError(CE_Failure, CPLE_AppDefined,
    4719               0 :                  "Cannot find GCS.Type object");
    4720               0 :         return FALSE;
    4721                 :     }
    4722                 : 
    4723             134 :     CPLDebug("PDF", "GCS.Type = %s", poGCSType->GetName().c_str());
    4724                 : 
    4725                 : /* -------------------------------------------------------------------- */
    4726                 : /*      Extract EPSG attribute                                          */
    4727                 : /* -------------------------------------------------------------------- */
    4728                 :     GDALPDFObject* poEPSG;
    4729             134 :     int nEPSGCode = 0;
    4730             258 :     if( (poEPSG = poGCSDict->Get("EPSG")) != NULL &&
    4731             124 :         poEPSG->GetType() == PDFObjectType_Int )
    4732                 :     {
    4733             124 :         nEPSGCode = poEPSG->GetInt();
    4734             124 :         CPLDebug("PDF", "GCS.EPSG = %d", nEPSGCode);
    4735                 :     }
    4736                 : 
    4737                 : /* -------------------------------------------------------------------- */
    4738                 : /*      Extract GCS.WKT attribute                                       */
    4739                 : /* -------------------------------------------------------------------- */
    4740             134 :     GDALPDFObject* poGCSWKT = poGCSDict->Get("WKT");
    4741             268 :     if( poGCSWKT != NULL &&
    4742             134 :         poGCSWKT->GetType() != PDFObjectType_String )
    4743                 :     {
    4744               0 :         poGCSWKT = NULL;
    4745                 :     }
    4746                 : 
    4747             134 :     if (poGCSWKT != NULL)
    4748             134 :         CPLDebug("PDF", "GCS.WKT = %s", poGCSWKT->GetString().c_str());
    4749                 : 
    4750             134 :     if (nEPSGCode <= 0 && poGCSWKT == NULL)
    4751                 :     {
    4752                 :         CPLError(CE_Failure, CPLE_AppDefined,
    4753               0 :                  "Cannot find GCS.WKT or GCS.EPSG objects");
    4754               0 :         return FALSE;
    4755                 :     }
    4756                 : 
    4757             134 :     OGRSpatialReference oSRS;
    4758             134 :     int bSRSOK = FALSE;
    4759             134 :     if (nEPSGCode != 0 &&
    4760                 :         oSRS.importFromEPSG(nEPSGCode) == OGRERR_NONE)
    4761                 :     {
    4762             124 :         bSRSOK = TRUE;
    4763             124 :         CPLFree(pszWKT);
    4764             124 :         pszWKT = NULL;
    4765             124 :         oSRS.exportToWkt(&pszWKT);
    4766                 :     }
    4767                 :     else
    4768                 :     {
    4769              10 :         if (poGCSWKT == NULL)
    4770                 :         {
    4771                 :             CPLError(CE_Failure, CPLE_AppDefined,
    4772               0 :                     "Cannot resolve EPSG object, and GCS.WKT not found");
    4773               0 :             return FALSE;
    4774                 :         }
    4775                 : 
    4776              10 :         CPLFree(pszWKT);
    4777              10 :         pszWKT = CPLStrdup(poGCSWKT->GetString().c_str());
    4778                 :     }
    4779                 : 
    4780             134 :     if (!bSRSOK)
    4781                 :     {
    4782              10 :         char* pszWktTemp = pszWKT;
    4783              10 :         if (oSRS.importFromWkt(&pszWktTemp) != OGRERR_NONE)
    4784                 :         {
    4785               0 :             CPLFree(pszWKT);
    4786               0 :             pszWKT = NULL;
    4787               0 :             return FALSE;
    4788                 :         }
    4789                 :     }
    4790                 : 
    4791                 :     /* For http://www.avenza.com/sites/default/files/spatialpdf/US_County_Populations.pdf */
    4792                 :     /* or http://www.agmkt.state.ny.us/soilwater/aem/gis_mapping_tools/HUC12_Albany.pdf */
    4793             134 :     const char* pszDatum = oSRS.GetAttrValue("Datum");
    4794             134 :     if (pszDatum && strncmp(pszDatum, "D_", 2) == 0)
    4795                 :     {
    4796              10 :         oSRS.morphFromESRI();
    4797                 : 
    4798              10 :         CPLFree(pszWKT);
    4799              10 :         pszWKT = NULL;
    4800              10 :         if (oSRS.exportToWkt(&pszWKT) != OGRERR_NONE)
    4801                 :         {
    4802               0 :             CPLFree(pszWKT);
    4803               0 :             pszWKT = NULL;
    4804                 :         }
    4805                 :         else
    4806                 :         {
    4807              10 :             CPLDebug("PDF", "WKT after morphFromESRI() = %s", pszWKT);
    4808                 :         }
    4809                 :     }
    4810                 : 
    4811                 : /* -------------------------------------------------------------------- */
    4812                 : /*      Compute geotransform                                            */
    4813                 : /* -------------------------------------------------------------------- */
    4814             134 :     OGRSpatialReference* poSRSGeog = oSRS.CloneGeogCS();
    4815                 : 
    4816                 :     /* Files found at http://carto.iict.ch/blog/publications-cartographiques-au-format-geospatial-pdf/ */
    4817                 :     /* are in a PROJCS. However the coordinates in GPTS array are not in (lat, long) as required by the */
    4818                 :     /* ISO 32000 supplement spec, but in (northing, easting). Adobe reader is able to understand that, */
    4819                 :     /* so let's also try to do it with a heuristics. */
    4820                 : 
    4821             134 :     int bReproject = TRUE;
    4822             998 :     if (oSRS.IsProjected() &&
    4823             432 :         (fabs(adfGPTS[0]) > 91 || fabs(adfGPTS[2]) > 91 || fabs(adfGPTS[4]) > 91 || fabs(adfGPTS[6]) > 91 ||
    4824             432 :          fabs(adfGPTS[1]) > 361 || fabs(adfGPTS[3]) > 361 || fabs(adfGPTS[5]) > 361 || fabs(adfGPTS[7]) > 361))
    4825                 :     {
    4826               0 :         CPLDebug("PDF", "GPTS coordinates seems to be in (northing, easting), which is non-standard");
    4827               0 :         bReproject = FALSE;
    4828                 :     }
    4829                 : 
    4830             134 :     OGRCoordinateTransformation* poCT = NULL;
    4831             134 :     if (bReproject)
    4832                 :     {
    4833             134 :         poCT = OGRCreateCoordinateTransformation( poSRSGeog, &oSRS);
    4834             134 :         if (poCT == NULL)
    4835                 :         {
    4836               0 :             delete poSRSGeog;
    4837               0 :             CPLFree(pszWKT);
    4838               0 :             pszWKT = NULL;
    4839               0 :             return FALSE;
    4840                 :         }
    4841                 :     }
    4842                 : 
    4843                 :     GDAL_GCP asGCPS[4];
    4844                 : 
    4845                 :     /* Create NEATLINE */
    4846             134 :     poNeatLine = new OGRPolygon();
    4847             268 :     OGRLinearRing* poRing = new OGRLinearRing();
    4848             134 :     poNeatLine->addRingDirectly(poRing);
    4849                 : 
    4850             670 :     for(i=0;i<4;i++)
    4851                 :     {
    4852                 :         /* We probably assume LPTS is 0 or 1 */
    4853             536 :         asGCPS[i].dfGCPPixel = (dfULX * (1 - adfLPTS[2*i+0]) + dfLRX * adfLPTS[2*i+0]) / dfMediaBoxWidth * nRasterXSize;
    4854             536 :         asGCPS[i].dfGCPLine  = (dfULY * (1 - adfLPTS[2*i+1]) + dfLRY * adfLPTS[2*i+1]) / dfMediaBoxHeight * nRasterYSize;
    4855                 : 
    4856             536 :         double lat = adfGPTS[2*i], lon = adfGPTS[2*i+1];
    4857             536 :         double x = lon, y = lat;
    4858             536 :         if (bReproject)
    4859                 :         {
    4860             536 :             if (!poCT->Transform(1, &x, &y, NULL))
    4861                 :             {
    4862                 :                 CPLError(CE_Failure, CPLE_AppDefined,
    4863               0 :                         "Cannot reproject (%f, %f)", lon, lat);
    4864               0 :                 delete poSRSGeog;
    4865               0 :                 delete poCT;
    4866               0 :                 CPLFree(pszWKT);
    4867               0 :                 pszWKT = NULL;
    4868               0 :                 return FALSE;
    4869                 :             }
    4870                 :         }
    4871                 : 
    4872             536 :         x = ROUND_TO_INT_IF_CLOSE(x);
    4873             536 :         y = ROUND_TO_INT_IF_CLOSE(y);
    4874                 : 
    4875             536 :         asGCPS[i].dfGCPX     = x;
    4876             536 :         asGCPS[i].dfGCPY     = y;
    4877                 : 
    4878             536 :         poRing->addPoint(x, y);
    4879                 :     }
    4880                 : 
    4881             134 :     delete poSRSGeog;
    4882             134 :     delete poCT;
    4883                 : 
    4884             134 :     if (!GDALGCPsToGeoTransform( 4, asGCPS,
    4885                 :                                adfGeoTransform, FALSE))
    4886                 :     {
    4887               0 :         CPLDebug("PDF", "Could not compute GT with exact match. Try with approximate");
    4888               0 :         if (!GDALGCPsToGeoTransform( 4, asGCPS,
    4889                 :                                adfGeoTransform, TRUE))
    4890                 :         {
    4891                 :             CPLError(CE_Failure, CPLE_AppDefined,
    4892               0 :                      "Could not compute GT with approximate match.");
    4893               0 :             return FALSE;
    4894                 :         }
    4895                 :     }
    4896             134 :     bGeoTransformValid = TRUE;
    4897                 : 
    4898                 :     /* If the non scaling terms of the geotransform are significantly smaller than */
    4899                 :     /* the pixel size, then nullify them as being just artifacts of reprojection and */
    4900                 :     /* GDALGCPsToGeoTransform() numerical imprecisions */
    4901             134 :     double dfPixelSize = MIN(fabs(adfGeoTransform[1]), fabs(adfGeoTransform[5]));
    4902             134 :     double dfRotationShearTerm = MAX(fabs(adfGeoTransform[2]), fabs(adfGeoTransform[4]));
    4903             134 :     if (dfRotationShearTerm < 1e-5 * dfPixelSize)
    4904                 :     {
    4905             134 :         double dfLRX = adfGeoTransform[0] + nRasterXSize * adfGeoTransform[1] + nRasterYSize * adfGeoTransform[2];
    4906             134 :         double dfLRY = adfGeoTransform[3] + nRasterXSize * adfGeoTransform[4] + nRasterYSize * adfGeoTransform[5];
    4907             134 :         adfGeoTransform[1] = (dfLRX - adfGeoTransform[0]) / nRasterXSize;
    4908             134 :         adfGeoTransform[5] = (dfLRY - adfGeoTransform[3]) / nRasterYSize;
    4909             134 :         adfGeoTransform[2] = adfGeoTransform[4] = 0;
    4910                 :     }
    4911                 : 
    4912             134 :     return TRUE;
    4913                 : }
    4914                 : 
    4915                 : /************************************************************************/
    4916                 : /*                          GetProjectionRef()                          */
    4917                 : /************************************************************************/
    4918                 : 
    4919              47 : const char* PDFDataset::GetProjectionRef()
    4920                 : {
    4921              47 :     if (pszWKT && bGeoTransformValid)
    4922              44 :         return pszWKT;
    4923               3 :     return "";
    4924                 : }
    4925                 : 
    4926                 : /************************************************************************/
    4927                 : /*                          GetGeoTransform()                           */
    4928                 : /************************************************************************/
    4929                 : 
    4930              40 : CPLErr PDFDataset::GetGeoTransform( double * padfTransform )
    4931                 : 
    4932                 : {
    4933              40 :     memcpy(padfTransform, adfGeoTransform, 6 * sizeof(double));
    4934                 : 
    4935              40 :     return( (bGeoTransformValid) ? CE_None : CE_Failure );
    4936                 : }
    4937                 : 
    4938                 : /************************************************************************/
    4939                 : /*                            SetProjection()                           */
    4940                 : /************************************************************************/
    4941                 : 
    4942               6 : CPLErr PDFDataset::SetProjection(const char* pszWKTIn)
    4943                 : {
    4944               6 :     CPLFree(pszWKT);
    4945               6 :     pszWKT = pszWKTIn ? CPLStrdup(pszWKTIn) : CPLStrdup("");
    4946               6 :     bProjDirty = TRUE;
    4947               6 :     return CE_None;
    4948                 : }
    4949                 : 
    4950                 : /************************************************************************/
    4951                 : /*                          SetGeoTransform()                           */
    4952                 : /************************************************************************/
    4953                 : 
    4954               4 : CPLErr PDFDataset::SetGeoTransform(double* padfGeoTransform)
    4955                 : {
    4956               4 :     memcpy(adfGeoTransform, padfGeoTransform, 6 * sizeof(double));
    4957               4 :     bGeoTransformValid = TRUE;
    4958               4 :     bProjDirty = TRUE;
    4959                 : 
    4960                 :     /* Reset NEATLINE if not explicitely set by the user */
    4961               4 :     if (!bNeatLineDirty)
    4962               4 :         SetMetadataItem("NEATLINE", NULL);
    4963               4 :     return CE_None;
    4964                 : }
    4965                 : 
    4966                 : /************************************************************************/
    4967                 : /*                           GetMetadata()                              */
    4968                 : /************************************************************************/
    4969                 : 
    4970              28 : char      **PDFDataset::GetMetadata( const char * pszDomain )
    4971                 : {
    4972              28 :     if( pszDomain != NULL && EQUAL(pszDomain, "LAYERS_WITH_REF") )
    4973                 :     {
    4974               2 :         return osLayerWithRefList.List(); /* Used by OGR driver */
    4975                 :     }
    4976              26 :     else if( pszDomain != NULL && EQUAL(pszDomain, "EMBEDDED_METADATA") )
    4977                 :     {
    4978               0 :         char** papszRet = oMDMD.GetMetadata(pszDomain);
    4979               0 :         if( papszRet )
    4980               0 :             return papszRet;
    4981                 : 
    4982               0 :         GDALPDFObject* poCatalog = GetCatalog();
    4983               0 :         if( poCatalog == NULL )
    4984               0 :             return NULL;
    4985               0 :         GDALPDFObject* poFirstElt = poCatalog->LookupObject("Names.EmbeddedFiles.Names[0]");
    4986               0 :         GDALPDFObject* poF = poCatalog->LookupObject("Names.EmbeddedFiles.Names[1].EF.F");
    4987                 : 
    4988               0 :         if( poFirstElt == NULL || poFirstElt->GetType() != PDFObjectType_String ||
    4989               0 :             poFirstElt->GetString() != "Metadata" )
    4990               0 :             return NULL;
    4991               0 :         if( poF == NULL || poF->GetType() != PDFObjectType_Dictionary )
    4992               0 :             return NULL;
    4993               0 :         GDALPDFStream* poStream = poF->GetStream();
    4994               0 :         if( poStream == NULL )
    4995               0 :             return NULL;
    4996                 : 
    4997               0 :         char* apszMetadata[2] = { NULL, NULL };
    4998               0 :         apszMetadata[0] = poStream->GetBytes();
    4999               0 :         oMDMD.SetMetadata(apszMetadata, pszDomain);
    5000               0 :         VSIFree(apszMetadata[0]);
    5001                 :     }
    5002                 : 
    5003              26 :     return oMDMD.GetMetadata(pszDomain);
    5004                 : }
    5005                 : 
    5006                 : /************************************************************************/
    5007                 : /*                            SetMetadata()                             */
    5008                 : /************************************************************************/
    5009                 : 
    5010              21 : CPLErr      PDFDataset::SetMetadata( char ** papszMetadata,
    5011                 :                                      const char * pszDomain )
    5012                 : {
    5013              21 :     if (pszDomain == NULL || EQUAL(pszDomain, ""))
    5014                 :     {
    5015               0 :         if (CSLFindString(papszMetadata, "NEATLINE") != -1)
    5016                 :         {
    5017               0 :             bProjDirty = TRUE;
    5018               0 :             bNeatLineDirty = TRUE;
    5019                 :         }
    5020               0 :         bInfoDirty = TRUE;
    5021                 :     }
    5022              21 :     else if (EQUAL(pszDomain, "xml:XMP"))
    5023              20 :         bXMPDirty = TRUE;
    5024              21 :     return oMDMD.SetMetadata(papszMetadata, pszDomain);
    5025                 : }
    5026                 : 
    5027                 : /************************************************************************/
    5028                 : /*                          GetMetadataItem()                           */
    5029                 : /************************************************************************/
    5030                 : 
    5031            1790 : const char *PDFDataset::GetMetadataItem( const char * pszName,
    5032                 :                                          const char * pszDomain )
    5033                 : {
    5034            1790 :     if ( (pszDomain == NULL || EQUAL(pszDomain, "")) && EQUAL(pszName, "PDF_PAGE_OBJECT") )
    5035                 :     {
    5036               6 :         return CPLSPrintf("%p", poPageObj);
    5037                 :     }
    5038            1784 :     if ( (pszDomain == NULL || EQUAL(pszDomain, "")) && EQUAL(pszName, "PDF_CATALOG_OBJECT") )
    5039                 :     {
    5040               6 :         return CPLSPrintf("%p", GetCatalog());
    5041                 :     }
    5042                 : 
    5043            1778 :     return oMDMD.GetMetadataItem(pszName, pszDomain);
    5044                 : }
    5045                 : 
    5046                 : /************************************************************************/
    5047                 : /*                          SetMetadataItem()                           */
    5048                 : /************************************************************************/
    5049                 : 
    5050             569 : CPLErr      PDFDataset::SetMetadataItem( const char * pszName,
    5051                 :                                          const char * pszValue,
    5052                 :                                          const char * pszDomain )
    5053                 : {
    5054            1118 :     if (pszDomain == NULL || EQUAL(pszDomain, ""))
    5055                 :     {
    5056             549 :         if (EQUAL(pszName, "NEATLINE"))
    5057                 :         {
    5058             162 :             bProjDirty = TRUE;
    5059             162 :             bNeatLineDirty = TRUE;
    5060                 :         }
    5061                 :         else
    5062                 :         {
    5063             387 :             if (pszValue == NULL)
    5064               2 :                 pszValue = "";
    5065             387 :             bInfoDirty = TRUE;
    5066                 :         }
    5067                 :     }
    5068              20 :     else if (EQUAL(pszDomain, "xml:XMP"))
    5069               0 :         bXMPDirty = TRUE;
    5070             569 :     return oMDMD.SetMetadataItem(pszName, pszValue, pszDomain);
    5071                 : }
    5072                 : 
    5073                 : /************************************************************************/
    5074                 : /*                            GetGCPCount()                             */
    5075                 : /************************************************************************/
    5076                 : 
    5077              18 : int PDFDataset::GetGCPCount()
    5078                 : {
    5079              18 :     return nGCPCount;
    5080                 : }
    5081                 : 
    5082                 : /************************************************************************/
    5083                 : /*                          GetGCPProjection()                          */
    5084                 : /************************************************************************/
    5085                 : 
    5086               5 : const char * PDFDataset::GetGCPProjection()
    5087                 : {
    5088               5 :     if (pszWKT != NULL && nGCPCount != 0)
    5089               3 :         return pszWKT;
    5090               2 :     return "";
    5091                 : }
    5092                 : 
    5093                 : /************************************************************************/
    5094                 : /*                              GetGCPs()                               */
    5095                 : /************************************************************************/
    5096                 : 
    5097               5 : const GDAL_GCP * PDFDataset::GetGCPs()
    5098                 : {
    5099               5 :     return pasGCPList;
    5100                 : }
    5101                 : 
    5102                 : /************************************************************************/
    5103                 : /*                               SetGCPs()                              */
    5104                 : /************************************************************************/
    5105                 : 
    5106               2 : CPLErr PDFDataset::SetGCPs( int nGCPCountIn, const GDAL_GCP *pasGCPListIn,
    5107                 :                             const char *pszGCPProjectionIn )
    5108                 : {
    5109                 :     const char* pszGEO_ENCODING =
    5110               2 :         CPLGetConfigOption("GDAL_PDF_GEO_ENCODING", "ISO32000");
    5111               2 :     if( nGCPCountIn != 4 && EQUAL(pszGEO_ENCODING, "ISO32000"))
    5112                 :     {
    5113                 :         CPLError(CE_Failure, CPLE_NotSupported,
    5114                 :                  "PDF driver only supports writing 4 GCPs when "
    5115               0 :                  "GDAL_PDF_GEO_ENCODING=ISO32000.");
    5116               0 :         return CE_Failure;
    5117                 :     }
    5118                 :     
    5119                 :     /* Free previous GCPs */
    5120               2 :     GDALDeinitGCPs( nGCPCount, pasGCPList );
    5121               2 :     CPLFree( pasGCPList );
    5122                 :     
    5123                 :     /* Duplicate in GCPs */
    5124               2 :     nGCPCount = nGCPCountIn;
    5125               2 :     pasGCPList = GDALDuplicateGCPs(nGCPCount, pasGCPListIn);
    5126                 :     
    5127               2 :     CPLFree(pszWKT);
    5128               2 :     pszWKT = CPLStrdup(pszGCPProjectionIn);
    5129                 :     
    5130               2 :     bProjDirty = TRUE;
    5131                 : 
    5132                 :     /* Reset NEATLINE if not explicitely set by the user */
    5133               2 :     if (!bNeatLineDirty)
    5134               2 :         SetMetadataItem("NEATLINE", NULL);
    5135                 : 
    5136               2 :     return CE_None;
    5137                 : }
    5138                 : 
    5139                 : #endif // #if defined(HAVE_POPPLER) || defined(HAVE_PODOFO)
    5140                 : 
    5141                 : 
    5142                 : /************************************************************************/
    5143                 : /*                          GDALPDFOpen()                               */
    5144                 : /************************************************************************/
    5145                 : 
    5146               6 : GDALDataset* GDALPDFOpen(const char* pszFilename, GDALAccess eAccess)
    5147                 : {
    5148                 : #if defined(HAVE_POPPLER) || defined(HAVE_PODOFO)
    5149               6 :     GDALOpenInfo oOpenInfo(pszFilename, eAccess);
    5150               6 :     return PDFDataset::Open(&oOpenInfo);
    5151                 : #else
    5152                 :     return NULL;
    5153                 : #endif
    5154                 : }
    5155                 : 
    5156                 : /************************************************************************/
    5157                 : /*                       GDALPDFUnloadDriver()                          */
    5158                 : /************************************************************************/
    5159                 : 
    5160             550 : static void GDALPDFUnloadDriver(GDALDriver * poDriver)
    5161                 : {
    5162                 : #ifdef HAVE_POPPLER
    5163             550 :     if( hGlobalParamsMutex != NULL )
    5164               1 :         CPLDestroyMutex(hGlobalParamsMutex);
    5165                 : #endif
    5166             550 : }
    5167                 : 
    5168                 : /************************************************************************/
    5169                 : /*                         GDALRegister_PDF()                           */
    5170                 : /************************************************************************/
    5171                 : 
    5172             610 : void GDALRegister_PDF()
    5173                 : 
    5174                 : {
    5175                 :     GDALDriver  *poDriver;
    5176                 : 
    5177             610 :     if (! GDAL_CHECK_VERSION("PDF driver"))
    5178               0 :         return;
    5179                 : 
    5180             610 :     if( GDALGetDriverByName( "PDF" ) == NULL )
    5181                 :     {
    5182             588 :         poDriver = new GDALDriver();
    5183                 : 
    5184             588 :         poDriver->SetDescription( "PDF" );
    5185                 :         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
    5186             588 :                                    "Geospatial PDF" );
    5187                 :         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
    5188             588 :                                    "frmt_pdf.html" );
    5189             588 :         poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "pdf" );
    5190                 :         poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
    5191             588 :                                    "Byte" );
    5192             588 :         poDriver->SetMetadataItem( GDAL_DMD_SUBDATASETS, "YES" );
    5193                 : #ifdef HAVE_POPPLER
    5194             588 :         poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
    5195             588 :         poDriver->SetMetadataItem( "HAVE_POPPLER", "YES" );
    5196                 : #endif
    5197                 : #ifdef HAVE_PODOFO
    5198             588 :         poDriver->SetMetadataItem( "HAVE_PODOFO", "YES" );
    5199                 : #endif
    5200                 : 
    5201                 :         poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
    5202                 : "<CreationOptionList>\n"
    5203                 : "   <Option name='COMPRESS' type='string-select' description='Compression method for raster data' default='DEFLATE'>\n"
    5204                 : "     <Value>NONE</Value>\n"
    5205                 : "     <Value>DEFLATE</Value>\n"
    5206                 : "     <Value>JPEG</Value>\n"
    5207                 : "     <Value>JPEG2000</Value>\n"
    5208                 : "   </Option>\n"
    5209                 : "   <Option name='STREAM_COMPRESS' type='string-select' description='Compression method for stream objects' default='DEFLATE'>\n"
    5210                 : "     <Value>NONE</Value>\n"
    5211                 : "     <Value>DEFLATE</Value>\n"
    5212                 : "   </Option>\n"
    5213                 : "   <Option name='GEO_ENCODING' type='string-select' description='Format of geo-encoding' default='ISO32000'>\n"
    5214                 : "     <Value>NONE</Value>\n"
    5215                 : "     <Value>ISO32000</Value>\n"
    5216                 : "     <Value>OGC_BP</Value>\n"
    5217                 : "     <Value>BOTH</Value>\n"
    5218                 : "   </Option>\n"
    5219                 : "   <Option name='NEATLINE' type='string' description='Neatline'/>\n"
    5220                 : "   <Option name='DPI' type='float' description='DPI' default='72'/>\n"
    5221                 : "   <Option name='PREDICTOR' type='int' description='Predictor Type (for DEFLATE compression)'/>\n"
    5222                 : "   <Option name='JPEG_QUALITY' type='int' description='JPEG quality 1-100' default='75'/>\n"
    5223                 : "   <Option name='JPEG2000_DRIVER' type='string'/>\n"
    5224                 : "   <Option name='TILED' type='boolean' description='Switch to tiled format' default='NO'/>\n"
    5225                 : "   <Option name='BLOCKXSIZE' type='int' description='Block Width'/>\n"
    5226                 : "   <Option name='BLOCKYSIZE' type='int' description='Block Height'/>\n"
    5227                 : "   <Option name='LAYER_NAME' type='string' description='Layer name for raster content'/>\n"
    5228                 : "   <Option name='CLIPPING_EXTENT' type='string' description='Clipping extent for main and extra rasters. Format: xmin,ymin,xmax,ymax'/>\n"
    5229                 : "   <Option name='EXTRA_RASTERS' type='string' description='List of extra (georeferenced) rasters.'/>\n"
    5230                 : "   <Option name='EXTRA_RASTERS_LAYER_NAME' type='string' description='List of layer names for the extra (georeferenced) rasters.'/>\n"
    5231                 : "   <Option name='EXTRA_STREAM' type='string' description='Extra data to insert into the page content stream'/>\n"
    5232                 : "   <Option name='EXTRA_IMAGES' type='string' description='List of image_file_name,x,y,scale[,link=some_url] (possibly repeated)'/>\n"
    5233                 : "   <Option name='EXTRA_LAYER_NAME' type='string' description='Layer name for extra content'/>\n"
    5234                 : "   <Option name='MARGIN' type='int' description='Margin around image in user units'/>\n"
    5235                 : "   <Option name='LEFT_MARGIN' type='int' description='Left margin in user units'/>\n"
    5236                 : "   <Option name='RIGHT_MARGIN' type='int' description='Right margin in user units'/>\n"
    5237                 : "   <Option name='TOP_MARGIN' type='int' description='Top margin in user units'/>\n"
    5238                 : "   <Option name='BOTTOM_MARGIN' type='int' description='Bottom margin in user units'/>\n"
    5239                 : "   <Option name='OGR_DATASOURCE' type='string' description='Name of OGR datasource to display on top of the raster layer'/>\n"
    5240                 : "   <Option name='OGR_DISPLAY_FIELD' type='string' description='Name of field to use as the display field in the feature tree'/>\n"
    5241                 : "   <Option name='OGR_DISPLAY_LAYER_NAMES' type='string' description='Comma separated list of OGR layer names to display in the feature tree'/>\n"
    5242                 : "   <Option name='OGR_WRITE_ATTRIBUTES' type='boolean' description='Whether to write attributes of OGR features' default='YES'/>\n"
    5243                 : "   <Option name='OGR_LINK_FIELD' type='string' description='Name of field to use as the URL field to make objects clickable.'/>\n"
    5244                 : "   <Option name='XMP' type='string' description='xml:XMP metadata'/>\n"
    5245                 : "   <Option name='WRITE_INFO' type='boolean' description='to control whether a Info block must be written' default='YES'/>\n"
    5246                 : "   <Option name='AUTHOR' type='string'/>\n"
    5247                 : "   <Option name='CREATOR' type='string'/>\n"
    5248                 : "   <Option name='CREATION_DATE' type='string'/>\n"
    5249                 : "   <Option name='KEYWORDS' type='string'/>\n"
    5250                 : "   <Option name='PRODUCER' type='string'/>\n"
    5251                 : "   <Option name='SUBJECT' type='string'/>\n"
    5252                 : "   <Option name='TITLE' type='string'/>\n"
    5253                 : "   <Option name='OFF_LAYERS' type='string' description='Comma separated list of layer names that should be initially hidden'/>\n"
    5254                 : "   <Option name='EXCLUSIVE_LAYERS' type='string' description='Comma separated list of layer names, such that only one of those layers can be ON at a time.'/>\n"
    5255                 : "   <Option name='JAVASCRIPT' type='string' description='Javascript script to embed and run at file opening'/>\n"
    5256                 : "   <Option name='JAVASCRIPT_FILE' type='string' description='Filename of the Javascript script to embed and run at file opening'/>\n"
    5257             588 : "</CreationOptionList>\n" );
    5258                 : 
    5259                 : #if defined(HAVE_POPPLER) || defined(HAVE_PODOFO)
    5260             588 :         poDriver->pfnOpen = PDFDataset::Open;
    5261             588 :         poDriver->pfnIdentify = PDFDataset::Identify;
    5262                 : #endif
    5263                 : 
    5264             588 :         poDriver->pfnCreateCopy = GDALPDFCreateCopy;
    5265             588 :         poDriver->pfnUnloadDriver = GDALPDFUnloadDriver;
    5266                 : 
    5267             588 :         GetGDALDriverManager()->RegisterDriver( poDriver );
    5268                 :     }
    5269            2274 : }
    5270                 : 

Generated by: LCOV version 1.7