LCOV - code coverage report
Current view: directory - frmts/pdf - pdfcreatecopy.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 2255 1978 87.7 %
Date: 2013-03-30 Functions: 50 45 90.0 %

       1                 : /******************************************************************************
       2                 :  * $Id: pdfcreatecopy.cpp 25613 2013-02-07 19:33:31Z 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) 2012, 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 "pdfcreatecopy.h"
      35                 : 
      36                 : #include "cpl_vsi_virtual.h"
      37                 : #include "cpl_conv.h"
      38                 : #include "cpl_error.h"
      39                 : #include "ogr_spatialref.h"
      40                 : #include "ogr_geometry.h"
      41                 : #include "vrt/vrtdataset.h"
      42                 : 
      43                 : #include "pdfobject.h"
      44                 : 
      45                 : #ifndef M_PI
      46                 : #define M_PI       3.14159265358979323846
      47                 : #endif
      48                 : 
      49                 : CPL_CVSID("$Id: pdfcreatecopy.cpp 25613 2013-02-07 19:33:31Z rouault $");
      50                 : 
      51                 : #define PIXEL_TO_GEO_X(x,y) adfGeoTransform[0] + x * adfGeoTransform[1] + y * adfGeoTransform[2]
      52                 : #define PIXEL_TO_GEO_Y(x,y) adfGeoTransform[3] + x * adfGeoTransform[4] + y * adfGeoTransform[5]
      53                 : 
      54                 : class GDALFakePDFDataset : public GDALDataset
      55                 : {
      56                 :     public:
      57                 :         GDALFakePDFDataset() {}
      58                 : };
      59                 : 
      60                 : /************************************************************************/
      61                 : /*                             Init()                                   */
      62                 : /************************************************************************/
      63                 : 
      64              79 : void GDALPDFWriter::Init()
      65                 : {
      66              79 :     nPageResourceId = 0;
      67              79 :     nStructTreeRootId = 0;
      68              79 :     nCatalogId = nCatalogGen = 0;
      69              79 :     bInWriteObj = FALSE;
      70              79 :     nInfoId = nInfoGen = 0;
      71              79 :     nXMPId = nXMPGen = 0;
      72              79 :     nNamesId = 0;
      73                 : 
      74              79 :     nLastStartXRef = 0;
      75              79 :     nLastXRefSize = 0;
      76              79 :     bCanUpdate = FALSE;
      77              79 : }
      78                 : 
      79                 : /************************************************************************/
      80                 : /*                         GDALPDFWriter()                              */
      81                 : /************************************************************************/
      82                 : 
      83              79 : GDALPDFWriter::GDALPDFWriter(VSILFILE* fpIn, int bAppend) : fp(fpIn)
      84                 : {
      85              79 :     Init();
      86                 : 
      87              79 :     if (!bAppend)
      88                 :     {
      89              53 :         VSIFPrintfL(fp, "%%PDF-1.6\n");
      90                 : 
      91                 :         /* See PDF 1.7 reference, page 92. Write 4 non-ASCII bytes to indicate that the content will be binary */
      92              53 :         VSIFPrintfL(fp, "%%%c%c%c%c\n", 0xFF, 0xFF, 0xFF, 0xFF);
      93                 : 
      94              53 :         nPageResourceId = AllocNewObject();
      95              53 :         nCatalogId = AllocNewObject();
      96                 :     }
      97              79 : }
      98                 : 
      99                 : /************************************************************************/
     100                 : /*                         ~GDALPDFWriter()                             */
     101                 : /************************************************************************/
     102                 : 
     103              79 : GDALPDFWriter::~GDALPDFWriter()
     104                 : {
     105              79 :     Close();
     106              79 : }
     107                 : 
     108                 : /************************************************************************/
     109                 : /*                          ParseIndirectRef()                          */
     110                 : /************************************************************************/
     111                 : 
     112              30 : static int ParseIndirectRef(const char* pszStr, int& nNum, int &nGen)
     113                 : {
     114              60 :     while(*pszStr == ' ')
     115               0 :         pszStr ++;
     116                 : 
     117              30 :     nNum = atoi(pszStr);
     118              94 :     while(*pszStr >= '0' && *pszStr <= '9')
     119              34 :         pszStr ++;
     120              30 :     if (*pszStr != ' ')
     121               0 :         return FALSE;
     122                 : 
     123              90 :     while(*pszStr == ' ')
     124              30 :         pszStr ++;
     125                 : 
     126              30 :     nGen = atoi(pszStr);
     127              90 :     while(*pszStr >= '0' && *pszStr <= '9')
     128              30 :         pszStr ++;
     129              30 :     if (*pszStr != ' ')
     130               0 :         return FALSE;
     131                 : 
     132              90 :     while(*pszStr == ' ')
     133              30 :         pszStr ++;
     134                 : 
     135              30 :     return *pszStr == 'R';
     136                 : }
     137                 : 
     138                 : /************************************************************************/
     139                 : /*                       ParseTrailerAndXRef()                          */
     140                 : /************************************************************************/
     141                 : 
     142              26 : int GDALPDFWriter::ParseTrailerAndXRef()
     143                 : {
     144              26 :     VSIFSeekL(fp, 0, SEEK_END);
     145                 :     char szBuf[1024+1];
     146              26 :     vsi_l_offset nOffset = VSIFTellL(fp);
     147                 : 
     148              26 :     if (nOffset > 128)
     149              26 :         nOffset -= 128;
     150                 :     else
     151               0 :         nOffset = 0;
     152                 : 
     153                 :     /* Find startxref section */
     154              26 :     VSIFSeekL(fp, nOffset, SEEK_SET);
     155              26 :     int nRead = (int) VSIFReadL(szBuf, 1, 128, fp);
     156              26 :     szBuf[nRead] = 0;
     157              26 :     if (nRead < 9)
     158               0 :         return FALSE;
     159                 : 
     160              26 :     const char* pszStartXRef = NULL;
     161                 :     int i;
     162             336 :     for(i = nRead - 9; i>= 0; i --)
     163                 :     {
     164             336 :         if (strncmp(szBuf + i, "startxref", 9) == 0)
     165                 :         {
     166              26 :             pszStartXRef = szBuf + i;
     167              26 :             break;
     168                 :         }
     169                 :     }
     170              26 :     if (pszStartXRef == NULL)
     171                 :     {
     172               0 :         CPLError(CE_Failure, CPLE_AppDefined, "Cannot find startxref");
     173               0 :         return FALSE;
     174                 :     }
     175              26 :     pszStartXRef += 9;
     176              78 :     while(*pszStartXRef == '\r' || *pszStartXRef == '\n')
     177              26 :         pszStartXRef ++;
     178              26 :     if (*pszStartXRef == '\0')
     179                 :     {
     180               0 :         CPLError(CE_Failure, CPLE_AppDefined, "Cannot find startxref");
     181               0 :         return FALSE;
     182                 :     }
     183                 : 
     184              26 :     nLastStartXRef = CPLScanUIntBig(pszStartXRef,16);
     185                 : 
     186                 :     /* Skip to beginning of xref section */
     187              26 :     VSIFSeekL(fp, nLastStartXRef, SEEK_SET);
     188                 : 
     189                 :     /* And skip to trailer */
     190                 :     const char* pszLine;
     191              26 :     while( (pszLine = CPLReadLineL(fp)) != NULL)
     192                 :     {
     193             324 :         if (strncmp(pszLine, "trailer", 7) == 0)
     194              26 :             break;
     195                 :     }
     196                 : 
     197              26 :     if( pszLine == NULL )
     198                 :     {
     199               0 :         CPLError(CE_Failure, CPLE_AppDefined, "Cannot find trailer");
     200               0 :         return FALSE;
     201                 :     }
     202                 : 
     203                 :     /* Read trailer content */
     204              26 :     nRead = (int) VSIFReadL(szBuf, 1, 1024, fp);
     205              26 :     szBuf[nRead] = 0;
     206                 : 
     207                 :     /* Find XRef size */
     208              26 :     const char* pszSize = strstr(szBuf, "/Size");
     209              26 :     if (pszSize == NULL)
     210                 :     {
     211               0 :         CPLError(CE_Failure, CPLE_AppDefined, "Cannot find trailer /Size");
     212               0 :         return FALSE;
     213                 :     }
     214              26 :     pszSize += 5;
     215              78 :     while(*pszSize == ' ')
     216              26 :         pszSize ++;
     217              26 :     nLastXRefSize = atoi(pszSize);
     218                 : 
     219                 :     /* Find Root object */
     220              26 :     const char* pszRoot = strstr(szBuf, "/Root");
     221              26 :     if (pszRoot == NULL)
     222                 :     {
     223               0 :         CPLError(CE_Failure, CPLE_AppDefined, "Cannot find trailer /Root");
     224               0 :         return FALSE;
     225                 :     }
     226              26 :     pszRoot += 5;
     227              78 :     while(*pszRoot == ' ')
     228              26 :         pszRoot ++;
     229                 : 
     230              26 :     if (!ParseIndirectRef(pszRoot, nCatalogId, nCatalogGen))
     231                 :     {
     232               0 :         CPLError(CE_Failure, CPLE_AppDefined, "Cannot parse trailer /Root");
     233               0 :         return FALSE;
     234                 :     }
     235                 : 
     236                 :     /* Find Info object */
     237              26 :     const char* pszInfo = strstr(szBuf, "/Info");
     238              26 :     if (pszInfo != NULL)
     239                 :     {
     240               4 :         pszInfo += 5;
     241              12 :         while(*pszInfo == ' ')
     242               4 :             pszInfo ++;
     243                 : 
     244               4 :         if (!ParseIndirectRef(pszInfo, nInfoId, nInfoGen))
     245                 :         {
     246               0 :             CPLError(CE_Failure, CPLE_AppDefined, "Cannot parse trailer /Info");
     247               0 :             nInfoId = nInfoGen = 0;
     248                 :         }
     249                 :     }
     250                 : 
     251              26 :     VSIFSeekL(fp, 0, SEEK_END);
     252                 : 
     253              26 :     return TRUE;
     254                 : }
     255                 : 
     256                 : /************************************************************************/
     257                 : /*                              Close()                                 */
     258                 : /************************************************************************/
     259                 : 
     260             158 : void GDALPDFWriter::Close()
     261                 : {
     262             158 :     if (fp)
     263                 :     {
     264              79 :         CPLAssert(!bInWriteObj);
     265              79 :         if (nPageResourceId)
     266                 :         {
     267              53 :             WritePages();
     268              53 :             WriteXRefTableAndTrailer();
     269                 :         }
     270              26 :         else if (bCanUpdate)
     271                 :         {
     272              22 :             WriteXRefTableAndTrailer();
     273                 :         }
     274              79 :         VSIFCloseL(fp);
     275                 :     }
     276             158 :     fp = NULL;
     277             158 : }
     278                 : 
     279                 : /************************************************************************/
     280                 : /*                           UpdateProj()                               */
     281                 : /************************************************************************/
     282                 : 
     283              10 : void GDALPDFWriter::UpdateProj(GDALDataset* poSrcDS,
     284                 :                                double dfDPI,
     285                 :                                GDALPDFDictionaryRW* poPageDict,
     286                 :                                int nPageNum, int nPageGen)
     287                 : {
     288              10 :     bCanUpdate = TRUE;
     289              10 :     if ((int)asXRefEntries.size() < nLastXRefSize - 1)
     290              10 :         asXRefEntries.resize(nLastXRefSize - 1);
     291                 : 
     292              10 :     int nViewportId = 0;
     293              10 :     int nLGIDictId = 0;
     294                 : 
     295              10 :     CPLAssert(nPageNum != 0);
     296              10 :     CPLAssert(poPageDict != NULL);
     297                 : 
     298              10 :     PDFMargins sMargins = {0, 0, 0, 0};
     299                 : 
     300              10 :     const char* pszGEO_ENCODING = CPLGetConfigOption("GDAL_PDF_GEO_ENCODING", "ISO32000");
     301              10 :     if (EQUAL(pszGEO_ENCODING, "ISO32000") || EQUAL(pszGEO_ENCODING, "BOTH"))
     302               9 :         nViewportId = WriteSRS_ISO32000(poSrcDS, dfDPI / 72.0, NULL, &sMargins, TRUE);
     303              10 :     if (EQUAL(pszGEO_ENCODING, "OGC_BP") || EQUAL(pszGEO_ENCODING, "BOTH"))
     304               1 :         nLGIDictId = WriteSRS_OGC_BP(poSrcDS, dfDPI / 72.0, NULL, &sMargins);
     305                 : 
     306                 : #ifdef invalidate_xref_entry
     307                 :     GDALPDFObject* poVP = poPageDict->Get("VP");
     308                 :     if (poVP)
     309                 :     {
     310                 :         if (poVP->GetType() == PDFObjectType_Array &&
     311                 :             poVP->GetArray()->GetLength() == 1)
     312                 :             poVP = poVP->GetArray()->Get(0);
     313                 : 
     314                 :         int nVPId = poVP->GetRefNum();
     315                 :         if (nVPId)
     316                 :         {
     317                 :             asXRefEntries[nVPId - 1].bFree = TRUE;
     318                 :             asXRefEntries[nVPId - 1].nGen ++;
     319                 :         }
     320                 :     }
     321                 : #endif
     322                 : 
     323              10 :     poPageDict->Remove("VP");
     324              10 :     poPageDict->Remove("LGIDict");
     325                 : 
     326              10 :     if (nViewportId)
     327                 :     {
     328                 :         poPageDict->Add("VP", &((new GDALPDFArrayRW())->
     329               7 :                 Add(nViewportId, 0)));
     330                 :     }
     331                 : 
     332              10 :     if (nLGIDictId)
     333                 :     {
     334               1 :         poPageDict->Add("LGIDict", nLGIDictId, 0);
     335                 :     }
     336                 : 
     337              10 :     StartObj(nPageNum, nPageGen);
     338              10 :     VSIFPrintfL(fp, "%s\n", poPageDict->Serialize().c_str());
     339              10 :     EndObj();
     340              10 : }
     341                 : 
     342                 : /************************************************************************/
     343                 : /*                           UpdateInfo()                               */
     344                 : /************************************************************************/
     345                 : 
     346               6 : void GDALPDFWriter::UpdateInfo(GDALDataset* poSrcDS)
     347                 : {
     348               6 :     bCanUpdate = TRUE;
     349               6 :     if ((int)asXRefEntries.size() < nLastXRefSize - 1)
     350               6 :         asXRefEntries.resize(nLastXRefSize - 1);
     351                 : 
     352               6 :     int nNewInfoId = SetInfo(poSrcDS, NULL);
     353                 :     /* Write empty info, because podofo driver will find the dangling info instead */
     354               6 :     if (nNewInfoId == 0 && nInfoId != 0)
     355                 :     {
     356                 : #ifdef invalidate_xref_entry
     357                 :         asXRefEntries[nInfoId - 1].bFree = TRUE;
     358                 :         asXRefEntries[nInfoId - 1].nGen ++;
     359                 : #else
     360               2 :         StartObj(nInfoId, nInfoGen);
     361               2 :         VSIFPrintfL(fp, "<< >>\n");
     362               2 :         EndObj();
     363                 : #endif
     364                 :     }
     365               6 : }
     366                 : 
     367                 : /************************************************************************/
     368                 : /*                           UpdateXMP()                                */
     369                 : /************************************************************************/
     370                 : 
     371               6 : void GDALPDFWriter::UpdateXMP(GDALDataset* poSrcDS,
     372                 :                               GDALPDFDictionaryRW* poCatalogDict)
     373                 : {
     374               6 :     bCanUpdate = TRUE;
     375               6 :     if ((int)asXRefEntries.size() < nLastXRefSize - 1)
     376               6 :         asXRefEntries.resize(nLastXRefSize - 1);
     377                 : 
     378               6 :     CPLAssert(nCatalogId != 0);
     379               6 :     CPLAssert(poCatalogDict != NULL);
     380                 : 
     381               6 :     GDALPDFObject* poMetadata = poCatalogDict->Get("Metadata");
     382               6 :     if (poMetadata)
     383                 :     {
     384               4 :         nXMPId = poMetadata->GetRefNum();
     385               4 :         nXMPGen = poMetadata->GetRefGen();
     386                 :     }
     387                 : 
     388               6 :     poCatalogDict->Remove("Metadata");
     389               6 :     int nNewXMPId = SetXMP(poSrcDS, NULL);
     390                 : 
     391                 :     /* Write empty metadata, because podofo driver will find the dangling info instead */
     392               6 :     if (nNewXMPId == 0 && nXMPId != 0)
     393                 :     {
     394               2 :         StartObj(nXMPId, nXMPGen);
     395               2 :         VSIFPrintfL(fp, "<< >>\n");
     396               2 :         EndObj();
     397                 :     }
     398                 : 
     399               6 :     if (nXMPId)
     400               6 :         poCatalogDict->Add("Metadata", nXMPId, 0);
     401                 : 
     402               6 :     StartObj(nCatalogId, nCatalogGen);
     403               6 :     VSIFPrintfL(fp, "%s\n", poCatalogDict->Serialize().c_str());
     404               6 :     EndObj();
     405               6 : }
     406                 : 
     407                 : /************************************************************************/
     408                 : /*                           AllocNewObject()                           */
     409                 : /************************************************************************/
     410                 : 
     411            1044 : int GDALPDFWriter::AllocNewObject()
     412                 : {
     413            1044 :     asXRefEntries.push_back(GDALXRefEntry());
     414            1044 :     return (int)asXRefEntries.size();
     415                 : }
     416                 : 
     417                 : /************************************************************************/
     418                 : /*                        WriteXRefTableAndTrailer()                    */
     419                 : /************************************************************************/
     420                 : 
     421              75 : void GDALPDFWriter::WriteXRefTableAndTrailer()
     422                 : {
     423              75 :     vsi_l_offset nOffsetXREF = VSIFTellL(fp);
     424              75 :     VSIFPrintfL(fp, "xref\n");
     425                 : 
     426                 :     char buffer[16];
     427              75 :     if (bCanUpdate)
     428                 :     {
     429              22 :         VSIFPrintfL(fp, "0 1\n");
     430              22 :         VSIFPrintfL(fp, "0000000000 65535 f \n");
     431             332 :         for(size_t i=0;i<asXRefEntries.size();)
     432                 :         {
     433             288 :             if (asXRefEntries[i].nOffset != 0 || asXRefEntries[i].bFree)
     434                 :             {
     435                 :                 /* Find number of consecutive objects */
     436              36 :                 size_t nCount = 1;
     437              86 :                 while(i + nCount <asXRefEntries.size() &&
     438                 :                     (asXRefEntries[i + nCount].nOffset != 0 || asXRefEntries[i + nCount].bFree))
     439              14 :                     nCount ++;
     440                 : 
     441              36 :                 VSIFPrintfL(fp, "%d %d\n", (int)i + 1, (int)nCount);
     442              36 :                 size_t iEnd = i + nCount;
     443              86 :                 for(; i < iEnd; i++)
     444                 :                 {
     445                 :                     snprintf (buffer, sizeof(buffer),
     446                 :                               "%010" CPL_FRMT_GB_WITHOUT_PREFIX "u",
     447              50 :                               asXRefEntries[i].nOffset);
     448                 :                     VSIFPrintfL(fp, "%s %05d %c \n",
     449                 :                                 buffer, asXRefEntries[i].nGen,
     450              50 :                                 asXRefEntries[i].bFree ? 'f' : 'n');
     451                 :                 }
     452                 :             }
     453                 :             else
     454                 :             {
     455             252 :                 i++;
     456                 :             }
     457                 :         }
     458                 :     }
     459                 :     else
     460                 :     {
     461                 :         VSIFPrintfL(fp, "%d %d\n",
     462              53 :                     0, (int)asXRefEntries.size() + 1);
     463              53 :         VSIFPrintfL(fp, "0000000000 65535 f \n");
     464            1071 :         for(size_t i=0;i<asXRefEntries.size();i++)
     465                 :         {
     466                 :             snprintf (buffer, sizeof(buffer),
     467                 :                       "%010" CPL_FRMT_GB_WITHOUT_PREFIX "u",
     468            1018 :                       asXRefEntries[i].nOffset);
     469            1018 :             VSIFPrintfL(fp, "%s %05d n \n", buffer, asXRefEntries[i].nGen);
     470                 :         }
     471                 :     }
     472                 : 
     473              75 :     VSIFPrintfL(fp, "trailer\n");
     474              75 :     GDALPDFDictionaryRW oDict;
     475                 :     oDict.Add("Size", (int)asXRefEntries.size() + 1)
     476              75 :          .Add("Root", nCatalogId, nCatalogGen);
     477              75 :     if (nInfoId)
     478               8 :         oDict.Add("Info", nInfoId, nInfoGen);
     479              75 :     if (nLastStartXRef)
     480              22 :         oDict.Add("Prev", (double)nLastStartXRef);
     481              75 :     VSIFPrintfL(fp, "%s\n", oDict.Serialize().c_str());
     482                 : 
     483                 :     VSIFPrintfL(fp,
     484                 :                 "startxref\n"
     485                 :                 CPL_FRMT_GUIB "\n"
     486                 :                 "%%%%EOF\n",
     487              75 :                 nOffsetXREF);
     488              75 : }
     489                 : 
     490                 : /************************************************************************/
     491                 : /*                              StartObj()                              */
     492                 : /************************************************************************/
     493                 : 
     494            1068 : void GDALPDFWriter::StartObj(int nObjectId, int nGen)
     495                 : {
     496            1068 :     CPLAssert(!bInWriteObj);
     497            1068 :     CPLAssert(nObjectId - 1 < (int)asXRefEntries.size());
     498            1068 :     CPLAssert(asXRefEntries[nObjectId - 1].nOffset == 0);
     499            1068 :     asXRefEntries[nObjectId - 1].nOffset = VSIFTellL(fp);
     500            1068 :     asXRefEntries[nObjectId - 1].nGen = nGen;
     501            1068 :     VSIFPrintfL(fp, "%d %d obj\n", nObjectId, nGen);
     502            1068 :     bInWriteObj = TRUE;
     503            1068 : }
     504                 : 
     505                 : /************************************************************************/
     506                 : /*                               EndObj()                               */
     507                 : /************************************************************************/
     508                 : 
     509            1068 : void GDALPDFWriter::EndObj()
     510                 : {
     511            1068 :     CPLAssert(bInWriteObj);
     512            1068 :     VSIFPrintfL(fp, "endobj\n");
     513            1068 :     bInWriteObj = FALSE;
     514            1068 : }
     515                 : 
     516                 : 
     517                 : /************************************************************************/
     518                 : /*                         GDALPDFFind4Corners()                        */
     519                 : /************************************************************************/
     520                 : 
     521                 : static
     522              12 : void GDALPDFFind4Corners(const GDAL_GCP* pasGCPList,
     523                 :                          int& iUL, int& iUR, int& iLR, int& iLL)
     524                 : {
     525              12 :     double dfMeanX = 0, dfMeanY = 0;
     526                 :     int i;
     527                 : 
     528              12 :     iUL = 0;
     529              12 :     iUR = 0;
     530              12 :     iLR = 0;
     531              12 :     iLL = 0;
     532                 : 
     533              60 :     for(i = 0; i < 4; i++ )
     534                 :     {
     535              48 :         dfMeanX += pasGCPList[i].dfGCPPixel;
     536              48 :         dfMeanY += pasGCPList[i].dfGCPLine;
     537                 :     }
     538              12 :     dfMeanX /= 4;
     539              12 :     dfMeanY /= 4;
     540                 : 
     541              60 :     for(i = 0; i < 4; i++ )
     542                 :     {
     543              84 :         if (pasGCPList[i].dfGCPPixel < dfMeanX &&
     544              24 :             pasGCPList[i].dfGCPLine  < dfMeanY )
     545              12 :             iUL = i;
     546                 : 
     547              72 :         else if (pasGCPList[i].dfGCPPixel > dfMeanX &&
     548              24 :                     pasGCPList[i].dfGCPLine  < dfMeanY )
     549              12 :             iUR = i;
     550                 : 
     551              48 :         else if (pasGCPList[i].dfGCPPixel > dfMeanX &&
     552              12 :                     pasGCPList[i].dfGCPLine  > dfMeanY )
     553              12 :             iLR = i;
     554                 : 
     555              24 :         else if (pasGCPList[i].dfGCPPixel < dfMeanX &&
     556              12 :                     pasGCPList[i].dfGCPLine  > dfMeanY )
     557              12 :             iLL = i;
     558                 :     }
     559              12 : }
     560                 : 
     561                 : /************************************************************************/
     562                 : /*                         WriteSRS_ISO32000()                          */
     563                 : /************************************************************************/
     564                 : 
     565              54 : int  GDALPDFWriter::WriteSRS_ISO32000(GDALDataset* poSrcDS,
     566                 :                                       double dfUserUnit,
     567                 :                                       const char* pszNEATLINE,
     568                 :                                       PDFMargins* psMargins,
     569                 :                                       int bWriteViewport)
     570                 : {
     571              54 :     int  nWidth = poSrcDS->GetRasterXSize();
     572              54 :     int  nHeight = poSrcDS->GetRasterYSize();
     573              54 :     const char* pszWKT = poSrcDS->GetProjectionRef();
     574                 :     double adfGeoTransform[6];
     575                 : 
     576              54 :     int bHasGT = (poSrcDS->GetGeoTransform(adfGeoTransform) == CE_None);
     577              54 :     const GDAL_GCP* pasGCPList = (poSrcDS->GetGCPCount() == 4) ? poSrcDS->GetGCPs() : NULL;
     578              54 :     if (pasGCPList != NULL)
     579               1 :         pszWKT = poSrcDS->GetGCPProjection();
     580                 : 
     581              54 :     if( !bHasGT && pasGCPList == NULL )
     582               6 :         return 0;
     583                 : 
     584              48 :     if( pszWKT == NULL || EQUAL(pszWKT, "") )
     585               2 :         return 0;
     586                 : 
     587                 :     double adfGPTS[8];
     588                 : 
     589              46 :     double dfULPixel = 0;
     590              46 :     double dfULLine = 0;
     591              46 :     double dfLRPixel = nWidth;
     592              46 :     double dfLRLine = nHeight;
     593                 : 
     594                 :     GDAL_GCP asNeatLineGCPs[4];
     595              46 :     if (pszNEATLINE == NULL)
     596              45 :         pszNEATLINE = poSrcDS->GetMetadataItem("NEATLINE");
     597              46 :     if( bHasGT && pszNEATLINE != NULL && pszNEATLINE[0] != '\0' )
     598                 :     {
     599               5 :         OGRGeometry* poGeom = NULL;
     600               5 :         OGRGeometryFactory::createFromWkt( (char**)&pszNEATLINE, NULL, &poGeom );
     601               5 :         if ( poGeom != NULL && wkbFlatten(poGeom->getGeometryType()) == wkbPolygon )
     602                 :         {
     603               5 :             OGRLineString* poLS = ((OGRPolygon*)poGeom)->getExteriorRing();
     604                 :             double adfGeoTransformInv[6];
     605               5 :             if( poLS != NULL && poLS->getNumPoints() == 5 &&
     606                 :                 GDALInvGeoTransform(adfGeoTransform, adfGeoTransformInv) )
     607                 :             {
     608              25 :                 for(int i=0;i<4;i++)
     609                 :                 {
     610              20 :                     double X = asNeatLineGCPs[i].dfGCPX = poLS->getX(i);
     611              20 :                     double Y = asNeatLineGCPs[i].dfGCPY = poLS->getY(i);
     612              20 :                     double x = adfGeoTransformInv[0] + X * adfGeoTransformInv[1] + Y * adfGeoTransformInv[2];
     613              20 :                     double y = adfGeoTransformInv[3] + X * adfGeoTransformInv[4] + Y * adfGeoTransformInv[5];
     614              20 :                     asNeatLineGCPs[i].dfGCPPixel = x;
     615              20 :                     asNeatLineGCPs[i].dfGCPLine = y;
     616                 :                 }
     617                 : 
     618               5 :                 int iUL = 0, iUR = 0, iLR = 0, iLL = 0;
     619                 :                 GDALPDFFind4Corners(asNeatLineGCPs,
     620               5 :                                     iUL,iUR, iLR, iLL);
     621                 : 
     622               5 :                 if (fabs(asNeatLineGCPs[iUL].dfGCPPixel - asNeatLineGCPs[iLL].dfGCPPixel) > .5 ||
     623                 :                     fabs(asNeatLineGCPs[iUR].dfGCPPixel - asNeatLineGCPs[iLR].dfGCPPixel) > .5 ||
     624                 :                     fabs(asNeatLineGCPs[iUL].dfGCPLine - asNeatLineGCPs[iUR].dfGCPLine) > .5 ||
     625                 :                     fabs(asNeatLineGCPs[iLL].dfGCPLine - asNeatLineGCPs[iLR].dfGCPLine) > .5)
     626                 :                 {
     627                 :                     CPLError(CE_Warning, CPLE_NotSupported,
     628               0 :                             "Neatline coordinates should form a rectangle in pixel space. Ignoring it");
     629               0 :                     for(int i=0;i<4;i++)
     630                 :                     {
     631                 :                         CPLDebug("PDF", "pixel[%d] = %.1f, line[%d] = %.1f",
     632                 :                                 i, asNeatLineGCPs[i].dfGCPPixel,
     633               0 :                                 i, asNeatLineGCPs[i].dfGCPLine);
     634                 :                     }
     635                 :                 }
     636                 :                 else
     637                 :                 {
     638               5 :                     pasGCPList = asNeatLineGCPs;
     639                 :                 }
     640                 :             }
     641                 :         }
     642               5 :         delete poGeom;
     643                 :     }
     644                 : 
     645              46 :     if( pasGCPList )
     646                 :     {
     647               6 :         int iUL = 0, iUR = 0, iLR = 0, iLL = 0;
     648                 :         GDALPDFFind4Corners(pasGCPList,
     649               6 :                             iUL,iUR, iLR, iLL);
     650                 : 
     651              42 :         if (fabs(pasGCPList[iUL].dfGCPPixel - pasGCPList[iLL].dfGCPPixel) > .5 ||
     652              12 :             fabs(pasGCPList[iUR].dfGCPPixel - pasGCPList[iLR].dfGCPPixel) > .5 ||
     653              12 :             fabs(pasGCPList[iUL].dfGCPLine - pasGCPList[iUR].dfGCPLine) > .5 ||
     654              12 :             fabs(pasGCPList[iLL].dfGCPLine - pasGCPList[iLR].dfGCPLine) > .5)
     655                 :         {
     656                 :             CPLError(CE_Failure, CPLE_NotSupported,
     657               0 :                      "GCPs should form a rectangle in pixel space");
     658               0 :             return 0;
     659                 :         }
     660                 :         
     661               6 :         dfULPixel = pasGCPList[iUL].dfGCPPixel;
     662               6 :         dfULLine = pasGCPList[iUL].dfGCPLine;
     663               6 :         dfLRPixel = pasGCPList[iLR].dfGCPPixel;
     664               6 :         dfLRLine = pasGCPList[iLR].dfGCPLine;
     665                 :         
     666                 :         /* Upper-left */
     667               6 :         adfGPTS[0] = pasGCPList[iUL].dfGCPX;
     668               6 :         adfGPTS[1] = pasGCPList[iUL].dfGCPY;
     669                 :         
     670                 :         /* Lower-left */
     671               6 :         adfGPTS[2] = pasGCPList[iLL].dfGCPX;
     672               6 :         adfGPTS[3] = pasGCPList[iLL].dfGCPY;
     673                 :         
     674                 :         /* Lower-right */
     675               6 :         adfGPTS[4] = pasGCPList[iLR].dfGCPX;
     676               6 :         adfGPTS[5] = pasGCPList[iLR].dfGCPY;
     677                 :         
     678                 :         /* Upper-right */
     679               6 :         adfGPTS[6] = pasGCPList[iUR].dfGCPX;
     680               6 :         adfGPTS[7] = pasGCPList[iUR].dfGCPY;
     681                 :     }
     682                 :     else
     683                 :     {
     684                 :         /* Upper-left */
     685              40 :         adfGPTS[0] = PIXEL_TO_GEO_X(0, 0);
     686              40 :         adfGPTS[1] = PIXEL_TO_GEO_Y(0, 0);
     687                 : 
     688                 :         /* Lower-left */
     689              40 :         adfGPTS[2] = PIXEL_TO_GEO_X(0, nHeight);
     690              40 :         adfGPTS[3] = PIXEL_TO_GEO_Y(0, nHeight);
     691                 : 
     692                 :         /* Lower-right */
     693              40 :         adfGPTS[4] = PIXEL_TO_GEO_X(nWidth, nHeight);
     694              40 :         adfGPTS[5] = PIXEL_TO_GEO_Y(nWidth, nHeight);
     695                 : 
     696                 :         /* Upper-right */
     697              40 :         adfGPTS[6] = PIXEL_TO_GEO_X(nWidth, 0);
     698              40 :         adfGPTS[7] = PIXEL_TO_GEO_Y(nWidth, 0);
     699                 :     }
     700                 :     
     701              46 :     OGRSpatialReferenceH hSRS = OSRNewSpatialReference(pszWKT);
     702              46 :     if( hSRS == NULL )
     703               0 :         return 0;
     704              46 :     OGRSpatialReferenceH hSRSGeog = OSRCloneGeogCS(hSRS);
     705              46 :     if( hSRSGeog == NULL )
     706                 :     {
     707               0 :         OSRDestroySpatialReference(hSRS);
     708               0 :         return 0;
     709                 :     }
     710              46 :     OGRCoordinateTransformationH hCT = OCTNewCoordinateTransformation( hSRS, hSRSGeog);
     711              46 :     if( hCT == NULL )
     712                 :     {
     713               0 :         OSRDestroySpatialReference(hSRS);
     714               0 :         OSRDestroySpatialReference(hSRSGeog);
     715               0 :         return 0;
     716                 :     }
     717                 : 
     718              46 :     int bSuccess = TRUE;
     719                 :     
     720              46 :     bSuccess &= (OCTTransform( hCT, 1, adfGPTS + 0, adfGPTS + 1, NULL ) == 1);
     721              46 :     bSuccess &= (OCTTransform( hCT, 1, adfGPTS + 2, adfGPTS + 3, NULL ) == 1);
     722              46 :     bSuccess &= (OCTTransform( hCT, 1, adfGPTS + 4, adfGPTS + 5, NULL ) == 1);
     723              46 :     bSuccess &= (OCTTransform( hCT, 1, adfGPTS + 6, adfGPTS + 7, NULL ) == 1);
     724                 : 
     725              46 :     if (!bSuccess)
     726                 :     {
     727               0 :         OSRDestroySpatialReference(hSRS);
     728               0 :         OSRDestroySpatialReference(hSRSGeog);
     729               0 :         OCTDestroyCoordinateTransformation(hCT);
     730               0 :         return 0;
     731                 :     }
     732                 : 
     733              46 :     const char * pszAuthorityCode = OSRGetAuthorityCode( hSRS, NULL );
     734              46 :     const char * pszAuthorityName = OSRGetAuthorityName( hSRS, NULL );
     735              46 :     int nEPSGCode = 0;
     736              46 :     if( pszAuthorityName != NULL && EQUAL(pszAuthorityName, "EPSG") &&
     737                 :         pszAuthorityCode != NULL )
     738              44 :         nEPSGCode = atoi(pszAuthorityCode);
     739                 : 
     740              46 :     int bIsGeographic = OSRIsGeographic(hSRS);
     741                 : 
     742              46 :     OSRMorphToESRI(hSRS);
     743              46 :     char* pszESRIWKT = NULL;
     744              46 :     OSRExportToWkt(hSRS, &pszESRIWKT);
     745                 : 
     746              46 :     OSRDestroySpatialReference(hSRS);
     747              46 :     OSRDestroySpatialReference(hSRSGeog);
     748              46 :     OCTDestroyCoordinateTransformation(hCT);
     749              46 :     hSRS = NULL;
     750              46 :     hSRSGeog = NULL;
     751              46 :     hCT = NULL;
     752                 : 
     753              46 :     if (pszESRIWKT == NULL)
     754               0 :         return 0;
     755                 : 
     756              46 :     int nViewportId = (bWriteViewport) ? AllocNewObject() : 0;
     757              46 :     int nMeasureId = AllocNewObject();
     758              46 :     int nGCSId = AllocNewObject();
     759                 : 
     760              46 :     if (nViewportId)
     761                 :     {
     762              44 :         StartObj(nViewportId);
     763              44 :         GDALPDFDictionaryRW oViewPortDict;
     764                 :         oViewPortDict.Add("Type", GDALPDFObjectRW::CreateName("Viewport"))
     765                 :                     .Add("Name", "Layer")
     766                 :                     .Add("BBox", &((new GDALPDFArrayRW())
     767                 :                                     ->Add(dfULPixel / dfUserUnit + psMargins->nLeft)
     768                 :                                     .Add((nHeight - dfLRLine) / dfUserUnit + psMargins->nBottom)
     769                 :                                     .Add(dfLRPixel / dfUserUnit + psMargins->nLeft)
     770                 :                                     .Add((nHeight - dfULLine) / dfUserUnit + psMargins->nBottom)))
     771              44 :                     .Add("Measure", nMeasureId, 0);
     772              44 :         VSIFPrintfL(fp, "%s\n", oViewPortDict.Serialize().c_str());
     773              44 :         EndObj();
     774                 :     }
     775                 : 
     776              46 :     StartObj(nMeasureId);
     777              46 :     GDALPDFDictionaryRW oMeasureDict;
     778                 :     oMeasureDict .Add("Type", GDALPDFObjectRW::CreateName("Measure"))
     779                 :                  .Add("Subtype", GDALPDFObjectRW::CreateName("GEO"))
     780                 :                  .Add("Bounds", &((new GDALPDFArrayRW())
     781                 :                                 ->Add(0).Add(1).
     782                 :                                   Add(0).Add(0).
     783                 :                                   Add(1).Add(0).
     784                 :                                   Add(1).Add(1)))
     785                 :                  .Add("GPTS", &((new GDALPDFArrayRW())
     786                 :                                 ->Add(adfGPTS[1]).Add(adfGPTS[0]).
     787                 :                                   Add(adfGPTS[3]).Add(adfGPTS[2]).
     788                 :                                   Add(adfGPTS[5]).Add(adfGPTS[4]).
     789                 :                                   Add(adfGPTS[7]).Add(adfGPTS[6])))
     790                 :                  .Add("LPTS", &((new GDALPDFArrayRW())
     791                 :                                 ->Add(0).Add(1).
     792                 :                                   Add(0).Add(0).
     793                 :                                   Add(1).Add(0).
     794                 :                                   Add(1).Add(1)))
     795              46 :                  .Add("GCS", nGCSId, 0);
     796              46 :     VSIFPrintfL(fp, "%s\n", oMeasureDict.Serialize().c_str());
     797              46 :     EndObj();
     798                 : 
     799                 : 
     800              46 :     StartObj(nGCSId);
     801              46 :     GDALPDFDictionaryRW oGCSDict;
     802                 :     oGCSDict.Add("Type", GDALPDFObjectRW::CreateName(bIsGeographic ? "GEOGCS" : "PROJCS"))
     803              46 :             .Add("WKT", pszESRIWKT);
     804              46 :     if (nEPSGCode)
     805              44 :         oGCSDict.Add("EPSG", nEPSGCode);
     806              46 :     VSIFPrintfL(fp, "%s\n", oGCSDict.Serialize().c_str());
     807              46 :     EndObj();
     808                 : 
     809              46 :     CPLFree(pszESRIWKT);
     810                 : 
     811              46 :     return nViewportId ? nViewportId : nMeasureId;
     812                 : }
     813                 : 
     814                 : /************************************************************************/
     815                 : /*                     GDALPDFBuildOGC_BP_Datum()                       */
     816                 : /************************************************************************/
     817                 : 
     818               7 : static GDALPDFObject* GDALPDFBuildOGC_BP_Datum(const OGRSpatialReference* poSRS)
     819                 : {
     820               7 :     const OGR_SRSNode* poDatumNode = poSRS->GetAttrNode("DATUM");
     821               7 :     const char* pszDatumDescription = NULL;
     822               7 :     if (poDatumNode && poDatumNode->GetChildCount() > 0)
     823               7 :         pszDatumDescription = poDatumNode->GetChild(0)->GetValue();
     824                 : 
     825               7 :     GDALPDFObjectRW* poPDFDatum = NULL;
     826                 : 
     827               7 :     if (pszDatumDescription)
     828                 :     {
     829               7 :         double dfSemiMajor = poSRS->GetSemiMajor();
     830               7 :         double dfInvFlattening = poSRS->GetInvFlattening();
     831               7 :         int nEPSGDatum = -1;
     832               7 :         const char *pszAuthority = poSRS->GetAuthorityName( "DATUM" );
     833               7 :         if( pszAuthority != NULL && EQUAL(pszAuthority,"EPSG") )
     834               7 :             nEPSGDatum = atoi(poSRS->GetAuthorityCode( "DATUM" ));
     835                 : 
     836               8 :         if( EQUAL(pszDatumDescription,SRS_DN_WGS84) || nEPSGDatum == 6326 )
     837               1 :             poPDFDatum = GDALPDFObjectRW::CreateString("WGE");
     838              12 :         else if( EQUAL(pszDatumDescription, SRS_DN_NAD27) || nEPSGDatum == 6267 )
     839               6 :             poPDFDatum = GDALPDFObjectRW::CreateString("NAS");
     840               0 :         else if( EQUAL(pszDatumDescription, SRS_DN_NAD83) || nEPSGDatum == 6269 )
     841               0 :             poPDFDatum = GDALPDFObjectRW::CreateString("NAR");
     842                 :         else
     843                 :         {
     844                 :             CPLDebug("PDF",
     845                 :                      "Unhandled datum name (%s). Write datum parameters then.",
     846               0 :                      pszDatumDescription);
     847                 : 
     848               0 :             GDALPDFDictionaryRW* poPDFDatumDict = new GDALPDFDictionaryRW();
     849               0 :             poPDFDatum = GDALPDFObjectRW::CreateDictionary(poPDFDatumDict);
     850                 : 
     851               0 :             const OGR_SRSNode* poSpheroidNode = poSRS->GetAttrNode("SPHEROID");
     852               0 :             if (poSpheroidNode && poSpheroidNode->GetChildCount() >= 3)
     853                 :             {
     854               0 :                 poPDFDatumDict->Add("Description", pszDatumDescription);
     855                 : 
     856               0 :                 const char* pszEllipsoidCode = NULL;
     857                 : #ifdef disabled_because_terrago_toolbar_does_not_like_it
     858                 :                 if( ABS(dfSemiMajor-6378249.145) < 0.01
     859                 :                     && ABS(dfInvFlattening-293.465) < 0.0001 )
     860                 :                 {
     861                 :                     pszEllipsoidCode = "CD";     /* Clark 1880 */
     862                 :                 }
     863                 :                 else if( ABS(dfSemiMajor-6378245.0) < 0.01
     864                 :                          && ABS(dfInvFlattening-298.3) < 0.0001 )
     865                 :                 {
     866                 :                     pszEllipsoidCode = "KA";      /* Krassovsky */
     867                 :                 }
     868                 :                 else if( ABS(dfSemiMajor-6378388.0) < 0.01
     869                 :                          && ABS(dfInvFlattening-297.0) < 0.0001 )
     870                 :                 {
     871                 :                     pszEllipsoidCode = "IN";       /* International 1924 */
     872                 :                 }
     873                 :                 else if( ABS(dfSemiMajor-6378160.0) < 0.01
     874                 :                          && ABS(dfInvFlattening-298.25) < 0.0001 )
     875                 :                 {
     876                 :                     pszEllipsoidCode = "AN";    /* Australian */
     877                 :                 }
     878                 :                 else if( ABS(dfSemiMajor-6377397.155) < 0.01
     879                 :                          && ABS(dfInvFlattening-299.1528128) < 0.0001 )
     880                 :                 {
     881                 :                     pszEllipsoidCode = "BR";     /* Bessel 1841 */
     882                 :                 }
     883                 :                 else if( ABS(dfSemiMajor-6377483.865) < 0.01
     884                 :                          && ABS(dfInvFlattening-299.1528128) < 0.0001 )
     885                 :                 {
     886                 :                     pszEllipsoidCode = "BN";   /* Bessel 1841 (Namibia / Schwarzeck)*/
     887                 :                 }
     888                 : #if 0
     889                 :                 else if( ABS(dfSemiMajor-6378160.0) < 0.01
     890                 :                          && ABS(dfInvFlattening-298.247167427) < 0.0001 )
     891                 :                 {
     892                 :                     pszEllipsoidCode = "GRS67";      /* GRS 1967 */
     893                 :                 }
     894                 : #endif
     895                 :                 else if( ABS(dfSemiMajor-6378137) < 0.01
     896                 :                          && ABS(dfInvFlattening-298.257222101) < 0.000001 )
     897                 :                 {
     898                 :                     pszEllipsoidCode = "RF";      /* GRS 1980 */
     899                 :                 }
     900                 :                 else if( ABS(dfSemiMajor-6378206.4) < 0.01
     901                 :                          && ABS(dfInvFlattening-294.9786982) < 0.0001 )
     902                 :                 {
     903                 :                     pszEllipsoidCode = "CC";     /* Clarke 1866 */
     904                 :                 }
     905                 :                 else if( ABS(dfSemiMajor-6377340.189) < 0.01
     906                 :                          && ABS(dfInvFlattening-299.3249646) < 0.0001 )
     907                 :                 {
     908                 :                     pszEllipsoidCode = "AM";   /* Modified Airy */
     909                 :                 }
     910                 :                 else if( ABS(dfSemiMajor-6377563.396) < 0.01
     911                 :                          && ABS(dfInvFlattening-299.3249646) < 0.0001 )
     912                 :                 {
     913                 :                     pszEllipsoidCode = "AA";       /* Airy */
     914                 :                 }
     915                 :                 else if( ABS(dfSemiMajor-6378200) < 0.01
     916                 :                          && ABS(dfInvFlattening-298.3) < 0.0001 )
     917                 :                 {
     918                 :                     pszEllipsoidCode = "HE";    /* Helmert 1906 */
     919                 :                 }
     920                 :                 else if( ABS(dfSemiMajor-6378155) < 0.01
     921                 :                          && ABS(dfInvFlattening-298.3) < 0.0001 )
     922                 :                 {
     923                 :                     pszEllipsoidCode = "FA";   /* Modified Fischer 1960 */
     924                 :                 }
     925                 : #if 0
     926                 :                 else if( ABS(dfSemiMajor-6377298.556) < 0.01
     927                 :                          && ABS(dfInvFlattening-300.8017) < 0.0001 )
     928                 :                 {
     929                 :                     pszEllipsoidCode = "evrstSS";    /* Everest (Sabah & Sarawak) */
     930                 :                 }
     931                 :                 else if( ABS(dfSemiMajor-6378165.0) < 0.01
     932                 :                          && ABS(dfInvFlattening-298.3) < 0.0001 )
     933                 :                 {
     934                 :                     pszEllipsoidCode = "WGS60";
     935                 :                 }
     936                 :                 else if( ABS(dfSemiMajor-6378145.0) < 0.01
     937                 :                          && ABS(dfInvFlattening-298.25) < 0.0001 )
     938                 :                 {
     939                 :                     pszEllipsoidCode = "WGS66";
     940                 :                 }
     941                 : #endif
     942                 :                 else if( ABS(dfSemiMajor-6378135.0) < 0.01
     943                 :                          && ABS(dfInvFlattening-298.26) < 0.0001 )
     944                 :                 {
     945                 :                     pszEllipsoidCode = "WD";
     946                 :                 }
     947                 :                 else if( ABS(dfSemiMajor-6378137.0) < 0.01
     948                 :                          && ABS(dfInvFlattening-298.257223563) < 0.000001 )
     949                 :                 {
     950                 :                     pszEllipsoidCode = "WE";
     951                 :                 }
     952                 : #endif
     953                 : 
     954               0 :                 if( pszEllipsoidCode != NULL )
     955                 :                 {
     956               0 :                     poPDFDatumDict->Add("Ellipsoid", pszEllipsoidCode);
     957                 :                 }
     958                 :                 else
     959                 :                 {
     960                 :                     const char* pszEllipsoidDescription =
     961               0 :                         poSpheroidNode->GetChild(0)->GetValue();
     962                 : 
     963                 :                     CPLDebug("PDF",
     964                 :                          "Unhandled ellipsoid name (%s). Write ellipsoid parameters then.",
     965               0 :                          pszEllipsoidDescription);
     966                 : 
     967                 :                     poPDFDatumDict->Add("Ellipsoid",
     968                 :                         &((new GDALPDFDictionaryRW())
     969                 :                         ->Add("Description", pszEllipsoidDescription)
     970                 :                          .Add("SemiMajorAxis", dfSemiMajor, TRUE)
     971               0 :                          .Add("InvFlattening", dfInvFlattening, TRUE)));
     972                 :                 }
     973                 : 
     974               0 :                 const OGR_SRSNode *poTOWGS84 = poSRS->GetAttrNode( "TOWGS84" );
     975               0 :                 if( poTOWGS84 != NULL
     976                 :                     && poTOWGS84->GetChildCount() >= 3
     977                 :                     && (poTOWGS84->GetChildCount() < 7
     978                 :                     || (EQUAL(poTOWGS84->GetChild(3)->GetValue(),"")
     979                 :                         && EQUAL(poTOWGS84->GetChild(4)->GetValue(),"")
     980                 :                         && EQUAL(poTOWGS84->GetChild(5)->GetValue(),"")
     981                 :                         && EQUAL(poTOWGS84->GetChild(6)->GetValue(),""))) )
     982                 :                 {
     983                 :                     poPDFDatumDict->Add("ToWGS84",
     984                 :                         &((new GDALPDFDictionaryRW())
     985                 :                         ->Add("dx", poTOWGS84->GetChild(0)->GetValue())
     986                 :                          .Add("dy", poTOWGS84->GetChild(1)->GetValue())
     987               0 :                          .Add("dz", poTOWGS84->GetChild(2)->GetValue())) );
     988                 :                 }
     989               0 :                 else if( poTOWGS84 != NULL && poTOWGS84->GetChildCount() >= 7)
     990                 :                 {
     991                 :                     poPDFDatumDict->Add("ToWGS84",
     992                 :                         &((new GDALPDFDictionaryRW())
     993                 :                         ->Add("dx", poTOWGS84->GetChild(0)->GetValue())
     994                 :                          .Add("dy", poTOWGS84->GetChild(1)->GetValue())
     995                 :                          .Add("dz", poTOWGS84->GetChild(2)->GetValue())
     996                 :                          .Add("rx", poTOWGS84->GetChild(3)->GetValue())
     997                 :                          .Add("ry", poTOWGS84->GetChild(4)->GetValue())
     998                 :                          .Add("rz", poTOWGS84->GetChild(5)->GetValue())
     999               0 :                          .Add("sf", poTOWGS84->GetChild(6)->GetValue())) );
    1000                 :                 }
    1001                 :             }
    1002                 :         }
    1003                 :     }
    1004                 :     else
    1005                 :     {
    1006                 :         CPLError(CE_Warning, CPLE_NotSupported,
    1007               0 :                  "No datum name. Defaulting to WGS84.");
    1008                 :     }
    1009                 : 
    1010               7 :     if (poPDFDatum == NULL)
    1011               0 :         poPDFDatum = GDALPDFObjectRW::CreateString("WGE");
    1012                 : 
    1013               7 :     return poPDFDatum;
    1014                 : }
    1015                 : 
    1016                 : /************************************************************************/
    1017                 : /*                   GDALPDFBuildOGC_BP_Projection()                    */
    1018                 : /************************************************************************/
    1019                 : 
    1020               7 : static GDALPDFDictionaryRW* GDALPDFBuildOGC_BP_Projection(const OGRSpatialReference* poSRS)
    1021                 : {
    1022                 : 
    1023               7 :     const char* pszProjectionOGCBP = "GEOGRAPHIC";
    1024               7 :     const char *pszProjection = poSRS->GetAttrValue("PROJECTION");
    1025                 : 
    1026               7 :     GDALPDFDictionaryRW* poProjectionDict = new GDALPDFDictionaryRW();
    1027               7 :     poProjectionDict->Add("Type", GDALPDFObjectRW::CreateName("Projection"));
    1028               7 :     poProjectionDict->Add("Datum", GDALPDFBuildOGC_BP_Datum(poSRS));
    1029                 : 
    1030               7 :     if( pszProjection == NULL )
    1031                 :     {
    1032               1 :         if( poSRS->IsGeographic() )
    1033               1 :             pszProjectionOGCBP = "GEOGRAPHIC";
    1034               0 :         else if( poSRS->IsLocal() )
    1035               0 :             pszProjectionOGCBP = "LOCAL CARTESIAN";
    1036                 :         else
    1037                 :         {
    1038               0 :             CPLError(CE_Warning, CPLE_NotSupported, "Unsupported SRS type");
    1039               0 :             delete poProjectionDict;
    1040               0 :             return NULL;
    1041                 :         }
    1042                 :     }
    1043               6 :     else if( EQUAL(pszProjection, SRS_PT_TRANSVERSE_MERCATOR) )
    1044                 :     {
    1045                 :         int bNorth;
    1046               6 :         int nZone = poSRS->GetUTMZone( &bNorth );
    1047                 : 
    1048               6 :         if( nZone != 0 )
    1049                 :         {
    1050               6 :             pszProjectionOGCBP = "UT";
    1051               6 :             poProjectionDict->Add("Hemisphere", (bNorth) ? "N" : "S");
    1052               6 :             poProjectionDict->Add("Zone", nZone);
    1053                 :         }
    1054                 :         else
    1055                 :         {
    1056               0 :             double dfCenterLat = poSRS->GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,90.L);
    1057               0 :             double dfCenterLong = poSRS->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0);
    1058               0 :             double dfScale = poSRS->GetNormProjParm(SRS_PP_SCALE_FACTOR,1.0);
    1059               0 :             double dfFalseEasting = poSRS->GetNormProjParm(SRS_PP_FALSE_EASTING,0.0);
    1060               0 :             double dfFalseNorthing = poSRS->GetNormProjParm(SRS_PP_FALSE_NORTHING,0.0);
    1061                 : 
    1062                 :             /* OGC_BP supports representing numbers as strings for better precision */
    1063                 :             /* so use it */
    1064                 : 
    1065               0 :             pszProjectionOGCBP = "TC";
    1066               0 :             poProjectionDict->Add("OriginLatitude", dfCenterLat, TRUE);
    1067               0 :             poProjectionDict->Add("CentralMeridian", dfCenterLong, TRUE);
    1068               0 :             poProjectionDict->Add("ScaleFactor", dfScale, TRUE);
    1069               0 :             poProjectionDict->Add("FalseEasting", dfFalseEasting, TRUE);
    1070               0 :             poProjectionDict->Add("FalseNorthing", dfFalseNorthing, TRUE);
    1071                 :         }
    1072                 :     }
    1073               0 :     else if( EQUAL(pszProjection,SRS_PT_POLAR_STEREOGRAPHIC) )
    1074                 :     {
    1075               0 :         double dfCenterLat = poSRS->GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0);
    1076               0 :         double dfCenterLong = poSRS->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0);
    1077               0 :         double dfScale = poSRS->GetNormProjParm(SRS_PP_SCALE_FACTOR,1.0);
    1078               0 :         double dfFalseEasting = poSRS->GetNormProjParm(SRS_PP_FALSE_EASTING,0.0);
    1079               0 :         double dfFalseNorthing = poSRS->GetNormProjParm(SRS_PP_FALSE_NORTHING,0.0);
    1080                 : 
    1081               0 :         if( fabs(dfCenterLat) == 90.0 && dfCenterLong == 0.0 &&
    1082                 :             dfScale == 0.994 && dfFalseEasting == 200000.0 && dfFalseNorthing == 200000.0)
    1083                 :         {
    1084               0 :             pszProjectionOGCBP = "UP";
    1085               0 :             poProjectionDict->Add("Hemisphere", (dfCenterLat > 0) ? "N" : "S");
    1086                 :         }
    1087                 :         else
    1088                 :         {
    1089               0 :             pszProjectionOGCBP = "PG";
    1090               0 :             poProjectionDict->Add("LatitudeTrueScale", dfCenterLat, TRUE);
    1091               0 :             poProjectionDict->Add("LongitudeDownFromPole", dfCenterLong, TRUE);
    1092               0 :             poProjectionDict->Add("ScaleFactor", dfScale, TRUE);
    1093               0 :             poProjectionDict->Add("FalseEasting", dfFalseEasting, TRUE);
    1094               0 :             poProjectionDict->Add("FalseNorthing", dfFalseNorthing, TRUE);
    1095                 :         }
    1096                 :     }
    1097                 : 
    1098               0 :     else if( EQUAL(pszProjection,SRS_PT_LAMBERT_CONFORMAL_CONIC_2SP))
    1099                 :     {
    1100               0 :         double dfStdP1 = poSRS->GetNormProjParm(SRS_PP_STANDARD_PARALLEL_1,0.0);
    1101               0 :         double dfStdP2 = poSRS->GetNormProjParm(SRS_PP_STANDARD_PARALLEL_2,0.0);
    1102               0 :         double dfCenterLat = poSRS->GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0);
    1103               0 :         double dfCenterLong = poSRS->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0);
    1104               0 :         double dfFalseEasting = poSRS->GetNormProjParm(SRS_PP_FALSE_EASTING,0.0);
    1105               0 :         double dfFalseNorthing = poSRS->GetNormProjParm(SRS_PP_FALSE_NORTHING,0.0);
    1106                 : 
    1107               0 :         pszProjectionOGCBP = "LE";
    1108               0 :         poProjectionDict->Add("StandardParallelOne", dfStdP1, TRUE);
    1109               0 :         poProjectionDict->Add("StandardParallelTwo", dfStdP2, TRUE);
    1110               0 :         poProjectionDict->Add("OriginLatitude", dfCenterLat, TRUE);
    1111               0 :         poProjectionDict->Add("CentralMeridian", dfCenterLong, TRUE);
    1112               0 :         poProjectionDict->Add("FalseEasting", dfFalseEasting, TRUE);
    1113               0 :         poProjectionDict->Add("FalseNorthing", dfFalseNorthing, TRUE);
    1114                 :     }
    1115                 : 
    1116               0 :     else if( EQUAL(pszProjection,SRS_PT_MERCATOR_1SP) )
    1117                 :     {
    1118               0 :         double dfCenterLong = poSRS->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0);
    1119               0 :         double dfCenterLat = poSRS->GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0);
    1120               0 :         double dfScale = poSRS->GetNormProjParm(SRS_PP_SCALE_FACTOR,1.0);
    1121               0 :         double dfFalseEasting = poSRS->GetNormProjParm(SRS_PP_FALSE_EASTING,0.0);
    1122               0 :         double dfFalseNorthing = poSRS->GetNormProjParm(SRS_PP_FALSE_NORTHING,0.0);
    1123                 : 
    1124               0 :         pszProjectionOGCBP = "MC";
    1125               0 :         poProjectionDict->Add("CentralMeridian", dfCenterLong, TRUE);
    1126               0 :         poProjectionDict->Add("OriginLatitude", dfCenterLat, TRUE);
    1127               0 :         poProjectionDict->Add("ScaleFactor", dfScale, TRUE);
    1128               0 :         poProjectionDict->Add("FalseEasting", dfFalseEasting, TRUE);
    1129               0 :         poProjectionDict->Add("FalseNorthing", dfFalseNorthing, TRUE);
    1130                 :     }
    1131                 : 
    1132                 : #ifdef not_supported
    1133                 :     else if( EQUAL(pszProjection,SRS_PT_MERCATOR_2SP) )
    1134                 :     {
    1135                 :         double dfStdP1 = poSRS->GetNormProjParm(SRS_PP_STANDARD_PARALLEL_1,0.0);
    1136                 :         double dfCenterLong = poSRS->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0);
    1137                 :         double dfFalseEasting = poSRS->GetNormProjParm(SRS_PP_FALSE_EASTING,0.0);
    1138                 :         double dfFalseNorthing = poSRS->GetNormProjParm(SRS_PP_FALSE_NORTHING,0.0);
    1139                 : 
    1140                 :         pszProjectionOGCBP = "MC";
    1141                 :         poProjectionDict->Add("StandardParallelOne", dfStdP1, TRUE);
    1142                 :         poProjectionDict->Add("CentralMeridian", dfCenterLong, TRUE);
    1143                 :         poProjectionDict->Add("FalseEasting", dfFalseEasting, TRUE);
    1144                 :         poProjectionDict->Add("FalseNorthing", dfFalseNorthing, TRUE);
    1145                 :     }
    1146                 : #endif
    1147                 : 
    1148                 :     else
    1149                 :     {
    1150                 :         CPLError(CE_Warning, CPLE_NotSupported,
    1151               0 :                  "Unhandled projection type (%s) for now", pszProjection);
    1152                 :     }
    1153                 : 
    1154               7 :     poProjectionDict->Add("ProjectionType", pszProjectionOGCBP);
    1155                 : 
    1156               7 :     if( poSRS->IsProjected() )
    1157                 :     {
    1158               6 :         char* pszUnitName = NULL;
    1159               6 :         double dfLinearUnits = poSRS->GetLinearUnits(&pszUnitName);
    1160               6 :         if (dfLinearUnits == 1.0)
    1161               6 :             poProjectionDict->Add("Units", "M");
    1162               0 :         else if (dfLinearUnits == 0.3048)
    1163               0 :             poProjectionDict->Add("Units", "FT");
    1164                 :     }
    1165                 : 
    1166               7 :     return poProjectionDict;
    1167                 : }
    1168                 : 
    1169                 : /************************************************************************/
    1170                 : /*                           WriteSRS_OGC_BP()                          */
    1171                 : /************************************************************************/
    1172                 : 
    1173               7 : int GDALPDFWriter::WriteSRS_OGC_BP(GDALDataset* poSrcDS,
    1174                 :                                    double dfUserUnit,
    1175                 :                                    const char* pszNEATLINE,
    1176                 :                                    PDFMargins* psMargins)
    1177                 : {
    1178               7 :     int  nWidth = poSrcDS->GetRasterXSize();
    1179               7 :     int  nHeight = poSrcDS->GetRasterYSize();
    1180               7 :     const char* pszWKT = poSrcDS->GetProjectionRef();
    1181                 :     double adfGeoTransform[6];
    1182                 : 
    1183               7 :     int bHasGT = (poSrcDS->GetGeoTransform(adfGeoTransform) == CE_None);
    1184               7 :     int nGCPCount = poSrcDS->GetGCPCount();
    1185               7 :     const GDAL_GCP* pasGCPList = (nGCPCount >= 4) ? poSrcDS->GetGCPs() : NULL;
    1186               7 :     if (pasGCPList != NULL)
    1187               2 :         pszWKT = poSrcDS->GetGCPProjection();
    1188                 : 
    1189               7 :     if( !bHasGT && pasGCPList == NULL )
    1190               0 :         return 0;
    1191                 : 
    1192               7 :     if( pszWKT == NULL || EQUAL(pszWKT, "") )
    1193               0 :         return 0;
    1194                 :     
    1195               7 :     if( !bHasGT )
    1196                 :     {
    1197               2 :         if (!GDALGCPsToGeoTransform( nGCPCount, pasGCPList,
    1198                 :                                      adfGeoTransform, FALSE ))
    1199                 :         {
    1200               1 :             CPLDebug("PDF", "Could not compute GT with exact match. Writing Registration then");
    1201                 :         }
    1202                 :         else
    1203                 :         {
    1204               1 :             bHasGT = TRUE;
    1205                 :         }
    1206                 :     }
    1207                 : 
    1208               7 :     OGRSpatialReferenceH hSRS = OSRNewSpatialReference(pszWKT);
    1209               7 :     if( hSRS == NULL )
    1210               0 :         return 0;
    1211                 : 
    1212               7 :     const OGRSpatialReference* poSRS = (const OGRSpatialReference*)hSRS;
    1213               7 :     GDALPDFDictionaryRW* poProjectionDict = GDALPDFBuildOGC_BP_Projection(poSRS);
    1214               7 :     if (poProjectionDict == NULL)
    1215                 :     {
    1216               0 :         OSRDestroySpatialReference(hSRS);
    1217               0 :         return 0;
    1218                 :     }
    1219                 : 
    1220               7 :     GDALPDFArrayRW* poNeatLineArray = NULL;
    1221                 : 
    1222               7 :     if (pszNEATLINE == NULL)
    1223               6 :         pszNEATLINE = poSrcDS->GetMetadataItem("NEATLINE");
    1224               7 :     if( bHasGT && pszNEATLINE != NULL && !EQUAL(pszNEATLINE, "NO") && pszNEATLINE[0] != '\0' )
    1225                 :     {
    1226               1 :         OGRGeometry* poGeom = NULL;
    1227               1 :         OGRGeometryFactory::createFromWkt( (char**)&pszNEATLINE, NULL, &poGeom );
    1228               1 :         if ( poGeom != NULL && wkbFlatten(poGeom->getGeometryType()) == wkbPolygon )
    1229                 :         {
    1230               1 :             OGRLineString* poLS = ((OGRPolygon*)poGeom)->getExteriorRing();
    1231                 :             double adfGeoTransformInv[6];
    1232               1 :             if( poLS != NULL && poLS->getNumPoints() >= 5 &&
    1233                 :                 GDALInvGeoTransform(adfGeoTransform, adfGeoTransformInv) )
    1234                 :             {
    1235               1 :                 poNeatLineArray = new GDALPDFArrayRW();
    1236                 : 
    1237                 :                  // FIXME : ensure that they are in clockwise order ?
    1238               6 :                 for(int i=0;i<poLS->getNumPoints() - 1;i++)
    1239                 :                 {
    1240               5 :                     double X = poLS->getX(i);
    1241               5 :                     double Y = poLS->getY(i);
    1242               5 :                     double x = adfGeoTransformInv[0] + X * adfGeoTransformInv[1] + Y * adfGeoTransformInv[2];
    1243               5 :                     double y = adfGeoTransformInv[3] + X * adfGeoTransformInv[4] + Y * adfGeoTransformInv[5];
    1244               5 :                     poNeatLineArray->Add(x / dfUserUnit + psMargins->nLeft, TRUE);
    1245               5 :                     poNeatLineArray->Add((nHeight - y) / dfUserUnit + psMargins->nBottom, TRUE);
    1246                 :                 }
    1247                 :             }
    1248                 :         }
    1249               1 :         delete poGeom;
    1250                 :     }
    1251                 : 
    1252               7 :     if( pszNEATLINE != NULL && EQUAL(pszNEATLINE, "NO") )
    1253                 :     {
    1254                 :         // Do nothing
    1255                 :     }
    1256               9 :     else if( pasGCPList && poNeatLineArray == NULL)
    1257                 :     {
    1258               2 :         if (nGCPCount == 4)
    1259                 :         {
    1260               1 :             int iUL = 0, iUR = 0, iLR = 0, iLL = 0;
    1261                 :             GDALPDFFind4Corners(pasGCPList,
    1262               1 :                                 iUL,iUR, iLR, iLL);
    1263                 : 
    1264                 :             double adfNL[8];
    1265               1 :             adfNL[0] = pasGCPList[iUL].dfGCPPixel / dfUserUnit + psMargins->nLeft;
    1266               1 :             adfNL[1] = (nHeight - pasGCPList[iUL].dfGCPLine) / dfUserUnit + psMargins->nBottom;
    1267               1 :             adfNL[2] = pasGCPList[iLL].dfGCPPixel / dfUserUnit + psMargins->nLeft;
    1268               1 :             adfNL[3] = (nHeight - pasGCPList[iLL].dfGCPLine) / dfUserUnit + psMargins->nBottom;
    1269               1 :             adfNL[4] = pasGCPList[iLR].dfGCPPixel / dfUserUnit + psMargins->nLeft;
    1270               1 :             adfNL[5] = (nHeight - pasGCPList[iLR].dfGCPLine) / dfUserUnit + psMargins->nBottom;
    1271               1 :             adfNL[6] = pasGCPList[iUR].dfGCPPixel / dfUserUnit + psMargins->nLeft;
    1272               1 :             adfNL[7] = (nHeight - pasGCPList[iUR].dfGCPLine) / dfUserUnit + psMargins->nBottom;
    1273                 : 
    1274               1 :             poNeatLineArray = new GDALPDFArrayRW();
    1275               1 :             poNeatLineArray->Add(adfNL, 8, TRUE);
    1276                 :         }
    1277                 :         else
    1278                 :         {
    1279               1 :             poNeatLineArray = new GDALPDFArrayRW();
    1280                 : 
    1281                 :             // FIXME : ensure that they are in clockwise order ?
    1282                 :             int i;
    1283               6 :             for(i = 0; i < nGCPCount; i++)
    1284                 :             {
    1285               5 :                 poNeatLineArray->Add(pasGCPList[i].dfGCPPixel / dfUserUnit + psMargins->nLeft, TRUE);
    1286               5 :                 poNeatLineArray->Add((nHeight - pasGCPList[i].dfGCPLine) / dfUserUnit + psMargins->nBottom, TRUE);
    1287                 :             }
    1288                 :         }
    1289                 :     }
    1290               5 :     else if (poNeatLineArray == NULL)
    1291                 :     {
    1292               4 :         poNeatLineArray = new GDALPDFArrayRW();
    1293                 : 
    1294               4 :         poNeatLineArray->Add(0 / dfUserUnit + psMargins->nLeft, TRUE);
    1295               4 :         poNeatLineArray->Add((nHeight - 0) / dfUserUnit + psMargins->nBottom, TRUE);
    1296                 : 
    1297               4 :         poNeatLineArray->Add(0 / dfUserUnit + psMargins->nLeft, TRUE);
    1298               4 :         poNeatLineArray->Add((nHeight -nHeight) / dfUserUnit + psMargins->nBottom, TRUE);
    1299                 : 
    1300               4 :         poNeatLineArray->Add(nWidth / dfUserUnit + psMargins->nLeft, TRUE);
    1301               4 :         poNeatLineArray->Add((nHeight -nHeight) / dfUserUnit + psMargins->nBottom, TRUE);
    1302                 : 
    1303               4 :         poNeatLineArray->Add(nWidth / dfUserUnit + psMargins->nLeft, TRUE);
    1304               4 :         poNeatLineArray->Add((nHeight - 0) / dfUserUnit + psMargins->nBottom, TRUE);
    1305                 :     }
    1306                 : 
    1307               7 :     int nLGIDictId = AllocNewObject();
    1308               7 :     StartObj(nLGIDictId);
    1309               7 :     GDALPDFDictionaryRW oLGIDict;
    1310                 :     oLGIDict.Add("Type", GDALPDFObjectRW::CreateName("LGIDict"))
    1311               7 :             .Add("Version", "2.1");
    1312               7 :     if( bHasGT )
    1313                 :     {
    1314                 :         double adfCTM[6];
    1315               6 :         double dfX1 = psMargins->nLeft;
    1316               6 :         double dfY2 = nHeight / dfUserUnit + psMargins->nBottom ;
    1317                 : 
    1318               6 :         adfCTM[0] = adfGeoTransform[1] * dfUserUnit;
    1319               6 :         adfCTM[1] = adfGeoTransform[2] * dfUserUnit;
    1320               6 :         adfCTM[2] = - adfGeoTransform[4] * dfUserUnit;
    1321               6 :         adfCTM[3] = - adfGeoTransform[5] * dfUserUnit;
    1322               6 :         adfCTM[4] = adfGeoTransform[0] - (adfCTM[0] * dfX1 + adfCTM[2] * dfY2);
    1323               6 :         adfCTM[5] = adfGeoTransform[3] - (adfCTM[1] * dfX1 + adfCTM[3] * dfY2);
    1324                 : 
    1325               6 :         oLGIDict.Add("CTM", &((new GDALPDFArrayRW())->Add(adfCTM, 6, TRUE)));
    1326                 :     }
    1327                 :     else
    1328                 :     {
    1329               1 :         GDALPDFArrayRW* poRegistrationArray = new GDALPDFArrayRW();
    1330                 :         int i;
    1331               6 :         for(i = 0; i < nGCPCount; i++)
    1332                 :         {
    1333               5 :             GDALPDFArrayRW* poPTArray = new GDALPDFArrayRW();
    1334               5 :             poPTArray->Add(pasGCPList[i].dfGCPPixel / dfUserUnit + psMargins->nLeft, TRUE);
    1335               5 :             poPTArray->Add((nHeight - pasGCPList[i].dfGCPLine) / dfUserUnit + psMargins->nBottom, TRUE);
    1336               5 :             poPTArray->Add(pasGCPList[i].dfGCPX, TRUE);
    1337               5 :             poPTArray->Add(pasGCPList[i].dfGCPY, TRUE);
    1338               5 :             poRegistrationArray->Add(poPTArray);
    1339                 :         }
    1340               1 :         oLGIDict.Add("Registration", poRegistrationArray);
    1341                 :     }
    1342               7 :     if( poNeatLineArray )
    1343                 :     {
    1344               7 :         oLGIDict.Add("Neatline", poNeatLineArray);
    1345                 :     }
    1346                 : 
    1347               7 :     const OGR_SRSNode* poNode = poSRS->GetRoot();
    1348               7 :     if( poNode != NULL )
    1349               7 :         poNode = poNode->GetChild(0);
    1350               7 :     const char* pszDescription = NULL;
    1351               7 :     if( poNode != NULL )
    1352               7 :         pszDescription = poNode->GetValue();
    1353               7 :     if( pszDescription )
    1354                 :     {
    1355               7 :         oLGIDict.Add("Description", pszDescription);
    1356                 :     }
    1357                 : 
    1358               7 :     oLGIDict.Add("Projection", poProjectionDict);
    1359                 : 
    1360                 :     /* GDAL extension */
    1361               7 :     if( CSLTestBoolean( CPLGetConfigOption("GDAL_PDF_OGC_BP_WRITE_WKT", "TRUE") ) )
    1362               3 :         poProjectionDict->Add("WKT", pszWKT);
    1363                 : 
    1364               7 :     VSIFPrintfL(fp, "%s\n", oLGIDict.Serialize().c_str());
    1365               7 :     EndObj();
    1366                 : 
    1367               7 :     OSRDestroySpatialReference(hSRS);
    1368                 :     
    1369               7 :     return nLGIDictId;
    1370                 : }
    1371                 : 
    1372                 : /************************************************************************/
    1373                 : /*                     GDALPDFGetValueFromDSOrOption()                  */
    1374                 : /************************************************************************/
    1375                 : 
    1376             406 : static const char* GDALPDFGetValueFromDSOrOption(GDALDataset* poSrcDS,
    1377                 :                                                  char** papszOptions,
    1378                 :                                                  const char* pszKey)
    1379                 : {
    1380             406 :     const char* pszValue = CSLFetchNameValue(papszOptions, pszKey);
    1381             406 :     if (pszValue == NULL)
    1382             400 :         pszValue = poSrcDS->GetMetadataItem(pszKey);
    1383             406 :     if (pszValue != NULL && pszValue[0] == '\0')
    1384               2 :         return NULL;
    1385                 :     else
    1386             404 :         return pszValue;
    1387                 : }
    1388                 : 
    1389                 : /************************************************************************/
    1390                 : /*                             SetInfo()                                */
    1391                 : /************************************************************************/
    1392                 : 
    1393              58 : int GDALPDFWriter::SetInfo(GDALDataset* poSrcDS,
    1394                 :                            char** papszOptions)
    1395                 : {
    1396              58 :     const char* pszAUTHOR = GDALPDFGetValueFromDSOrOption(poSrcDS, papszOptions, "AUTHOR");
    1397              58 :     const char* pszPRODUCER = GDALPDFGetValueFromDSOrOption(poSrcDS, papszOptions, "PRODUCER");
    1398              58 :     const char* pszCREATOR = GDALPDFGetValueFromDSOrOption(poSrcDS, papszOptions, "CREATOR");
    1399              58 :     const char* pszCREATION_DATE = GDALPDFGetValueFromDSOrOption(poSrcDS, papszOptions, "CREATION_DATE");
    1400              58 :     const char* pszSUBJECT = GDALPDFGetValueFromDSOrOption(poSrcDS, papszOptions, "SUBJECT");
    1401              58 :     const char* pszTITLE = GDALPDFGetValueFromDSOrOption(poSrcDS, papszOptions, "TITLE");
    1402              58 :     const char* pszKEYWORDS = GDALPDFGetValueFromDSOrOption(poSrcDS, papszOptions, "KEYWORDS");
    1403                 : 
    1404              58 :     if (pszAUTHOR == NULL && pszPRODUCER == NULL && pszCREATOR == NULL && pszCREATION_DATE == NULL &&
    1405                 :         pszSUBJECT == NULL && pszTITLE == NULL && pszKEYWORDS == NULL)
    1406              52 :         return 0;
    1407                 : 
    1408               6 :     if (nInfoId == 0)
    1409               4 :         nInfoId = AllocNewObject();
    1410               6 :     StartObj(nInfoId, nInfoGen);
    1411               6 :     GDALPDFDictionaryRW oDict;
    1412               6 :     if (pszAUTHOR != NULL)
    1413               6 :         oDict.Add("Author", pszAUTHOR);
    1414               6 :     if (pszPRODUCER != NULL)
    1415               2 :         oDict.Add("Producer", pszPRODUCER);
    1416               6 :     if (pszCREATOR != NULL)
    1417               2 :         oDict.Add("Creator", pszCREATOR);
    1418               6 :     if (pszCREATION_DATE != NULL)
    1419               0 :         oDict.Add("CreationDate", pszCREATION_DATE);
    1420               6 :     if (pszSUBJECT != NULL)
    1421               2 :         oDict.Add("Subject", pszSUBJECT);
    1422               6 :     if (pszTITLE != NULL)
    1423               2 :         oDict.Add("Title", pszTITLE);
    1424               6 :     if (pszKEYWORDS != NULL)
    1425               2 :         oDict.Add("Keywords", pszKEYWORDS);
    1426               6 :     VSIFPrintfL(fp, "%s\n", oDict.Serialize().c_str());
    1427               6 :     EndObj();
    1428                 : 
    1429               6 :     return nInfoId;
    1430                 : }
    1431                 : 
    1432                 : /************************************************************************/
    1433                 : /*                             SetXMP()                                 */
    1434                 : /************************************************************************/
    1435                 : 
    1436              57 : int  GDALPDFWriter::SetXMP(GDALDataset* poSrcDS,
    1437                 :                            const char* pszXMP)
    1438                 : {
    1439              57 :     if (pszXMP != NULL && EQUALN(pszXMP, "NO", 2))
    1440               1 :         return 0;
    1441              56 :     if (pszXMP != NULL && pszXMP[0] == '\0')
    1442               0 :         return 0;
    1443                 : 
    1444              56 :     char** papszXMP = poSrcDS->GetMetadata("xml:XMP");
    1445              56 :     if (pszXMP == NULL && papszXMP != NULL && papszXMP[0] != NULL)
    1446               5 :         pszXMP = papszXMP[0];
    1447                 : 
    1448              56 :     if (pszXMP == NULL)
    1449              51 :         return 0;
    1450                 : 
    1451               5 :     CPLXMLNode* psNode = CPLParseXMLString(pszXMP);
    1452               5 :     if (psNode == NULL)
    1453               0 :         return 0;
    1454               5 :     CPLDestroyXMLNode(psNode);
    1455                 : 
    1456               5 :     if(nXMPId == 0)
    1457               3 :         nXMPId = AllocNewObject();
    1458               5 :     StartObj(nXMPId, nXMPGen);
    1459               5 :     GDALPDFDictionaryRW oDict;
    1460                 :     oDict.Add("Type", GDALPDFObjectRW::CreateName("Metadata"))
    1461                 :          .Add("Subtype", GDALPDFObjectRW::CreateName("XML"))
    1462               5 :          .Add("Length", (int)strlen(pszXMP));
    1463               5 :     VSIFPrintfL(fp, "%s\n", oDict.Serialize().c_str());
    1464               5 :     VSIFPrintfL(fp, "stream\n");
    1465               5 :     VSIFPrintfL(fp, "%s\n", pszXMP);
    1466               5 :     VSIFPrintfL(fp, "endstream\n");
    1467               5 :     EndObj();
    1468               5 :     return nXMPId;
    1469                 : }
    1470                 : 
    1471                 : /************************************************************************/
    1472                 : /*                              WriteOCG()                              */
    1473                 : /************************************************************************/
    1474                 : 
    1475             112 : int GDALPDFWriter::WriteOCG(const char* pszLayerName, int nParentId)
    1476                 : {
    1477             112 :     if (pszLayerName == NULL || pszLayerName[0] == '\0')
    1478             101 :         return 0;
    1479                 : 
    1480              11 :     int nOGCId = AllocNewObject();
    1481                 : 
    1482              11 :     GDALPDFOCGDesc oOCGDesc;
    1483              11 :     oOCGDesc.nId = nOGCId;
    1484              11 :     oOCGDesc.nParentId = nParentId;
    1485              11 :     oOCGDesc.osLayerName = pszLayerName;
    1486                 : 
    1487              11 :     asOCGs.push_back(oOCGDesc);
    1488                 : 
    1489              11 :     StartObj(nOGCId);
    1490                 :     {
    1491              11 :         GDALPDFDictionaryRW oDict;
    1492              11 :         oDict.Add("Type", GDALPDFObjectRW::CreateName("OCG"));
    1493              11 :         oDict.Add("Name", pszLayerName);
    1494              11 :         VSIFPrintfL(fp, "%s\n", oDict.Serialize().c_str());
    1495                 :     }
    1496              11 :     EndObj();
    1497                 : 
    1498              11 :     return nOGCId;
    1499                 : }
    1500                 : 
    1501                 : /************************************************************************/
    1502                 : /*                              StartPage()                             */
    1503                 : /************************************************************************/
    1504                 : 
    1505              53 : int GDALPDFWriter::StartPage(GDALDataset* poClippingDS,
    1506                 :                              double dfDPI,
    1507                 :                              const char* pszGEO_ENCODING,
    1508                 :                              const char* pszNEATLINE,
    1509                 :                              PDFMargins* psMargins,
    1510                 :                              PDFCompressMethod eStreamCompressMethod,
    1511                 :                              int bHasOGRData)
    1512                 : {
    1513              53 :     int  nWidth = poClippingDS->GetRasterXSize();
    1514              53 :     int  nHeight = poClippingDS->GetRasterYSize();
    1515              53 :     int  nBands = poClippingDS->GetRasterCount();
    1516                 : 
    1517              53 :     double dfUserUnit = dfDPI / 72.0;
    1518              53 :     double dfWidthInUserUnit = nWidth / dfUserUnit + psMargins->nLeft + psMargins->nRight;
    1519              53 :     double dfHeightInUserUnit = nHeight / dfUserUnit + psMargins->nBottom + psMargins->nTop;
    1520                 : 
    1521              53 :     int nPageId = AllocNewObject();
    1522              53 :     asPageId.push_back(nPageId);
    1523                 : 
    1524              53 :     int nContentId = AllocNewObject();
    1525              53 :     int nResourcesId = AllocNewObject();
    1526                 : 
    1527              53 :     int nAnnotsId = AllocNewObject();
    1528                 : 
    1529                 :     int bISO32000 = EQUAL(pszGEO_ENCODING, "ISO32000") ||
    1530              53 :                     EQUAL(pszGEO_ENCODING, "BOTH");
    1531                 :     int bOGC_BP   = EQUAL(pszGEO_ENCODING, "OGC_BP") ||
    1532              53 :                     EQUAL(pszGEO_ENCODING, "BOTH");
    1533                 : 
    1534              53 :     int nViewportId = 0;
    1535              53 :     if( bISO32000 )
    1536              43 :         nViewportId = WriteSRS_ISO32000(poClippingDS, dfUserUnit, pszNEATLINE, psMargins, TRUE);
    1537                 : 
    1538              53 :     int nLGIDictId = 0;
    1539              53 :     if( bOGC_BP )
    1540               6 :         nLGIDictId = WriteSRS_OGC_BP(poClippingDS, dfUserUnit, pszNEATLINE, psMargins);
    1541                 : 
    1542              53 :     StartObj(nPageId);
    1543              53 :     GDALPDFDictionaryRW oDictPage;
    1544                 :     oDictPage.Add("Type", GDALPDFObjectRW::CreateName("Page"))
    1545                 :              .Add("Parent", nPageResourceId, 0)
    1546                 :              .Add("MediaBox", &((new GDALPDFArrayRW())
    1547                 :                                ->Add(0).Add(0).Add(dfWidthInUserUnit).Add(dfHeightInUserUnit)))
    1548                 :              .Add("UserUnit", dfUserUnit)
    1549                 :              .Add("Contents", nContentId, 0)
    1550                 :              .Add("Resources", nResourcesId, 0)
    1551              53 :              .Add("Annots", nAnnotsId, 0);
    1552                 : 
    1553              53 :     if (nBands == 4)
    1554                 :     {
    1555                 :         oDictPage.Add("Group",
    1556                 :                       &((new GDALPDFDictionaryRW())
    1557                 :                         ->Add("Type", GDALPDFObjectRW::CreateName("Group"))
    1558                 :                          .Add("S", GDALPDFObjectRW::CreateName("Transparency"))
    1559               5 :                          .Add("CS", GDALPDFObjectRW::CreateName("DeviceRGB"))));
    1560                 :     }
    1561              53 :     if (nViewportId)
    1562                 :     {
    1563                 :         oDictPage.Add("VP", &((new GDALPDFArrayRW())
    1564              37 :                                ->Add(nViewportId, 0)));
    1565                 :     }
    1566              53 :     if (nLGIDictId)
    1567                 :     {
    1568               6 :         oDictPage.Add("LGIDict", nLGIDictId, 0);
    1569                 :     }
    1570                 : 
    1571              53 :     if (bHasOGRData)
    1572               3 :         oDictPage.Add("StructParents", 0);
    1573                 : 
    1574              53 :     VSIFPrintfL(fp, "%s\n", oDictPage.Serialize().c_str());
    1575              53 :     EndObj();
    1576                 : 
    1577              53 :     oPageContext.poClippingDS = poClippingDS;
    1578              53 :     oPageContext.nPageId = nPageId;
    1579              53 :     oPageContext.nContentId = nContentId;
    1580              53 :     oPageContext.nResourcesId = nResourcesId;
    1581              53 :     oPageContext.nAnnotsId = nAnnotsId;
    1582              53 :     oPageContext.dfDPI = dfDPI;
    1583              53 :     oPageContext.sMargins = *psMargins;
    1584              53 :     oPageContext.eStreamCompressMethod = eStreamCompressMethod;
    1585                 : 
    1586              53 :     return TRUE;
    1587                 : }
    1588                 : 
    1589                 : /************************************************************************/
    1590                 : /*                             WriteColorTable()                        */
    1591                 : /************************************************************************/
    1592                 : 
    1593             183 : int GDALPDFWriter::WriteColorTable(GDALDataset* poSrcDS)
    1594                 : {
    1595                 :     /* Does the source image has a color table ? */
    1596             183 :     GDALColorTable* poCT = NULL;
    1597             183 :     if (poSrcDS->GetRasterCount() > 0)
    1598             183 :         poCT = poSrcDS->GetRasterBand(1)->GetColorTable();
    1599             183 :     int nColorTableId = 0;
    1600             183 :     if (poCT != NULL && poCT->GetColorEntryCount() <= 256)
    1601                 :     {
    1602               1 :         int nColors = poCT->GetColorEntryCount();
    1603               1 :         nColorTableId = AllocNewObject();
    1604                 : 
    1605               1 :         int nLookupTableId = AllocNewObject();
    1606                 : 
    1607                 :         /* Index object */
    1608               1 :         StartObj(nColorTableId);
    1609                 :         {
    1610               1 :             GDALPDFArrayRW oArray;
    1611                 :             oArray.Add(GDALPDFObjectRW::CreateName("Indexed"))
    1612                 :                   .Add(&((new GDALPDFArrayRW())->Add(GDALPDFObjectRW::CreateName("DeviceRGB"))))
    1613                 :                   .Add(nColors-1)
    1614               1 :                   .Add(nLookupTableId, 0);
    1615               1 :             VSIFPrintfL(fp, "%s\n", oArray.Serialize().c_str());
    1616                 :         }
    1617               1 :         EndObj();
    1618                 : 
    1619                 :         /* Lookup table object */
    1620               1 :         StartObj(nLookupTableId);
    1621                 :         {
    1622               1 :             GDALPDFDictionaryRW oDict;
    1623               1 :             oDict.Add("Length", nColors * 3);
    1624               1 :             VSIFPrintfL(fp, "%s %% Lookup table\n", oDict.Serialize().c_str());
    1625                 :         }
    1626               1 :         VSIFPrintfL(fp, "stream\n");
    1627                 :         GByte pabyLookup[768];
    1628              17 :         for(int i=0;i<nColors;i++)
    1629                 :         {
    1630              16 :             const GDALColorEntry* poEntry = poCT->GetColorEntry(i);
    1631              16 :             pabyLookup[3 * i + 0] = (GByte)poEntry->c1;
    1632              16 :             pabyLookup[3 * i + 1] = (GByte)poEntry->c2;
    1633              16 :             pabyLookup[3 * i + 2] = (GByte)poEntry->c3;
    1634                 :         }
    1635               1 :         VSIFWriteL(pabyLookup, 3 * nColors, 1, fp);
    1636               1 :         VSIFPrintfL(fp, "\n");
    1637               1 :         VSIFPrintfL(fp, "endstream\n");
    1638               1 :         EndObj();
    1639                 :     }
    1640                 : 
    1641             183 :     return nColorTableId;
    1642                 : }
    1643                 : 
    1644                 : /************************************************************************/
    1645                 : /*                             WriteImagery()                           */
    1646                 : /************************************************************************/
    1647                 : 
    1648              50 : int GDALPDFWriter::WriteImagery(GDALDataset* poDS,
    1649                 :                                 const char* pszLayerName,
    1650                 :                                 PDFCompressMethod eCompressMethod,
    1651                 :                                 int nPredictor,
    1652                 :                                 int nJPEGQuality,
    1653                 :                                 const char* pszJPEG2000_DRIVER,
    1654                 :                                 int nBlockXSize, int nBlockYSize,
    1655                 :                                 GDALProgressFunc pfnProgress,
    1656                 :                                 void * pProgressData)
    1657                 : {
    1658              50 :     int  nWidth = poDS->GetRasterXSize();
    1659              50 :     int  nHeight = poDS->GetRasterYSize();
    1660              50 :     double dfUserUnit = oPageContext.dfDPI / 72.0;
    1661                 : 
    1662              50 :     GDALPDFRasterDesc oRasterDesc;
    1663                 : 
    1664              50 :     if( pfnProgress == NULL )
    1665               0 :         pfnProgress = GDALDummyProgress;
    1666                 : 
    1667              50 :     oRasterDesc.nOCGRasterId = WriteOCG(pszLayerName);
    1668                 : 
    1669                 :     /* Does the source image has a color table ? */
    1670              50 :     int nColorTableId = WriteColorTable(poDS);
    1671                 : 
    1672              50 :     int nXBlocks = (nWidth + nBlockXSize - 1) / nBlockXSize;
    1673              50 :     int nYBlocks = (nHeight + nBlockYSize - 1) / nBlockYSize;
    1674              50 :     int nBlocks = nXBlocks * nYBlocks;
    1675                 :     int nBlockXOff, nBlockYOff;
    1676             112 :     for(nBlockYOff = 0; nBlockYOff < nYBlocks; nBlockYOff ++)
    1677                 :     {
    1678             188 :         for(nBlockXOff = 0; nBlockXOff < nXBlocks; nBlockXOff ++)
    1679                 :         {
    1680             126 :             int nReqWidth = MIN(nBlockXSize, nWidth - nBlockXOff * nBlockXSize);
    1681             126 :             int nReqHeight = MIN(nBlockYSize, nHeight - nBlockYOff * nBlockYSize);
    1682             126 :             int iImage = nBlockYOff * nXBlocks + nBlockXOff;
    1683                 : 
    1684                 :             void* pScaledData = GDALCreateScaledProgress( iImage / (double)nBlocks,
    1685                 :                                                           (iImage + 1) / (double)nBlocks,
    1686             126 :                                                           pfnProgress, pProgressData);
    1687             126 :             int nX = nBlockXOff * nBlockXSize;
    1688             126 :             int nY = nBlockYOff * nBlockYSize;
    1689                 : 
    1690                 :             int nImageId = WriteBlock(poDS,
    1691                 :                                     nX,
    1692                 :                                     nY,
    1693                 :                                     nReqWidth, nReqHeight,
    1694                 :                                     nColorTableId,
    1695                 :                                     eCompressMethod,
    1696                 :                                     nPredictor,
    1697                 :                                     nJPEGQuality,
    1698                 :                                     pszJPEG2000_DRIVER,
    1699                 :                                     GDALScaledProgress,
    1700             126 :                                     pScaledData);
    1701                 : 
    1702             126 :             GDALDestroyScaledProgress(pScaledData);
    1703                 : 
    1704             126 :             if (nImageId == 0)
    1705               0 :                 return FALSE;
    1706                 : 
    1707                 :             GDALPDFImageDesc oImageDesc;
    1708             126 :             oImageDesc.nImageId = nImageId;
    1709             126 :             oImageDesc.dfXOff = nX / dfUserUnit + oPageContext.sMargins.nLeft;
    1710             126 :             oImageDesc.dfYOff = (nHeight - nY - nReqHeight) / dfUserUnit + oPageContext.sMargins.nBottom;
    1711             126 :             oImageDesc.dfXSize = nReqWidth / dfUserUnit;
    1712             126 :             oImageDesc.dfYSize = nReqHeight / dfUserUnit;
    1713                 : 
    1714             126 :             oRasterDesc.asImageDesc.push_back(oImageDesc);
    1715                 :         }
    1716                 :     }
    1717                 : 
    1718              50 :     oPageContext.asRasterDesc.push_back(oRasterDesc);
    1719                 : 
    1720              50 :     return TRUE;
    1721                 : }
    1722                 : 
    1723                 : /************************************************************************/
    1724                 : /*                        WriteClippedImagery()                         */
    1725                 : /************************************************************************/
    1726                 : 
    1727               2 : int GDALPDFWriter::WriteClippedImagery(
    1728                 :                                 GDALDataset* poDS,
    1729                 :                                 const char* pszLayerName,
    1730                 :                                 PDFCompressMethod eCompressMethod,
    1731                 :                                 int nPredictor,
    1732                 :                                 int nJPEGQuality,
    1733                 :                                 const char* pszJPEG2000_DRIVER,
    1734                 :                                 int nBlockXSize, int nBlockYSize,
    1735                 :                                 GDALProgressFunc pfnProgress,
    1736                 :                                 void * pProgressData)
    1737                 : {
    1738               2 :     double dfUserUnit = oPageContext.dfDPI / 72.0;
    1739                 : 
    1740               2 :     GDALPDFRasterDesc oRasterDesc;
    1741                 : 
    1742                 :     /* Get clipping dataset bounding-box */
    1743                 :     double adfClippingGeoTransform[6];
    1744               2 :     GDALDataset* poClippingDS = oPageContext.poClippingDS;
    1745               2 :     poClippingDS->GetGeoTransform(adfClippingGeoTransform);
    1746               2 :     int  nClippingWidth = poClippingDS->GetRasterXSize();
    1747               2 :     int  nClippingHeight = poClippingDS->GetRasterYSize();
    1748               2 :     double dfClippingMinX = adfClippingGeoTransform[0];
    1749               2 :     double dfClippingMaxX = dfClippingMinX + nClippingWidth * adfClippingGeoTransform[1];
    1750               2 :     double dfClippingMaxY = adfClippingGeoTransform[3];
    1751               2 :     double dfClippingMinY = dfClippingMaxY + nClippingHeight * adfClippingGeoTransform[5];
    1752                 : 
    1753               2 :     if( dfClippingMaxY < dfClippingMinY )
    1754                 :     {
    1755               0 :         double dfTmp = dfClippingMinY;
    1756               0 :         dfClippingMinY = dfClippingMaxY;
    1757               0 :         dfClippingMaxY = dfTmp;
    1758                 :     }
    1759                 : 
    1760                 :     /* Get current dataset dataset bounding-box */
    1761                 :     double adfGeoTransform[6];
    1762               2 :     poDS->GetGeoTransform(adfGeoTransform);
    1763               2 :     int  nWidth = poDS->GetRasterXSize();
    1764               2 :     int  nHeight = poDS->GetRasterYSize();
    1765               2 :     double dfRasterMinX = adfGeoTransform[0];
    1766                 :     //double dfRasterMaxX = dfRasterMinX + nWidth * adfGeoTransform[1];
    1767               2 :     double dfRasterMaxY = adfGeoTransform[3];
    1768               2 :     double dfRasterMinY = dfRasterMaxY + nHeight * adfGeoTransform[5];
    1769                 : 
    1770               2 :     if( dfRasterMaxY < dfRasterMinY )
    1771                 :     {
    1772               0 :         double dfTmp = dfRasterMinY;
    1773               0 :         dfRasterMinY = dfRasterMaxY;
    1774               0 :         dfRasterMaxY = dfTmp;
    1775                 :     }
    1776                 : 
    1777               2 :     if( pfnProgress == NULL )
    1778               1 :         pfnProgress = GDALDummyProgress;
    1779                 : 
    1780               2 :     oRasterDesc.nOCGRasterId = WriteOCG(pszLayerName);
    1781                 : 
    1782                 :     /* Does the source image has a color table ? */
    1783               2 :     int nColorTableId = WriteColorTable(poDS);
    1784                 : 
    1785               2 :     int nXBlocks = (nWidth + nBlockXSize - 1) / nBlockXSize;
    1786               2 :     int nYBlocks = (nHeight + nBlockYSize - 1) / nBlockYSize;
    1787               2 :     int nBlocks = nXBlocks * nYBlocks;
    1788                 :     int nBlockXOff, nBlockYOff;
    1789               4 :     for(nBlockYOff = 0; nBlockYOff < nYBlocks; nBlockYOff ++)
    1790                 :     {
    1791               4 :         for(nBlockXOff = 0; nBlockXOff < nXBlocks; nBlockXOff ++)
    1792                 :         {
    1793               2 :             int nReqWidth = MIN(nBlockXSize, nWidth - nBlockXOff * nBlockXSize);
    1794               2 :             int nReqHeight = MIN(nBlockYSize, nHeight - nBlockYOff * nBlockYSize);
    1795               2 :             int iImage = nBlockYOff * nXBlocks + nBlockXOff;
    1796                 : 
    1797                 :             void* pScaledData = GDALCreateScaledProgress( iImage / (double)nBlocks,
    1798                 :                                                           (iImage + 1) / (double)nBlocks,
    1799               2 :                                                           pfnProgress, pProgressData);
    1800                 : 
    1801               2 :             int nX = nBlockXOff * nBlockXSize;
    1802               2 :             int nY = nBlockYOff * nBlockYSize;
    1803                 : 
    1804                 :             /* Compute extent of block to write */
    1805               2 :             double dfBlockMinX = adfGeoTransform[0] + nX * adfGeoTransform[1];
    1806               2 :             double dfBlockMaxX = adfGeoTransform[0] + (nX + nReqWidth) * adfGeoTransform[1];
    1807               2 :             double dfBlockMinY = adfGeoTransform[3] + (nY + nReqHeight) * adfGeoTransform[5];
    1808               2 :             double dfBlockMaxY = adfGeoTransform[3] + nY * adfGeoTransform[5];
    1809                 : 
    1810               2 :             if( dfBlockMaxY < dfBlockMinY )
    1811                 :             {
    1812               0 :                 double dfTmp = dfBlockMinY;
    1813               0 :                 dfBlockMinY = dfBlockMaxY;
    1814               0 :                 dfBlockMaxY = dfTmp;
    1815                 :             }
    1816                 : 
    1817                 :             /* Clip the extent of the block with the extent of the main raster */
    1818               2 :             double dfIntersectMinX = MAX(dfBlockMinX, dfClippingMinX);
    1819               2 :             double dfIntersectMinY = MAX(dfBlockMinY, dfClippingMinY);
    1820               2 :             double dfIntersectMaxX = MIN(dfBlockMaxX, dfClippingMaxX);
    1821               2 :             double dfIntersectMaxY = MIN(dfBlockMaxY, dfClippingMaxY);
    1822                 : 
    1823               2 :             if( dfIntersectMinX < dfIntersectMaxX &&
    1824                 :                 dfIntersectMinY < dfIntersectMaxY )
    1825                 :             {
    1826                 :                 /* Re-compute (x,y,width,height) subwindow of current raster from */
    1827                 :                 /* the extent of the clipped block */
    1828               2 :                 nX = (int)((dfIntersectMinX - dfRasterMinX) / adfGeoTransform[1] + 0.5);
    1829               2 :                 if( adfGeoTransform[5] < 0 )
    1830               2 :                     nY = (int)((dfRasterMaxY - dfIntersectMaxY) / (-adfGeoTransform[5]) + 0.5);
    1831                 :                 else
    1832               0 :                     nY = (int)((dfIntersectMinY - dfRasterMinY) / adfGeoTransform[5] + 0.5);
    1833               2 :                 nReqWidth = (int)((dfIntersectMaxX - dfRasterMinX) / adfGeoTransform[1] + 0.5) - nX;
    1834               2 :                 if( adfGeoTransform[5] < 0 )
    1835               2 :                     nReqHeight = (int)((dfRasterMaxY - dfIntersectMinY) / (-adfGeoTransform[5]) + 0.5) - nY;
    1836                 :                 else
    1837               0 :                     nReqHeight = (int)((dfIntersectMaxY - dfRasterMinY) / adfGeoTransform[5] + 0.5) - nY;
    1838                 : 
    1839               2 :                 if( nReqWidth > 0 && nReqHeight > 0)
    1840                 :                 {
    1841                 :                     int nImageId = WriteBlock(poDS,
    1842                 :                                             nX,
    1843                 :                                             nY,
    1844                 :                                             nReqWidth, nReqHeight,
    1845                 :                                             nColorTableId,
    1846                 :                                             eCompressMethod,
    1847                 :                                             nPredictor,
    1848                 :                                             nJPEGQuality,
    1849                 :                                             pszJPEG2000_DRIVER,
    1850                 :                                             GDALScaledProgress,
    1851               2 :                                             pScaledData);
    1852                 : 
    1853               2 :                     if (nImageId == 0)
    1854                 :                     {
    1855               0 :                         GDALDestroyScaledProgress(pScaledData);
    1856               0 :                         return FALSE;
    1857                 :                     }
    1858                 : 
    1859                 :                     /* Compute the subwindow in image coordinates of the main raster corresponding */
    1860                 :                     /* to the extent of the clipped block */
    1861                 :                     double dfXInClippingUnits, dfYInClippingUnits, dfReqWidthInClippingUnits, dfReqHeightInClippingUnits;
    1862                 : 
    1863               2 :                     dfXInClippingUnits = (dfIntersectMinX - dfClippingMinX) / adfClippingGeoTransform[1];
    1864               2 :                     if( adfClippingGeoTransform[5] < 0 )
    1865               2 :                         dfYInClippingUnits = (dfClippingMaxY - dfIntersectMaxY) / (-adfClippingGeoTransform[5]);
    1866                 :                     else
    1867               0 :                         dfYInClippingUnits = (dfIntersectMinY - dfClippingMinY) / adfClippingGeoTransform[5];
    1868               2 :                     dfReqWidthInClippingUnits = (dfIntersectMaxX - dfClippingMinX) / adfClippingGeoTransform[1] - dfXInClippingUnits;
    1869               2 :                     if( adfClippingGeoTransform[5] < 0 )
    1870               2 :                         dfReqHeightInClippingUnits = (dfClippingMaxY - dfIntersectMinY) / (-adfClippingGeoTransform[5]) - dfYInClippingUnits;
    1871                 :                     else
    1872               0 :                         dfReqHeightInClippingUnits = (dfIntersectMaxY - dfClippingMinY) / adfClippingGeoTransform[5] - dfYInClippingUnits;
    1873                 : 
    1874                 :                     GDALPDFImageDesc oImageDesc;
    1875               2 :                     oImageDesc.nImageId = nImageId;
    1876               2 :                     oImageDesc.dfXOff = dfXInClippingUnits / dfUserUnit + oPageContext.sMargins.nLeft;
    1877               2 :                     oImageDesc.dfYOff = (nClippingHeight - dfYInClippingUnits - dfReqHeightInClippingUnits) / dfUserUnit + oPageContext.sMargins.nBottom;
    1878               2 :                     oImageDesc.dfXSize = dfReqWidthInClippingUnits / dfUserUnit;
    1879               2 :                     oImageDesc.dfYSize = dfReqHeightInClippingUnits / dfUserUnit;
    1880                 : 
    1881               2 :                     oRasterDesc.asImageDesc.push_back(oImageDesc);
    1882                 :                 }
    1883                 :             }
    1884                 : 
    1885               2 :             GDALDestroyScaledProgress(pScaledData);
    1886                 :         }
    1887                 :     }
    1888                 : 
    1889               2 :     oPageContext.asRasterDesc.push_back(oRasterDesc);
    1890                 : 
    1891               2 :     return TRUE;
    1892                 : }
    1893                 : 
    1894                 : #ifdef OGR_ENABLED
    1895                 : 
    1896                 : /************************************************************************/
    1897                 : /*                          WriteOGRDataSource()                        */
    1898                 : /************************************************************************/
    1899                 : 
    1900               2 : int GDALPDFWriter::WriteOGRDataSource(const char* pszOGRDataSource,
    1901                 :                                       const char* pszOGRDisplayField,
    1902                 :                                       const char* pszOGRDisplayLayerNames,
    1903                 :                                       const char* pszOGRLinkField,
    1904                 :                                       int bWriteOGRAttributes)
    1905                 : {
    1906               2 :     if (OGRGetDriverCount() == 0)
    1907               0 :         OGRRegisterAll();
    1908                 : 
    1909               2 :     OGRDataSourceH hDS = OGROpen(pszOGRDataSource, 0, NULL);
    1910               2 :     if (hDS == NULL)
    1911               0 :         return FALSE;
    1912                 : 
    1913               2 :     int iObj = 0;
    1914                 : 
    1915               2 :     int nLayers = OGR_DS_GetLayerCount(hDS);
    1916                 : 
    1917               2 :     char** papszLayerNames = CSLTokenizeString2(pszOGRDisplayLayerNames,",",0);
    1918                 : 
    1919               4 :     for(int iLayer = 0; iLayer < nLayers; iLayer ++)
    1920                 :     {
    1921               2 :         CPLString osLayerName;
    1922               2 :         if (CSLCount(papszLayerNames) < nLayers)
    1923               0 :             osLayerName = OGR_L_GetName(OGR_DS_GetLayer(hDS, iLayer));
    1924                 :         else
    1925               2 :             osLayerName = papszLayerNames[iLayer];
    1926                 : 
    1927                 :         WriteOGRLayer(hDS, iLayer,
    1928                 :                       pszOGRDisplayField,
    1929                 :                       pszOGRLinkField,
    1930                 :                       osLayerName,
    1931                 :                       bWriteOGRAttributes,
    1932               2 :                       iObj);
    1933                 :     }
    1934                 : 
    1935               2 :     OGRReleaseDataSource(hDS);
    1936                 : 
    1937               2 :     CSLDestroy(papszLayerNames);
    1938                 : 
    1939               2 :     return TRUE;
    1940                 : }
    1941                 : 
    1942                 : /************************************************************************/
    1943                 : /*                           StartOGRLayer()                            */
    1944                 : /************************************************************************/
    1945                 : 
    1946               4 : GDALPDFLayerDesc GDALPDFWriter::StartOGRLayer(CPLString osLayerName,
    1947                 :                                               int bWriteOGRAttributes)
    1948                 : {
    1949               4 :     GDALPDFLayerDesc osVectorDesc;
    1950               4 :     osVectorDesc.osLayerName = osLayerName;
    1951               4 :     osVectorDesc.bWriteOGRAttributes = bWriteOGRAttributes;
    1952               4 :     osVectorDesc.nOGCId = WriteOCG(osLayerName);
    1953               4 :     osVectorDesc.nFeatureLayerId = (bWriteOGRAttributes) ? AllocNewObject() : 0;
    1954               4 :     osVectorDesc.nOCGTextId = 0;
    1955                 : 
    1956               0 :     return osVectorDesc;
    1957                 : }
    1958                 : 
    1959                 : /************************************************************************/
    1960                 : /*                           EndOGRLayer()                              */
    1961                 : /************************************************************************/
    1962                 : 
    1963               4 : void GDALPDFWriter::EndOGRLayer(GDALPDFLayerDesc& osVectorDesc)
    1964                 : {
    1965               4 :     if (osVectorDesc.bWriteOGRAttributes)
    1966                 :     {
    1967               3 :         StartObj(osVectorDesc.nFeatureLayerId);
    1968                 : 
    1969               3 :         GDALPDFDictionaryRW oDict;
    1970                 :         oDict.Add("A", &(new GDALPDFDictionaryRW())->Add("O",
    1971               3 :                 GDALPDFObjectRW::CreateName("UserProperties")));
    1972                 : 
    1973               3 :         GDALPDFArrayRW* poArray = new GDALPDFArrayRW();
    1974               3 :         oDict.Add("K", poArray);
    1975                 : 
    1976              26 :         for(int i = 0; i < (int)osVectorDesc.aUserPropertiesIds.size(); i++)
    1977                 :         {
    1978              23 :             poArray->Add(osVectorDesc.aUserPropertiesIds[i], 0);
    1979                 :         }
    1980                 : 
    1981               3 :         if (nStructTreeRootId == 0)
    1982               3 :             nStructTreeRootId = AllocNewObject();
    1983                 : 
    1984               3 :         oDict.Add("P", nStructTreeRootId, 0);
    1985               3 :         oDict.Add("S", GDALPDFObjectRW::CreateName("Feature"));
    1986               3 :         oDict.Add("T", osVectorDesc.osLayerName);
    1987                 : 
    1988               3 :         VSIFPrintfL(fp, "%s\n", oDict.Serialize().c_str());
    1989                 : 
    1990               3 :         EndObj();
    1991                 :     }
    1992                 : 
    1993               4 :     oPageContext.asVectorDesc.push_back(osVectorDesc);
    1994               4 : }
    1995                 : 
    1996                 : /************************************************************************/
    1997                 : /*                           WriteOGRLayer()                            */
    1998                 : /************************************************************************/
    1999                 : 
    2000               4 : int GDALPDFWriter::WriteOGRLayer(OGRDataSourceH hDS,
    2001                 :                                  int iLayer,
    2002                 :                                  const char* pszOGRDisplayField,
    2003                 :                                  const char* pszOGRLinkField,
    2004                 :                                  CPLString osLayerName,
    2005                 :                                  int bWriteOGRAttributes,
    2006                 :                                  int& iObj)
    2007                 : {
    2008               4 :     GDALDataset* poClippingDS = oPageContext.poClippingDS;
    2009                 :     double adfGeoTransform[6];
    2010               4 :     if (poClippingDS->GetGeoTransform(adfGeoTransform) != CE_None)
    2011               0 :         return FALSE;
    2012                 : 
    2013                 :     GDALPDFLayerDesc osVectorDesc = StartOGRLayer(osLayerName,
    2014               4 :                                                   bWriteOGRAttributes);
    2015               4 :     OGRLayerH hLyr = OGR_DS_GetLayer(hDS, iLayer);
    2016                 : 
    2017               4 :     const char* pszWKT = poClippingDS->GetProjectionRef();
    2018               4 :     OGRSpatialReferenceH hGDAL_SRS = NULL;
    2019               4 :     if( pszWKT && pszWKT[0] != '\0' )
    2020               4 :         hGDAL_SRS = OSRNewSpatialReference(pszWKT);
    2021               4 :     OGRSpatialReferenceH hOGR_SRS = OGR_L_GetSpatialRef(hLyr);
    2022               4 :     OGRCoordinateTransformationH hCT = NULL;
    2023                 : 
    2024               4 :     if( hGDAL_SRS == NULL && hOGR_SRS != NULL )
    2025                 :     {
    2026                 :         CPLError(CE_Warning, CPLE_AppDefined,
    2027               0 :                  "Vector layer has a SRS set, but Raster layer has no SRS set. Assuming they are the same.");
    2028                 :     }
    2029               4 :     else if( hGDAL_SRS != NULL && hOGR_SRS == NULL )
    2030                 :     {
    2031                 :         CPLError(CE_Warning, CPLE_AppDefined,
    2032               0 :                  "Vector layer has no SRS set, but Raster layer has a SRS set. Assuming they are the same.");
    2033                 :     }
    2034               4 :     else if( hGDAL_SRS != NULL && hOGR_SRS != NULL )
    2035                 :     {
    2036               4 :         if (!OSRIsSame(hGDAL_SRS, hOGR_SRS))
    2037                 :         {
    2038               1 :             hCT = OCTNewCoordinateTransformation( hOGR_SRS, hGDAL_SRS );
    2039               1 :             if( hCT == NULL )
    2040                 :             {
    2041                 :                 CPLError(CE_Warning, CPLE_AppDefined,
    2042               0 :                          "Cannot compute coordinate transformation from vector SRS to raster SRS");
    2043                 :             }
    2044                 :         }
    2045                 :     }
    2046                 : 
    2047               4 :     if( hCT == NULL )
    2048                 :     {
    2049               3 :         double dfXMin = adfGeoTransform[0];
    2050               3 :         double dfYMin = adfGeoTransform[3] + poClippingDS->GetRasterYSize() * adfGeoTransform[5];
    2051               3 :         double dfXMax = adfGeoTransform[0] + poClippingDS->GetRasterXSize() * adfGeoTransform[1];
    2052               3 :         double dfYMax = adfGeoTransform[3];
    2053               3 :         OGR_L_SetSpatialFilterRect(hLyr, dfXMin, dfYMin, dfXMax, dfYMax);
    2054                 :     }
    2055                 : 
    2056                 :     OGRFeatureH hFeat;
    2057               4 :     int iObjLayer = 0;
    2058                 : 
    2059              47 :     while( (hFeat = OGR_L_GetNextFeature(hLyr)) != NULL)
    2060                 :     {
    2061                 :         WriteOGRFeature(osVectorDesc,
    2062                 :                         hFeat,
    2063                 :                         hCT,
    2064                 :                         pszOGRDisplayField,
    2065                 :                         pszOGRLinkField,
    2066                 :                         bWriteOGRAttributes,
    2067                 :                         iObj,
    2068              39 :                         iObjLayer);
    2069                 : 
    2070              39 :         OGR_F_Destroy(hFeat);
    2071                 :     }
    2072                 : 
    2073               4 :     EndOGRLayer(osVectorDesc);
    2074                 : 
    2075               4 :     if( hCT != NULL )
    2076               1 :         OCTDestroyCoordinateTransformation(hCT);
    2077               4 :     if( hGDAL_SRS != NULL )
    2078               4 :         OSRDestroySpatialReference(hGDAL_SRS);
    2079                 : 
    2080               4 :     return TRUE;
    2081                 : }
    2082                 : 
    2083                 : /************************************************************************/
    2084                 : /*                             DrawGeometry()                           */
    2085                 : /************************************************************************/
    2086                 : 
    2087              19 : static void DrawGeometry(VSILFILE* fp, OGRGeometryH hGeom, double adfMatrix[4], int bPaint = TRUE)
    2088                 : {
    2089              19 :     switch(wkbFlatten(OGR_G_GetGeometryType(hGeom)))
    2090                 :     {
    2091                 :         case wkbLineString:
    2092                 :         {
    2093              12 :             int nPoints = OGR_G_GetPointCount(hGeom);
    2094              63 :             for(int i=0;i<nPoints;i++)
    2095                 :             {
    2096              51 :                 double dfX = OGR_G_GetX(hGeom, i) * adfMatrix[1] + adfMatrix[0];
    2097              51 :                 double dfY = OGR_G_GetY(hGeom, i) * adfMatrix[3] + adfMatrix[2];
    2098              51 :                 VSIFPrintfL(fp, "%f %f %c\n", dfX, dfY, (i == 0) ? 'm' : 'l');
    2099                 :             }
    2100              12 :             if (bPaint)
    2101               3 :                 VSIFPrintfL(fp, "S\n");
    2102              12 :             break;
    2103                 :         }
    2104                 : 
    2105                 :         case wkbPolygon:
    2106                 :         {
    2107               6 :             int nParts = OGR_G_GetGeometryCount(hGeom);
    2108              15 :             for(int i=0;i<nParts;i++)
    2109                 :             {
    2110               9 :                 DrawGeometry(fp, OGR_G_GetGeometryRef(hGeom, i), adfMatrix, FALSE);
    2111               9 :                 VSIFPrintfL(fp, "h\n");
    2112                 :             }
    2113               6 :             if (bPaint)
    2114               4 :                 VSIFPrintfL(fp, "b*\n");
    2115               6 :             break;
    2116                 :         }
    2117                 : 
    2118                 :         case wkbMultiLineString:
    2119                 :         {
    2120               0 :             int nParts = OGR_G_GetGeometryCount(hGeom);
    2121               0 :             for(int i=0;i<nParts;i++)
    2122                 :             {
    2123               0 :                 DrawGeometry(fp, OGR_G_GetGeometryRef(hGeom, i), adfMatrix, FALSE);
    2124                 :             }
    2125               0 :             if (bPaint)
    2126               0 :                 VSIFPrintfL(fp, "S\n");
    2127               0 :             break;
    2128                 :         }
    2129                 : 
    2130                 :         case wkbMultiPolygon:
    2131                 :         {
    2132               1 :             int nParts = OGR_G_GetGeometryCount(hGeom);
    2133               3 :             for(int i=0;i<nParts;i++)
    2134                 :             {
    2135               2 :                 DrawGeometry(fp, OGR_G_GetGeometryRef(hGeom, i), adfMatrix, FALSE);
    2136                 :             }
    2137               1 :             if (bPaint)
    2138               1 :                 VSIFPrintfL(fp, "b*\n");
    2139                 :             break;
    2140                 :         }
    2141                 : 
    2142                 :         default:
    2143                 :             break;
    2144                 :     }
    2145              19 : }
    2146                 : 
    2147                 : /************************************************************************/
    2148                 : /*                          WriteOGRFeature()                           */
    2149                 : /************************************************************************/
    2150                 : 
    2151              39 : int GDALPDFWriter::WriteOGRFeature(GDALPDFLayerDesc& osVectorDesc,
    2152                 :                                    OGRFeatureH hFeat,
    2153                 :                                    OGRCoordinateTransformationH hCT,
    2154                 :                                    const char* pszOGRDisplayField,
    2155                 :                                    const char* pszOGRLinkField,
    2156                 :                                    int bWriteOGRAttributes,
    2157                 :                                    int& iObj,
    2158                 :                                    int& iObjLayer)
    2159                 : {
    2160              39 :     GDALDataset* poClippingDS = oPageContext.poClippingDS;
    2161              39 :     int  nHeight = poClippingDS->GetRasterYSize();
    2162              39 :     double dfUserUnit = oPageContext.dfDPI / 72.0;
    2163                 :     double adfGeoTransform[6];
    2164              39 :     poClippingDS->GetGeoTransform(adfGeoTransform);
    2165                 : 
    2166                 :     double adfMatrix[4];
    2167              39 :     adfMatrix[0] = - adfGeoTransform[0] / (adfGeoTransform[1] * dfUserUnit) + oPageContext.sMargins.nLeft;
    2168              39 :     adfMatrix[1] = 1.0 / (adfGeoTransform[1] * dfUserUnit);
    2169              39 :     adfMatrix[2] = - (adfGeoTransform[3] + adfGeoTransform[5] * nHeight) / (-adfGeoTransform[5] * dfUserUnit) + oPageContext.sMargins.nBottom;
    2170              39 :     adfMatrix[3] = 1.0 / (-adfGeoTransform[5] * dfUserUnit);
    2171                 : 
    2172              39 :     OGRGeometryH hGeom = OGR_F_GetGeometryRef(hFeat);
    2173              39 :     if (hGeom == NULL)
    2174                 :     {
    2175               0 :         return TRUE;
    2176                 :     }
    2177                 : 
    2178              39 :     OGREnvelope sEnvelope;
    2179                 : 
    2180              39 :     if( hCT != NULL )
    2181                 :     {
    2182                 :         /* Reproject */
    2183               6 :         if( OGR_G_Transform(hGeom, hCT) != OGRERR_NONE )
    2184                 :         {
    2185               0 :             return TRUE;
    2186                 :         }
    2187                 : 
    2188               6 :         OGREnvelope sRasterEnvelope;
    2189               6 :         sRasterEnvelope.MinX = adfGeoTransform[0];
    2190               6 :         sRasterEnvelope.MinY = adfGeoTransform[3] + poClippingDS->GetRasterYSize() * adfGeoTransform[5];
    2191               6 :         sRasterEnvelope.MaxX = adfGeoTransform[0] + poClippingDS->GetRasterXSize() * adfGeoTransform[1];
    2192               6 :         sRasterEnvelope.MaxY = adfGeoTransform[3];
    2193                 : 
    2194                 :         /* Check that the reprojected geometry interescts the raster envelope */
    2195               6 :         OGR_G_GetEnvelope(hGeom, &sEnvelope);
    2196               6 :         if( !(sRasterEnvelope.Intersects(sEnvelope)) )
    2197                 :         {
    2198               1 :             return TRUE;
    2199                 :         }
    2200                 :     }
    2201                 :     else
    2202                 :     {
    2203              33 :         OGR_G_GetEnvelope(hGeom, &sEnvelope);
    2204                 :     }
    2205                 : 
    2206                 :     /* -------------------------------------------------------------- */
    2207                 :     /*  Get style                                                     */
    2208                 :     /* -------------------------------------------------------------- */
    2209              38 :     int nPenR = 0, nPenG = 0, nPenB = 0, nPenA = 255;
    2210              38 :     int nBrushR = 127, nBrushG = 127, nBrushB = 127, nBrushA = 127;
    2211              38 :     int nTextR = 0, nTextG = 0, nTextB = 0, nTextA = 255;
    2212              38 :     int bSymbolColorDefined = FALSE;
    2213              38 :     int nSymbolR = 0, nSymbolG = 0, nSymbolB = 0, nSymbolA = 255;
    2214              38 :     double dfTextSize = 12, dfTextAngle = 0, dfTextDx = 0, dfTextDy = 0;
    2215              38 :     double dfPenWidth = 1;
    2216              38 :     double dfSymbolSize = 5;
    2217              38 :     CPLString osDashArray;
    2218              38 :     CPLString osLabelText;
    2219              38 :     CPLString osSymbolId;
    2220              38 :     int nImageSymbolId = 0, nImageWidth = 0, nImageHeight = 0;
    2221                 : 
    2222              38 :     OGRStyleMgrH hSM = OGR_SM_Create(NULL);
    2223              38 :     OGR_SM_InitFromFeature(hSM, hFeat);
    2224              38 :     int nCount = OGR_SM_GetPartCount(hSM, NULL);
    2225              67 :     for(int iPart = 0; iPart < nCount; iPart++)
    2226                 :     {
    2227              29 :         OGRStyleToolH hTool = OGR_SM_GetPart(hSM, iPart, NULL);
    2228              29 :         if (hTool)
    2229                 :         {
    2230              28 :             if (OGR_ST_GetType(hTool) == OGRSTCPen)
    2231                 :             {
    2232               2 :                 int bIsNull = TRUE;
    2233               2 :                 const char* pszColor = OGR_ST_GetParamStr(hTool, OGRSTPenColor, &bIsNull);
    2234               2 :                 if (pszColor && !bIsNull)
    2235                 :                 {
    2236               2 :                     int nRed = 0, nGreen = 0, nBlue = 0, nAlpha = 255;
    2237               2 :                     int nVals = sscanf(pszColor,"#%2x%2x%2x%2x",&nRed,&nGreen,&nBlue,&nAlpha);
    2238               2 :                     if (nVals >= 3)
    2239                 :                     {
    2240               2 :                         nPenR = nRed;
    2241               2 :                         nPenG = nGreen;
    2242               2 :                         nPenB = nBlue;
    2243               2 :                         if (nVals == 4)
    2244               0 :                             nPenA = nAlpha;
    2245                 :                     }
    2246                 :                 }
    2247                 : 
    2248               2 :                 const char* pszDash = OGR_ST_GetParamStr(hTool, OGRSTPenPattern, &bIsNull);
    2249               2 :                 if (pszDash && !bIsNull)
    2250                 :                 {
    2251               1 :                     char** papszTokens = CSLTokenizeString2(pszDash, " ", 0);
    2252               1 :                     int nTokens = CSLCount(papszTokens);
    2253               1 :                     if ((nTokens % 2) == 0)
    2254                 :                     {
    2255               3 :                         for(int i=0;i<nTokens;i++)
    2256                 :                         {
    2257               2 :                             osDashArray += CPLSPrintf("%d ", atoi(papszTokens[i]));
    2258                 :                         }
    2259                 :                     }
    2260               1 :                     CSLDestroy(papszTokens);
    2261                 :                 }
    2262                 : 
    2263                 :                 //OGRSTUnitId eUnit = OGR_ST_GetUnit(hTool);
    2264               2 :                 double dfWidth = OGR_ST_GetParamDbl(hTool, OGRSTPenWidth, &bIsNull);
    2265               2 :                 if (!bIsNull)
    2266               2 :                     dfPenWidth = dfWidth;
    2267                 :             }
    2268              26 :             else if (OGR_ST_GetType(hTool) == OGRSTCBrush)
    2269                 :             {
    2270                 :                 int bIsNull;
    2271               1 :                 const char* pszColor = OGR_ST_GetParamStr(hTool, OGRSTBrushFColor, &bIsNull);
    2272               1 :                 if (pszColor)
    2273                 :                 {
    2274               1 :                     int nRed = 0, nGreen = 0, nBlue = 0, nAlpha = 255;
    2275               1 :                     int nVals = sscanf(pszColor,"#%2x%2x%2x%2x",&nRed,&nGreen,&nBlue,&nAlpha);
    2276               1 :                     if (nVals >= 3)
    2277                 :                     {
    2278               1 :                         nBrushR = nRed;
    2279               1 :                         nBrushG = nGreen;
    2280               1 :                         nBrushB = nBlue;
    2281               1 :                         if (nVals == 4)
    2282               0 :                             nBrushA = nAlpha;
    2283                 :                     }
    2284                 :                 }
    2285                 :             }
    2286              25 :             else if (OGR_ST_GetType(hTool) == OGRSTCLabel)
    2287                 :             {
    2288                 :                 int bIsNull;
    2289               3 :                 const char* pszStr = OGR_ST_GetParamStr(hTool, OGRSTLabelTextString, &bIsNull);
    2290               3 :                 if (pszStr)
    2291                 :                 {
    2292               3 :                     osLabelText = pszStr;
    2293                 : 
    2294                 :                     /* If the text is of the form {stuff}, then it means we want to fetch */
    2295                 :                     /* the value of the field "stuff" in the feature */
    2296               3 :                     if( osLabelText.size() && osLabelText[0] == '{' &&
    2297                 :                         osLabelText[osLabelText.size() - 1] == '}' )
    2298                 :                     {
    2299               2 :                         osLabelText = pszStr + 1;
    2300               2 :                         osLabelText.resize(osLabelText.size() - 1);
    2301                 : 
    2302               2 :                         int nIdxField = OGR_F_GetFieldIndex(hFeat, osLabelText);
    2303               2 :                         if( nIdxField >= 0 )
    2304               2 :                             osLabelText = OGR_F_GetFieldAsString(hFeat, nIdxField);
    2305                 :                         else
    2306               0 :                             osLabelText = "";
    2307                 :                     }
    2308                 :                 }
    2309                 : 
    2310               3 :                 const char* pszColor = OGR_ST_GetParamStr(hTool, OGRSTLabelFColor, &bIsNull);
    2311               3 :                 if (pszColor && !bIsNull)
    2312                 :                 {
    2313               1 :                     int nRed = 0, nGreen = 0, nBlue = 0, nAlpha = 255;
    2314               1 :                     int nVals = sscanf(pszColor,"#%2x%2x%2x%2x",&nRed,&nGreen,&nBlue,&nAlpha);
    2315               1 :                     if (nVals >= 3)
    2316                 :                     {
    2317               1 :                         nTextR = nRed;
    2318               1 :                         nTextG = nGreen;
    2319               1 :                         nTextB = nBlue;
    2320               1 :                         if (nVals == 4)
    2321               1 :                             nTextA = nAlpha;
    2322                 :                     }
    2323                 :                 }
    2324                 : 
    2325               3 :                 double dfVal = OGR_ST_GetParamDbl(hTool, OGRSTLabelSize, &bIsNull);
    2326               3 :                 if (!bIsNull)
    2327                 :                 {
    2328               1 :                     dfTextSize = dfVal;
    2329                 :                 }
    2330                 : 
    2331               3 :                 dfVal = OGR_ST_GetParamDbl(hTool, OGRSTLabelAngle, &bIsNull);
    2332               3 :                 if (!bIsNull)
    2333                 :                 {
    2334               1 :                     dfTextAngle = dfVal;
    2335                 :                 }
    2336                 : 
    2337               3 :                 dfVal = OGR_ST_GetParamDbl(hTool, OGRSTLabelDx, &bIsNull);
    2338               3 :                 if (!bIsNull)
    2339                 :                 {
    2340               2 :                     dfTextDx = dfVal;
    2341                 :                 }
    2342                 : 
    2343               3 :                 dfVal = OGR_ST_GetParamDbl(hTool, OGRSTLabelDy, &bIsNull);
    2344               3 :                 if (!bIsNull)
    2345                 :                 {
    2346               2 :                     dfTextDy = dfVal;
    2347                 :                 }
    2348                 : 
    2349                 :             }
    2350              22 :             else if (OGR_ST_GetType(hTool) == OGRSTCSymbol)
    2351                 :             {
    2352                 :                 int bIsNull;
    2353              22 :                 const char* pszSymbolId = OGR_ST_GetParamStr(hTool, OGRSTSymbolId, &bIsNull);
    2354              22 :                 if (pszSymbolId && !bIsNull)
    2355                 :                 {
    2356              22 :                     osSymbolId = pszSymbolId;
    2357                 : 
    2358              22 :                     if (strstr(pszSymbolId, "ogr-sym-") == NULL)
    2359                 :                     {
    2360               2 :                         if (oMapSymbolFilenameToDesc.find(osSymbolId) == oMapSymbolFilenameToDesc.end())
    2361                 :                         {
    2362               2 :                             CPLPushErrorHandler(CPLQuietErrorHandler);
    2363               2 :                             GDALDatasetH hImageDS = GDALOpen(osSymbolId, GA_ReadOnly);
    2364               2 :                             CPLPopErrorHandler();
    2365               2 :                             if (hImageDS != NULL)
    2366                 :                             {
    2367               2 :                                 nImageWidth = GDALGetRasterXSize(hImageDS);
    2368               2 :                                 nImageHeight = GDALGetRasterYSize(hImageDS);
    2369                 : 
    2370                 :                                 nImageSymbolId = WriteBlock((GDALDataset*) hImageDS,
    2371                 :                                                         0, 0,
    2372                 :                                                         nImageWidth,
    2373                 :                                                         nImageHeight,
    2374                 :                                                         0,
    2375                 :                                                         COMPRESS_DEFAULT,
    2376                 :                                                         0,
    2377                 :                                                         -1,
    2378                 :                                                         NULL,
    2379                 :                                                         NULL,
    2380               2 :                                                         NULL);
    2381               2 :                                 GDALClose(hImageDS);
    2382                 :                             }
    2383                 : 
    2384                 :                             GDALPDFImageDesc oDesc;
    2385               2 :                             oDesc.nImageId = nImageSymbolId;
    2386               2 :                             oDesc.dfXOff = 0;
    2387               2 :                             oDesc.dfYOff = 0;
    2388               2 :                             oDesc.dfXSize = nImageWidth;
    2389               2 :                             oDesc.dfYSize = nImageHeight;
    2390               2 :                             oMapSymbolFilenameToDesc[osSymbolId] = oDesc;
    2391                 :                         }
    2392                 :                         else
    2393                 :                         {
    2394               0 :                             GDALPDFImageDesc& oDesc = oMapSymbolFilenameToDesc[osSymbolId];
    2395               0 :                             nImageSymbolId = oDesc.nImageId;
    2396               0 :                             nImageWidth = (int)oDesc.dfXSize;
    2397               0 :                             nImageHeight = (int)oDesc.dfYSize;
    2398                 :                         }
    2399                 :                     }
    2400                 :                 }
    2401                 : 
    2402              22 :                 double dfVal = OGR_ST_GetParamDbl(hTool, OGRSTSymbolSize, &bIsNull);
    2403              22 :                 if (!bIsNull)
    2404                 :                 {
    2405              20 :                     dfSymbolSize = dfVal;
    2406                 :                 }
    2407                 : 
    2408              22 :                 const char* pszColor = OGR_ST_GetParamStr(hTool, OGRSTSymbolColor, &bIsNull);
    2409              22 :                 if (pszColor && !bIsNull)
    2410                 :                 {
    2411              22 :                     int nRed = 0, nGreen = 0, nBlue = 0, nAlpha = 255;
    2412              22 :                     int nVals = sscanf(pszColor,"#%2x%2x%2x%2x",&nRed,&nGreen,&nBlue,&nAlpha);
    2413              22 :                     if (nVals >= 3)
    2414                 :                     {
    2415              22 :                         bSymbolColorDefined = TRUE;
    2416              22 :                         nSymbolR = nRed;
    2417              22 :                         nSymbolG = nGreen;
    2418              22 :                         nSymbolB = nBlue;
    2419              22 :                         if (nVals == 4)
    2420               0 :                             nSymbolA = nAlpha;
    2421                 :                     }
    2422                 :                 }
    2423                 :             }
    2424                 : 
    2425              28 :             OGR_ST_Destroy(hTool);
    2426                 :         }
    2427                 :     }
    2428              38 :     OGR_SM_Destroy(hSM);
    2429                 : 
    2430              38 :     if (wkbFlatten(OGR_G_GetGeometryType(hGeom)) == wkbPoint && bSymbolColorDefined)
    2431                 :     {
    2432              22 :         nPenR = nSymbolR;
    2433              22 :         nPenG = nSymbolG;
    2434              22 :         nPenB = nSymbolB;
    2435              22 :         nPenA = nSymbolA;
    2436              22 :         nBrushR = nSymbolR;
    2437              22 :         nBrushG = nSymbolG;
    2438              22 :         nBrushB = nSymbolB;
    2439              22 :         nBrushA = nSymbolA;
    2440                 :     }
    2441                 : 
    2442              38 :     double dfRadius = dfSymbolSize * dfUserUnit;
    2443                 : 
    2444                 :     /* -------------------------------------------------------------- */
    2445                 :     /*  Write object dictionary                                       */
    2446                 :     /* -------------------------------------------------------------- */
    2447              38 :     int nObjectId = AllocNewObject();
    2448              38 :     int nObjectLengthId = AllocNewObject();
    2449                 : 
    2450              38 :     osVectorDesc.aIds.push_back(nObjectId);
    2451                 : 
    2452                 :     int bboxXMin, bboxYMin, bboxXMax, bboxYMax;
    2453              38 :     if (wkbFlatten(OGR_G_GetGeometryType(hGeom)) == wkbPoint && nImageSymbolId != 0)
    2454                 :     {
    2455               2 :         bboxXMin = (int)floor(sEnvelope.MinX * adfMatrix[1] + adfMatrix[0] - nImageWidth / 2);
    2456               2 :         bboxYMin = (int)floor(sEnvelope.MinY * adfMatrix[3] + adfMatrix[2] - nImageHeight / 2);
    2457               2 :         bboxXMax = (int)ceil(sEnvelope.MaxX * adfMatrix[1] + adfMatrix[0] + nImageWidth / 2);
    2458               2 :         bboxYMax = (int)ceil(sEnvelope.MaxY * adfMatrix[3] + adfMatrix[2] + nImageHeight / 2);
    2459                 :     }
    2460                 :     else
    2461                 :     {
    2462              36 :         double dfMargin = dfPenWidth;
    2463              36 :         if( wkbFlatten(OGR_G_GetGeometryType(hGeom)) == wkbPoint )
    2464                 :         {
    2465              28 :             if (osSymbolId == "ogr-sym-6" ||
    2466                 :                 osSymbolId == "ogr-sym-7")
    2467                 :             {
    2468               4 :                 const double dfSqrt3 = 1.73205080757;
    2469               4 :                 dfMargin += dfRadius * 2 * dfSqrt3 / 3;
    2470                 :             }
    2471                 :             else
    2472              24 :                 dfMargin += dfRadius;
    2473                 :         }
    2474              36 :         bboxXMin = (int)floor(sEnvelope.MinX * adfMatrix[1] + adfMatrix[0] - dfMargin);
    2475              36 :         bboxYMin = (int)floor(sEnvelope.MinY * adfMatrix[3] + adfMatrix[2] - dfMargin);
    2476              36 :         bboxXMax = (int)ceil(sEnvelope.MaxX * adfMatrix[1] + adfMatrix[0] + dfMargin);
    2477              36 :         bboxYMax = (int)ceil(sEnvelope.MaxY * adfMatrix[3] + adfMatrix[2] + dfMargin);
    2478                 :     }
    2479                 : 
    2480              38 :     int iField = -1;
    2481              38 :     const char* pszLinkVal = NULL;
    2482              38 :     if (pszOGRLinkField != NULL &&
    2483                 :         (iField = OGR_FD_GetFieldIndex(OGR_F_GetDefnRef(hFeat), pszOGRLinkField)) >= 0 &&
    2484                 :         OGR_F_IsFieldSet(hFeat, iField) &&
    2485                 :         strcmp((pszLinkVal = OGR_F_GetFieldAsString(hFeat, iField)), "") != 0)
    2486                 :     {
    2487               4 :         int nAnnotId = AllocNewObject();
    2488               4 :         oPageContext.anAnnotationsId.push_back(nAnnotId);
    2489               4 :         StartObj(nAnnotId);
    2490                 :         {
    2491               4 :             GDALPDFDictionaryRW oDict;
    2492               4 :             oDict.Add("Type", GDALPDFObjectRW::CreateName("Annot"));
    2493               4 :             oDict.Add("Subtype", GDALPDFObjectRW::CreateName("Link"));
    2494               4 :             oDict.Add("Rect", &(new GDALPDFArrayRW())->Add(bboxXMin).Add(bboxYMin).Add(bboxXMax).Add(bboxYMax));
    2495                 :             oDict.Add("A", &(new GDALPDFDictionaryRW())->
    2496                 :                 Add("S", GDALPDFObjectRW::CreateName("URI")).
    2497               4 :                 Add("URI", pszLinkVal));
    2498                 :             oDict.Add("BS", &(new GDALPDFDictionaryRW())->
    2499                 :                 Add("Type", GDALPDFObjectRW::CreateName("Border")).
    2500                 :                 Add("S", GDALPDFObjectRW::CreateName("S")).
    2501               4 :                 Add("W", 0));
    2502               4 :             oDict.Add("Border", &(new GDALPDFArrayRW())->Add(0).Add(0).Add(0));
    2503               4 :             oDict.Add("H", GDALPDFObjectRW::CreateName("I"));
    2504                 : 
    2505               4 :             if( wkbFlatten(OGR_G_GetGeometryType(hGeom)) == wkbPolygon && 
    2506                 :                 OGR_G_GetGeometryCount(hGeom) == 1 )
    2507                 :             {
    2508               2 :                 OGRGeometryH hSubGeom = OGR_G_GetGeometryRef(hGeom, 0);
    2509               2 :                 int nPoints = OGR_G_GetPointCount(hSubGeom);
    2510               2 :                 if( nPoints == 4 || nPoints == 5 )
    2511                 :                 {
    2512               2 :                     std::vector<double> adfX, adfY;
    2513              12 :                     for(int i=0;i<nPoints;i++)
    2514                 :                     {
    2515              10 :                         double dfX = OGR_G_GetX(hSubGeom, i) * adfMatrix[1] + adfMatrix[0];
    2516              10 :                         double dfY = OGR_G_GetY(hSubGeom, i) * adfMatrix[3] + adfMatrix[2];
    2517              10 :                         adfX.push_back(dfX);
    2518              10 :                         adfY.push_back(dfY);
    2519                 :                     }
    2520               2 :                     if( nPoints == 4 )
    2521                 :                     {
    2522                 :                         oDict.Add("QuadPoints", &(new GDALPDFArrayRW())->
    2523                 :                             Add(adfX[0]).Add(adfY[0]).
    2524                 :                             Add(adfX[1]).Add(adfY[1]).
    2525                 :                             Add(adfX[2]).Add(adfY[2]).
    2526               0 :                             Add(adfX[0]).Add(adfY[0]));
    2527                 :                     }
    2528               2 :                     else if( nPoints == 5 )
    2529                 :                     {
    2530                 :                         oDict.Add("QuadPoints", &(new GDALPDFArrayRW())->
    2531                 :                             Add(adfX[0]).Add(adfY[0]).
    2532                 :                             Add(adfX[1]).Add(adfY[1]).
    2533                 :                             Add(adfX[2]).Add(adfY[2]).
    2534               2 :                             Add(adfX[3]).Add(adfY[3]));
    2535               2 :                     }
    2536                 :                 }
    2537                 :             }
    2538                 : 
    2539               4 :             VSIFPrintfL(fp, "%s\n", oDict.Serialize().c_str());
    2540                 :         }
    2541               4 :         EndObj();
    2542                 :     }
    2543                 : 
    2544              38 :     StartObj(nObjectId);
    2545                 :     {
    2546              38 :         GDALPDFDictionaryRW oDict;
    2547              38 :         GDALPDFArrayRW* poBBOX = new GDALPDFArrayRW();
    2548              76 :         poBBOX->Add(bboxXMin).Add(bboxYMin).Add(bboxXMax). Add(bboxYMax);
    2549                 :         oDict.Add("Length", nObjectLengthId, 0)
    2550                 :             .Add("Type", GDALPDFObjectRW::CreateName("XObject"))
    2551                 :             .Add("BBox", poBBOX)
    2552              38 :             .Add("Subtype", GDALPDFObjectRW::CreateName("Form"));
    2553              38 :         if( oPageContext.eStreamCompressMethod != COMPRESS_NONE )
    2554                 :         {
    2555              38 :             oDict.Add("Filter", GDALPDFObjectRW::CreateName("FlateDecode"));
    2556                 :         }
    2557                 : 
    2558              38 :         GDALPDFDictionaryRW* poGS1 = new GDALPDFDictionaryRW();
    2559              76 :         poGS1->Add("Type", GDALPDFObjectRW::CreateName("ExtGState"));
    2560              38 :         if (nPenA != 255)
    2561               0 :             poGS1->Add("CA", (nPenA == 127 || nPenA == 128) ? 0.5 : nPenA / 255.0);
    2562              38 :         if (nBrushA != 255)
    2563              16 :             poGS1->Add("ca", (nBrushA == 127 || nBrushA == 128) ? 0.5 : nBrushA / 255.0 );
    2564                 : 
    2565              38 :         GDALPDFDictionaryRW* poExtGState = new GDALPDFDictionaryRW();
    2566              38 :         poExtGState->Add("GS1", poGS1);
    2567                 : 
    2568              38 :         GDALPDFDictionaryRW* poResources = new GDALPDFDictionaryRW();
    2569              38 :         poResources->Add("ExtGState", poExtGState);
    2570                 : 
    2571              38 :         if( nImageSymbolId != 0 )
    2572                 :         {
    2573               2 :             GDALPDFDictionaryRW* poDictXObject = new GDALPDFDictionaryRW();
    2574               2 :             poResources->Add("XObject", poDictXObject);
    2575                 : 
    2576               2 :             poDictXObject->Add(CPLSPrintf("SymImage%d", nImageSymbolId), nImageSymbolId, 0);
    2577                 :         }
    2578                 : 
    2579              38 :         oDict.Add("Resources", poResources);
    2580                 : 
    2581              38 :         VSIFPrintfL(fp, "%s\n", oDict.Serialize().c_str());
    2582                 :     }
    2583                 : 
    2584                 :     /* -------------------------------------------------------------- */
    2585                 :     /*  Write object stream                                           */
    2586                 :     /* -------------------------------------------------------------- */
    2587              38 :     VSIFPrintfL(fp, "stream\n");
    2588                 : 
    2589              38 :     vsi_l_offset nStreamStart = VSIFTellL(fp);
    2590                 : 
    2591              38 :     VSILFILE* fpGZip = NULL;
    2592              38 :     VSILFILE* fpBack = fp;
    2593              38 :     if( oPageContext.eStreamCompressMethod != COMPRESS_NONE )
    2594                 :     {
    2595              38 :         fpGZip = (VSILFILE* )VSICreateGZipWritable( (VSIVirtualHandle*) fp, TRUE, FALSE );
    2596              38 :         fp = fpGZip;
    2597                 :     }
    2598                 : 
    2599              38 :     VSIFPrintfL(fp, "q\n");
    2600                 : 
    2601              38 :     VSIFPrintfL(fp, "/GS1 gs\n");
    2602                 : 
    2603              38 :     if (nImageSymbolId == 0)
    2604                 :     {
    2605                 :         VSIFPrintfL(fp, "%f w\n"
    2606                 :                         "0 J\n"
    2607                 :                         "0 j\n"
    2608                 :                         "10 M\n"
    2609                 :                         "[%s]0 d\n",
    2610                 :                         dfPenWidth,
    2611              36 :                         osDashArray.c_str());
    2612                 : 
    2613              36 :         VSIFPrintfL(fp, "%f %f %f RG\n", nPenR / 255.0, nPenG / 255.0, nPenB / 255.0);
    2614              36 :         VSIFPrintfL(fp, "%f %f %f rg\n", nBrushR / 255.0, nBrushG / 255.0, nBrushB / 255.0);
    2615                 :     }
    2616                 : 
    2617              38 :     if (wkbFlatten(OGR_G_GetGeometryType(hGeom)) == wkbPoint)
    2618                 :     {
    2619              30 :         double dfX = OGR_G_GetX(hGeom, 0) * adfMatrix[1] + adfMatrix[0];
    2620              30 :         double dfY = OGR_G_GetY(hGeom, 0) * adfMatrix[3] + adfMatrix[2];
    2621                 : 
    2622              30 :         if (nImageSymbolId != 0)
    2623                 :         {
    2624                 :             VSIFPrintfL(fp, "%d 0 0 %d %f %f cm\n",
    2625                 :                         nImageWidth, nImageHeight,
    2626               2 :                         dfX - nImageWidth / 2, dfY - nImageHeight / 2);
    2627               2 :             VSIFPrintfL(fp, "/SymImage%d Do\n", nImageSymbolId);
    2628                 :         }
    2629              28 :         else if (osSymbolId == "")
    2630               8 :             osSymbolId = "ogr-sym-3"; /* symbol by default */
    2631              20 :         else if ( !(osSymbolId == "ogr-sym-0" ||
    2632                 :                     osSymbolId == "ogr-sym-1" ||
    2633                 :                     osSymbolId == "ogr-sym-2" ||
    2634                 :                     osSymbolId == "ogr-sym-3" ||
    2635                 :                     osSymbolId == "ogr-sym-4" ||
    2636                 :                     osSymbolId == "ogr-sym-5" ||
    2637                 :                     osSymbolId == "ogr-sym-6" ||
    2638                 :                     osSymbolId == "ogr-sym-7" ||
    2639                 :                     osSymbolId == "ogr-sym-8" ||
    2640                 :                     osSymbolId == "ogr-sym-9") )
    2641                 :         {
    2642               0 :             CPLDebug("PDF", "Unhandled symbol id : %s. Using ogr-sym-3 instead", osSymbolId.c_str());
    2643               0 :             osSymbolId = "ogr-sym-3";
    2644                 :         }
    2645                 : 
    2646              30 :         if (osSymbolId == "ogr-sym-0") /* cross (+)  */
    2647                 :         {
    2648               2 :             VSIFPrintfL(fp, "%f %f m\n", dfX - dfRadius, dfY);
    2649               2 :             VSIFPrintfL(fp, "%f %f l\n", dfX + dfRadius, dfY);
    2650               2 :             VSIFPrintfL(fp, "%f %f m\n", dfX, dfY - dfRadius);
    2651               2 :             VSIFPrintfL(fp, "%f %f l\n", dfX, dfY + dfRadius);
    2652               2 :             VSIFPrintfL(fp, "S\n");
    2653                 :         }
    2654              28 :         else if (osSymbolId == "ogr-sym-1") /* diagcross (X) */
    2655                 :         {
    2656               2 :             VSIFPrintfL(fp, "%f %f m\n", dfX - dfRadius, dfY - dfRadius);
    2657               2 :             VSIFPrintfL(fp, "%f %f l\n", dfX + dfRadius, dfY + dfRadius);
    2658               2 :             VSIFPrintfL(fp, "%f %f m\n", dfX - dfRadius, dfY + dfRadius);
    2659               2 :             VSIFPrintfL(fp, "%f %f l\n", dfX + dfRadius, dfY - dfRadius);
    2660               2 :             VSIFPrintfL(fp, "S\n");
    2661                 :         }
    2662              26 :         else if (osSymbolId == "ogr-sym-2" ||
    2663                 :                  osSymbolId == "ogr-sym-3") /* circle */
    2664                 :         {
    2665                 :             /* See http://www.whizkidtech.redprince.net/bezier/circle/kappa/ */
    2666              12 :             const double dfKappa = 0.5522847498;
    2667                 : 
    2668              12 :             VSIFPrintfL(fp, "%f %f m\n", dfX - dfRadius, dfY);
    2669                 :             VSIFPrintfL(fp, "%f %f %f %f %f %f c\n",
    2670                 :                         dfX - dfRadius, dfY - dfRadius * dfKappa,
    2671                 :                         dfX - dfRadius * dfKappa, dfY - dfRadius,
    2672              12 :                         dfX, dfY - dfRadius);
    2673                 :             VSIFPrintfL(fp, "%f %f %f %f %f %f c\n",
    2674                 :                         dfX + dfRadius * dfKappa, dfY - dfRadius,
    2675                 :                         dfX + dfRadius, dfY - dfRadius * dfKappa,
    2676              12 :                         dfX + dfRadius, dfY);
    2677                 :             VSIFPrintfL(fp, "%f %f %f %f %f %f c\n",
    2678                 :                         dfX + dfRadius, dfY + dfRadius * dfKappa,
    2679                 :                         dfX + dfRadius * dfKappa, dfY + dfRadius,
    2680              12 :                         dfX, dfY + dfRadius);
    2681                 :             VSIFPrintfL(fp, "%f %f %f %f %f %f c\n",
    2682                 :                         dfX - dfRadius * dfKappa, dfY + dfRadius,
    2683                 :                         dfX - dfRadius, dfY + dfRadius * dfKappa,
    2684              12 :                         dfX - dfRadius, dfY);
    2685              12 :             if (osSymbolId == "ogr-sym-2") 
    2686               2 :                 VSIFPrintfL(fp, "s\n"); /* not filled */
    2687                 :             else
    2688              10 :                 VSIFPrintfL(fp, "b*\n"); /* filled */
    2689                 :         }
    2690              14 :         else if (osSymbolId == "ogr-sym-4" ||
    2691                 :                  osSymbolId == "ogr-sym-5") /* square */
    2692                 :         {
    2693               4 :             VSIFPrintfL(fp, "%f %f m\n", dfX - dfRadius, dfY + dfRadius);
    2694               4 :             VSIFPrintfL(fp, "%f %f l\n", dfX + dfRadius, dfY + dfRadius);
    2695               4 :             VSIFPrintfL(fp, "%f %f l\n", dfX + dfRadius, dfY - dfRadius);
    2696               4 :             VSIFPrintfL(fp, "%f %f l\n", dfX - dfRadius, dfY - dfRadius);
    2697               4 :             if (osSymbolId == "ogr-sym-4")
    2698               2 :                 VSIFPrintfL(fp, "s\n"); /* not filled */
    2699                 :             else
    2700               2 :                 VSIFPrintfL(fp, "b*\n"); /* filled */
    2701                 :         }
    2702              10 :         else if (osSymbolId == "ogr-sym-6" ||
    2703                 :                  osSymbolId == "ogr-sym-7") /* triangle */
    2704                 :         {
    2705               4 :             const double dfSqrt3 = 1.73205080757;
    2706               4 :             VSIFPrintfL(fp, "%f %f m\n", dfX - dfRadius, dfY - dfRadius * dfSqrt3 / 3);
    2707               4 :             VSIFPrintfL(fp, "%f %f l\n", dfX, dfY + 2 * dfRadius * dfSqrt3 / 3);
    2708               4 :             VSIFPrintfL(fp, "%f %f l\n", dfX + dfRadius, dfY - dfRadius * dfSqrt3 / 3);
    2709               4 :             if (osSymbolId == "ogr-sym-6")
    2710               2 :                 VSIFPrintfL(fp, "s\n"); /* not filled */
    2711                 :             else
    2712               2 :                 VSIFPrintfL(fp, "b*\n"); /* filled */
    2713                 :         }
    2714               6 :         else if (osSymbolId == "ogr-sym-8" ||
    2715                 :                  osSymbolId == "ogr-sym-9") /* star */
    2716                 :         {
    2717               4 :             const double dfSin18divSin126 = 0.38196601125;
    2718               4 :             VSIFPrintfL(fp, "%f %f m\n", dfX, dfY + dfRadius);
    2719              40 :             for(int i=1; i<10;i++)
    2720                 :             {
    2721              36 :                 double dfFactor = ((i % 2) == 1) ? dfSin18divSin126 : 1.0;
    2722                 :                 VSIFPrintfL(fp, "%f %f l\n",
    2723                 :                             dfX + cos(M_PI / 2 - i * M_PI * 36 / 180) * dfRadius * dfFactor,
    2724              36 :                             dfY + sin(M_PI / 2 - i * M_PI * 36 / 180) * dfRadius * dfFactor);
    2725                 :             }
    2726               4 :             if (osSymbolId == "ogr-sym-8")
    2727               2 :                 VSIFPrintfL(fp, "s\n"); /* not filled */
    2728                 :             else
    2729               2 :                 VSIFPrintfL(fp, "b*\n"); /* filled */
    2730                 :         }
    2731                 :     }
    2732                 :     else
    2733                 :     {
    2734               8 :         DrawGeometry(fp, hGeom, adfMatrix);
    2735                 :     }
    2736                 : 
    2737              38 :     VSIFPrintfL(fp, "Q");
    2738                 : 
    2739              38 :     if (fpGZip)
    2740              38 :         VSIFCloseL(fpGZip);
    2741              38 :     fp = fpBack;
    2742                 : 
    2743              38 :     vsi_l_offset nStreamEnd = VSIFTellL(fp);
    2744              38 :     VSIFPrintfL(fp, "\n");
    2745              38 :     VSIFPrintfL(fp, "endstream\n");
    2746              38 :     EndObj();
    2747                 : 
    2748              38 :     StartObj(nObjectLengthId);
    2749                 :     VSIFPrintfL(fp,
    2750                 :                 "   %ld\n",
    2751              38 :                 (long)(nStreamEnd - nStreamStart));
    2752              38 :     EndObj();
    2753                 : 
    2754                 :     /* -------------------------------------------------------------- */
    2755                 :     /*  Write label                                                   */
    2756                 :     /* -------------------------------------------------------------- */
    2757              38 :     if (osLabelText.size() && wkbFlatten(OGR_G_GetGeometryType(hGeom)) == wkbPoint)
    2758                 :     {
    2759               3 :         if (osVectorDesc.nOCGTextId == 0)
    2760               3 :             osVectorDesc.nOCGTextId = WriteOCG("Text", osVectorDesc.nOGCId);
    2761                 : 
    2762                 :         /* -------------------------------------------------------------- */
    2763                 :         /*  Write object dictionary                                       */
    2764                 :         /* -------------------------------------------------------------- */
    2765               3 :         nObjectId = AllocNewObject();
    2766               3 :         nObjectLengthId = AllocNewObject();
    2767                 : 
    2768               3 :         osVectorDesc.aIdsText.push_back(nObjectId);
    2769                 : 
    2770               3 :         StartObj(nObjectId);
    2771                 :         {
    2772               3 :             GDALPDFDictionaryRW oDict;
    2773                 : 
    2774               3 :             GDALDataset* poClippingDS = oPageContext.poClippingDS;
    2775               3 :             int  nWidth = poClippingDS->GetRasterXSize();
    2776               3 :             int  nHeight = poClippingDS->GetRasterYSize();
    2777               3 :             double dfUserUnit = oPageContext.dfDPI / 72.0;
    2778               3 :             double dfWidthInUserUnit = nWidth / dfUserUnit + oPageContext.sMargins.nLeft + oPageContext.sMargins.nRight;
    2779               3 :             double dfHeightInUserUnit = nHeight / dfUserUnit + oPageContext.sMargins.nBottom + oPageContext.sMargins.nTop;
    2780                 : 
    2781                 :             oDict.Add("Length", nObjectLengthId, 0)
    2782                 :                 .Add("Type", GDALPDFObjectRW::CreateName("XObject"))
    2783                 :                 .Add("BBox", &((new GDALPDFArrayRW())
    2784                 :                                 ->Add(0).Add(0)).Add(dfWidthInUserUnit).Add(dfHeightInUserUnit))
    2785               3 :                 .Add("Subtype", GDALPDFObjectRW::CreateName("Form"));
    2786               3 :             if( oPageContext.eStreamCompressMethod != COMPRESS_NONE )
    2787                 :             {
    2788               3 :                 oDict.Add("Filter", GDALPDFObjectRW::CreateName("FlateDecode"));
    2789                 :             }
    2790                 : 
    2791               3 :             GDALPDFDictionaryRW* poResources = new GDALPDFDictionaryRW();
    2792                 : 
    2793               3 :             if (nTextA != 255)
    2794                 :             {
    2795               1 :                 GDALPDFDictionaryRW* poGS1 = new GDALPDFDictionaryRW();
    2796               2 :                 poGS1->Add("Type", GDALPDFObjectRW::CreateName("ExtGState"));
    2797               1 :                 poGS1->Add("ca", (nTextA == 127 || nTextA == 128) ? 0.5 : nTextA / 255.0);
    2798                 : 
    2799               1 :                 GDALPDFDictionaryRW* poExtGState = new GDALPDFDictionaryRW();
    2800               1 :                 poExtGState->Add("GS1", poGS1);
    2801                 : 
    2802               1 :                 poResources->Add("ExtGState", poExtGState);
    2803                 :             }
    2804                 : 
    2805               3 :             GDALPDFDictionaryRW* poDictFTimesRoman = NULL;
    2806               3 :             poDictFTimesRoman = new GDALPDFDictionaryRW();
    2807               6 :             poDictFTimesRoman->Add("Type", GDALPDFObjectRW::CreateName("Font"));
    2808               3 :             poDictFTimesRoman->Add("BaseFont", GDALPDFObjectRW::CreateName("Times-Roman"));
    2809               3 :             poDictFTimesRoman->Add("Encoding", GDALPDFObjectRW::CreateName("WinAnsiEncoding"));
    2810               3 :             poDictFTimesRoman->Add("Subtype", GDALPDFObjectRW::CreateName("Type1"));
    2811                 : 
    2812               3 :             GDALPDFDictionaryRW* poDictFont = new GDALPDFDictionaryRW();
    2813               3 :             if (poDictFTimesRoman)
    2814               3 :                 poDictFont->Add("FTimesRoman", poDictFTimesRoman);
    2815               3 :             poResources->Add("Font", poDictFont);
    2816                 : 
    2817               3 :             oDict.Add("Resources", poResources);
    2818                 : 
    2819               3 :             VSIFPrintfL(fp, "%s\n", oDict.Serialize().c_str());
    2820                 :         }
    2821                 : 
    2822                 :         /* -------------------------------------------------------------- */
    2823                 :         /*  Write object stream                                           */
    2824                 :         /* -------------------------------------------------------------- */
    2825               3 :         VSIFPrintfL(fp, "stream\n");
    2826                 : 
    2827               3 :         vsi_l_offset nStreamStart = VSIFTellL(fp);
    2828                 : 
    2829               3 :         VSILFILE* fpGZip = NULL;
    2830               3 :         VSILFILE* fpBack = fp;
    2831               3 :         if( oPageContext.eStreamCompressMethod != COMPRESS_NONE )
    2832                 :         {
    2833               3 :             fpGZip = (VSILFILE* )VSICreateGZipWritable( (VSIVirtualHandle*) fp, TRUE, FALSE );
    2834               3 :             fp = fpGZip;
    2835                 :         }
    2836                 : 
    2837               3 :         double dfX = OGR_G_GetX(hGeom, 0) * adfMatrix[1] + adfMatrix[0] + dfTextDx;
    2838               3 :         double dfY = OGR_G_GetY(hGeom, 0) * adfMatrix[3] + adfMatrix[2] + dfTextDy;
    2839                 : 
    2840               3 :         VSIFPrintfL(fp, "q\n");
    2841               3 :         VSIFPrintfL(fp, "BT\n");
    2842               3 :         if (nTextA != 255)
    2843                 :         {
    2844               1 :             VSIFPrintfL(fp, "/GS1 gs\n");
    2845                 :         }
    2846               3 :         if (dfTextAngle == 0)
    2847                 :         {
    2848               2 :             VSIFPrintfL(fp, "%f %f Td\n", dfX, dfY);
    2849                 :         }
    2850                 :         else
    2851                 :         {
    2852               1 :             dfTextAngle = - dfTextAngle * M_PI / 180.0;
    2853                 :             VSIFPrintfL(fp, "%f %f %f %f %f %f Tm\n",
    2854                 :                         cos(dfTextAngle), -sin(dfTextAngle),
    2855                 :                         sin(dfTextAngle), cos(dfTextAngle),
    2856               1 :                         dfX, dfY);
    2857                 :         }
    2858               3 :         VSIFPrintfL(fp, "%f %f %f rg\n", nTextR / 255.0, nTextG / 255.0, nTextB / 255.0);
    2859               3 :         VSIFPrintfL(fp, "/FTimesRoman %f Tf\n", dfTextSize);
    2860               3 :         VSIFPrintfL(fp, "(");
    2861              37 :         for(size_t i=0;i<osLabelText.size();i++)
    2862                 :         {
    2863                 :             /*if (osLabelText[i] == '\n')
    2864                 :                 VSIFPrintfL(fp, ") Tj T* (");
    2865              34 :             else */if (osLabelText[i] >= 32 && osLabelText[i] <= 127)
    2866              34 :                 VSIFPrintfL(fp, "%c", osLabelText[i]);
    2867                 :             else
    2868               0 :                 VSIFPrintfL(fp, "_");
    2869                 :         }
    2870               3 :         VSIFPrintfL(fp, ") Tj\n");
    2871               3 :         VSIFPrintfL(fp, "ET\n");
    2872               3 :         VSIFPrintfL(fp, "Q");
    2873                 : 
    2874               3 :         if (fpGZip)
    2875               3 :             VSIFCloseL(fpGZip);
    2876               3 :         fp = fpBack;
    2877                 : 
    2878               3 :         vsi_l_offset nStreamEnd = VSIFTellL(fp);
    2879               3 :         VSIFPrintfL(fp, "\n");
    2880               3 :         VSIFPrintfL(fp, "endstream\n");
    2881               3 :         EndObj();
    2882                 : 
    2883               3 :         StartObj(nObjectLengthId);
    2884                 :         VSIFPrintfL(fp,
    2885                 :                     "   %ld\n",
    2886               3 :                     (long)(nStreamEnd - nStreamStart));
    2887               3 :         EndObj();
    2888                 :     }
    2889                 :     else
    2890                 :     {
    2891              35 :         osVectorDesc.aIdsText.push_back(0);
    2892                 :     }
    2893                 : 
    2894                 :     /* -------------------------------------------------------------- */
    2895                 :     /*  Write feature attributes                                      */
    2896                 :     /* -------------------------------------------------------------- */
    2897              38 :     int nFeatureUserProperties = 0;
    2898                 : 
    2899              38 :     CPLString osFeatureName;
    2900                 : 
    2901              38 :     if (bWriteOGRAttributes)
    2902                 :     {
    2903              23 :         int iField = -1;
    2904              23 :         if (pszOGRDisplayField &&
    2905                 :             (iField = OGR_FD_GetFieldIndex(OGR_F_GetDefnRef(hFeat), pszOGRDisplayField)) >= 0)
    2906               3 :             osFeatureName = OGR_F_GetFieldAsString(hFeat, iField);
    2907                 :         else
    2908              20 :             osFeatureName = CPLSPrintf("feature%d", iObjLayer + 1);
    2909                 : 
    2910              23 :         nFeatureUserProperties = AllocNewObject();
    2911              23 :         StartObj(nFeatureUserProperties);
    2912                 : 
    2913              23 :         GDALPDFDictionaryRW oDict;
    2914              23 :         GDALPDFDictionaryRW* poDictA = new GDALPDFDictionaryRW();
    2915              23 :         oDict.Add("A", poDictA);
    2916              23 :         poDictA->Add("O", GDALPDFObjectRW::CreateName("UserProperties"));
    2917                 : 
    2918              23 :         int nFields = OGR_F_GetFieldCount(hFeat);
    2919              23 :         GDALPDFArrayRW* poArray = new GDALPDFArrayRW();
    2920              97 :         for(int i = 0; i < nFields; i++)
    2921                 :         {
    2922              74 :             if (OGR_F_IsFieldSet(hFeat, i))
    2923                 :             {
    2924              20 :                 OGRFieldDefnH hFDefn = OGR_F_GetFieldDefnRef( hFeat, i );
    2925              20 :                 GDALPDFDictionaryRW* poKV = new GDALPDFDictionaryRW();
    2926              40 :                 poKV->Add("N", OGR_Fld_GetNameRef(hFDefn));
    2927              20 :                 if (OGR_Fld_GetType(hFDefn) == OFTInteger)
    2928               9 :                     poKV->Add("V", OGR_F_GetFieldAsInteger(hFeat, i));
    2929              11 :                 else if (OGR_Fld_GetType(hFDefn) == OFTReal)
    2930               1 :                     poKV->Add("V", OGR_F_GetFieldAsDouble(hFeat, i));
    2931                 :                 else
    2932              10 :                     poKV->Add("V", OGR_F_GetFieldAsString(hFeat, i));
    2933              20 :                 poArray->Add(poKV);
    2934                 :             }
    2935                 :         }
    2936                 : 
    2937              23 :         poDictA->Add("P", poArray);
    2938                 : 
    2939              23 :         oDict.Add("K", iObj);
    2940              23 :         oDict.Add("P", osVectorDesc.nFeatureLayerId, 0);
    2941              23 :         oDict.Add("Pg", oPageContext.nPageId, 0);
    2942              23 :         oDict.Add("S", GDALPDFObjectRW::CreateName("feature"));
    2943              23 :         oDict.Add("T", osFeatureName);
    2944                 : 
    2945              23 :         VSIFPrintfL(fp, "%s\n", oDict.Serialize().c_str());
    2946                 : 
    2947              23 :         EndObj();
    2948                 :     }
    2949                 : 
    2950              38 :     iObj ++;
    2951              38 :     iObjLayer ++;
    2952                 : 
    2953              38 :     osVectorDesc.aUserPropertiesIds.push_back(nFeatureUserProperties);
    2954              38 :     osVectorDesc.aFeatureNames.push_back(osFeatureName);
    2955                 : 
    2956              38 :     return TRUE;
    2957                 : }
    2958                 : 
    2959                 : #endif
    2960                 : 
    2961                 : /************************************************************************/
    2962                 : /*                               EndPage()                              */
    2963                 : /************************************************************************/
    2964                 : 
    2965              53 : int GDALPDFWriter::EndPage(const char* pszExtraImages,
    2966                 :                            const char* pszExtraStream,
    2967                 :                            const char* pszExtraLayerName,
    2968                 :                            const char* pszOffLayers,
    2969                 :                            const char* pszExclusiveLayers)
    2970                 : {
    2971              53 :     int nLayerExtraId = WriteOCG(pszExtraLayerName);
    2972              53 :     if( pszOffLayers )
    2973               1 :         osOffLayers = pszOffLayers;
    2974              53 :     if( pszExclusiveLayers )
    2975               1 :         osExclusiveLayers = pszExclusiveLayers;
    2976                 : 
    2977              53 :     int bHasTimesRoman = pszExtraStream && strstr(pszExtraStream, "/FTimesRoman");
    2978              53 :     int bHasTimesBold = pszExtraStream && strstr(pszExtraStream, "/FTimesBold");
    2979                 : 
    2980                 :     /* -------------------------------------------------------------- */
    2981                 :     /*  Write extra images                                            */
    2982                 :     /* -------------------------------------------------------------- */
    2983              53 :     std::vector<GDALPDFImageDesc> asExtraImageDesc;
    2984              53 :     if (pszExtraImages)
    2985                 :     {
    2986               1 :         if( GDALGetDriverCount() == 0 )
    2987               0 :             GDALAllRegister();
    2988                 : 
    2989               1 :         char** papszExtraImagesTokens = CSLTokenizeString2(pszExtraImages, ",", 0);
    2990               1 :         double dfUserUnit = oPageContext.dfDPI / 72.0;
    2991               1 :         int nCount = CSLCount(papszExtraImagesTokens);
    2992               4 :         for(int i=0;i+4<=nCount; /* */)
    2993                 :         {
    2994               2 :             const char* pszImageFilename = papszExtraImagesTokens[i+0];
    2995               2 :             double dfX = atof(papszExtraImagesTokens[i+1]);
    2996               2 :             double dfY = atof(papszExtraImagesTokens[i+2]);
    2997               2 :             double dfScale = atof(papszExtraImagesTokens[i+3]);
    2998               2 :             const char* pszLinkVal = NULL;
    2999               2 :             i += 4;
    3000               2 :             if( i < nCount && EQUALN(papszExtraImagesTokens[i],"link=",5) )
    3001                 :             {
    3002               1 :                 pszLinkVal = papszExtraImagesTokens[i] + 5;
    3003               1 :                 i++;
    3004                 :             }
    3005               2 :             GDALDataset* poImageDS = (GDALDataset* )GDALOpen(pszImageFilename, GA_ReadOnly);
    3006               2 :             if (poImageDS)
    3007                 :             {
    3008                 :                 int nImageId = WriteBlock( poImageDS,
    3009                 :                                             0, 0,
    3010                 :                                             poImageDS->GetRasterXSize(),
    3011                 :                                             poImageDS->GetRasterYSize(),
    3012                 :                                             0,
    3013                 :                                             COMPRESS_DEFAULT,
    3014                 :                                             0,
    3015                 :                                             -1,
    3016                 :                                             NULL,
    3017                 :                                             NULL,
    3018               2 :                                             NULL );
    3019                 : 
    3020               2 :                 if (nImageId)
    3021                 :                 {
    3022                 :                     GDALPDFImageDesc oImageDesc;
    3023               2 :                     oImageDesc.nImageId = nImageId;
    3024               2 :                     oImageDesc.dfXSize = poImageDS->GetRasterXSize() / dfUserUnit * dfScale;
    3025               2 :                     oImageDesc.dfYSize = poImageDS->GetRasterYSize() / dfUserUnit * dfScale;
    3026               2 :                     oImageDesc.dfXOff = dfX;
    3027               2 :                     oImageDesc.dfYOff = dfY;
    3028                 : 
    3029               2 :                     asExtraImageDesc.push_back(oImageDesc);
    3030                 : 
    3031               2 :                     if( pszLinkVal != NULL )
    3032                 :                     {
    3033               1 :                         int nAnnotId = AllocNewObject();
    3034               1 :                         oPageContext.anAnnotationsId.push_back(nAnnotId);
    3035               1 :                         StartObj(nAnnotId);
    3036                 :                         {
    3037               1 :                             GDALPDFDictionaryRW oDict;
    3038               1 :                             oDict.Add("Type", GDALPDFObjectRW::CreateName("Annot"));
    3039               1 :                             oDict.Add("Subtype", GDALPDFObjectRW::CreateName("Link"));
    3040                 :                             oDict.Add("Rect", &(new GDALPDFArrayRW())->
    3041                 :                                 Add(oImageDesc.dfXOff).
    3042                 :                                 Add(oImageDesc.dfYOff).
    3043                 :                                 Add(oImageDesc.dfXOff + oImageDesc.dfXSize).
    3044               1 :                                 Add(oImageDesc.dfYOff + oImageDesc.dfYSize));
    3045                 :                             oDict.Add("A", &(new GDALPDFDictionaryRW())->
    3046                 :                                 Add("S", GDALPDFObjectRW::CreateName("URI")).
    3047               1 :                                 Add("URI", pszLinkVal));
    3048                 :                             oDict.Add("BS", &(new GDALPDFDictionaryRW())->
    3049                 :                                 Add("Type", GDALPDFObjectRW::CreateName("Border")).
    3050                 :                                 Add("S", GDALPDFObjectRW::CreateName("S")).
    3051               1 :                                 Add("W", 0));
    3052               1 :                             oDict.Add("Border", &(new GDALPDFArrayRW())->Add(0).Add(0).Add(0));
    3053               1 :                             oDict.Add("H", GDALPDFObjectRW::CreateName("I"));
    3054                 : 
    3055               1 :                             VSIFPrintfL(fp, "%s\n", oDict.Serialize().c_str());
    3056                 :                         }
    3057               1 :                         EndObj();
    3058                 :                     }
    3059                 :                 }
    3060                 : 
    3061               2 :                 GDALClose(poImageDS);
    3062                 :             }
    3063                 :         }
    3064               1 :         CSLDestroy(papszExtraImagesTokens);
    3065                 :     }
    3066                 : 
    3067                 :     /* -------------------------------------------------------------- */
    3068                 :     /*  Write content dictionary                                      */
    3069                 :     /* -------------------------------------------------------------- */
    3070              53 :     int nContentLengthId = AllocNewObject();
    3071                 : 
    3072              53 :     StartObj(oPageContext.nContentId);
    3073                 :     {
    3074              53 :         GDALPDFDictionaryRW oDict;
    3075              53 :         oDict.Add("Length", nContentLengthId, 0);
    3076              53 :         if( oPageContext.eStreamCompressMethod != COMPRESS_NONE )
    3077                 :         {
    3078              51 :             oDict.Add("Filter", GDALPDFObjectRW::CreateName("FlateDecode"));
    3079                 :         }
    3080              53 :         VSIFPrintfL(fp, "%s\n", oDict.Serialize().c_str());
    3081                 :     }
    3082                 : 
    3083                 :     /* -------------------------------------------------------------- */
    3084                 :     /*  Write content stream                                          */
    3085                 :     /* -------------------------------------------------------------- */
    3086              53 :     VSIFPrintfL(fp, "stream\n");
    3087              53 :     vsi_l_offset nStreamStart = VSIFTellL(fp);
    3088                 : 
    3089              53 :     VSILFILE* fpGZip = NULL;
    3090              53 :     VSILFILE* fpBack = fp;
    3091              53 :     if( oPageContext.eStreamCompressMethod != COMPRESS_NONE )
    3092                 :     {
    3093              51 :         fpGZip = (VSILFILE* )VSICreateGZipWritable( (VSIVirtualHandle*) fp, TRUE, FALSE );
    3094              51 :         fp = fpGZip;
    3095                 :     }
    3096                 : 
    3097                 :     /* -------------------------------------------------------------- */
    3098                 :     /*  Write drawing instructions for raster blocks                  */
    3099                 :     /* -------------------------------------------------------------- */
    3100             105 :     for(size_t iRaster = 0; iRaster < oPageContext.asRasterDesc.size(); iRaster++)
    3101                 :     {
    3102              52 :         const GDALPDFRasterDesc& oDesc = oPageContext.asRasterDesc[iRaster];
    3103              52 :         if (oDesc.nOCGRasterId)
    3104               3 :             VSIFPrintfL(fp, "/OC /Lyr%d BDC\n", oDesc.nOCGRasterId);
    3105                 : 
    3106             180 :         for(size_t iImage = 0; iImage < oDesc.asImageDesc.size(); iImage ++)
    3107                 :         {
    3108             128 :             VSIFPrintfL(fp, "q\n");
    3109             128 :             GDALPDFObjectRW* poXSize = GDALPDFObjectRW::CreateReal(oDesc.asImageDesc[iImage].dfXSize);
    3110             128 :             GDALPDFObjectRW* poYSize = GDALPDFObjectRW::CreateReal(oDesc.asImageDesc[iImage].dfYSize);
    3111             128 :             GDALPDFObjectRW* poXOff = GDALPDFObjectRW::CreateReal(oDesc.asImageDesc[iImage].dfXOff);
    3112             128 :             GDALPDFObjectRW* poYOff = GDALPDFObjectRW::CreateReal(oDesc.asImageDesc[iImage].dfYOff);
    3113                 :             VSIFPrintfL(fp, "%s 0 0 %s %s %s cm\n",
    3114                 :                         poXSize->Serialize().c_str(),
    3115                 :                         poYSize->Serialize().c_str(),
    3116                 :                         poXOff->Serialize().c_str(),
    3117             128 :                         poYOff->Serialize().c_str());
    3118             128 :             delete poXSize;
    3119             128 :             delete poYSize;
    3120             128 :             delete poXOff;
    3121             128 :             delete poYOff;
    3122                 :             VSIFPrintfL(fp, "/Image%d Do\n",
    3123             128 :                         oDesc.asImageDesc[iImage].nImageId);
    3124             128 :             VSIFPrintfL(fp, "Q\n");
    3125                 :         }
    3126                 : 
    3127              52 :         if (oDesc.nOCGRasterId)
    3128               3 :             VSIFPrintfL(fp, "EMC\n");
    3129                 :     }
    3130                 : 
    3131                 :     /* -------------------------------------------------------------- */
    3132                 :     /*  Write drawing instructions for vector features                */
    3133                 :     /* -------------------------------------------------------------- */
    3134              53 :     int iObj = 0;
    3135              57 :     for(size_t iLayer = 0; iLayer < oPageContext.asVectorDesc.size(); iLayer ++)
    3136                 :     {
    3137               4 :         GDALPDFLayerDesc& oLayerDesc = oPageContext.asVectorDesc[iLayer];
    3138                 : 
    3139               4 :         VSIFPrintfL(fp, "/OC /Lyr%d BDC\n", oLayerDesc.nOGCId);
    3140                 : 
    3141              42 :         for(size_t iVector = 0; iVector < oLayerDesc.aIds.size(); iVector ++)
    3142                 :         {
    3143              38 :             CPLString osName = oLayerDesc.aFeatureNames[iVector];
    3144              38 :             if (osName.size())
    3145                 :             {
    3146                 :                 VSIFPrintfL(fp, "/feature <</MCID %d>> BDC\n",
    3147              23 :                             iObj);
    3148                 :             }
    3149                 : 
    3150              38 :             iObj ++;
    3151                 : 
    3152              38 :             VSIFPrintfL(fp, "/Vector%d Do\n", oLayerDesc.aIds[iVector]);
    3153                 : 
    3154              38 :             if (osName.size())
    3155                 :             {
    3156              23 :                 VSIFPrintfL(fp, "EMC\n");
    3157                 :             }
    3158                 :         }
    3159                 : 
    3160               4 :         VSIFPrintfL(fp, "EMC\n");
    3161                 :     }
    3162                 : 
    3163                 :     /* -------------------------------------------------------------- */
    3164                 :     /*  Write drawing instructions for labels of vector features      */
    3165                 :     /* -------------------------------------------------------------- */
    3166              53 :     iObj = 0;
    3167              57 :     for(size_t iLayer = 0; iLayer < oPageContext.asVectorDesc.size(); iLayer ++)
    3168                 :     {
    3169               4 :         GDALPDFLayerDesc& oLayerDesc = oPageContext.asVectorDesc[iLayer];
    3170               4 :         if (oLayerDesc.nOCGTextId)
    3171                 :         {
    3172               3 :             VSIFPrintfL(fp, "/OC /Lyr%d BDC\n", oLayerDesc.nOGCId);
    3173               3 :             VSIFPrintfL(fp, "/OC /Lyr%d BDC\n", oLayerDesc.nOCGTextId);
    3174                 : 
    3175              36 :             for(size_t iVector = 0; iVector < oLayerDesc.aIds.size(); iVector ++)
    3176                 :             {
    3177              33 :                 if (oLayerDesc.aIdsText[iVector])
    3178                 :                 {
    3179               3 :                     CPLString osName = oLayerDesc.aFeatureNames[iVector];
    3180               3 :                     if (osName.size())
    3181                 :                     {
    3182                 :                         VSIFPrintfL(fp, "/feature <</MCID %d>> BDC\n",
    3183               2 :                                     iObj);
    3184                 :                     }
    3185                 : 
    3186               3 :                     VSIFPrintfL(fp, "/Text%d Do\n", oLayerDesc.aIdsText[iVector]);
    3187                 : 
    3188               3 :                     if (osName.size())
    3189                 :                     {
    3190               2 :                         VSIFPrintfL(fp, "EMC\n");
    3191               3 :                     }
    3192                 :                 }
    3193                 : 
    3194              33 :                 iObj ++;
    3195                 :             }
    3196                 : 
    3197               3 :             VSIFPrintfL(fp, "EMC\n");
    3198               3 :             VSIFPrintfL(fp, "EMC\n");
    3199                 :         }
    3200                 :         else
    3201               1 :             iObj += (int) oLayerDesc.aIds.size();
    3202                 :     }
    3203                 : 
    3204                 :     /* -------------------------------------------------------------- */
    3205                 :     /*  Write drawing instructions for extra content.                 */
    3206                 :     /* -------------------------------------------------------------- */
    3207              53 :     if (pszExtraStream || asExtraImageDesc.size())
    3208                 :     {
    3209               1 :         if (nLayerExtraId)
    3210               1 :             VSIFPrintfL(fp, "/OC /Lyr%d BDC\n", nLayerExtraId);
    3211                 : 
    3212                 :         /* -------------------------------------------------------------- */
    3213                 :         /*  Write drawing instructions for extra images.                  */
    3214                 :         /* -------------------------------------------------------------- */
    3215               3 :         for(size_t iImage = 0; iImage < asExtraImageDesc.size(); iImage ++)
    3216                 :         {
    3217               2 :             VSIFPrintfL(fp, "q\n");
    3218               2 :             GDALPDFObjectRW* poXSize = GDALPDFObjectRW::CreateReal(asExtraImageDesc[iImage].dfXSize);
    3219               2 :             GDALPDFObjectRW* poYSize = GDALPDFObjectRW::CreateReal(asExtraImageDesc[iImage].dfYSize);
    3220               2 :             GDALPDFObjectRW* poXOff = GDALPDFObjectRW::CreateReal(asExtraImageDesc[iImage].dfXOff);
    3221               2 :             GDALPDFObjectRW* poYOff = GDALPDFObjectRW::CreateReal(asExtraImageDesc[iImage].dfYOff);
    3222                 :             VSIFPrintfL(fp, "%s 0 0 %s %s %s cm\n",
    3223                 :                         poXSize->Serialize().c_str(),
    3224                 :                         poYSize->Serialize().c_str(),
    3225                 :                         poXOff->Serialize().c_str(),
    3226               2 :                         poYOff->Serialize().c_str());
    3227               2 :             delete poXSize;
    3228               2 :             delete poYSize;
    3229               2 :             delete poXOff;
    3230               2 :             delete poYOff;
    3231                 :             VSIFPrintfL(fp, "/Image%d Do\n",
    3232               2 :                         asExtraImageDesc[iImage].nImageId);
    3233               2 :             VSIFPrintfL(fp, "Q\n");
    3234                 :         }
    3235                 : 
    3236               1 :         if (pszExtraStream)
    3237               1 :             VSIFPrintfL(fp, "%s\n", pszExtraStream);
    3238                 : 
    3239               1 :         if (nLayerExtraId)
    3240               1 :             VSIFPrintfL(fp, "EMC\n");
    3241                 :     }
    3242                 : 
    3243              53 :     if (fpGZip)
    3244              51 :         VSIFCloseL(fpGZip);
    3245              53 :     fp = fpBack;
    3246                 : 
    3247              53 :     vsi_l_offset nStreamEnd = VSIFTellL(fp);
    3248              53 :     if (fpGZip)
    3249              51 :         VSIFPrintfL(fp, "\n");
    3250              53 :     VSIFPrintfL(fp, "endstream\n");
    3251              53 :     EndObj();
    3252                 : 
    3253              53 :     StartObj(nContentLengthId);
    3254                 :     VSIFPrintfL(fp,
    3255                 :                 "   %ld\n",
    3256              53 :                 (long)(nStreamEnd - nStreamStart));
    3257              53 :     EndObj();
    3258                 : 
    3259                 :     /* -------------------------------------------------------------- */
    3260                 :     /*  Write objects for feature tree.                               */
    3261                 :     /* -------------------------------------------------------------- */
    3262              53 :     if (nStructTreeRootId)
    3263                 :     {
    3264               3 :         int nParentTreeId = AllocNewObject();
    3265               3 :         StartObj(nParentTreeId);
    3266               3 :         VSIFPrintfL(fp, "<< /Nums [ 0 ");
    3267               3 :         VSIFPrintfL(fp, "[ ");
    3268               6 :         for(size_t iLayer = 0; iLayer < oPageContext.asVectorDesc.size(); iLayer ++)
    3269                 :         {
    3270               3 :             GDALPDFLayerDesc& oLayerDesc = oPageContext.asVectorDesc[iLayer];
    3271              26 :             for(size_t iVector = 0; iVector < oLayerDesc.aIds.size(); iVector ++)
    3272                 :             {
    3273              23 :                 int nId = oLayerDesc.aUserPropertiesIds[iVector];
    3274              23 :                 if (nId)
    3275              23 :                     VSIFPrintfL(fp, "%d 0 R ", nId);
    3276                 :             }
    3277                 :         }
    3278               3 :         VSIFPrintfL(fp, " ]\n");
    3279               3 :         VSIFPrintfL(fp, " ] >> \n");
    3280               3 :         EndObj();
    3281                 : 
    3282               3 :         StartObj(nStructTreeRootId);
    3283                 :         VSIFPrintfL(fp,
    3284                 :                     "<< "
    3285                 :                     "/Type /StructTreeRoot "
    3286                 :                     "/ParentTree %d 0 R "
    3287               3 :                     "/K [ ", nParentTreeId);
    3288               6 :         for(size_t iLayer = 0; iLayer < oPageContext.asVectorDesc.size(); iLayer ++)
    3289                 :         {
    3290               3 :             VSIFPrintfL(fp, "%d 0 R ", oPageContext.asVectorDesc[iLayer]. nFeatureLayerId);
    3291                 :         }
    3292               3 :         VSIFPrintfL(fp,"] >>\n");
    3293               3 :         EndObj();
    3294                 :     }
    3295                 : 
    3296                 :     /* -------------------------------------------------------------- */
    3297                 :     /*  Write page resource dictionary.                               */
    3298                 :     /* -------------------------------------------------------------- */
    3299              53 :     StartObj(oPageContext.nResourcesId);
    3300                 :     {
    3301              53 :         GDALPDFDictionaryRW oDict;
    3302              53 :         GDALPDFDictionaryRW* poDictXObject = new GDALPDFDictionaryRW();
    3303              53 :         oDict.Add("XObject", poDictXObject);
    3304                 :         size_t iImage;
    3305             105 :         for(size_t iRaster = 0; iRaster < oPageContext.asRasterDesc.size(); iRaster++)
    3306                 :         {
    3307              52 :             const GDALPDFRasterDesc& oDesc = oPageContext.asRasterDesc[iRaster];
    3308             180 :             for(iImage = 0; iImage < oDesc.asImageDesc.size(); iImage ++)
    3309                 :             {
    3310                 :                 poDictXObject->Add(CPLSPrintf("Image%d", oDesc.asImageDesc[iImage].nImageId),
    3311             128 :                                 oDesc.asImageDesc[iImage].nImageId, 0);
    3312                 :             }
    3313                 :         }
    3314              55 :         for(iImage = 0; iImage < asExtraImageDesc.size(); iImage ++)
    3315                 :         {
    3316                 :             poDictXObject->Add(CPLSPrintf("Image%d", asExtraImageDesc[iImage].nImageId),
    3317               2 :                                asExtraImageDesc[iImage].nImageId, 0);
    3318                 :         }
    3319              57 :         for(size_t iLayer = 0; iLayer < oPageContext.asVectorDesc.size(); iLayer ++)
    3320                 :         {
    3321               4 :             GDALPDFLayerDesc& oLayerDesc = oPageContext.asVectorDesc[iLayer];
    3322              42 :             for(size_t iVector = 0; iVector < oLayerDesc.aIds.size(); iVector ++)
    3323                 :             {
    3324                 :                 poDictXObject->Add(CPLSPrintf("Vector%d", oLayerDesc.aIds[iVector]),
    3325              38 :                                 oLayerDesc.aIds[iVector], 0);
    3326              38 :                 if (oLayerDesc.aIdsText[iVector])
    3327                 :                     poDictXObject->Add(CPLSPrintf("Text%d", oLayerDesc.aIdsText[iVector]),
    3328               3 :                                 oLayerDesc.aIdsText[iVector], 0);
    3329                 :             }
    3330                 :         }
    3331                 : 
    3332              53 :         GDALPDFDictionaryRW* poDictFTimesRoman = NULL;
    3333              53 :         if (bHasTimesRoman)
    3334                 :         {
    3335               1 :             poDictFTimesRoman = new GDALPDFDictionaryRW();
    3336               2 :             poDictFTimesRoman->Add("Type", GDALPDFObjectRW::CreateName("Font"));
    3337               1 :             poDictFTimesRoman->Add("BaseFont", GDALPDFObjectRW::CreateName("Times-Roman"));
    3338               1 :             poDictFTimesRoman->Add("Encoding", GDALPDFObjectRW::CreateName("WinAnsiEncoding"));
    3339               1 :             poDictFTimesRoman->Add("Subtype", GDALPDFObjectRW::CreateName("Type1"));
    3340                 :         }
    3341                 : 
    3342              53 :         GDALPDFDictionaryRW* poDictFTimesBold = NULL;
    3343              53 :         if (bHasTimesBold)
    3344                 :         {
    3345               0 :             poDictFTimesBold = new GDALPDFDictionaryRW();
    3346               0 :             poDictFTimesBold->Add("Type", GDALPDFObjectRW::CreateName("Font"));
    3347               0 :             poDictFTimesBold->Add("BaseFont", GDALPDFObjectRW::CreateName("Times-Bold"));
    3348               0 :             poDictFTimesBold->Add("Encoding", GDALPDFObjectRW::CreateName("WinAnsiEncoding"));
    3349               0 :             poDictFTimesBold->Add("Subtype", GDALPDFObjectRW::CreateName("Type1"));
    3350                 :         }
    3351                 : 
    3352              53 :         if (poDictFTimesRoman != NULL || poDictFTimesBold != NULL)
    3353                 :         {
    3354               1 :             GDALPDFDictionaryRW* poDictFont = new GDALPDFDictionaryRW();
    3355               1 :             if (poDictFTimesRoman)
    3356               1 :                 poDictFont->Add("FTimesRoman", poDictFTimesRoman);
    3357               1 :             if (poDictFTimesBold)
    3358               0 :                 poDictFont->Add("FTimesBold", poDictFTimesBold);
    3359               1 :             oDict.Add("Font", poDictFont);
    3360                 :         }
    3361                 : 
    3362              53 :         if (asOCGs.size())
    3363                 :         {
    3364               6 :             GDALPDFDictionaryRW* poDictProperties = new GDALPDFDictionaryRW();
    3365              17 :             for(size_t i=0; i<asOCGs.size(); i++)
    3366                 :                 poDictProperties->Add(CPLSPrintf("Lyr%d", asOCGs[i].nId),
    3367              11 :                                       asOCGs[i].nId, 0);
    3368               6 :             oDict.Add("Properties", poDictProperties);
    3369                 :         }
    3370                 : 
    3371              53 :         VSIFPrintfL(fp, "%s\n", oDict.Serialize().c_str());
    3372                 :     }
    3373              53 :     EndObj();
    3374                 : 
    3375                 :     /* -------------------------------------------------------------- */
    3376                 :     /*  Write annotation arrays.                                      */
    3377                 :     /* -------------------------------------------------------------- */
    3378              53 :     StartObj(oPageContext.nAnnotsId);
    3379                 :     {
    3380              53 :         GDALPDFArrayRW oArray;
    3381              58 :         for(size_t i = 0; i < oPageContext.anAnnotationsId.size(); i++)
    3382                 :         {
    3383               5 :             oArray.Add(oPageContext.anAnnotationsId[i], 0);
    3384                 :         }
    3385              53 :         VSIFPrintfL(fp, "%s\n", oArray.Serialize().c_str());
    3386                 :     }
    3387              53 :     EndObj();
    3388                 : 
    3389              53 :     return TRUE;
    3390                 : }
    3391                 : 
    3392                 : /************************************************************************/
    3393                 : /*                             WriteMask()                              */
    3394                 : /************************************************************************/
    3395                 : 
    3396              63 : int GDALPDFWriter::WriteMask(GDALDataset* poSrcDS,
    3397                 :                              int nXOff, int nYOff, int nReqXSize, int nReqYSize,
    3398                 :                              PDFCompressMethod eCompressMethod)
    3399                 : {
    3400              63 :     int nMaskSize = nReqXSize * nReqYSize;
    3401              63 :     GByte* pabyMask = (GByte*)VSIMalloc(nMaskSize);
    3402              63 :     if (pabyMask == NULL)
    3403               0 :         return 0;
    3404                 : 
    3405                 :     CPLErr eErr;
    3406                 :     eErr = poSrcDS->GetRasterBand(4)->RasterIO(
    3407                 :             GF_Read,
    3408                 :             nXOff, nYOff,
    3409                 :             nReqXSize, nReqYSize,
    3410                 :             pabyMask, nReqXSize, nReqYSize, GDT_Byte,
    3411              63 :             0, 0);
    3412              63 :     if (eErr != CE_None)
    3413                 :     {
    3414               0 :         VSIFree(pabyMask);
    3415               0 :         return 0;
    3416                 :     }
    3417                 : 
    3418              63 :     int bOnly0or255 = TRUE;
    3419              63 :     int bOnly255 = TRUE;
    3420              63 :     int bOnly0 = TRUE;
    3421                 :     int i;
    3422           16349 :     for(i=0;i<nReqXSize * nReqYSize;i++)
    3423                 :     {
    3424           16332 :         if (pabyMask[i] == 0)
    3425           12188 :             bOnly255 = FALSE;
    3426            4144 :         else if (pabyMask[i] == 255)
    3427            4098 :             bOnly0 = FALSE;
    3428                 :         else
    3429                 :         {
    3430              46 :             bOnly0 = FALSE;
    3431              46 :             bOnly255 = FALSE;
    3432              46 :             bOnly0or255 = FALSE;
    3433              46 :             break;
    3434                 :         }
    3435                 :     }
    3436                 : 
    3437              63 :     if (bOnly255)
    3438                 :     {
    3439               0 :         CPLFree(pabyMask);
    3440               0 :         return 0;
    3441                 :     }
    3442                 : 
    3443              63 :     if (bOnly0or255)
    3444                 :     {
    3445                 :         /* Translate to 1 bit */
    3446              17 :         int nReqXSize1 = (nReqXSize + 7) / 8;
    3447              17 :         GByte* pabyMask1 = (GByte*)VSICalloc(nReqXSize1, nReqYSize);
    3448              17 :         if (pabyMask1 == NULL)
    3449                 :         {
    3450               0 :             CPLFree(pabyMask);
    3451               0 :             return 0;
    3452                 :         }
    3453             499 :         for(int y=0;y<nReqYSize;y++)
    3454                 :         {
    3455            6686 :             for(int x=0;x<nReqXSize;x++)
    3456                 :             {
    3457            6204 :                 if (pabyMask[y * nReqXSize + x])
    3458            1792 :                     pabyMask1[y * nReqXSize1 + x / 8] |= 1 << (7 - (x % 8));
    3459                 :             }
    3460                 :         }
    3461              17 :         VSIFree(pabyMask);
    3462              17 :         pabyMask = pabyMask1;
    3463              17 :         nMaskSize = nReqXSize1 * nReqYSize;
    3464                 :     }
    3465                 : 
    3466              63 :     int nMaskId = AllocNewObject();
    3467              63 :     int nMaskLengthId = AllocNewObject();
    3468                 : 
    3469              63 :     StartObj(nMaskId);
    3470              63 :     GDALPDFDictionaryRW oDict;
    3471                 :     oDict.Add("Length", nMaskLengthId, 0)
    3472              63 :          .Add("Type", GDALPDFObjectRW::CreateName("XObject"));
    3473              63 :     if( eCompressMethod != COMPRESS_NONE )
    3474                 :     {
    3475              63 :         oDict.Add("Filter", GDALPDFObjectRW::CreateName("FlateDecode"));
    3476                 :     }
    3477                 :     oDict.Add("Subtype", GDALPDFObjectRW::CreateName("Image"))
    3478                 :          .Add("Width", nReqXSize)
    3479                 :          .Add("Height", nReqYSize)
    3480                 :          .Add("ColorSpace", GDALPDFObjectRW::CreateName("DeviceGray"))
    3481              63 :          .Add("BitsPerComponent", (bOnly0or255) ? 1 : 8);
    3482              63 :     VSIFPrintfL(fp, "%s\n", oDict.Serialize().c_str());
    3483              63 :     VSIFPrintfL(fp, "stream\n");
    3484              63 :     vsi_l_offset nStreamStart = VSIFTellL(fp);
    3485                 : 
    3486              63 :     VSILFILE* fpGZip = NULL;
    3487              63 :     VSILFILE* fpBack = fp;
    3488              63 :     if( eCompressMethod != COMPRESS_NONE )
    3489                 :     {
    3490              63 :         fpGZip = (VSILFILE* )VSICreateGZipWritable( (VSIVirtualHandle*) fp, TRUE, FALSE );
    3491              63 :         fp = fpGZip;
    3492                 :     }
    3493                 : 
    3494              63 :     VSIFWriteL(pabyMask, nMaskSize, 1, fp);
    3495              63 :     CPLFree(pabyMask);
    3496                 : 
    3497              63 :     if (fpGZip)
    3498              63 :         VSIFCloseL(fpGZip);
    3499              63 :     fp = fpBack;
    3500                 : 
    3501              63 :     vsi_l_offset nStreamEnd = VSIFTellL(fp);
    3502                 :     VSIFPrintfL(fp,
    3503                 :                 "\n"
    3504              63 :                 "endstream\n");
    3505              63 :     EndObj();
    3506                 : 
    3507              63 :     StartObj(nMaskLengthId);
    3508                 :     VSIFPrintfL(fp,
    3509                 :                 "   %ld\n",
    3510              63 :                 (long)(nStreamEnd - nStreamStart));
    3511              63 :     EndObj();
    3512                 : 
    3513              63 :     return nMaskId;
    3514                 : }
    3515                 : 
    3516                 : /************************************************************************/
    3517                 : /*                             WriteBlock()                             */
    3518                 : /************************************************************************/
    3519                 : 
    3520             132 : int GDALPDFWriter::WriteBlock(GDALDataset* poSrcDS,
    3521                 :                              int nXOff, int nYOff, int nReqXSize, int nReqYSize,
    3522                 :                              int nColorTableId,
    3523                 :                              PDFCompressMethod eCompressMethod,
    3524                 :                              int nPredictor,
    3525                 :                              int nJPEGQuality,
    3526                 :                              const char* pszJPEG2000_DRIVER,
    3527                 :                              GDALProgressFunc pfnProgress,
    3528                 :                              void * pProgressData)
    3529                 : {
    3530             132 :     int  nBands = poSrcDS->GetRasterCount();
    3531             132 :     if (nBands == 0)
    3532               0 :         return 0;
    3533                 : 
    3534             132 :     if (nColorTableId == 0)
    3535             131 :         nColorTableId = WriteColorTable(poSrcDS);
    3536                 : 
    3537             132 :     CPLErr eErr = CE_None;
    3538             132 :     GDALDataset* poBlockSrcDS = NULL;
    3539             132 :     GDALDatasetH hMemDS = NULL;
    3540             132 :     GByte* pabyMEMDSBuffer = NULL;
    3541                 : 
    3542             132 :     if (eCompressMethod == COMPRESS_DEFAULT)
    3543                 :     {
    3544             121 :         GDALDataset* poSrcDSToTest = poSrcDS;
    3545                 : 
    3546                 :         /* Test if we can directly copy original JPEG content */
    3547                 :         /* if available */
    3548             242 :         if (poSrcDS->GetDriver() != NULL &&
    3549             121 :             poSrcDS->GetDriver() == GDALGetDriverByName("VRT"))
    3550                 :         {
    3551               5 :             VRTDataset* poVRTDS = (VRTDataset* )poSrcDS;
    3552               5 :             poSrcDSToTest = poVRTDS->GetSingleSimpleSource();
    3553                 :         }
    3554                 : 
    3555             481 :         if (poSrcDSToTest != NULL &&
    3556             120 :             poSrcDSToTest->GetDriver() != NULL &&
    3557             240 :             EQUAL(poSrcDSToTest->GetDriver()->GetDescription(), "JPEG") &&
    3558                 :             nXOff == 0 && nYOff == 0 &&
    3559                 :             nReqXSize == poSrcDSToTest->GetRasterXSize() &&
    3560                 :             nReqYSize == poSrcDSToTest->GetRasterYSize() &&
    3561                 :             nJPEGQuality < 0)
    3562                 :         {
    3563               2 :             VSILFILE* fpSrc = VSIFOpenL(poSrcDSToTest->GetDescription(), "rb");
    3564               2 :             if (fpSrc != NULL)
    3565                 :             {
    3566               2 :                 CPLDebug("PDF", "Copying directly original JPEG file");
    3567                 : 
    3568               2 :                 VSIFSeekL(fpSrc, 0, SEEK_END);
    3569               2 :                 int nLength = (int)VSIFTellL(fpSrc);
    3570               2 :                 VSIFSeekL(fpSrc, 0, SEEK_SET);
    3571                 : 
    3572               2 :                 int nImageId = AllocNewObject();
    3573                 : 
    3574               2 :                 StartObj(nImageId);
    3575                 : 
    3576               2 :                 GDALPDFDictionaryRW oDict;
    3577                 :                 oDict.Add("Length", nLength)
    3578                 :                      .Add("Type", GDALPDFObjectRW::CreateName("XObject"))
    3579                 :                      .Add("Filter", GDALPDFObjectRW::CreateName("DCTDecode"))
    3580                 :                      .Add("Subtype", GDALPDFObjectRW::CreateName("Image"))
    3581                 :                      .Add("Width", nReqXSize)
    3582                 :                      .Add("Height", nReqYSize)
    3583                 :                      .Add("ColorSpace",
    3584                 :                         (nBands == 1) ?        GDALPDFObjectRW::CreateName("DeviceGray") :
    3585                 :                                                 GDALPDFObjectRW::CreateName("DeviceRGB"))
    3586               2 :                      .Add("BitsPerComponent", 8);
    3587               2 :                 VSIFPrintfL(fp, "%s\n", oDict.Serialize().c_str());
    3588               2 :                 VSIFPrintfL(fp, "stream\n");
    3589                 : 
    3590                 :                 GByte abyBuffer[1024];
    3591              12 :                 for(int i=0;i<nLength;i += 1024)
    3592                 :                 {
    3593              10 :                     int nRead = (int) VSIFReadL(abyBuffer, 1, 1024, fpSrc);
    3594              10 :                     if ((int)VSIFWriteL(abyBuffer, 1, nRead, fp) != nRead)
    3595                 :                     {
    3596               0 :                         eErr = CE_Failure;
    3597               0 :                         break;
    3598                 :                     }
    3599                 : 
    3600              10 :                     if( eErr == CE_None && pfnProgress != NULL
    3601                 :                         && !pfnProgress( (i + nRead) / (double)nLength,
    3602                 :                                         NULL, pProgressData ) )
    3603                 :                     {
    3604                 :                         CPLError( CE_Failure, CPLE_UserInterrupt,
    3605               0 :                                 "User terminated CreateCopy()" );
    3606               0 :                         eErr = CE_Failure;
    3607               0 :                         break;
    3608                 :                     }
    3609                 :                 }
    3610                 : 
    3611               2 :                 VSIFPrintfL(fp, "\nendstream\n");
    3612                 : 
    3613               2 :                 EndObj();
    3614                 : 
    3615               2 :                 VSIFCloseL(fpSrc);
    3616                 : 
    3617               2 :                 return eErr == CE_None ? nImageId : 0;
    3618                 :             }
    3619                 :         }
    3620                 : 
    3621             119 :         eCompressMethod = COMPRESS_DEFLATE;
    3622                 :     }
    3623                 : 
    3624             130 :     int nMaskId = 0;
    3625             130 :     if (nBands == 4)
    3626                 :     {
    3627                 :         nMaskId = WriteMask(poSrcDS,
    3628                 :                             nXOff, nYOff, nReqXSize, nReqYSize,
    3629              63 :                             eCompressMethod);
    3630                 :     }
    3631                 : 
    3632             130 :     if( nReqXSize == poSrcDS->GetRasterXSize() &&
    3633                 :         nReqYSize == poSrcDS->GetRasterYSize() &&
    3634                 :         nBands != 4)
    3635                 :     {
    3636              46 :         poBlockSrcDS = poSrcDS;
    3637                 :     }
    3638                 :     else
    3639                 :     {
    3640              84 :         if (nBands == 4)
    3641              63 :             nBands = 3;
    3642                 : 
    3643              84 :         GDALDriverH hMemDriver = GDALGetDriverByName("MEM");
    3644              84 :         if( hMemDriver == NULL )
    3645               0 :             return 0;
    3646                 : 
    3647                 :         hMemDS = GDALCreate(hMemDriver, "MEM:::",
    3648                 :                             nReqXSize, nReqYSize, 0,
    3649              84 :                             GDT_Byte, NULL);
    3650              84 :         if (hMemDS == NULL)
    3651               0 :             return 0;
    3652                 : 
    3653                 :         pabyMEMDSBuffer =
    3654              84 :             (GByte*)VSIMalloc3(nReqXSize, nReqYSize, nBands);
    3655              84 :         if (pabyMEMDSBuffer == NULL)
    3656                 :         {
    3657               0 :             GDALClose(hMemDS);
    3658               0 :             return 0;
    3659                 :         }
    3660                 : 
    3661                 :         eErr = poSrcDS->RasterIO(GF_Read,
    3662                 :                                 nXOff, nYOff,
    3663                 :                                 nReqXSize, nReqYSize,
    3664                 :                                 pabyMEMDSBuffer, nReqXSize, nReqYSize,
    3665                 :                                 GDT_Byte, nBands, NULL,
    3666              84 :                                 0, 0, 0);
    3667                 : 
    3668              84 :         if( eErr != CE_None )
    3669                 :         {
    3670               0 :             CPLFree(pabyMEMDSBuffer);
    3671               0 :             GDALClose(hMemDS);
    3672               0 :             return 0;
    3673                 :         }
    3674                 : 
    3675                 :         int iBand;
    3676             294 :         for(iBand = 0; iBand < nBands; iBand ++)
    3677                 :         {
    3678             210 :             char** papszMEMDSOptions = NULL;
    3679                 :             char szTmp[64];
    3680             210 :             memset(szTmp, 0, sizeof(szTmp));
    3681                 :             CPLPrintPointer(szTmp,
    3682             210 :                             pabyMEMDSBuffer + iBand * nReqXSize * nReqYSize, sizeof(szTmp));
    3683             210 :             papszMEMDSOptions = CSLSetNameValue(papszMEMDSOptions, "DATAPOINTER", szTmp);
    3684             210 :             GDALAddBand(hMemDS, GDT_Byte, papszMEMDSOptions);
    3685             210 :             CSLDestroy(papszMEMDSOptions);
    3686                 :         }
    3687                 : 
    3688              84 :         poBlockSrcDS = (GDALDataset*) hMemDS;
    3689                 :     }
    3690                 : 
    3691             130 :     int nImageId = AllocNewObject();
    3692             130 :     int nImageLengthId = AllocNewObject();
    3693                 : 
    3694             130 :     int nMeasureId = 0;
    3695             130 :     if( CSLTestBoolean(CPLGetConfigOption("GDAL_PDF_WRITE_GEOREF_ON_IMAGE", "FALSE")) &&
    3696                 :         nReqXSize == poSrcDS->GetRasterXSize() &&
    3697                 :         nReqYSize == poSrcDS->GetRasterYSize() )
    3698                 :     {
    3699               2 :         PDFMargins sMargins = {0, 0, 0, 0};
    3700               2 :         nMeasureId = WriteSRS_ISO32000(poSrcDS, 1, NULL, &sMargins, FALSE);
    3701                 :     }
    3702                 : 
    3703             130 :     StartObj(nImageId);
    3704                 : 
    3705             130 :     GDALPDFDictionaryRW oDict;
    3706                 :     oDict.Add("Length", nImageLengthId, 0)
    3707             130 :          .Add("Type", GDALPDFObjectRW::CreateName("XObject"));
    3708                 : 
    3709             130 :     if( eCompressMethod == COMPRESS_DEFLATE )
    3710                 :     {
    3711             121 :         oDict.Add("Filter", GDALPDFObjectRW::CreateName("FlateDecode"));
    3712             121 :         if( nPredictor == 2 )
    3713                 :             oDict.Add("DecodeParms", &((new GDALPDFDictionaryRW())
    3714                 :                                   ->Add("Predictor", 2)
    3715                 :                                    .Add("Colors", nBands)
    3716               2 :                                    .Add("Columns", nReqXSize)));
    3717                 :     }
    3718               9 :     else if( eCompressMethod == COMPRESS_JPEG )
    3719                 :     {
    3720               3 :         oDict.Add("Filter", GDALPDFObjectRW::CreateName("DCTDecode"));
    3721                 :     }
    3722               6 :     else if( eCompressMethod == COMPRESS_JPEG2000 )
    3723                 :     {
    3724               5 :         oDict.Add("Filter", GDALPDFObjectRW::CreateName("JPXDecode"));
    3725                 :     }
    3726                 : 
    3727                 :     oDict.Add("Subtype", GDALPDFObjectRW::CreateName("Image"))
    3728                 :          .Add("Width", nReqXSize)
    3729                 :          .Add("Height", nReqYSize)
    3730                 :          .Add("ColorSpace",
    3731                 :               (nColorTableId != 0) ? GDALPDFObjectRW::CreateIndirect(nColorTableId, 0) :
    3732                 :               (nBands == 1) ?        GDALPDFObjectRW::CreateName("DeviceGray") :
    3733                 :                                      GDALPDFObjectRW::CreateName("DeviceRGB"))
    3734             130 :          .Add("BitsPerComponent", 8);
    3735             130 :     if( nMaskId )
    3736                 :     {
    3737              63 :         oDict.Add("SMask", nMaskId, 0);
    3738                 :     }
    3739             130 :     if( nMeasureId )
    3740                 :     {
    3741               2 :         oDict.Add("Measure", nMeasureId, 0);
    3742                 :     }
    3743                 : 
    3744             130 :     VSIFPrintfL(fp, "%s\n", oDict.Serialize().c_str());
    3745             130 :     VSIFPrintfL(fp, "stream\n");
    3746                 : 
    3747             130 :     vsi_l_offset nStreamStart = VSIFTellL(fp);
    3748                 : 
    3749             138 :     if( eCompressMethod == COMPRESS_JPEG ||
    3750                 :         eCompressMethod == COMPRESS_JPEG2000 )
    3751                 :     {
    3752               8 :         GDALDriver* poJPEGDriver = NULL;
    3753                 :         char szTmp[64];
    3754               8 :         char** papszOptions = NULL;
    3755                 : 
    3756               8 :         if( eCompressMethod == COMPRESS_JPEG )
    3757                 :         {
    3758               3 :             poJPEGDriver = (GDALDriver*) GDALGetDriverByName("JPEG");
    3759               3 :             if (poJPEGDriver != NULL && nJPEGQuality > 0)
    3760               0 :                 papszOptions = CSLAddString(papszOptions, CPLSPrintf("QUALITY=%d", nJPEGQuality));
    3761               3 :             sprintf(szTmp, "/vsimem/pdftemp/%p.jpg", this);
    3762                 :         }
    3763                 :         else
    3764                 :         {
    3765               5 :             if (pszJPEG2000_DRIVER == NULL || EQUAL(pszJPEG2000_DRIVER, "JP2KAK"))
    3766               1 :                 poJPEGDriver = (GDALDriver*) GDALGetDriverByName("JP2KAK");
    3767               5 :             if (poJPEGDriver == NULL)
    3768                 :             {
    3769               5 :                 if (pszJPEG2000_DRIVER == NULL || EQUAL(pszJPEG2000_DRIVER, "JP2ECW"))
    3770                 :                 {
    3771               3 :                     poJPEGDriver = (GDALDriver*) GDALGetDriverByName("JP2ECW");
    3772               6 :                     if( poJPEGDriver &&
    3773               3 :                         poJPEGDriver->GetMetadataItem(GDAL_DMD_CREATIONDATATYPES) == NULL )
    3774                 :                     {
    3775               0 :                         poJPEGDriver = NULL;
    3776                 :                     }
    3777                 :                 }
    3778               5 :                 if (poJPEGDriver)
    3779                 :                 {
    3780               3 :                     papszOptions = CSLAddString(papszOptions, "PROFILE=NPJE");
    3781               3 :                     papszOptions = CSLAddString(papszOptions, "LAYERS=1");
    3782               3 :                     papszOptions = CSLAddString(papszOptions, "GeoJP2=OFF");
    3783               3 :                     papszOptions = CSLAddString(papszOptions, "GMLJP2=OFF");
    3784                 :                 }
    3785                 :             }
    3786               5 :             if (poJPEGDriver == NULL)
    3787                 :             {
    3788               2 :                 if (pszJPEG2000_DRIVER == NULL || EQUAL(pszJPEG2000_DRIVER, "JP2OpenJPEG"))
    3789               1 :                     poJPEGDriver = (GDALDriver*) GDALGetDriverByName("JP2OpenJPEG");
    3790               2 :                 if (poJPEGDriver)
    3791                 :                 {
    3792               1 :                     papszOptions = CSLAddString(papszOptions, "GeoJP2=OFF");
    3793               1 :                     papszOptions = CSLAddString(papszOptions, "GMLJP2=OFF");
    3794                 :                 }
    3795                 :             }
    3796               5 :             if (poJPEGDriver == NULL)
    3797                 :             {
    3798               1 :                 if (pszJPEG2000_DRIVER == NULL || EQUAL(pszJPEG2000_DRIVER, "JPEG2000"))
    3799               1 :                     poJPEGDriver = (GDALDriver*) GDALGetDriverByName("JPEG2000");
    3800                 :             }
    3801               5 :             sprintf(szTmp, "/vsimem/pdftemp/%p.jp2", this);
    3802                 :         }
    3803                 : 
    3804               8 :         if( poJPEGDriver == NULL )
    3805                 :         {
    3806                 :             CPLError(CE_Failure, CPLE_NotSupported,
    3807                 :                      "No %s driver found",
    3808               0 :                      ( eCompressMethod == COMPRESS_JPEG ) ? "JPEG" : "JPEG2000");
    3809               0 :             eErr = CE_Failure;
    3810               0 :             goto end;
    3811                 :         }
    3812                 : 
    3813               8 :         GDALDataset* poJPEGDS = NULL;
    3814                 : 
    3815                 :         poJPEGDS = poJPEGDriver->CreateCopy(szTmp, poBlockSrcDS,
    3816                 :                                             FALSE, papszOptions,
    3817               8 :                                             pfnProgress, pProgressData);
    3818                 : 
    3819               8 :         CSLDestroy(papszOptions);
    3820               8 :         if( poJPEGDS == NULL )
    3821                 :         {
    3822               0 :             eErr = CE_Failure;
    3823               0 :             goto end;
    3824                 :         }
    3825                 : 
    3826               8 :         GDALClose(poJPEGDS);
    3827                 : 
    3828               8 :         vsi_l_offset nJPEGDataSize = 0;
    3829               8 :         GByte* pabyJPEGData = VSIGetMemFileBuffer(szTmp, &nJPEGDataSize, TRUE);
    3830               8 :         VSIFWriteL(pabyJPEGData, nJPEGDataSize, 1, fp);
    3831               8 :         CPLFree(pabyJPEGData);
    3832                 :     }
    3833                 :     else
    3834                 :     {
    3835             122 :         VSILFILE* fpGZip = NULL;
    3836             122 :         VSILFILE* fpBack = fp;
    3837             122 :         if( eCompressMethod == COMPRESS_DEFLATE )
    3838                 :         {
    3839             121 :             fpGZip = (VSILFILE* )VSICreateGZipWritable( (VSIVirtualHandle*) fp, TRUE, FALSE );
    3840             121 :             fp = fpGZip;
    3841                 :         }
    3842                 : 
    3843             122 :         GByte* pabyLine = (GByte*)CPLMalloc(nReqXSize * nBands);
    3844            8465 :         for(int iLine = 0; iLine < nReqYSize; iLine ++)
    3845                 :         {
    3846                 :             /* Get pixel interleaved data */
    3847                 :             eErr = poBlockSrcDS->RasterIO(GF_Read,
    3848                 :                                           0, iLine, nReqXSize, 1,
    3849                 :                                           pabyLine, nReqXSize, 1, GDT_Byte,
    3850            8343 :                                           nBands, NULL, nBands, 0, 1);
    3851            8343 :             if( eErr != CE_None )
    3852               0 :                 break;
    3853                 : 
    3854                 :             /* Apply predictor if needed */
    3855            8343 :             if( nPredictor == 2 )
    3856                 :             {
    3857             562 :                 if( nBands == 1 )
    3858                 :                 {
    3859             512 :                     int nPrevValue = pabyLine[0];
    3860          262144 :                     for(int iPixel = 1; iPixel < nReqXSize; iPixel ++)
    3861                 :                     {
    3862          261632 :                         int nCurValue = pabyLine[iPixel];
    3863          261632 :                         pabyLine[iPixel] = (GByte) (nCurValue - nPrevValue);
    3864          261632 :                         nPrevValue = nCurValue;
    3865                 :                     }
    3866                 :                 }
    3867              50 :                 else if( nBands == 3 )
    3868                 :                 {
    3869              50 :                     int nPrevValueR = pabyLine[0];
    3870              50 :                     int nPrevValueG = pabyLine[1];
    3871              50 :                     int nPrevValueB = pabyLine[2];
    3872            2500 :                     for(int iPixel = 1; iPixel < nReqXSize; iPixel ++)
    3873                 :                     {
    3874            2450 :                         int nCurValueR = pabyLine[3 * iPixel + 0];
    3875            2450 :                         int nCurValueG = pabyLine[3 * iPixel + 1];
    3876            2450 :                         int nCurValueB = pabyLine[3 * iPixel + 2];
    3877            2450 :                         pabyLine[3 * iPixel + 0] = (GByte) (nCurValueR - nPrevValueR);
    3878            2450 :                         pabyLine[3 * iPixel + 1] = (GByte) (nCurValueG - nPrevValueG);
    3879            2450 :                         pabyLine[3 * iPixel + 2] = (GByte) (nCurValueB - nPrevValueB);
    3880            2450 :                         nPrevValueR = nCurValueR;
    3881            2450 :                         nPrevValueG = nCurValueG;
    3882            2450 :                         nPrevValueB = nCurValueB;
    3883                 :                     }
    3884                 :                 }
    3885                 :             }
    3886                 : 
    3887            8343 :             if( VSIFWriteL(pabyLine, nReqXSize * nBands, 1, fp) != 1 )
    3888                 :             {
    3889               0 :                 eErr = CE_Failure;
    3890               0 :                 break;
    3891                 :             }
    3892                 : 
    3893            8343 :             if( eErr == CE_None && pfnProgress != NULL
    3894                 :                 && !pfnProgress( (iLine+1) / (double)nReqYSize,
    3895                 :                                 NULL, pProgressData ) )
    3896                 :             {
    3897                 :                 CPLError( CE_Failure, CPLE_UserInterrupt,
    3898               0 :                         "User terminated CreateCopy()" );
    3899               0 :                 eErr = CE_Failure;
    3900               0 :                 break;
    3901                 :             }
    3902                 :         }
    3903                 : 
    3904             122 :         CPLFree(pabyLine);
    3905                 : 
    3906             122 :         if (fpGZip)
    3907             121 :             VSIFCloseL(fpGZip);
    3908             122 :         fp = fpBack;
    3909                 :     }
    3910                 : 
    3911                 : end:
    3912             130 :     CPLFree(pabyMEMDSBuffer);
    3913             130 :     pabyMEMDSBuffer = NULL;
    3914             130 :     if( hMemDS != NULL )
    3915                 :     {
    3916              84 :         GDALClose(hMemDS);
    3917              84 :         hMemDS = NULL;
    3918                 :     }
    3919                 : 
    3920             130 :     vsi_l_offset nStreamEnd = VSIFTellL(fp);
    3921                 :     VSIFPrintfL(fp,
    3922                 :                 "\n"
    3923             130 :                 "endstream\n");
    3924             130 :     EndObj();
    3925                 : 
    3926             130 :     StartObj(nImageLengthId);
    3927                 :     VSIFPrintfL(fp,
    3928                 :                 "   %ld\n",
    3929             130 :                 (long)(nStreamEnd - nStreamStart));
    3930             130 :     EndObj();
    3931                 : 
    3932             130 :     return eErr == CE_None ? nImageId : 0;
    3933                 : }
    3934                 : 
    3935                 : /************************************************************************/
    3936                 : /*                          WriteJavascript()                           */
    3937                 : /************************************************************************/
    3938                 : 
    3939               1 : int GDALPDFWriter::WriteJavascript(const char* pszJavascript)
    3940                 : {
    3941               1 :     int nJSId = AllocNewObject();
    3942               1 :     int nJSLengthId = AllocNewObject();
    3943               1 :     StartObj(nJSId);
    3944                 :     {
    3945               1 :         GDALPDFDictionaryRW oDict;
    3946               1 :         oDict.Add("Length", nJSLengthId, 0);
    3947               1 :         if( oPageContext.eStreamCompressMethod != COMPRESS_NONE )
    3948                 :         {
    3949               1 :             oDict.Add("Filter", GDALPDFObjectRW::CreateName("FlateDecode"));
    3950                 :         }
    3951               1 :         VSIFPrintfL(fp, "%s\n", oDict.Serialize().c_str());
    3952                 :     }
    3953               1 :     VSIFPrintfL(fp, "stream\n");
    3954               1 :     vsi_l_offset nStreamStart = VSIFTellL(fp);
    3955                 : 
    3956               1 :     VSILFILE* fpGZip = NULL;
    3957               1 :     VSILFILE* fpBack = fp;
    3958               1 :     if( oPageContext.eStreamCompressMethod != COMPRESS_NONE )
    3959                 :     {
    3960               1 :         fpGZip = (VSILFILE* )VSICreateGZipWritable( (VSIVirtualHandle*) fp, TRUE, FALSE );
    3961               1 :         fp = fpGZip;
    3962                 :     }
    3963                 : 
    3964               1 :     VSIFWriteL(pszJavascript, strlen(pszJavascript), 1, fp);
    3965                 : 
    3966               1 :     if (fpGZip)
    3967               1 :         VSIFCloseL(fpGZip);
    3968               1 :     fp = fpBack;
    3969                 : 
    3970               1 :     vsi_l_offset nStreamEnd = VSIFTellL(fp);
    3971                 :     VSIFPrintfL(fp,
    3972                 :                 "\n"
    3973               1 :                 "endstream\n");
    3974               1 :     EndObj();
    3975                 : 
    3976               1 :     StartObj(nJSLengthId);
    3977                 :     VSIFPrintfL(fp,
    3978                 :                 "   %ld\n",
    3979               1 :                 (long)(nStreamEnd - nStreamStart));
    3980               1 :     EndObj();
    3981                 : 
    3982               1 :     nNamesId = AllocNewObject();
    3983               1 :     StartObj(nNamesId);
    3984                 :     {
    3985               1 :         GDALPDFDictionaryRW oDict;
    3986               1 :         GDALPDFDictionaryRW* poJavaScriptDict = new GDALPDFDictionaryRW();
    3987               1 :         oDict.Add("JavaScript", poJavaScriptDict);
    3988                 : 
    3989               1 :         GDALPDFArrayRW* poNamesArray = new GDALPDFArrayRW();
    3990               1 :         poJavaScriptDict->Add("Names", poNamesArray);
    3991                 : 
    3992               1 :         poNamesArray->Add("GDAL");
    3993                 : 
    3994               1 :         GDALPDFDictionaryRW* poJSDict = new GDALPDFDictionaryRW();
    3995               1 :         poNamesArray->Add(poJSDict);
    3996                 : 
    3997               1 :         poJSDict->Add("JS", nJSId, 0);
    3998               1 :         poJSDict->Add("S", GDALPDFObjectRW::CreateName("JavaScript"));
    3999                 : 
    4000               1 :         VSIFPrintfL(fp, "%s\n", oDict.Serialize().c_str());
    4001                 :     }
    4002               1 :     EndObj();
    4003                 : 
    4004               1 :     return nNamesId;
    4005                 : }
    4006                 : 
    4007                 : /************************************************************************/
    4008                 : /*                        WriteJavascriptFile()                         */
    4009                 : /************************************************************************/
    4010                 : 
    4011               0 : int GDALPDFWriter::WriteJavascriptFile(const char* pszJavascriptFile)
    4012                 : {
    4013               0 :     int nRet = 0;
    4014               0 :     char* pszJavascriptToFree = (char*)CPLMalloc(65536);
    4015               0 :     VSILFILE* fpJS = VSIFOpenL(pszJavascriptFile, "rb");
    4016               0 :     if( fpJS != NULL )
    4017                 :     {
    4018               0 :         int nRead = (int)VSIFReadL(pszJavascriptToFree, 1, 65536, fpJS);
    4019               0 :         if( nRead < 65536 )
    4020                 :         {
    4021               0 :             pszJavascriptToFree[nRead] = '\0';
    4022               0 :             nRet = WriteJavascript(pszJavascriptToFree);
    4023                 :         }
    4024               0 :         VSIFCloseL(fpJS);
    4025                 :     }
    4026               0 :     CPLFree(pszJavascriptToFree);
    4027               0 :     return nRet;
    4028                 : }
    4029                 : /************************************************************************/
    4030                 : /*                              WritePages()                            */
    4031                 : /************************************************************************/
    4032                 : 
    4033              53 : void GDALPDFWriter::WritePages()
    4034                 : {
    4035              53 :     StartObj(nPageResourceId);
    4036                 :     {
    4037              53 :         GDALPDFDictionaryRW oDict;
    4038              53 :         GDALPDFArrayRW* poKids = new GDALPDFArrayRW();
    4039                 :         oDict.Add("Type", GDALPDFObjectRW::CreateName("Pages"))
    4040                 :              .Add("Count", (int)asPageId.size())
    4041             106 :              .Add("Kids", poKids);
    4042                 : 
    4043             106 :         for(size_t i=0;i<asPageId.size();i++)
    4044              53 :             poKids->Add(asPageId[i], 0);
    4045                 : 
    4046              53 :         VSIFPrintfL(fp, "%s\n", oDict.Serialize().c_str());
    4047                 :     }
    4048              53 :     EndObj();
    4049                 : 
    4050              53 :     StartObj(nCatalogId);
    4051                 :     {
    4052              53 :         GDALPDFDictionaryRW oDict;
    4053                 :         oDict.Add("Type", GDALPDFObjectRW::CreateName("Catalog"))
    4054             106 :              .Add("Pages", nPageResourceId, 0);
    4055              53 :         if (nXMPId)
    4056               1 :             oDict.Add("Metadata", nXMPId, 0);
    4057              53 :         if (asOCGs.size())
    4058                 :         {
    4059               6 :             GDALPDFDictionaryRW* poDictOCProperties = new GDALPDFDictionaryRW();
    4060               6 :             oDict.Add("OCProperties", poDictOCProperties);
    4061                 : 
    4062               6 :             GDALPDFDictionaryRW* poDictD = new GDALPDFDictionaryRW();
    4063               6 :             poDictOCProperties->Add("D", poDictD);
    4064                 : 
    4065                 :             /* Build "Order" array of D dict */
    4066               6 :             GDALPDFArrayRW* poArrayOrder = new GDALPDFArrayRW();
    4067                 :             size_t i;
    4068              14 :             for(i=0;i<asOCGs.size();i++)
    4069                 :             {
    4070               8 :                 poArrayOrder->Add(asOCGs[i].nId, 0);
    4071               8 :                 if (i + 1 < asOCGs.size() && asOCGs[i+1].nParentId == asOCGs[i].nId)
    4072                 :                 {
    4073               3 :                     GDALPDFArrayRW* poSubArrayOrder = new GDALPDFArrayRW();
    4074               6 :                     poSubArrayOrder->Add(asOCGs[i+1].nId, 0);
    4075               3 :                     poArrayOrder->Add(poSubArrayOrder);
    4076               3 :                     i ++;
    4077                 :                 }
    4078                 :             }
    4079               6 :             poDictD->Add("Order", poArrayOrder);
    4080                 : 
    4081                 :             /* Build "OFF" array of D dict */
    4082               6 :             if( osOffLayers.size() )
    4083                 :             {
    4084               1 :                 GDALPDFArrayRW* poArrayOFF = new GDALPDFArrayRW();
    4085               2 :                 char** papszTokens = CSLTokenizeString2(osOffLayers, ",", 0);
    4086               2 :                 for(int i=0; papszTokens[i] != NULL; i++)
    4087                 :                 {
    4088                 :                     size_t j;
    4089               1 :                     int bFound = FALSE;
    4090               3 :                     for(j=0;j<asOCGs.size();j++)
    4091                 :                     {
    4092               2 :                         if( strcmp(papszTokens[i], asOCGs[j].osLayerName) == 0)
    4093                 :                         {
    4094               1 :                             poArrayOFF->Add(asOCGs[j].nId, 0);
    4095               1 :                             bFound = TRUE;
    4096                 :                         }
    4097               2 :                         if (j + 1 < asOCGs.size() && asOCGs[j+1].nParentId == asOCGs[j].nId)
    4098                 :                         {
    4099               0 :                             j ++;
    4100                 :                         }
    4101                 :                     }
    4102               1 :                     if( !bFound )
    4103                 :                     {
    4104                 :                         CPLError(CE_Warning, CPLE_AppDefined,
    4105                 :                                  "Unknown layer name (%s) specified in OFF_LAYERS",
    4106               0 :                                  papszTokens[i]);
    4107                 :                     }
    4108                 :                 }
    4109               1 :                 CSLDestroy(papszTokens);
    4110                 : 
    4111               1 :                 poDictD->Add("OFF", poArrayOFF);
    4112                 :             }
    4113                 : 
    4114                 :             /* Build "RBGroups" array of D dict */
    4115               6 :             if( osExclusiveLayers.size() )
    4116                 :             {
    4117               1 :                 GDALPDFArrayRW* poArrayRBGroups = new GDALPDFArrayRW();
    4118               2 :                 char** papszTokens = CSLTokenizeString2(osExclusiveLayers, ",", 0);
    4119               3 :                 for(int i=0; papszTokens[i] != NULL; i++)
    4120                 :                 {
    4121                 :                     size_t j;
    4122               2 :                     int bFound = FALSE;
    4123               6 :                     for(j=0;j<asOCGs.size();j++)
    4124                 :                     {
    4125               4 :                         if( strcmp(papszTokens[i], asOCGs[j].osLayerName) == 0)
    4126                 :                         {
    4127               2 :                             poArrayRBGroups->Add(asOCGs[j].nId, 0);
    4128               2 :                             bFound = TRUE;
    4129                 :                         }
    4130               4 :                         if (j + 1 < asOCGs.size() && asOCGs[j+1].nParentId == asOCGs[j].nId)
    4131                 :                         {
    4132               0 :                             j ++;
    4133                 :                         }
    4134                 :                     }
    4135               2 :                     if( !bFound )
    4136                 :                     {
    4137                 :                         CPLError(CE_Warning, CPLE_AppDefined,
    4138                 :                                     "Unknown layer name (%s) specified in EXCLUSIVE_LAYERS",
    4139               0 :                                     papszTokens[i]);
    4140                 :                     }
    4141                 :                 }
    4142               1 :                 CSLDestroy(papszTokens);
    4143                 : 
    4144               1 :                 if( poArrayRBGroups->GetLength() )
    4145                 :                 {
    4146               1 :                     GDALPDFArrayRW* poMainArrayRBGroups = new GDALPDFArrayRW();
    4147               1 :                     poMainArrayRBGroups->Add(poArrayRBGroups);
    4148               1 :                     poDictD->Add("RBGroups", poMainArrayRBGroups);
    4149                 :                 }
    4150                 :                 else
    4151               0 :                     delete poArrayRBGroups;
    4152                 :             }
    4153                 : 
    4154               6 :             GDALPDFArrayRW* poArrayOGCs = new GDALPDFArrayRW();
    4155              17 :             for(i=0;i<asOCGs.size();i++)
    4156              11 :                 poArrayOGCs->Add(asOCGs[i].nId, 0);
    4157               6 :             poDictOCProperties->Add("OCGs", poArrayOGCs);
    4158                 :         }
    4159                 : 
    4160              53 :         if (nStructTreeRootId)
    4161                 :         {
    4162               3 :             GDALPDFDictionaryRW* poDictMarkInfo = new GDALPDFDictionaryRW();
    4163               3 :             oDict.Add("MarkInfo", poDictMarkInfo);
    4164               3 :             poDictMarkInfo->Add("UserProperties", GDALPDFObjectRW::CreateBool(TRUE));
    4165                 : 
    4166               3 :             oDict.Add("StructTreeRoot", nStructTreeRootId, 0);
    4167                 :         }
    4168                 : 
    4169              53 :         if (nNamesId)
    4170               1 :             oDict.Add("Names", nNamesId, 0);
    4171                 : 
    4172              53 :         VSIFPrintfL(fp, "%s\n", oDict.Serialize().c_str());
    4173                 :     }
    4174              53 :     EndObj();
    4175              53 : }
    4176                 : 
    4177                 : /************************************************************************/
    4178                 : /*                        GDALPDFGetJPEGQuality()                       */
    4179                 : /************************************************************************/
    4180                 : 
    4181              56 : static int GDALPDFGetJPEGQuality(char** papszOptions)
    4182                 : {
    4183              56 :     int nJpegQuality = -1;
    4184              56 :     const char* pszValue = CSLFetchNameValue( papszOptions, "JPEG_QUALITY" );
    4185              56 :     if( pszValue  != NULL )
    4186                 :     {
    4187               0 :         nJpegQuality = atoi( pszValue );
    4188               0 :         if (!(nJpegQuality >= 1 && nJpegQuality <= 100))
    4189                 :         {
    4190                 :             CPLError( CE_Warning, CPLE_IllegalArg,
    4191                 :                     "JPEG_QUALITY=%s value not recognised, ignoring.",
    4192               0 :                     pszValue );
    4193               0 :             nJpegQuality = -1;
    4194                 :         }
    4195                 :     }
    4196              56 :     return nJpegQuality;
    4197                 : }
    4198                 : 
    4199                 : /************************************************************************/
    4200                 : /*                         GDALPDFClippingDataset                       */
    4201                 : /************************************************************************/
    4202                 : 
    4203                 : class GDALPDFClippingDataset: public GDALDataset
    4204               1 : {
    4205                 :         GDALDataset* poSrcDS;
    4206                 :         double adfGeoTransform[6];
    4207                 : 
    4208                 :     public:
    4209               1 :         GDALPDFClippingDataset(GDALDataset* poSrcDS, double adfClippingExtent[4]) : poSrcDS(poSrcDS)
    4210                 :         {
    4211                 :             double adfSrcGeoTransform[6];
    4212               1 :             poSrcDS->GetGeoTransform(adfSrcGeoTransform);
    4213               1 :             adfGeoTransform[0] = adfClippingExtent[0];
    4214               1 :             adfGeoTransform[1] = adfSrcGeoTransform[1];
    4215               1 :             adfGeoTransform[2] = 0.0;
    4216               1 :             adfGeoTransform[3] = adfSrcGeoTransform[5] < 0 ? adfClippingExtent[3] : adfClippingExtent[1];
    4217               1 :             adfGeoTransform[4] = 0.0;
    4218               1 :             adfGeoTransform[5] = adfSrcGeoTransform[5];
    4219               1 :             nRasterXSize = (int)((adfClippingExtent[2] - adfClippingExtent[0]) / adfSrcGeoTransform[1]);
    4220               1 :             nRasterYSize = (int)((adfClippingExtent[3] - adfClippingExtent[1]) / fabs(adfSrcGeoTransform[5]));
    4221               1 :         }
    4222                 : 
    4223               3 :         virtual CPLErr GetGeoTransform( double * padfGeoTransform )
    4224                 :         {
    4225               3 :             memcpy(padfGeoTransform, adfGeoTransform, 6 * sizeof(double));
    4226               3 :             return CE_None;
    4227                 :         }
    4228                 : 
    4229               1 :         virtual const char* GetProjectionRef()
    4230                 :         {
    4231               1 :             return poSrcDS->GetProjectionRef();
    4232                 :         }
    4233                 : };
    4234                 : 
    4235                 : /************************************************************************/
    4236                 : /*                          GDALPDFCreateCopy()                         */
    4237                 : /************************************************************************/
    4238                 : 
    4239              69 : GDALDataset *GDALPDFCreateCopy( const char * pszFilename,
    4240                 :                                 GDALDataset *poSrcDS,
    4241                 :                                 int bStrict,
    4242                 :                                 char **papszOptions,
    4243                 :                                 GDALProgressFunc pfnProgress,
    4244                 :                                 void * pProgressData )
    4245                 : {
    4246              69 :     int  nBands = poSrcDS->GetRasterCount();
    4247              69 :     int  nWidth = poSrcDS->GetRasterXSize();
    4248              69 :     int  nHeight = poSrcDS->GetRasterYSize();
    4249                 : 
    4250              69 :     if( !pfnProgress( 0.0, NULL, pProgressData ) )
    4251               0 :         return NULL;
    4252                 : 
    4253                 : /* -------------------------------------------------------------------- */
    4254                 : /*      Some some rudimentary checks                                    */
    4255                 : /* -------------------------------------------------------------------- */
    4256              69 :     if( nBands != 1 && nBands != 3 && nBands != 4 )
    4257                 :     {
    4258                 :         CPLError( CE_Failure, CPLE_NotSupported,
    4259                 :                   "PDF driver doesn't support %d bands.  Must be 1 (grey or with color table), "
    4260               3 :                   "3 (RGB) or 4 bands.\n", nBands );
    4261                 : 
    4262               3 :         return NULL;
    4263                 :     }
    4264                 : 
    4265              66 :     GDALDataType eDT = poSrcDS->GetRasterBand(1)->GetRasterDataType();
    4266              66 :     if( eDT != GDT_Byte )
    4267                 :     {
    4268                 :         CPLError( (bStrict) ? CE_Failure : CE_Warning, CPLE_NotSupported,
    4269                 :                   "PDF driver doesn't support data type %s. "
    4270                 :                   "Only eight bit byte bands supported.\n",
    4271                 :                   GDALGetDataTypeName(
    4272              10 :                       poSrcDS->GetRasterBand(1)->GetRasterDataType()) );
    4273                 : 
    4274              10 :         if (bStrict)
    4275              10 :             return NULL;
    4276                 :     }
    4277                 : 
    4278                 : /* -------------------------------------------------------------------- */
    4279                 : /*     Read options.                                                    */
    4280                 : /* -------------------------------------------------------------------- */
    4281              56 :     PDFCompressMethod eCompressMethod = COMPRESS_DEFAULT;
    4282              56 :     const char* pszCompressMethod = CSLFetchNameValue(papszOptions, "COMPRESS");
    4283              56 :     if (pszCompressMethod)
    4284                 :     {
    4285               9 :         if( EQUAL(pszCompressMethod, "NONE") )
    4286               1 :             eCompressMethod = COMPRESS_NONE;
    4287               8 :         else if( EQUAL(pszCompressMethod, "DEFLATE") )
    4288               0 :             eCompressMethod = COMPRESS_DEFLATE;
    4289               8 :         else if( EQUAL(pszCompressMethod, "JPEG") )
    4290               3 :             eCompressMethod = COMPRESS_JPEG;
    4291               5 :         else if( EQUAL(pszCompressMethod, "JPEG2000") )
    4292               5 :             eCompressMethod = COMPRESS_JPEG2000;
    4293                 :         else
    4294                 :         {
    4295                 :             CPLError( (bStrict) ? CE_Failure : CE_Warning, CPLE_NotSupported,
    4296               0 :                     "Unsupported value for COMPRESS.");
    4297                 : 
    4298               0 :             if (bStrict)
    4299               0 :                 return NULL;
    4300                 :         }
    4301                 :     }
    4302                 : 
    4303              56 :     PDFCompressMethod eStreamCompressMethod = COMPRESS_DEFLATE;
    4304              56 :     const char* pszStreamCompressMethod = CSLFetchNameValue(papszOptions, "STREAM_COMPRESS");
    4305              56 :     if (pszStreamCompressMethod)
    4306                 :     {
    4307               2 :         if( EQUAL(pszStreamCompressMethod, "NONE") )
    4308               2 :             eStreamCompressMethod = COMPRESS_NONE;
    4309               0 :         else if( EQUAL(pszStreamCompressMethod, "DEFLATE") )
    4310               0 :             eStreamCompressMethod = COMPRESS_DEFLATE;
    4311                 :         else
    4312                 :         {
    4313                 :             CPLError( (bStrict) ? CE_Failure : CE_Warning, CPLE_NotSupported,
    4314               0 :                     "Unsupported value for STREAM_COMPRESS.");
    4315                 : 
    4316               0 :             if (bStrict)
    4317               0 :                 return NULL;
    4318                 :         }
    4319                 :     }
    4320                 : 
    4321              98 :     if (nBands == 1 &&
    4322              42 :         poSrcDS->GetRasterBand(1)->GetColorTable() != NULL &&
    4323                 :         (eCompressMethod == COMPRESS_JPEG || eCompressMethod == COMPRESS_JPEG2000))
    4324                 :     {
    4325                 :         CPLError( CE_Warning, CPLE_AppDefined,
    4326                 :                   "The source raster band has a color table, which is not appropriate with JPEG or JPEG2000 compression.\n"
    4327               0 :                   "You should rather consider using color table expansion (-expand option in gdal_translate)");
    4328                 :     }
    4329                 : 
    4330                 : 
    4331              56 :     int nBlockXSize = nWidth;
    4332              56 :     int nBlockYSize = nHeight;
    4333                 :     const char* pszValue;
    4334                 : 
    4335              56 :     int bTiled = CSLFetchBoolean( papszOptions, "TILED", FALSE );
    4336              56 :     if( bTiled )
    4337               1 :         nBlockXSize = nBlockYSize = 256;
    4338                 : 
    4339              56 :     pszValue = CSLFetchNameValue(papszOptions, "BLOCKXSIZE");
    4340              56 :     if( pszValue != NULL )
    4341                 :     {
    4342               3 :         nBlockXSize = atoi( pszValue );
    4343               3 :         if (nBlockXSize < 0 || nBlockXSize >= nWidth)
    4344               0 :             nBlockXSize = nWidth;
    4345                 :     }
    4346                 : 
    4347              56 :     pszValue = CSLFetchNameValue(papszOptions, "BLOCKYSIZE");
    4348              56 :     if( pszValue != NULL )
    4349                 :     {
    4350               3 :         nBlockYSize = atoi( pszValue );
    4351               3 :         if (nBlockYSize < 0 || nBlockYSize >= nHeight)
    4352               0 :             nBlockYSize = nHeight;
    4353                 :     }
    4354                 : 
    4355              56 :     int nJPEGQuality = GDALPDFGetJPEGQuality(papszOptions);
    4356                 : 
    4357              56 :     const char* pszJPEG2000_DRIVER = CSLFetchNameValue(papszOptions, "JPEG2000_DRIVER");
    4358                 : 
    4359                 :     const char* pszGEO_ENCODING =
    4360              56 :         CSLFetchNameValueDef(papszOptions, "GEO_ENCODING", "ISO32000");
    4361                 : 
    4362              56 :     const char* pszXMP = CSLFetchNameValue(papszOptions, "XMP");
    4363                 : 
    4364              56 :     double dfDPI = atof(CSLFetchNameValueDef(papszOptions, "DPI", "72"));
    4365              56 :     if (dfDPI < 72.0)
    4366               0 :         dfDPI = 72.0;
    4367                 : 
    4368              56 :     const char* pszPredictor = CSLFetchNameValue(papszOptions, "PREDICTOR");
    4369              56 :     int nPredictor = 1;
    4370              56 :     if (pszPredictor)
    4371                 :     {
    4372               2 :         if (eCompressMethod == COMPRESS_DEFAULT)
    4373               2 :             eCompressMethod = COMPRESS_DEFLATE;
    4374                 : 
    4375               2 :         if (eCompressMethod != COMPRESS_DEFLATE)
    4376                 :         {
    4377                 :             CPLError(CE_Warning, CPLE_NotSupported,
    4378               0 :                      "PREDICTOR option is only taken into account for DEFLATE compression");
    4379                 :         }
    4380                 :         else
    4381                 :         {
    4382               2 :             nPredictor = atoi(pszPredictor);
    4383               2 :             if (nPredictor != 1 && nPredictor != 2)
    4384                 :             {
    4385                 :                 CPLError(CE_Warning, CPLE_NotSupported,
    4386               0 :                                     "Supported PREDICTOR values are 1 or 2");
    4387               0 :                 nPredictor = 1;
    4388                 :             }
    4389                 :         }
    4390                 :     }
    4391                 : 
    4392              56 :     const char* pszNEATLINE = CSLFetchNameValue(papszOptions, "NEATLINE");
    4393                 : 
    4394              56 :     int nMargin = atoi(CSLFetchNameValueDef(papszOptions, "MARGIN", "0"));
    4395                 : 
    4396                 :     PDFMargins sMargins;
    4397              56 :     sMargins.nLeft = nMargin;
    4398              56 :     sMargins.nRight = nMargin;
    4399              56 :     sMargins.nTop = nMargin;
    4400              56 :     sMargins.nBottom = nMargin;
    4401                 : 
    4402              56 :     const char* pszLeftMargin = CSLFetchNameValue(papszOptions, "LEFT_MARGIN");
    4403              56 :     if (pszLeftMargin) sMargins.nLeft = atoi(pszLeftMargin);
    4404                 : 
    4405              56 :     const char* pszRightMargin = CSLFetchNameValue(papszOptions, "RIGHT_MARGIN");
    4406              56 :     if (pszRightMargin) sMargins.nRight = atoi(pszRightMargin);
    4407                 : 
    4408              56 :     const char* pszTopMargin = CSLFetchNameValue(papszOptions, "TOP_MARGIN");
    4409              56 :     if (pszTopMargin) sMargins.nTop = atoi(pszTopMargin);
    4410                 : 
    4411              56 :     const char* pszBottomMargin = CSLFetchNameValue(papszOptions, "BOTTOM_MARGIN");
    4412              56 :     if (pszBottomMargin) sMargins.nBottom = atoi(pszBottomMargin);
    4413                 : 
    4414              56 :     const char* pszClippingExtent = CSLFetchNameValue(papszOptions, "CLIPPING_EXTENT");
    4415              56 :     int bUseClippingExtent = FALSE;
    4416              56 :     double adfClippingExtent[4] = { 0.0, 0.0, 0.0, 0.0 };
    4417              56 :     if( pszClippingExtent != NULL )
    4418                 :     {
    4419               1 :         char** papszTokens = CSLTokenizeString2(pszClippingExtent, ",", 0);
    4420               1 :         if( CSLCount(papszTokens) == 4 )
    4421                 :         {
    4422               1 :             bUseClippingExtent = TRUE;
    4423               1 :             adfClippingExtent[0] = CPLAtof(papszTokens[0]);
    4424               1 :             adfClippingExtent[1] = CPLAtof(papszTokens[1]);
    4425               1 :             adfClippingExtent[2] = CPLAtof(papszTokens[2]);
    4426               1 :             adfClippingExtent[3] = CPLAtof(papszTokens[3]);
    4427               2 :             if( adfClippingExtent[0] > adfClippingExtent[2] ||
    4428               1 :                 adfClippingExtent[1] > adfClippingExtent[3] )
    4429                 :             {
    4430                 :                 CPLError(CE_Warning, CPLE_AppDefined,
    4431               0 :                          "Invalid value for CLIPPING_EXTENT. Should be xmin,ymin,xmax,ymax");
    4432               0 :                 bUseClippingExtent = TRUE;
    4433                 :             }
    4434                 : 
    4435               1 :             if( bUseClippingExtent )
    4436                 :             {
    4437                 :                 double adfGeoTransform[6];
    4438               1 :                 if( poSrcDS->GetGeoTransform(adfGeoTransform) == CE_None )
    4439                 :                 {
    4440               1 :                     if( adfGeoTransform[2] != 0.0 || adfGeoTransform[4] != 0.0 )
    4441                 :                     {
    4442                 :                         CPLError(CE_Warning, CPLE_AppDefined,
    4443               0 :                                 "Cannot use CLIPPING_EXTENT because main raster has a rotated geotransform");
    4444               0 :                         bUseClippingExtent = TRUE;
    4445                 :                     }
    4446                 :                 }
    4447                 :                 else
    4448                 :                 {
    4449                 :                     CPLError(CE_Warning, CPLE_AppDefined,
    4450               0 :                                 "Cannot use CLIPPING_EXTENT because main raster has no geotransform");
    4451               0 :                     bUseClippingExtent = TRUE;
    4452                 :                 }
    4453                 :             }
    4454                 :         }
    4455               1 :         CSLDestroy(papszTokens);
    4456                 :     }
    4457                 : 
    4458              56 :     const char* pszLayerName = CSLFetchNameValue(papszOptions, "LAYER_NAME");
    4459                 : 
    4460              56 :     const char* pszExtraImages = CSLFetchNameValue(papszOptions, "EXTRA_IMAGES");
    4461              56 :     const char* pszExtraStream = CSLFetchNameValue(papszOptions, "EXTRA_STREAM");
    4462              56 :     const char* pszExtraLayerName = CSLFetchNameValue(papszOptions, "EXTRA_LAYER_NAME");
    4463                 : 
    4464              56 :     const char* pszOGRDataSource = CSLFetchNameValue(papszOptions, "OGR_DATASOURCE");
    4465              56 :     const char* pszOGRDisplayField = CSLFetchNameValue(papszOptions, "OGR_DISPLAY_FIELD");
    4466              56 :     const char* pszOGRDisplayLayerNames = CSLFetchNameValue(papszOptions, "OGR_DISPLAY_LAYER_NAMES");
    4467              56 :     const char* pszOGRLinkField = CSLFetchNameValue(papszOptions, "OGR_LINK_FIELD");
    4468              56 :     int bWriteOGRAttributes = CSLFetchBoolean(papszOptions, "OGR_WRITE_ATTRIBUTES", TRUE);
    4469                 : 
    4470              56 :     const char* pszExtraRasters = CSLFetchNameValue(papszOptions, "EXTRA_RASTERS");
    4471              56 :     const char* pszExtraRastersLayerName = CSLFetchNameValue(papszOptions, "EXTRA_RASTERS_LAYER_NAME");
    4472                 :     
    4473              56 :     const char* pszOffLayers = CSLFetchNameValue(papszOptions, "OFF_LAYERS");
    4474              56 :     const char* pszExclusiveLayers = CSLFetchNameValue(papszOptions, "EXCLUSIVE_LAYERS");
    4475                 : 
    4476              56 :     const char* pszJavascript = CSLFetchNameValue(papszOptions, "JAVASCRIPT");
    4477              56 :     const char* pszJavascriptFile = CSLFetchNameValue(papszOptions, "JAVASCRIPT_FILE");
    4478                 : 
    4479                 : /* -------------------------------------------------------------------- */
    4480                 : /*      Create file.                                                    */
    4481                 : /* -------------------------------------------------------------------- */
    4482              56 :     VSILFILE* fp = VSIFOpenL(pszFilename, "wb");
    4483              56 :     if( fp == NULL )
    4484                 :     {
    4485                 :         CPLError( CE_Failure, CPLE_OpenFailed,
    4486                 :                   "Unable to create PDF file %s.\n",
    4487               5 :                   pszFilename );
    4488               5 :         return NULL;
    4489                 :     }
    4490                 : 
    4491                 : 
    4492              51 :     GDALPDFWriter oWriter(fp);
    4493                 : 
    4494              51 :     GDALDataset* poClippingDS = poSrcDS;
    4495              51 :     if( bUseClippingExtent )
    4496               1 :         poClippingDS = new GDALPDFClippingDataset(poSrcDS, adfClippingExtent);
    4497                 : 
    4498              51 :     if( CSLFetchBoolean(papszOptions, "WRITE_INFO", TRUE) )
    4499              50 :         oWriter.SetInfo(poSrcDS, papszOptions);
    4500              51 :     oWriter.SetXMP(poClippingDS, pszXMP);
    4501                 : 
    4502                 :     oWriter.StartPage(poClippingDS,
    4503                 :                       dfDPI,
    4504                 :                       pszGEO_ENCODING,
    4505                 :                       pszNEATLINE,
    4506                 :                       &sMargins,
    4507                 :                       eStreamCompressMethod,
    4508              51 :                       pszOGRDataSource != NULL && bWriteOGRAttributes);
    4509                 : 
    4510                 :     int bRet;
    4511                 : 
    4512              51 :     if( !bUseClippingExtent )
    4513                 :     {
    4514                 :         bRet = oWriter.WriteImagery(poSrcDS,
    4515                 :                                     pszLayerName,
    4516                 :                                     eCompressMethod,
    4517                 :                                     nPredictor,
    4518                 :                                     nJPEGQuality,
    4519                 :                                     pszJPEG2000_DRIVER,
    4520                 :                                     nBlockXSize, nBlockYSize,
    4521              50 :                                     pfnProgress, pProgressData);
    4522                 :     }
    4523                 :     else
    4524                 :     {
    4525                 :         bRet = oWriter.WriteClippedImagery(poSrcDS,
    4526                 :                                            pszLayerName,
    4527                 :                                            eCompressMethod,
    4528                 :                                            nPredictor,
    4529                 :                                            nJPEGQuality,
    4530                 :                                            pszJPEG2000_DRIVER,
    4531                 :                                            nBlockXSize, nBlockYSize,
    4532               1 :                                            pfnProgress, pProgressData);
    4533                 :     }
    4534                 : 
    4535                 :     char** papszExtraRasters = CSLTokenizeString2(
    4536              51 :         pszExtraRasters ? pszExtraRasters : "", ",", 0);
    4537                 :     char** papszExtraRastersLayerName = CSLTokenizeString2(
    4538              51 :         pszExtraRastersLayerName ? pszExtraRastersLayerName : "", ",", 0);
    4539                 :     int bUseExtraRastersLayerName = (CSLCount(papszExtraRasters) ==
    4540              51 :                                      CSLCount(papszExtraRastersLayerName));
    4541              51 :     int bUseExtraRasters = TRUE;
    4542                 : 
    4543              51 :     const char* pszClippingProjectionRef = poSrcDS->GetProjectionRef();
    4544              51 :     if( CSLCount(papszExtraRasters) != 0 )
    4545                 :     {
    4546                 :         double adfGeoTransform[6];
    4547               1 :         if( poSrcDS->GetGeoTransform(adfGeoTransform) == CE_None )
    4548                 :         {
    4549               1 :             if( adfGeoTransform[2] != 0.0 || adfGeoTransform[4] != 0.0 )
    4550                 :             {
    4551                 :                 CPLError(CE_Warning, CPLE_AppDefined,
    4552               0 :                          "Cannot use EXTRA_RASTERS because main raster has a rotated geotransform");
    4553               0 :                 bUseExtraRasters = FALSE;
    4554                 :             }
    4555                 :         }
    4556                 :         else
    4557                 :         {
    4558                 :             CPLError(CE_Warning, CPLE_AppDefined,
    4559               0 :                          "Cannot use EXTRA_RASTERS because main raster has no geotransform");
    4560               0 :             bUseExtraRasters = FALSE;
    4561                 :         }
    4562               2 :         if( bUseExtraRasters &&
    4563                 :             (pszClippingProjectionRef == NULL ||
    4564               1 :              pszClippingProjectionRef[0] == '\0') )
    4565                 :         {
    4566                 :             CPLError(CE_Warning, CPLE_AppDefined,
    4567               0 :                      "Cannot use EXTRA_RASTERS because main raster has no projection");
    4568               0 :             bUseExtraRasters = FALSE;
    4569                 :         }
    4570                 :     }
    4571                 : 
    4572              52 :     for(int i=0; bRet && bUseExtraRasters && papszExtraRasters[i] != NULL; i++)
    4573                 :     {
    4574               1 :         GDALDataset* poDS = (GDALDataset*)GDALOpen(papszExtraRasters[i], GA_ReadOnly);
    4575               1 :         if( poDS != NULL )
    4576                 :         {
    4577                 :             double adfGeoTransform[6];
    4578               1 :             int bUseRaster = TRUE;
    4579               1 :             if( poDS->GetGeoTransform(adfGeoTransform) == CE_None )
    4580                 :             {
    4581               1 :                 if( adfGeoTransform[2] != 0.0 || adfGeoTransform[4] != 0.0 )
    4582                 :                 {
    4583                 :                     CPLError(CE_Warning, CPLE_AppDefined,
    4584                 :                             "Cannot use %s because it has a rotated geotransform",
    4585               0 :                              papszExtraRasters[i]);
    4586               0 :                     bUseRaster = FALSE;
    4587                 :                 }
    4588                 :             }
    4589                 :             else
    4590                 :             {
    4591                 :                 CPLError(CE_Warning, CPLE_AppDefined,
    4592                 :                             "Cannot use %s because it has no geotransform",
    4593               0 :                          papszExtraRasters[i]);
    4594               0 :                 bUseRaster = FALSE;
    4595                 :             }
    4596               1 :             const char* pszProjectionRef = poDS->GetProjectionRef();
    4597               2 :             if( bUseRaster &&
    4598               1 :                 (pszProjectionRef == NULL || pszProjectionRef[0] == '\0')  )
    4599                 :             {
    4600                 :                 CPLError(CE_Warning, CPLE_AppDefined,
    4601                 :                          "Cannot use %s because it has no projection",
    4602               0 :                          papszExtraRasters[i]);
    4603               0 :                 bUseRaster = FALSE;
    4604                 :             }
    4605               1 :             if( bUseRaster )
    4606                 :             {
    4607               1 :                 if( pszClippingProjectionRef != NULL &&
    4608                 :                     pszProjectionRef != NULL &&
    4609                 :                     !EQUAL(pszClippingProjectionRef, pszProjectionRef) )
    4610                 :                 {
    4611                 :                     OGRSpatialReferenceH hClippingSRS =
    4612               0 :                         OSRNewSpatialReference(pszClippingProjectionRef);
    4613                 :                     OGRSpatialReferenceH hSRS =
    4614               0 :                         OSRNewSpatialReference(pszProjectionRef);
    4615               0 :                     if (!OSRIsSame(hClippingSRS, hSRS))
    4616                 :                     {
    4617                 :                         CPLError(CE_Warning, CPLE_AppDefined,
    4618                 :                                 "Cannot use %s because it has a different projection than main dataset",
    4619               0 :                                 papszExtraRasters[i]);
    4620               0 :                         bUseRaster = FALSE;
    4621                 :                     }
    4622               0 :                     OSRDestroySpatialReference(hClippingSRS);
    4623               0 :                     OSRDestroySpatialReference(hSRS);
    4624                 :                 }
    4625                 :             }
    4626               1 :             if( bUseRaster )
    4627                 :             {
    4628                 :                 bRet = oWriter.WriteClippedImagery(poDS,
    4629                 :                                     bUseExtraRastersLayerName ?
    4630               1 :                                         papszExtraRastersLayerName[i] : NULL,
    4631                 :                                     eCompressMethod,
    4632                 :                                     nPredictor,
    4633                 :                                     nJPEGQuality,
    4634                 :                                     pszJPEG2000_DRIVER,
    4635                 :                                     nBlockXSize, nBlockYSize,
    4636               2 :                                     NULL, NULL);
    4637                 :             }
    4638                 : 
    4639               1 :             GDALClose(poDS);
    4640                 :         }
    4641                 :     }
    4642                 : 
    4643              51 :     CSLDestroy(papszExtraRasters);
    4644              51 :     CSLDestroy(papszExtraRastersLayerName);
    4645                 : 
    4646                 : #ifdef OGR_ENABLED
    4647              51 :     if (bRet && pszOGRDataSource != NULL)
    4648                 :         oWriter.WriteOGRDataSource(pszOGRDataSource,
    4649                 :                                    pszOGRDisplayField,
    4650                 :                                    pszOGRDisplayLayerNames,
    4651                 :                                    pszOGRLinkField,
    4652               2 :                                    bWriteOGRAttributes);
    4653                 : #endif
    4654                 : 
    4655              51 :     if (bRet)
    4656                 :         oWriter.EndPage(pszExtraImages,
    4657                 :                         pszExtraStream,
    4658                 :                         pszExtraLayerName,
    4659                 :                         pszOffLayers,
    4660              51 :                         pszExclusiveLayers);
    4661                 : 
    4662              51 :     if (pszJavascript)
    4663               1 :         oWriter.WriteJavascript(pszJavascript);
    4664              50 :     else if (pszJavascriptFile)
    4665               0 :         oWriter.WriteJavascriptFile(pszJavascriptFile);
    4666                 : 
    4667              51 :     oWriter.Close();
    4668                 :     
    4669              51 :     if (poClippingDS != poSrcDS)
    4670               1 :         delete poClippingDS;
    4671                 : 
    4672              51 :     if (!bRet)
    4673                 :     {
    4674               0 :         VSIUnlink(pszFilename);
    4675               0 :         return NULL;
    4676                 :     }
    4677                 :     else
    4678                 :     {
    4679                 : #if defined(HAVE_POPPLER) || defined(HAVE_PODOFO)
    4680              51 :         return (GDALDataset*) GDALOpen(pszFilename, GA_ReadOnly);
    4681                 : #else
    4682                 :         return new GDALFakePDFDataset();
    4683                 : #endif
    4684               0 :     }
    4685            2274 : }

Generated by: LCOV version 1.7