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